├── audio_summary.md
├── cordova_learing.md
└── img
├── audio_summary
├── audio_tag.jpg
└── web_audio_support.jpg
└── cordova_learning
├── accelerator.JPG
├── api19.JPG
├── chrome.JPG
├── intel image.JPG
├── vitural.JPG
└── webview.JPG
/audio_summary.md:
--------------------------------------------------------------------------------
1 |
2 | # 移动端音频解决方案
3 |
4 | ## 音频传输原理
5 |
6 | 目前音频在互联网上的传输基于流媒体技术, 音频是流媒体的一种, 称其为流媒体是一种形象的比喻, 将数据的传输比作水流, "流"的重要作用体现在可以明显的节省时间, 实现边下载边播放, 而不需要下载完成后才进行播放.
7 |
8 | * 缓存
9 |
10 | 流媒体的传输需要缓存, 因为Internet是一个分组交换网, 在其上面传输文件数据都要拆分成一个个数据包, 最后在接收端进行组装, 由于网络是动态变化的, 各个数据包选择的路由可能不尽相同, 故到达客户端的时间延迟也就不等, 先发的数据后到也是常有的事. 因此, 使用缓存来保证到达的数据包进行正确的排序, 从而使媒体数据能连续输出.
11 |
12 | 之前提到的边下边播, 也是在缓存中接收到足够的数据时才能进行播放的, 这一点在HTML5的文档中也有所体现.
13 |
14 | [ 题外话: HTML5 media 文档中, 提到了两个事件 'canplay' 和 'canplaythrough'.
15 | 'canplay': '表示浏览器已经加载了足够的数据去播放媒体文件, 但预计以后的播放可能会产生停顿去加载新的数据'
16 | 'canplaythrough': '表示浏览器已经加载了足够的数据去播放媒体文件并且预计在播放中不会产生停顿去加载新的数据' ]
17 |
18 | * UDP
19 |
20 | 流媒体传输的实现需要合适的传输协议. 由于TCP需要较多的开销, 因此不太适合传输实时数据. 在流媒体传输的实现方案中一般采用HTTP/TCP来传输控制信息, 使用RTP/UDP来传输实时声音数据.
21 |
22 | ## 目前可使用的技术
23 |
24 | * Web Audio API
25 |
26 | Web Auido API 是 JavaScript 中用于在网页应用中处理音频的一个高级应该用接口, 主要用于实现Web端的音频处理, 并可以同已存在的其他API相配合, 包括XMLHttpRequest, Canvas 2D 和 WebGL 3D API.
27 |
28 | 其支持的功能包括
29 |
30 | * 支持各种类型的音频滤波器以实现各种音频效果, 包括回声, 消除噪音等
31 | * 支持利用合成声音 (Sound synthesis) 创建电子音乐
32 | * 支持3D位置音频模拟效果, 比如某种声音随着游戏场景而移动 (3D游戏中应该用处比较大...)
33 | * 支持外部输入的声音与 WebRTC 进行集成
34 | * 以及各种高端音频处理方法...
35 |
36 | 但是...
37 |
38 | 由于移动端对其支持不是很完善 [ iOS已支持, 安卓原生浏览器目前还不支持 ], 目前还是使用支持广泛的 HTML5 Audio 好一些
39 |
40 | 
41 |
42 | * HTML5 Audio 标签
43 |
44 | 
45 |
46 | Audio 标签是 HTML5 新定义的一个元素, 提供了在 Web 端播放音频的很多功能. 虽然没有 Web Audio API 那么强大, 但足以满足日常音频播放需求, 更重要的是使浏览器原生支持音频播放, 而不依赖 Flash 或 Sliverlight 之类的外部插件
47 |
48 |
49 | ## 移动端音频可能存在的坑及解决方案
50 |
51 | * 编码格式
52 |
53 | audio 元素可以包含多个音频资源, 这些音频资源可以使用 src 属性或者 source 元素来进行描述, 浏览器会选择最适合的一个来使用.
54 |
55 | 浏览器不仅要支持 audio 标签而且要支持相应的格式, 并不是所有浏览器都支持相同的音频文件格式.
56 |
57 | 目前主有三种主要格式.
58 |
59 | * MP3: MPEG-1 Audio Layer
60 | * OGG: 一种开放容器格式 (open container format)
61 | * AAC: 高级音频编码 (Advanced Audio Coding)
62 |
63 | * 属性相关 [ 注: webview 为来往客户端 ]
64 |
65 | * autoplay
66 |
67 | 描述: 布尔值, 用来指定音频在加载完成后自动播放. 如果被指定, 即使值为 false, 音频依然会在数据加载到预计可以不停顿的播放到结尾时开始自动播放.
68 |
69 | 测试代码:
70 |
71 | ```
72 |
73 | ```
74 | 测试结果:
75 |
76 | 安卓 4.4 webview 页面载入后播放
77 |
78 | 安卓 Chrome35 页面载入后不播放 (需用户触发事件, 才会进行播放)
79 |
80 | iOS 7 webview 页面载入后播放
81 |
82 | iOS 7 Safari 页面载入后不播放 (需用户触发事件, 才会进行播放)
83 |
84 | 解决方案:
85 | AJAX加载, 需 Web Audio API 支持, 可解决安卓移动版Chrome问题, 无需用户触发, 但是解码音频数据需要消耗较长时间.
86 | ```
87 | var audio = document.querySelector('audio');
88 | var xhr = new XMLHttpRequest();
89 | xhr.open('GET', audio.src, true);
90 | xhr.responseType = 'arraybuffer';
91 | xhr.onload = function() {
92 | console.log('load [ok]');
93 | var ctx = new AudioContext();
94 | ctx.decodeAudioData(xhr.response, function(buffer) { // 解码音频数据, 较耗时
95 | if (buffer) {
96 | console.log('decode [ok]');
97 | var source = ctx.createBufferSource();
98 | source.buffer = buffer;
99 | source.connect(ctx.destination); // 将解码后的数据连接到 destination 节点, 用于播放
100 | console.log('play start...');
101 | source.noteOn(0); // 立即播放
102 | }
103 | })
104 | }
105 | xhr.send();
106 | ```
107 | 对于 iOS Safari 限制比较严格, 比较常见到的做法是在用户第一次 touchstart 时进行事件绑定.
108 |
109 | 下面是 howler.js 库针对 iOS 问题的做法
110 | ```
111 | _enableiOSAudio: function() {
112 | var self = this;
113 |
114 | // 已解除限制或非 iOS 设备不执行此函数
115 | if (ctx && (self._iOSEnabled || !/iPhone|iPad|iPod/i.test(navigator.userAgent))) {
116 | return;
117 | }
118 |
119 | self._iOSEnabled = false;
120 |
121 | // touchstart 事件函数
122 | // 创建并播放一个缓冲区, 然后通过检测音频是否播放来判断 iOS 的音频限制是否解除
123 | var unlock = function() {
124 | // iOS 支持 Web Audio API, 创建一个空的缓冲区 (单声道, 1帧, 22050赫兹)
125 | var buffer = ctx.createBuffer(1, 1, 22050);
126 | var source = ctx.createBufferSource();
127 | source.buffer = buffer;
128 | source.connect(ctx.destination);
129 |
130 | // 播放空缓冲区
131 | if (typeof source.start === 'undefined') {
132 | source.noteOn(0);
133 | } else {
134 | source.start(0);
135 | }
136 |
137 | // 在下一个事件循环检测 iOS 限制是否解除
138 | setTimeout(function() {
139 | if ((source.playbackState === source.PLAYING_STATE || source.playbackState === source.FINISHED_STATE)) {
140 | // 限制解除, 更新标志位并且防止 unlock 事件函数再次执行
141 | self._iOSEnabled = true;
142 | self.iOSAutoEnable = false;
143 |
144 | // 移除 touchstart 事件函数
145 | window.removeEventListener('touchstart', unlock, false);
146 | }
147 | }, 0);
148 | };
149 |
150 | // 绑定 touchstart 事件以解除限制
151 | window.addEventListener('touchstart', unlock, false);
152 |
153 | return self;
154 | }
155 | ```
156 |
157 | * buffered [未发现兼容性问题]
158 |
159 | 描述: 可以通过该属性获取已缓冲的资源时间段信息.
160 |
161 | * controls [未发现兼容性问题]
162 |
163 | 描述: 如果设置了该属性, 浏览器将提供一个包含声音, 播放进度, 播放暂停的控制面板, 让用户可以控制音频播放
164 |
165 | 测试代码:
166 |
167 | ```
168 |
169 | ```
170 |
171 | 测试结果:
172 |
173 | 安卓 4.4 webview 显示控制条
174 |
175 | 安卓 Chrome35 显示控制条
176 |
177 | iOS 7 webview 显示播放暂停控制块
178 |
179 | iOS 7 Safari 显示播放暂停控制块
180 |
181 | * loop [未发现兼容性问题]
182 |
183 | 描述: 布尔值, 如果指定, 将循环播放音频
184 |
185 | 测试代码:
186 |
187 | ```
188 |
189 | ```
190 |
191 | 测试结果:
192 |
193 | 安卓 4.4 webview 循环播放
194 |
195 | 安卓 Chrome35 循环播放
196 |
197 | iOS 7 webview 循环播放
198 |
199 | iOS 7 Safari 循环播放
200 |
201 | * muted
202 |
203 | 描述: 表示是否静音的布尔值. 默认值为 false, 表示有声音
204 |
205 | 注: 更改 muted 值后即时生效.
206 |
207 | 安卓 4.4 webview 可读写
208 |
209 | 安卓 Chrome35 可读写
210 |
211 | iOS 7 webview 只读
212 |
213 | iOS 7 Safari 只读
214 |
215 | * played
216 |
217 | 描述: 一个 TimeRange 对象, 表示所有已播放的声音片段
218 |
219 | * preload [ none | metadata | auto ]
220 |
221 | 描述: 枚举属性, 选择音频预加载方式, autoplay 属性优先于 preload, 即设置了 autoplay 属性后 preload 将不起作用.
222 |
223 | * none: 不进行预加载, 需要播放时进行加载
224 | * metadata: 不会预加载整个音频, 但对元数据(包括音频长度等音频相关信息)进行预加载
225 | * auto: 预加载全部音频 [ 空字符串代表 auto ]
226 |
227 | 默认: 浏览器自行选择
228 |
229 | 测试代码:
230 |
231 | ```
232 |
233 | ```
234 | 测试结果:
235 |
236 | 移动端除非由用户交互事件触发, 比如 onclick, ontouchstart 触发事件, 否则不会加载音频流.
237 |
238 | 解决方案:
239 |
240 | 支持 Web Audio API 可以采用和 autoplay 同样的方法. iOS 设备可以在第一次用户交互时添加事件函数解除限制, 见 autoplay 部分.
241 |
242 | * src [未发现兼容性问题]
243 |
244 | 描述: 用于描述嵌入音频的URL, 也可以在 audio 元素中使用 source 元素来代替该属性指定嵌入的音频
245 |
246 | 注: 动态变更 src 地址时, 会暂停之前正在播放的音频, 当再次播放时采用变更后的地址.
247 |
248 | * volume [ 0.0 - 1.0 ]
249 |
250 | 描述: 音频播放的音量, 0 为无声, 1 为最大声
251 |
252 | 注: 更改 volume 值后即时生效.
253 |
254 | 测试结果:
255 |
256 | 安卓 4.4 webview 可读写
257 |
258 | 安卓 Chrome35 可读写
259 |
260 | iOS 7 webview 只读
261 |
262 | iOS 7 Safari 只读
263 |
264 | * 方法相关
265 |
266 | * canPlayType()
267 |
268 | 描述: 给出浏览器是否能播放指定类型的媒体
269 |
270 | * "probably" : 浏览器最核能支持该类型媒体
271 | * "maybe" : 浏览器也许支持该类型媒体
272 | * "" : 浏览器不支持该类型媒体
273 |
274 | * load()
275 |
276 | 描述: 载入指定音频文件
277 |
278 | 移动端 load 函数无效, 在需要播放时进行加载
279 |
280 | * pause()
281 |
282 | 描述: 暂停音频播放
283 |
284 | * play()
285 |
286 | 描述: 播放音频
287 |
288 | 安卓 4.4 webview 调用无限制
289 |
290 | 安卓 Chrome35 需要在交互事件函数中调用 (如 click, touchstart) 以解除调用限制, 之后的调用无限制
291 |
292 | iOS 7 webview 调用无限制
293 |
294 | iOS 7 Safari 同 Chrome 表现一致, 需要在交互事件函数中调用 (如 click, touchstart) 以解除调用限制, 之后的调用无限制
295 |
296 | 测试代码:
297 | ```
298 | playCtl.addEventListener('click', function() {
299 | audio.play();
300 | }, false);
301 | stopCtl.addEventListener('click', function() {
302 | audio.pause();
303 | audio.currentTime = 0;
304 | }, false);
305 | setTimeout(function() {
306 | // chrome & safari
307 | // 1. 10s 内不点击 playCtl, 则此函数无效
308 | // 2. 10s 内点击 playCtl, 后调用stopCtl, 10s 后开始播放
309 | // webview
310 | // 10s 后自动播放
311 | audio.play();
312 | }, 10000);
313 | ```
314 |
315 | * 无 stop 函数
316 |
317 | 可采用 pause 函数 和 currentTime 属性配合的方式实现
318 |
319 | ```
320 | audio.pause();
321 | audio.currentTime = 0;
322 | ```
323 |
324 | * 并行播放 [ 播放第一个音频时, 执行另一个音频播放操作 ]
325 |
326 | 测试代码:
327 | ```
328 | ctl1.addEventListener('click', function() {
329 | audio1.play();
330 | }, false);
331 |
332 | ctl2.addEventListener('click', function() {
333 | audio2.play();
334 | }, false);
335 | ```
336 |
337 | 测试结果:
338 |
339 | 安卓 4.4 webview 播放新的音频会暂停之前播放的音频 [ 目前还木有发现较好的解决方案 ]
340 |
341 | 安卓 Chrome35 可以同时播放
342 |
343 | iOS 7 webview 可以同时播放
344 |
345 | iOS 7 Safari 可以同时播放
346 |
347 | ## PhoneGap (Cordova) 音频探索
348 |
349 | 详见 [ https://github.com/wangjx9110/document/blob/master/cordova_learing.md ]
350 |
351 | ## 总结
352 |
353 | 加载和并行播放是两个问题稍微多一些的地方, 针对自动加载后播放及其他一些小的兼容性问题推荐使用 howler.js 音频库 (sound.js貌似也很好还没有使用过) ,
354 | 并行播放问题目前还没有发现比较好的解决方法, 大家如果发现写的有什么错误或者有一些好的解决方案的话, 希望可以告诉我, 也欢迎大家一起交流填坑哈.
355 |
356 | ### 参考文献
357 |
358 | [ http://www.ibm.com/developerworks/cn/web/wa-ioshtml5/ ]
359 |
360 | [ https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio ]
361 |
362 | [ https://developer.mozilla.org/en-US/docs/Web/API/AudioContext.createBuffer ]
363 |
--------------------------------------------------------------------------------
/cordova_learing.md:
--------------------------------------------------------------------------------
1 | # Cordova (PhoneGap) 探索总结
2 |
3 | ## 目的
4 |
5 | 由于在探索 Cordova 的时候遇到了很多坑, 在此做下总结和分享. 大家看到有错误或不好的地方欢迎指正哈.
6 |
7 | ## 简介
8 |
9 | PhoneGap 是一个用基于 HTML, CSS 和 JavaScript 的, 创建移动跨平台移动应用程序的快速开发平台. 它使开发者能够利用 iPhone, Android, Palm, Symbian, WP7, Bada 和 Blackberry 智能手机的核心功能 —— 包括地理定位, 加速器, 联系人, 声音和振动等, 此外 PhoneGap 拥有丰富的插件, 可以调用.
10 |
11 | Cordova 是贡献给 Apache 后的开源项目, 是从 PhoneGap 中抽出的核心代码, 是驱动 PhoneGap 的核心引擎.
12 |
13 | ## 环境搭建
14 |
15 | * 相应开发平台的 SDK 包 [ 构建跨平台应用需要对应平台的开发包 ]
16 |
17 | 由于目前使用 Windows 系统, 采用 Android SDK 包作为探索.
18 |
19 | Android 开发包需要 Java 作为支持, 所以 Java SDK 的安装也是必须的.
20 |
21 | * Java SDK
22 |
23 | 地址: [ http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html ]
24 |
25 | 环境变量配置:
26 |
27 | [新增] JAVA_HOME: JDK 安装路径 [ 例: D:\Java\jdk1.8.0_11 ]
28 |
29 | [添加] Path: %JAVA_HOME%\jre\bin;
30 |
31 | <可用控制台 java 命令验证>
32 |
33 | [添加] Path: %JAVA_HOME%\bin;
34 |
35 | <可用控制台 javac 命令验证>
36 |
37 | * Android SDK
38 |
39 | 地址: [ http://developer.android.com/sdk/index.html ]
40 |
41 | 环境变量配置:
42 |
43 | [添加] Path: 解压后的 sdk\platform-tools 路径 [ 例: D:\adt-bundle-windows-x86_64-20140702\sdk\platform-tools; ]
44 |
45 | <可用控制台 adb 命令验证>
46 |
47 | [添加] Path: 解压后的 sdk\tools 路径 [ 例: D:\adt-bundle-windows-x86_64-20140702\sdk\tools; ]
48 |
49 | <可用控制台 android 命令验证>
50 |
51 | * Cordova command-line interface (CLI)
52 |
53 | Cordova 命令行工具, 用于项目新建, 将其构建成不同平台的应用, 并在真实设备或者虚拟机上运行. 它是构建跨平台应用的主要工具.
54 |
55 | * 安装 Cordova
56 |
57 | 安装 Cordova 需要 Node.js 和 Git 的支持, 使用如下命令安装
58 |
59 | ```
60 | npm install -g cordova
61 | ```
62 |
63 | 注: cordova 的运行也需要 Apache Ant 的支持 [ 构建部分需要, 否则 cordova platform add 部分会报错 ] [ 此部分官网没有提及, 在此作为补充 ]
64 |
65 | 地址: [ http://ant.apache.org/bindownload.cgi ]
66 |
67 | 环境变量配置:
68 |
69 | [添加] Path: 解压后的 bin 路径 [ 例: D:\apache-ant-1.9.4\bin; ]
70 |
71 | <可用控制台 ant 命令验证> [ 一般会出现 `Buildfile: build.xml does not exist!` 提示 ]
72 |
73 | * 创建项目 [ cordova create ]
74 |
75 | ```
76 | cordova create hello com.example.hello HelloWorld
77 | ```
78 | 第一个参数 hello 用于声明项目目录文件名, 当前目录下不应该有重名目录或文件. 生成后的项目目录中的 www子目录用于存储你的应用的主页, 其中包括 css, js 和 img 文件. 项目目录中的 config.xml 文件则描述了对于生成和部署都比较重要的元数据 (metadata).
79 |
80 | 第二个参数 com.example.hello 给你的项目提供一个反向域名式的标识符
81 |
82 | 第三个参数 HelloWorld 用于描述应用的标题
83 |
84 | * 添加平台 [ cordova platform add ]
85 | ```
86 | cd hello // 需要在项目目录执行
87 | ```
88 | ```
89 | cordova platform add android // 添加平台
90 | ```
91 | ```
92 | cordova platforms ls // 查看平台状态
93 | ```
94 | * 构建项目 [ cordova build ]
95 |
96 | ```
97 | cordova build // 构建项目
98 | ```
99 | ```
100 | cordova build android // 构建特定平台项目
101 | ```
102 | * 在虚拟机或设备上测试应用
103 |
104 | * 虚拟机
105 | ```
106 | cordova emulate android
107 | ```
108 | 1. 在执行之前, 需要安装对应的虚拟设备, 在控制台中输入 `android` 调出 Andriod SDK Manager, 安装对应的 SDK Platform 和 System Image. [ Cordova 应该有特定 API 需求, 目前是 19 ]
109 |
110 | 2. 在 Eclipse 里配置虚拟机 [ Window -> Android Virtual Device Manager 进行配置 ], 配置结束后执行 `cordova emulate android` 命令即可启动虚拟机 <未优化虚拟机会比较卡, 后文介绍加速方式>
111 |
112 | * 真实设备
113 |
114 | ```
115 | cordova run android
116 | ```
117 | 1. 在控制台检测连接设备 (测试设备要开启 USB 调试)
118 | ```
119 | adb devices
120 | ```
121 | 用于检测连接设备, 结果如下所示
122 | ```
123 | List of devices attached
124 | [ 设备编号 ] device
125 | ```
126 | 2. 如果有连接设备, 执行 `cordova run android` 后, 会在真实设备上运行应用
127 |
128 | * Andriod 虚拟机加速 (Intel 虚化技术)
129 |
130 | 直接运行 Andriod 虚拟机会比较卡, 之前想采用 GenyMotion 作为虚拟机, 没有找到方式.
131 | Cordova 官网介绍了一种开启 Intel 虚化技术来加速 Android 虚拟机的方式.
132 |
133 | * Intel Processor Identification Utility 用于检测当前芯片是否支持虚化技术
134 |
135 | 地址: [ https://downloadcenter.intel.com/Detail_Desc.aspx?ProductID=1881&DwnldID=7838 ]
136 |
137 | 
138 |
139 | 若支持需要在 BIOS 中进行开启
140 |
141 | * 在 Android SDK Manager 中安装 `Intel x86 Atom System Image` 和 `Intel x86 Emulator Accelerator (HAXM)`
142 |
143 | 注: 点击 'Install Package' 后 `Intel x86 Emulator Accelerator (HAXM)` 只是下载完成, 并未进行安装. 需找到下载文件并进行安装, 不同机型可能不同, 安装后虚拟机速度会快不少.
144 | [ 我这边是 Andriod SDK 安装目录的 'sdk\extras\intel\Hardware_Accelerated_Execution_Manager' 文件夹下的 'intelhaxm.exe' 文件 ]
145 |
146 | 
147 |
148 | 
149 |
150 | * Chrome WebView 调试
151 |
152 | 无论是虚拟机或真实设备都可以通过 Chrome 进行 WebView 的调试, 在 Chrome 中打开 '工具 -> 检查设备' 即可对特定设备的 WebView 进行调试.
153 |
154 | 
155 |
156 | 
157 |
158 |
159 | ## 音频组件
160 |
161 | Cordova 大部分硬件事件的支持采用插件的形式提供, 比如 电量信息, 摄像头, 设备移动等
162 |
163 | 详细介绍: [ http://cordova.apache.org/docs/en/3.5.0/cordova_plugins_pluginapis.md.html#Plugin%20APIs ]
164 |
165 | 如果需要应用支持音频播放, 需要安装 org.apache.cordova.media 插件
166 |
167 | 官方提供的安装方式为 `cordova plugin add org.apache.cordova.media` 网络环境不好可能会下载不下来, 可以换用 `cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-media.git`
168 |
169 | * 创建音频对象
170 | ```
171 | var media = new Media(src, mediaSuccess, [mediaError], [mediaStatus]);
172 | ```
173 | * 参数
174 |
175 | * src 音频 URI
176 | * mediaSuccess 成功的回调函数
177 | * mediaError 错误的回调函数
178 | * mediaStatus 音频对象状态改变时触发的回调函数, 状态值会作为参数传递给回调函数
179 |
180 | * 常量
181 |
182 | 作为传递给 mediaStatus 回调函数的参数
183 |
184 | * Media.MEDIA_NONE = 0;
185 | * Media.MEDIA_STARTING = 1;
186 | * Media.MEDIA_RUNNING = 2;
187 | * Media.MEDIA_PAUSED = 3;
188 | * Media.MEDIA_STOPPED = 4;
189 |
190 | * 方法
191 |
192 | * media.getCurrentPosition: 返回音频文件的当前播放位置
193 | * media.getDuration: 返回音频文件的持续时间
194 | * media.play: 播放或恢复一个音频文件
195 | * media.pause: 暂停音频文件的播放
196 | * media.release: 释放操作系统底层的音频资源
197 | * media.seekTo: 移动一个音频文件的当前位置
198 | * media.setVolume: 设置音量大小
199 | * media.stop: 停止音频播放
200 |
201 | 官方文档: [ https://github.com/apache/cordova-plugin-media/blob/master/doc/index.md ]
202 |
203 | ### 参考文献
204 |
205 | [ http://baike.baidu.com/view/4157600.htm ]
206 |
207 | [ http://cordova.apache.org/docs/en/3.5.0/ ]
208 |
209 | [ http://stackoverflow.com/questions/17688030/html5-audio-on-apache-cordova-android-native-app ]
210 |
211 |
212 |
--------------------------------------------------------------------------------
/img/audio_summary/audio_tag.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjx9110/document/93d237f79f414e088b4d6ccafcf56aca459e06bb/img/audio_summary/audio_tag.jpg
--------------------------------------------------------------------------------
/img/audio_summary/web_audio_support.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjx9110/document/93d237f79f414e088b4d6ccafcf56aca459e06bb/img/audio_summary/web_audio_support.jpg
--------------------------------------------------------------------------------
/img/cordova_learning/accelerator.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjx9110/document/93d237f79f414e088b4d6ccafcf56aca459e06bb/img/cordova_learning/accelerator.JPG
--------------------------------------------------------------------------------
/img/cordova_learning/api19.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjx9110/document/93d237f79f414e088b4d6ccafcf56aca459e06bb/img/cordova_learning/api19.JPG
--------------------------------------------------------------------------------
/img/cordova_learning/chrome.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjx9110/document/93d237f79f414e088b4d6ccafcf56aca459e06bb/img/cordova_learning/chrome.JPG
--------------------------------------------------------------------------------
/img/cordova_learning/intel image.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjx9110/document/93d237f79f414e088b4d6ccafcf56aca459e06bb/img/cordova_learning/intel image.JPG
--------------------------------------------------------------------------------
/img/cordova_learning/vitural.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjx9110/document/93d237f79f414e088b4d6ccafcf56aca459e06bb/img/cordova_learning/vitural.JPG
--------------------------------------------------------------------------------
/img/cordova_learning/webview.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjx9110/document/93d237f79f414e088b4d6ccafcf56aca459e06bb/img/cordova_learning/webview.JPG
--------------------------------------------------------------------------------