http://item.congci.com/item/html5-speech-api-and-audio-api
浏览器提供语音搜索已经不是什么新鲜事,在google上搜索了一下speech api相关内容,发现存在三个不同的标准规范,分别是:
HTML Speech Web API
HTML Speech Web API是由微软、google、mozilla等公司的人提出,目前最近的版本是2011年10月29日。
该规范提出了一个reco标记用来进行语音识别,该标记在用户界面上表示一个语音输入,可以将另一个表单元素与之进行关联,从而将识别结果呈献给用户。此外规范还提供了tts标记完成语音合成功能。
[NamedConstructor=Reco(), NamedConstructor=Reco(in DOMString for)] interface HTMLRecoElement : HTMLElement { // Attributes readonly attribute HTMLFormElement? form; attribute DOMString htmlFor; readonly attribute HTMLElement? control; attribute SpeechInputRequest request; attribute DOMString grammar; // From the SpeechInputRequest integer maxNBest; DOMString language; boolean saveForRereco; boolean endpointDetection; boolean finalizeBeforeEnd; integer interimResults; float confidenceThreshold; float sensitivity; float speedVsAccuracy; integer completeTimeout; integer incompleteTimeout; integer maxSpeechTimeout; DOMString inputWaveformURI; attribute DOMString serviceURI; attribute boolean continuous; // event handlers attribute Function onaudiostart; attribute Function onsoundstart; attribute Function onspeechstart; attribute Function onspeechend; attribute Function onsoundend; attribute Function onaudioend; attribute Function onresult; attribute Function onnomatch; attribute Function onerror; attribute Function onauthorizationchange; attribute Function onopen; attribute Function onstart; };
TTS定义如下:
[NamedConstructor=TTS(), NamedConstructor=TTS(in DOMString src)] interface HTMLTTSElement : HTMLMediaElement { attribute DOMString serviceURI; attribute DOMString lastMark; };
在JS方面,规范定义了SpeechInputRequest接口可以独立发起语音识别并将结果通过回调返回给浏览器。
[Constructor] interface SpeechInputRequest { // recognition parameters SpeechGrammars[] grammars; // misc parameter attributes integer maxNBest; DOMString language; boolean saveForRereco; boolean endpointDetection; boolean finalizeBeforeEnd; integer interimResults; float confidenceThreshold; float sensitivity; float speedVsAccuracy; integer completeTimeout; integer incompleteTimeout; integer maxSpeechTimeout; DOMString inputWaveformURI; // the generic set of parameters SpeechParameter[] parameters; // other attributes attribute DOMString serviceURI; attribute MediaStream input; const unsigned short SPEECH_AUTHORIZATION_UNKNOWN = 0; const unsigned short SPEECH_AUTHORIZATION_AUTHROIZED = 1; const unsigned short SPEECH_AUTHORIZATION_NOT_AUTHORIZED = 2; readonly attribute unsigned short authorizationState; attribute boolean continuous; // the generic send info method void sendInfo(in DOMString type, in DOMString value); // Default markup binding methods void addGrammarFrom(in Element inputElement, optional float weight, optional boolean modal); void outputToElement(in Element outputElement); // methods to drive the speech interaction void open(); void start(); void stop(); void abort(); void interpret(in DOMString text); // event methods attribute Function onaudiostart; attribute Function onsoundstart; attribute Function onspeechstart; attribute Function onspeechend; attribute Function onsoundend; attribute Function onaudioend; attribute Function onresult; attribute Function onnomatch; attribute Function onerror; attribute Function onauthorizationchange; attribute Function onopen; attribute Function onstart; attribute Function onend; }; SpeechInputRequest implements EventTarget; interface SpeechInputNomatchEvent : Event { readonly attribute SpeechInputResult result; }; interface SpeechInputErrorEvent : Event { readonly attribute SpeechInputError error; }; interface SpeechInputError { const unsigned short SPEECH_INPUT_ERR_OTHER = 0; const unsigned short SPEECH_INPUT_ERR_NO_SPEECH = 1; const unsigned short SPEECH_INPUT_ERR_ABORTED = 2; const unsigned short SPEECH_INPUT_ERR_AUDIO_CAPTURE = 3; const unsigned short SPEECH_INPUT_ERR_NETWORK = 4; const unsigned short SPEECH_INPUT_ERR_NOT_ALLOWED = 5; const unsigned short SPEECH_INPUT_ERR_SERVICE_NOT_ALLOWED = 6; const unsigned short SPEECH_INPUT_ERR_BAD_GRAMMAR = 7; const unsigned short SPEECH_INPUT_ERR_LANGUAGE_NOT_SUPPORTED = 8; readonly attribute unsigned short code; readonly attribute DOMString message; }; // Item in N-best list interface SpeechInputAlternative { readonly attribute DOMString utterance; readonly attribute float confidence; readonly attribute any interpretation; }; // A complete one-shot simple response interface SpeechInputResult { readonly attribute Document resultEMMAXML; readonly attribute DOMString resultEMMAText; readonly attribute unsigned long length; getter SpeechInputAlternative item(in unsigned long index); readonly attribute boolean final; }; // A full response, which could be interim or final, part of a continuous response or not interface SpeechInputResultEvent : Event { readonly attribute SpeechInputResult result; readonly attribute short resultIndex; readonly attribute SpeechInputResult[] results; readonly attribute DOMString sessionId; }; // The object representing a speech grammar [Constructor] interface SpeechGrammar { attribute DOMString src; attribute float weight; attribute boolean modal; }; // The object representing a speech parameter [Constructor] interface SpeechParameter { attribute DOMString name; attribute DOMString value; };
Speech Input API Specification
Speech Input API Specification这一份是2个google的员工提交的方案,时间也比较早,为2010年10月18日,不知道现在是否还在维护,Latest Editor's Draft的链接都没有了。该文档提供的语音输入方案为在现有的input标签上增加speech属性,另外通过给input元素增加相应事件来获取语音输入的状态。具体扩展的方案如下:
interface HTMLInputElement : HTMLElement { ... // speech input attributes attribute boolean speech; attribute DOMString grammar; attribute short maxresults; attribute long nospeechtimeout; // speech input event handler IDL attributes attribute Function oncapturestart(); attribute Function onspeechstart(); attribute Function onspeechchange(in SpeechInputEvent event); attribute Function onspeechend(); attribute Function onspeecherror(in SpeechInputError error); // speech input methods void startSpeechInput(); void stopSpeechInput(); void cancelSpeechInput(); };
该规范还提出同一时刻只允许有一个speech input sesseion存在。
Speech JavaScript API Specification
该规范最新版本为2011年12月22日,也是由google工程师提交的,目前处于非正式提案的状态,该规范可以和Speech Input API Specification一起看(工程师基本是同一拨人),一个是针对input元素的扩展,一个是针对js层面的扩展。
该规范仅涉及JS的API,提供了两个接口:SpeechReco和TTS,其中SpeechReco与HTML Speech Web API的SpeechInputRequest功能类似,可以发起语音识别,并通过事件获取结果。
[Constructor] interface SpeechReco { // recognition parameters SpeechGrammarList grammars; DOMString lang; attribute boolean continuous; // methods to drive the speech interaction void start(); void stop(); void abort(); // event methods attribute Function onaudiostart; attribute Function onsoundstart; attribute Function onspeechstart; attribute Function onspeechend; attribute Function onsoundend; attribute Function onaudioend; attribute Function onresult; attribute Function onnomatch; attribute Function onresultdeleted; attribute Function onerror; attribute Function onstart; attribute Function onend; }; SpeechReco implements EventTarget; interface SpeechInputError { const unsigned short OTHER = 0; const unsigned short NO_SPEECH = 1; const unsigned short ABORTED = 2; const unsigned short AUDIO_CAPTURE = 3; const unsigned short NETWORK = 4; const unsigned short NOT_ALLOWED = 5; const unsigned short SERVICE_NOT_ALLOWED = 6; const unsigned short BAD_GRAMMAR = 7; const unsigned short LANGUAGE_NOT_SUPPORTED = 8; readonly attribute unsigned short code; readonly attribute DOMString message; }; // Item in N-best list interface SpeechInputAlternative { readonly attribute DOMString transcript; readonly attribute float confidence; readonly attribute any interpretation; }; // A complete one-shot simple response interface SpeechInputResult { readonly attribute unsigned long length; getter SpeechInputAlternative item(in unsigned long index); readonly attribute boolean final; }; // A collection of responses (used in continuous mode) interface SpeechInputResultList { readonly attribute unsigned long length; getter SpeechInputResult item(in unsigned long index); }; // A full response, which could be interim or final, part of a continuous response or not interface SpeechInputResultEvent : Event { readonly attribute SpeechInputResult result; readonly attribute SpeechInputError error; readonly attribute short resultIndex; readonly attribute SpeechInputResultList resultHistory; }; // The object representing a speech grammar [Constructor] interface SpeechGrammar { attribute DOMString src; attribute float weight; }; // The object representing a speech grammar collection [Constructor] interface SpeechGrammarList { readonly attribute unsigned long length; getter SpeechGrammar item(in unsigned long index); void addFromUri(in DOMString src, optional float weight); void addFromString(in DOMString string, optional float weight); };
[Constructor] interface TTS { attribute DOMString text; attribute DOMString lang; readonly attribute boolean paused; readonly attribute boolean ended; // methods to drive the speech interaction void play(); void pause(); void stop(); attribute Function onstart; attribute Function onend; };
小结
HTML Speech Web API方案为增加reco元素负责提供语音输入的UI,tts元素负责提供text-to-speech功能,JS的SpeechInputRequest可作为独立的接口调用获取语音识别结果。Speech Input API Specification和Speech Javascript API Specification可以一起来看,它的方案是在原有的input元素上扩展,在界面上提供语音输入入口,同时提供SpeechReco的JS接口来单独发起语音识别并获取结果。
HTML5项目笔记4:使用Audio API设计HTML5音乐播放器
HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用。
无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道和一些元数据,这些是和你的视频或者音频控件绑定到一块的,这样才形成了一个完整的播放组件。
浏览器支持情况:
浏览器 | 支持情况 | 编解码器 |
Chrome | 3.0 | Theora 、 Vorbis 、Ogg H.264 、 AAC 、MPEG4 |
FireFox | 3.5 | Theora 、 Vorbis 、Ogg |
IE | 不支持 | 无 |
Opera | 10.5 | Theora 、 Vorbis 、Ogg(10.5) VP8、Vorbis 、 WebM(10.6) |
Safari | 3.2 | H.264 、 ACC 、MPEG4 |
常用的控制函数:
函数 | 动作 |
load() | 加载音频、视频软件 |
play() | 加载并播放音频、视频文件或重新播放暂停的的音频、视频 |
pause() | 暂停出于播放状态的音频、视频文件 |
canPlayType(obj) | 测试是否支持给定的Mini类型的文件 |
只读的媒体属性:
只读属性 | 值 |
duration | 获取媒体文件的播放时长,以s为单位,如果无法获取,则为NaN |
paused | 如果媒体文件被暂停,则返回true,否则返回false |
ended | 如果媒体文件播放完毕,则返回true |
startTime | 返回起始播放时间 |
error | 返回错误代码 |
currentSrc | 以字符串形式返回正在播放或已加载的文件 |
可脚本控制的属性值:
属性 | 值 |
autoplay | 自动播放已经加载的的媒体文件 |
loop | 为true的时候则设定为自动播放 |
currentTime | 以s为单位返回从开始播放到目前所花的时间 |
controls | 显示或者隐藏用户控制界面 |
volume | 音量值,从0.0至1.0之间 |
muted | 设置是否静音 |
autobuffer | 是否进行缓冲加载 |
首先,我们在页面中添加一个音频元素:
<audio src="../Media/The sound of silence.mp3" controls="controls" autoplay="autoplay"></audio>
在谷歌Chrome浏览器中的效果如下:
controls指的是用户控制界面,所以我们可以在Web页面中看到上面这个操作面板,包括播放和暂停,播放进度条,音量进度条,和进度时间显示等。autoplay 指的是自动播发已加载的媒体文件,所以我们一打开页面就可以直接播放了
HTML5 Audio API 的界面很强大,功能也很完善,但是我们的Web应用会根据不同的需求、设计风格和界面颜色来要求不同的播放器样式和功能,这就要求我们能基于他们的API 设计出灵活的应用。
接下来,我们设计一款适合我们离线工作系统需要的播放器:
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 //在页面放置一个audio元素,因为我们使用自己设计的播放界面,所以这边不用他们的controls。 2 <audio id="myMusic" > </audio> 3 4 //这边放置一个隐藏域,他的作用是存放媒体文件暂停的时间点 5 <input id="PauseTime" type="hidden" /> 6 7 //编写音乐盒的界面 8 <div class="MusicBox" > 9 10 <div class="LeftControl" ></div> //上一个媒体文件的控制图标 11 <div id="MainControl" class="MainControl" ></div> //开始和暂停的控制图标 12 <div class="RightControl" ></div> //下一个媒体文件的控制图标 13 14 <div class="ProcessControl">//进度条 15 <div class="SongName">Ben's Music Box!</div> //媒体文件标题 16 <div class="SongTime">00:00 | 00:00</div> //时间进度 17 <div class="Process" ></div> //全部时长的进度条 18 <div class="ProcessYet"></div> //已播放时长的进度条 19 </div> 20 21 <div class="VoiceEmp"></div> //静音图标 22 <div class="VoidProcess" ></div> //全音量进度条 23 <div class="VoidProcessYet" ></div> //当前音量进度条 24 <div class="VoiceFull" ></div>//全音量图标 25 <div class="ShowMusicList" ></div> //显示或隐藏媒体文件列表图标 26 27 </div> 28 29 30 <div class="MusicList"> //媒体文件列表区域 31 <div class="Author"></div> //当前媒体文件的 32 <div class="List"> //媒体文件列表 33 34 <div class="Single" > //单个媒体文件 35 <span class="SongName" KV="Fate" >01.Fate</span> 36 </div> 37 38 </div> 39 </div>
画好这个结构之后,我们就来写相应的CSS样式了:
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 //这是音乐盒整体框架 2 3 .MusicBox 4 5 { 6 7 font: 9px 'Lucida Sans Unicode', 'Trebuchet MS', Arial, Helvetica; 8 9 background-color: #212121; 10 11 12 13 //设置渐变的颜色,左上到左下,颜色从#1B1B1B 到 #212121。 14 15 background-image: -webkit-gradient(linear, left top, left bottom, from(#1B1B1B), to(#212121)); 16 17 background-image: -webkit-linear-gradient(top, #1B1B1B, #212121); 18 19 background-image: -moz-linear-gradient(top, #1B1B1B, #212121); 20 21 background-image: -ms-linear-gradient(top, #1B1B1B, #212121); 22 23 background-image: -o-linear-gradient(top, #1B1B1B, #212121); 24 25 background-image: linear-gradient(top, #1B1B1B, #212121); 26 27 28 29 //设置边框的弧度值,为3px 30 31 -moz-border-radius: 3px; 32 33 -webkit-border-radius: 3px; 34 35 border-radius: 3px; 36 37 38 39 40 41 42 43 44 45 /*阴影*/ 46 47 text-shadow: 0 1px 0 rgba(255,255,255,0.5); 48 49 -webkit-box-shadow: 10px 10px 25px #ccc; 50 51 -moz-box-shadow: 10px 10px 25px #ccc; 52 53 box-shadow: 10px 10px 25px #ccc; 54 55 56 57 /*透明度*/ 58 59 opacity:0.9; 60 61 62 63 /*基本属性*/ 64 65 border-width: 1px; 66 67 border-style: solid; 68 69 border-color: #488BF0 #488BF0 #488BF0 #488BF0; 70 71 width:810px; 72 73 height:40px; 74 75 padding:2px 5px; 76 77 position:absolute; 78 79 z-index:9; 80 81 } 82 83 84 85 //上一个媒体文件的控制图标 86 87 .LeftControl 88 89 { 90 91 width:0px; 92 93 padding: 10px 10px 10px 10px; 94 95 float:left; 96 97 height:20px; 98 99 background:url(../Images/sk-dark.png) left 2px no-repeat; 100 101 margin-right:8px; 102 103 margin-left:10px; 104 105 } 106 107 .LeftControl:hover 108 109 { 110 111 background:url(../Images/sk-dark.png) left -30px no-repeat; 112 113 } 114 115 116 117 118 119 //下一个媒体文件的控制图标 120 121 .RightControl 122 123 { 124 125 width:0px; 126 127 padding: 10px 10px 10px 10px; 128 129 float:left; 130 131 height:20px; 132 133 background:url(../Images/sk-dark.png) left -62px no-repeat; 134 135 margin-right:8px; 136 137 } 138 139 140 141 .RightControl:hover 142 143 { 144 145 background:url(../Images/sk-dark.png) left -93px no-repeat; 146 147 } 148 149 150 151 //音频进度控制 152 153 (注意这边有两个高度为2px的div,一个是.Process 一个是.ProcessYet,用来显示音频播放的进度条,一个是显示全部的音频长度,长度是固定的;一个用来实时显示播放的进度的) 154 155 .ProcessControl 156 157 { 158 159 width:500px; 160 161 padding: 5px 10px 10px 10px; 162 163 float:left; 164 165 height:20px; 166 167 margin-right:12px; 168 169 color:#ffffff; 170 171 } 172 173 174 175 .ProcessControl .SongName { float:left; } 176 177 .ProcessControl .SongTime { float:right; } 178 179 .ProcessControl .Process 180 181 { 182 183 width: 500px; 184 185 float: left; 186 187 height: 2px; 188 189 cursor: pointer; 190 191 background-color:#000000; 192 193 margin-top:7px; 194 195 } 196 197 198 199 .ProcessControl .ProcessYet 200 201 { 202 203 width: 0px; 204 205 position:absolute; 206 207 height: 2px; 208 209 left:131px; 210 211 top:30px; 212 213 cursor: pointer; 214 215 background-color:#7A8093; 216 217 } 218 219 220 221 //静音图标 222 223 .VoiceEmp 224 225 { 226 227 width:0px; 228 229 padding: 10px 10px 10px 10px; 230 231 float:left; 232 233 height:17px; 234 235 background:url(../Images/sk-dark.png) -28px -180px no-repeat; 236 237 margin-right:2px; 238 239 } 240 241 .VoiceEmp:hover 242 243 { 244 245 background:url(../Images/sk-dark.png) -28px -212px no-repeat; 246 247 } 248 249 250 251 //总音量进度条 252 253 .VoidProcess 254 255 { 256 257 width: 66px; 258 259 height: 2px; 260 261 cursor: pointer; 262 263 background-color:#000; 264 265 float:left; 266 267 margin-top:19px; 268 269 margin-right:6px; 270 271 } 272 273 274 275 //当前音量进度条 276 277 .VoidProcessYet 278 279 { 280 281 width: 66px; 282 283 position:absolute; 284 285 height: 2px; 286 287 left:675px; 288 289 top:21px; 290 291 cursor: pointer; 292 293 background-color:#7A8093; 294 295 } 296 297 298 299 //全音量图标 300 301 .VoiceFull 302 303 { 304 305 width:0px; 306 307 padding: 10px 10px 10px 10px; 308 309 float:left; 310 311 height:17px; 312 313 background:url(../Images/sk-dark.png) -28px -116px no-repeat; 314 315 } 316 317 318 319 .VoiceFull:hover 320 321 { 322 323 background:url(../Images/sk-dark.png) -28px -148px no-repeat; 324 325 } 326 327 328 329 330 331 //呈现出播放图标 332 333 .MainControl 334 335 { 336 337 width:25px; 338 339 padding: 10px 15px 5px 10px; 340 341 float:left; 342 343 height:20px; 344 345 background:url(../Images/sk-dark.png) -80px -130px no-repeat; 346 347 } 348 349 350 351 .MainControl:hover 352 353 { 354 355 background:url(../Images/sk-dark.png) -80px -166px no-repeat; 356 357 } 358 359 360 361 //呈现出暂停或停止图标 362 363 .StopControl 364 365 { 366 367 width:14px; 368 369 padding: 10px 10px 5px 10px; 370 371 float:left; 372 373 height:20px; 374 375 background:url(../Images/sk-dark.png) -50px -130px no-repeat; 376 377 margin-right:16px; 378 379 } 380 381 .StopControl:hover 382 383 { 384 385 background:url(../Images/sk-dark.png) -50px -165px no-repeat; 386 387 } 388 389 //显示多媒体文件列表的控制图标 390 391 .ShowMusicList 392 393 { 394 395 width:10px; 396 397 padding: 10px 10px 5px 10px; 398 399 float:left; 400 401 height:10px; 402 403 background:url(../Images/sk-dark.png) -20px 0 no-repeat; 404 405 margin:5px 0 0 12px; 406 407 cursor:pointer; 408 409 } 410 411 412 413 .ShowMusicList:hover 414 415 { 416 417 background:url(../Images/sk-dark.png) -20px -29px no-repeat; 418 419 } 420 421 422 423 //文件列表区域的样式代码 424 425 .MusicList 426 427 { 428 429 font: 9px 'Lucida Sans Unicode', 'Trebuchet MS', Arial, Helvetica; 430 431 background-color: #212121; 432 433 background-image: -webkit-gradient(linear, left top, left bottom, from(#1B1B1B), to(#212121)); 434 435 background-image: -webkit-linear-gradient(top, #1B1B1B, #212121); 436 437 background-image: -moz-linear-gradient(top, #1B1B1B, #212121); 438 439 background-image: -ms-linear-gradient(top, #1B1B1B, #212121); 440 441 background-image: -o-linear-gradient(top, #1B1B1B, #212121); 442 443 background-image: linear-gradient(top, #1B1B1B, #212121); 444 445 446 447 -moz-border-radius: 3px; 448 449 -webkit-border-radius: 3px; 450 451 border-radius: 3px; 452 453 454 455 text-shadow: 0 1px 0 rgba(255,255,255,0.5); 456 457 458 459 border-width: 1px; 460 461 border-style: solid; 462 463 border-color: #488BF0 #488BF0 #488BF0 #488BF0; 464 465 466 467 width:600px; 468 469 height:200px; 470 471 472 473 /*阴影*/ 474 475 -webkit-box-shadow: 10px 10px 25px #ccc; 476 477 -moz-box-shadow: 10px 10px 25px #ccc; 478 479 box-shadow: 10px 10px 25px #ccc; 480 481 482 483 /*透明度*/ 484 485 opacity:0.9; 486 487 488 489 /*基本性质*/ 490 491 padding:2px 5px; 492 493 position:absolute; 494 495 z-index:1000; 496 497 display:none; 498 499 } 500 501 502 503 .MusicList .Author 504 505 { 506 507 font: 9px 'Lucida Sans Unicode', 'Trebuchet MS', Arial, Helvetica; 508 509 background-color: #212121; 510 511 background-image:url(../Images/Eson.jpg); 512 513 514 515 -moz-border-radius: 3px; 516 517 -webkit-border-radius: 3px; 518 519 border-radius: 3px; 520 521 522 523 width:158px; 524 525 height:200px; 526 527 float:left; 528 529 } 530 531 532 533 .MusicList .List 534 535 { 536 537 font: 9px 'Lucida Sans Unicode', 'Trebuchet MS', Arial, Helvetica; 538 539 background-color: #212121; 540 541 -moz-border-radius: 3px; 542 543 -webkit-border-radius: 3px; 544 545 border-radius: 3px; 546 547 548 549 width:410px; 550 551 height:180px; 552 553 float:right; 554 555 overflow:hidden; 556 557 padding:10px 13px; 558 559 color:#fff; 560 561 } 562 563 564 565 .MusicList .List .Single 566 567 { 568 569 width:100%; 570 571 float:left; 572 573 overflow:hidden; 574 575 height:15px; 576 577 font-size:13px; 578 579 cursor:pointer; 580 581 margin-bottom:8px; 582 583 } 584 585 586 587 .MusicList .List .Single .SongName 588 589 { 590 591 width:90%; 592 593 float:left; 594 595 }
页面的元素和CSS样式写完之后,就可以看到一个漂亮的音乐播放器的模型了,如图:
只是现在的播放器上面的按钮都是空壳,没有任何功能。所以,现在我们就来添加这些功能 , 脚本的顶层框架就用Jquery。
![](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
1 $(document).ready(function () { 2 3 //获取音频工具 4 5 var audio = document.getElementById("myMusic"); 6 7 //开始,暂停按钮 8 9 $("#MainControl")._toggle(function () { 10 11 $(this).removeClass("MainControl").addClass("StopControl"); 12 13 if (audio.src == "") { 14 15 var Defaultsong = $(".Single .SongName").eq(0).attr("KV"); 16 17 $(".MusicBox .ProcessControl .SongName").text(Defaultsong); 18 19 $(".Single .SongName").eq(0).css("color", "#7A8093"); 20 21 audio.src = "../Media/" + Defaultsong + ".mp3"; 22 23 } 24 25 audio.play(); 26 27 TimeSpan(); 28 29 }, function () { 30 31 $(this).removeClass("StopControl").addClass("MainControl"); 32 33 audio.pause(); 34 35 }); 36 37 38 39 40 41 //歌曲列表的选择操作 42 43 $(".MusicList .List .Single .SongName").click(function () { 44 45 $(".MusicList .List .Single .SongName").css("color", "#fff"); 46 47 $("#MainControl").removeClass("MainControl").addClass("StopControl"); 48 49 $(this).css("color", "#7A8093"); 50 51 var SongName = $(this).attr("KV"); 52 53 $(".MusicBox .ProcessControl .SongName").text(SongName); 54 55 audio.src = "../Media/" + SongName + ".mp3"; 56 57 audio.play(); 58 59 TimeSpan(); 60 61 }); 62 63 64 65 //左前进按钮 66 67 $(".LeftControl").click(function () { 68 69 $(".MusicList .List .Single .SongName").each(function () { 70 71 if ($(this).css("color") == "rgb(122, 128, 147)") { 72 73 var IsTop = $(this).parent(".Single").prev(".Single").length == 0 ? true : false; //检查是否是最顶端的歌曲 74 75 var PrevSong; 76 77 if (IsTop) { 78 79 PrevSong = $(".Single").last().children(".SongName").attr("KV"); 80 81 $(".Single").last().children(".SongName").css("color", "#7A8093"); 82 83 } 84 85 else { 86 87 PrevSong = $(this).parent(".Single").prev(".Single").children(".SongName").attr("KV"); 88 89 $(this).parent(".Single").prev(".Single").children(".SongName").css("color", "#7A8093"); 90 91 } 92 93 94 95 audio.src = "../Media/" + PrevSong + ".mp3"; 96 97 $(".MusicBox .ProcessControl .SongName").text(PrevSong); 98 99 $(this).css("color", "#fff"); 100 101 audio.play(); 102 103 return false; //代表break 104 105 } 106 107 }) 108 109 }); 110 111 112 113 //右前进按钮 114 115 $(".RightControl").click(function () { 116 117 $(".MusicList .List .Single .SongName").each(function () { 118 119 if ($(this).css("color") == "rgb(122, 128, 147)") { 120 121 var IsBottom = $(this).parent(".Single").next(".Single").length == 0 ? true : false; //检查是否是最尾端的歌曲 122 123 var NextSong; 124 125 if (IsBottom) { 126 127 NextSong = $(".Single").first().children(".SongName").attr("KV"); 128 129 $(".Single").first().children(".SongName").css("color", "#7A8093"); 130 131 } 132 133 else { 134 135 NextSong = $(this).parent(".Single").next(".Single").children(".SongName").attr("KV"); 136 137 $(this).parent(".Single").next(".Single").children(".SongName").css("color", "#7A8093"); 138 139 } 140 141 142 143 audio.src = "../Media/" + NextSong + ".mp3"; 144 145 $(".MusicBox .ProcessControl .SongName").text(NextSong); 146 147 $(this).css("color", "#fff"); 148 149 audio.play(); 150 151 return false; //代表break 152 153 } 154 155 }) 156 157 }); 158 159 160 161 //静音按钮 162 163 $(".VoiceEmp").click(function () { 164 165 $(".VoidProcessYet").css("width", "0"); 166 167 audio.volume = 0; 168 169 }); 170 171 172 173 //满音量按钮 174 175 $(".VoiceFull").click(function () { 176 177 $(".VoidProcessYet").css("width", "66px"); 178 179 audio.volume = 1; 180 181 }); 182 183 184 185 /* 186 187 之前一直考虑进度条的原理,这边进度条的做法启发自腾讯一款播放器的做法,采用两个2px高度的div,重叠, 188 189 上面那个与下面那个div的颜色不一样,用于区分进度,顶层div的width是根据播放的长度来调整的,width越长,说明播放越长, 190 191 知道上层的div完全覆盖下面的div,达到长度的一致,说明播放完毕。我们的播放进度条和音量进度条都是这样做的 192 193 */ 194 195 196 197 // 音频进度条事件(进度增加) 198 199 $(".Process").click(function (e) { 200 201 202 203 //播放进度条的基准参数 204 205 var Process = $(".Process").offset(); 206 207 var ProcessStart = Process.left; 208 209 var ProcessLength = $(".Process").width(); 210 211 212 213 214 215 var CurrentProces = e.clientX - ProcessStart; 216 217 DurationProcessRange(CurrentProces / ProcessLength); 218 219 $(".ProcessYet").css("width", CurrentProces); 220 221 }); 222 223 224 225 //音频进度条事件(进度减少) 226 227 $(".ProcessYet").click(function (e) { 228 229 230 231 //播放进度条的基准参数 232 233 var Process = $(".Process").offset(); 234 235 var ProcessStart = Process.left; 236 237 var ProcessLength = $(".Process").width(); 238 239 240 241 var CurrentProces = e.clientX - ProcessStart; 242 243 DurationProcessRange(CurrentProces / ProcessLength); 244 245 $(".ProcessYet").css("width", CurrentProces); 246 247 }); 248 249 250 251 //音量进度条事件(进度增加) 252 253 $(".VoidProcess").click(function (e) { 254 255 //音量进度条的基准参数 256 257 var VoidProcess = $(".VoidProcess").offset(); 258 259 var VoidProcessStart = VoidProcess.left; 260 261 var VoidProcessLength = $(".VoidProcess").width(); 262 263 264 265 var CurrentProces = e.clientX - VoidProcessStart; 266 267 VolumeProcessRange(CurrentProces / VoidProcessLength); 268 269 $(".VoidProcessYet").css("width", CurrentProces); 270 271 }); 272 273 274 275 //音量进度条时间(进度减少) 276 277 $(".VoidProcessYet").click(function (e) { 278 279 //音量进度条的基准参数 280 281 var VoidProcess = $(".VoidProcess").offset(); 282 283 var VoidProcessStart = VoidProcess.left; 284 285 var VoidProcessLength = $(".VoidProcess").width(); 286 287 288 289 var CurrentProces = e.clientX - VoidProcessStart; 290 291 VolumeProcessRange(CurrentProces / VoidProcessLength); 292 293 $(".VoidProcessYet").css("width", CurrentProces); 294 295 }); 296 297 298 299 //显示或隐藏多媒体文件列表事件 300 301 $(".ShowMusicList").toggle(function () { 302 303 $(".MusicList").show(); 304 305 306 307 var MusicBoxRight = $(".MusicBox").offset().left + $(".MusicBox").width(); 308 309 var MusicBoxBottom = $(".MusicBox").offset().top + $(".MusicBox").height(); 310 311 $(".MusicList").css("left", MusicBoxRight - $(".MusicList").width()); 312 313 $(".MusicList").css("top", MusicBoxBottom + 15); 314 315 }, function () { 316 317 $(".MusicList").hide(); 318 319 }); 320 321 322 323 324 325 //监听媒体文件结束的事件(ended),这边一首歌曲结束就读取下一首歌曲,实现播放上的循环播放 326 327 audio.addEventListener('ended', function () { 328 329 $(".MusicList .List .Single .SongName").each(function () { 330 331 if ($(this).css("color") == "rgb(122, 128, 147)") { 332 333 var IsBottom = $(this).parent(".Single").next(".Single").length == 0 ? true : false; //检查是否是最尾端的歌曲 334 335 var NextSong; 336 337 if (IsBottom) { 338 339 NextSong = $(".Single").first().children(".SongName").attr("KV"); 340 341 $(".Single").first().children(".SongName").css("color", "#7A8093"); 342 343 } 344 345 else { 346 347 NextSong = $(this).parent(".Single").next(".Single").children(".SongName").attr("KV"); 348 349 $(this).parent(".Single").next(".Single").children(".SongName").css("color", "#7A8093"); 350 351 } 352 353 354 355 audio.src = "../Media/" + NextSong + ".mp3"; 356 357 $(".MusicBox .ProcessControl .SongName").text(NextSong); 358 359 $(this).css("color", "#fff"); 360 361 audio.play(); 362 363 return false; //代表break 364 365 } 366 367 }); 368 369 }, false); 370 371 372 373 374 375 }); 376 377 378 379 //音量进度条的转变事件 380 381 function VolumeProcessRange(rangeVal) { 382 383 var audio = document.getElementById("myMusic"); 384 385 audio.volume = parseFloat(rangeVal); 386 387 } 388 389 390 391 //播放进度条的转变事件 392 393 function DurationProcessRange(rangeVal) { 394 395 var audio = document.getElementById("myMusic"); 396 397 audio.currentTime = rangeVal * audio.duration; 398 399 audio.play(); 400 401 } 402 403 404 405 //播放事件 406 407 function Play(obj) { 408 409 var SongUrl = obj.getAttribute("SongUrl"); 410 411 var audio = document.getElementById("myMusic"); 412 413 audio.src = "../Media/" + SongUrl + ".mp3"; 414 415 audio.play(); 416 417 TimeSpan(); 418 419 } 420 421 422 423 //暂停事件 424 425 function Pause() { 426 427 var audio = document.getElementById("myMusic"); 428 429 $("#PauseTime").val(audio.currentTime); 430 431 audio.pause(); 432 433 } 434 435 436 437 //继续播放事件 438 439 function Continue() { 440 441 var audio = document.getElementById("myMusic"); 442 443 audio.startTime = $("PauseTime").val(); 444 445 audio.play(); 446 447 } 448 449 450 451 //时间进度处理程序 452 453 function TimeSpan() { 454 455 var audio = document.getElementById("myMusic"); 456 457 var ProcessYet = 0; 458 459 setInterval(function () { 460 461 var ProcessYet = (audio.currentTime / audio.duration) * 500; 462 463 $(".ProcessYet").css("width", ProcessYet); 464 465 var currentTime = timeDispose(audio.currentTime); 466 467 var timeAll = timeDispose(TimeAll()); 468 469 $(".SongTime").html(currentTime + " | " + timeAll); 470 471 }, 1000); 472 473 } 474 475 476 477 //时间处理,因为时间是以为单位算的,所以这边执行格式处理一下 478 479 function timeDispose(number) { 480 481 var minute = parseInt(number / 60); 482 483 var second = parseInt(number % 60); 484 485 minute = minute >= 10 ? minute : "0" + minute; 486 487 second = second >= 10 ? second : "0" + second; 488 489 return minute + ":" + second; 490 491 } 492 493 494 495 //当前歌曲的总时间 496 497 function TimeAll() { 498 499 var audio = document.getElementById("myMusic"); 500 501 return audio.duration; 502 503 }
至此,一款播放器做完了,默认执行的是列表循环播放,包含了上一首,下一首,播放,暂停,播放进度条调整,音量调进度条整,列表选择等功能。播放的歌曲是固定的写在列表里面的,我喜欢的ESON的照片也是贴上去的,这些都可以做成动态获取或则与服务器交互,有兴趣的可以去试一下,扩展一下。
本来准备在我们的离线工作系统中添加音频播放器,后来需求变更,放弃了,所以这个版本不是完善的版本。视频播放器的功能大同小异,也可以自己试试。