前言

正常情况,除了非常简陋的小功能H5,音乐播放是必不可少的,对于带有互动的小游戏,还必须有各种酷炫的音效,这就必须用到音频使用了,而对于视频,主要用到过场动画和品牌广告宣传。

audio标签

audio 标签是 HTML 5 的新标签。

其中controls属性可以向用户显示控件,是浏览器自带的样式,否则audio是隐藏不显示的,但是每个浏览器自带样式都不一样,例如在chrome下样子是这样



功能也比较单一,所以一般要做播放器啥的就不会用自带的样式了…取而代之的是使用HTMLAudioElement DOM对象来进行操作,里面提供了许多方法事件给我们使用。它继承自HTMLMediaElement

PS:对于查看dom对象的方法,除了查看官方文档,也可以这样(我经常这样)

chrome浏览器里面,直接在debug窗口pause脚本,然后再监视窗口new dom元素,直接展开查看即可

Web Audio API

Web Audio API提供了一套强大&通用的音频操控接口,可以允许用户选择音源,给音频添加效果,添加声场特效,可视化音频等等。基本上可以玩转音频!

一般情况下用不到……所以有兴趣的同学可以研究一下,以后我有机会研究过后也会补充。

自动播放的问题

正常PC客户端的浏览器audio都能够正常使用,不幸的是,在移动设备中大多数浏览器都屏蔽了autoplay属性,也就是无法实现默认的自动播放。

原因当然也很简单,移动设备流量被你这样一播放就去了一大半了,当然要保护起来。必须是要用户主动出发play方法才行。

下面是引自Safari Reference

In Safari on iPhone OS (for all devices, including iPad), where the

user may be on a cellular network and be charged per data unit,

autobuffering and autoplay are disabled. No data is loaded until the

user initiates it. This means the JavaScript play() and load() methods

are also inactive until the user initiates playback, unless the play()

method is triggered by user action.

但是产品说了,一定要给播放背景音乐!那怎么办?

1、对于android的webview

  1. // 设置4.2以后版本支持autoPlay,非用户手势促发
  2. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
  3. webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
  4. }

2、对于手机浏览器

这是我个人的测试,在手机Safari/Chrome中,如果调用play,报错audio.play can only be initiated by a user gesture.

所以,目前没有什么太好的方案,除非欺骗用户主动点击屏幕,然后播放。

3、微信浏览器

注册使用微信JS-SDK的ready事件(前提是需要有公众号,好在目前JS-SDK的权限基本都开放了)

在事件内调用play方法是没有任何问题的。

  1. wx.ready(function(){
  2. // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
  3. audio.play();
  4. });

理论是大多H5都是在微信传播的,所以首选方案3,其他就没有考虑那么多了。

背景音乐的实现

看起来是这个样子的,左上角一个音乐图标在旋转(很多h5都是这么干的)



默认情况,一进入便加载背景音乐,这种情况一般不用SoundJS,在wx.ready中调用方法即可

  1. wx.ready(function(){
  2. music_player = new Player($('#btn_play_music'), "./audio/107192078.m4a");
  3. });

如果需要在正常浏览器也能使用,判断一下是否是浏览器即可

  1. //判断是否是微信浏览器
  2. function is_weixin() {
  3. var ua = navigator.userAgent.toLowerCase();
  4. if (ua.match(/MicroMessenger/i) == "micromessenger") {
  5. return true;
  6. } else {
  7. return false;
  8. }
  9. }

核心代码如下,具体可以见demo

CSS样式

  1. /*音乐按钮*/
  2. #wraper_music {
  3. position: fixed;
  4. width: 40px;
  5. height: 40px;
  6. top: 10px;
  7. right: 10px;
  8. z-index: 999;
  9. border-radius: 40px;
  10. display: block;
  11. }
  12. #btn_play_music {
  13. width: 40px;
  14. height: 40px;
  15. cursor: pointer;
  16. background-size: 40px 40px;
  17. }
  18. .c_btn_play_music_playing {
  19. background: url(./img/music_playing.png) no-repeat;
  20. -webkit-animation: kf_music_playing 8s linear infinite;
  21. animation: kf_music_playing 8s linear infinite;
  22. }
  23. .c_btn_play_music_paused {
  24. background: url(./img/music_stop.png) no-repeat;
  25. }
  26. @keyframes kf_music_playing {
  27. 0% {
  28. -webkit-transform: rotateZ(0deg);
  29. }
  30. 100% {
  31. -webkit-transform: rotateZ(360deg);
  32. }
  33. }
  34. @-webkit-keyframes kf_music_playing {
  35. 0% {
  36. -webkit-transform: rotateZ(0deg);
  37. }
  38. 100% {
  39. -webkit-transform: rotateZ(360deg);
  40. }
  41. }
  42. @media screen and (max-width: 380px) {
  43. #btn_qtcs {
  44. font-size: small;
  45. }
  46. #btn_toumiao {
  47. font-size: small;
  48. }
  49. }
  50. @media screen and (max-width: 320px) {
  51. #btn_qtcs {
  52. font-size: x-small;
  53. }
  54. #btn_toumiao {
  55. font-size: x-small;
  56. }
  57. }

播放器JS

  1. //---------start播放器代码---------
  2. function Player(el, src) {
  3. this.el = el;
  4. this.isPlay = true;
  5. if (src == undefined) {
  6. src = '';
  7. }
  8. this.init(src);
  9. }
  10. Player.prototype = {
  11. init: function(src) {
  12. var _this = this,
  13. attr = {
  14. loop: true,
  15. preload: "auto",
  16. autoplay: true,
  17. src: src
  18. };
  19. this._audio = new Audio;
  20. for (var i in attr) {
  21. attr.hasOwnProperty(i) && i in this._audio && (this._audio[i] = attr[i]);
  22. }
  23. this.inited = false;
  24. $(this._audio).on('durationchange', function() {
  25. // 播放加载
  26. if (_this._audio.duration > 1) {
  27. _this.inited = true;
  28. }
  29. });
  30. $(this._audio).on('ended', function() {
  31. // 播放结束
  32. _this._audio.currentTime = 0;
  33. _this.isPlay = false;
  34. _this._play();
  35. });
  36. if (src != '') {
  37. this._audio.load();
  38. }
  39. if (typeof this.el !== 'string') {
  40. this.el.on('click', function() {
  41. _this._play();
  42. });
  43. }
  44. },
  45. _load: function() {
  46. this._audio.load();
  47. },
  48. _src: function(src) {
  49. this._audio['src'] = src;
  50. },
  51. _isplay: function() {
  52. return this.isPlay;
  53. },
  54. _play: function() {
  55. if (!this.isPlay) {
  56. this._audio.play();
  57. if (typeof this.el !== 'string') {
  58. this.el.removeClass('c_btn_play_music_paused');
  59. this.el.addClass('c_btn_play_music_playing');
  60. }
  61. } else {
  62. this._audio.pause();
  63. if (typeof this.el !== 'string') {
  64. this.el.removeClass('c_btn_play_music_playing');
  65. this.el.addClass('c_btn_play_music_paused');
  66. }
  67. }
  68. this.isPlay = !this.isPlay;
  69. },
  70. _playOn: function() {
  71. this._audio.play();
  72. if (typeof this.el !== 'string') {
  73. this.el.removeClass('c_btn_play_music_paused');
  74. this.el.addClass('c_btn_play_music_playing');
  75. }
  76. this.isPlay = true;
  77. },
  78. _playOff: function() {
  79. this._audio.pause();
  80. if (typeof this.el !== 'string') {
  81. this.el.removeClass('c_btn_play_music_playing');
  82. this.el.addClass('c_btn_play_music_paused');
  83. }
  84. this.isPlay = false;
  85. },
  86. _volume: function(num) {
  87. this._audio.volume = num;
  88. }
  89. }
  90. //---------end播放器代码---------

立即播放的问题

默认情况下,播放个单个背景音乐,不用太在乎加载播放延迟的问题,但是H5互动小游戏就不行了,会影响用户体验。

上面可以知道,在微信中是可以主动加载音频的,这时候new Audio(src)的音频加载方法就可以适用了,可以做到多个音频的加载,加载完成再在需要的时候播放。但实际测试手机过程中发现,即使已经加载完毕了,在代码用audio标签更换src路径,还是会有一定的延迟(PC端没有这个问题,可能是由于手机内存限制,又要从本地缓冲读取加载一次),然而就算是建立N个audio标签,然后用到的时候用该标签播放,也没有用,还是有延迟,特别是Safari中,本身就有300毫秒的延迟,这样更加明显了。当时候就没有什么头绪了,最后还是找到了神器SoundJS,在H5互动小游戏上,完美解决音频的播放问题。

SoundJS

SoundJS为我们提供了一套具有较高兼容性的简单API,来解决H5互动游戏时的音频操控问题。

当然是配合PreloadJS的效果更棒哦!

  1. //建议使用资源清单,方便管理,如果资源较多,可以考虑独立出json文件,脚本自动生成。
  2. var manifest = [
  3. {
  4. id: '告白气球',
  5. src: './audio/107192078.m4a'
  6. }, {
  7. id: '一生有你',
  8. src: './audio/95484.m4a'
  9. },
  10. ]
  11. var queue = new createjs.LoadQueue();
  12. //SoundJS默认用的是复杂的Web Audio接口,这会导致加载音频变慢,所以显示注册使用html的audio即可
  13. createjs.Sound.registerPlugins([createjs.HTMLAudioPlugin]);
  14. //如果需要加载音频,需要注册SoundJs插件
  15. queue.installPlugin(createjs.Sound);
  16. queue.on("complete", function() {
  17. createjs.Sound.play("告白气球");
  18. }, this);
  19. queue.on("progress", function(event) {
  20. console.log("Progress:", queue.progress, event.progress);
  21. });
  22. //设置并列加载,否则每次只加载一个,太耗时
  23. queue.setMaxConnections(5);
  24. queue.maintainScriptOrder = true;
  25. queue.loadManifest(manifest);

具体的操作可以查阅官方文档,由于当时项目进度比较赶,到目前我也还未研究具体的实现原理。有知道的同学麻烦留言解答一下…

video标签

video标签同样继承自HTMLVideoElement,所以用法和audio大庭相径,具体参考官方文档即可。

播放样式的问题

对于PC客户端,使用controls属性,不同浏览器的样式也是不一样的,下面是chrome的样式,如果不加controls属性,就只能通过dom控制播放了。



悲剧的是!!手机上就又各种坑了……默认都是弹框全屏播放的。

对于android微信,是不能自动播放的,即使在wx.ready中调用代码



播出完成竟然还有广告!

而对于IOS微信,也没广告,默认在wx.ready中是可以自动播放的。

对于一般没啥高要求的H5来说,是可以接受的,但其实用户体验确实都不太好,最好是能统一样式,没有其他任何广告!

那怎么办?感谢Avin同学分享了《视频H5のVideo标签在微信里的坑和技巧》,研究如此透彻,想必也是花了很多的时间。

最后还有一个方案,用canvas实时读video画图,但这个太耗CPU,PC端是可以考虑使用的。

格式的问题

需要注意的是,格式支持的问题,如果格式不对,要嘛就无法播放,要嘛就白屏只有声音,具体可以参考这里《Media formats supported by the HTML audio and video elements》。而且!MP4的编码其实是有很多种的,不一定是mp4就可以用, 转之前我在这个问题就郁闷了挺久,最终的方案就是使用格式工厂,编码选择H.264

总结

才第二篇,已经各种坑了,想想前端其实也不容易啊~!各种兼容调试!什么时候是个头呢?自己也有些惭愧,很多内部原理其实也没深入去了解,只是做到符合业务需求,不过目前前端混乱之治,也是挺头疼,技术变化挺快,没太多时间研究。

啥时候大家才能统一标准呢?这种感觉就好像是我买了个充电器,电源本来都是统一标准的东西,结果在我家能充电,在你家就不能充,我难道还要去研究你家为什么电源不能充电?然后再配合拆开我的充电器研究一下原理?或许还有公司再生产一个万能充电器来适应各种私自改的标准?好像没啥意义,我只是想冲个电(就像我只是想播放个音视频,咋就不能同意效果呢?)…有些浪费生命呐,但是标准终究是标准,人家就是愿意改来自己用也没啥办法……

下一篇将介绍另一个H5神器!!swiper.js!用它我们就可以实现酷炫的上下左右滑动展示特特效了!

demo地址:

https://github.com/leestar54/h5-demo/blob/master/audio%26video.html

那些H5用到的技术(2)——音频和视频播放的更多相关文章

  1. 那些H5用到的技术(1)——素材加载

    编码环境前言什么时候用到素材加载?loading提示,让用户等待图片的加载音频的加载利用神器PreloadJS总结 编码环境 Sublime Text 3 插件包括: Autoprefixer 自动补 ...

  2. H5的本地存储技术及其与Cookie的比较

    第一部分: H5的本地存储技术 HTML5 提供了两种在客户端存储数据的新方法.先看下面的例子: 例1:var mySelection = {name:"car", amount: ...

  3. H5 视频直播相关技术

    一.移动视频直播发展 大家首先来看下面这张图: 可以看到,直播从 PC 到一直发展到移动端,越来越多的直播类 App 上线,同时移动直播进入了前所未有的爆发阶段,但是对于大多数移动直播来说,还是要以 ...

  4. H5传奇世界服务器架设技术及源码

    以前是传奇迷,虽然现在不玩,但当作兴趣,研究了一下H5传奇世界的架设,架设成功并分享给大家.注意,此技术只可用于个人娱乐,不可用于商业用途. 首先下载 传奇世界H5源码   450M的样子. H5传奇 ...

  5. 那些H5用到的技术(6)——屏幕适配

    前言长屏适配单页适配参考 前言 曾经屏幕适配一直是个头疼的问题,各种坑,各种浏览器&设备兼容问题,好在的是,随着技术&标准的不断发展,这个问题得到了极大程度的解决,这篇文章主要对之前开 ...

  6. 将海康大华等网络摄像机RTSP流进行网页Flash rtmp和H5 hls直播的技术方案

    前言 再小的技术点也会有他的市场! 一直以来,都有一些不被看好,认为是成本太高,无法大规模展开的软件和产品形态,就好比每一座城市都会有他的著名小吃一样,即使是慕名而来的人源源不断,受众群体也总是有限, ...

  7. 手机QQ会员H5加速方案——sonic技术内幕

    版权声明:本文由况鹰原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/141 来源:腾云阁 https://www.qclou ...

  8. 那些H5用到的技术(6)——数字滚动特效

    前言原理源码使用方式补充CountUp.js 前言 会有这么一种情况,H5页面需要进行数字统计展示,以此来强调产品or工作的成果.如果只是静态显示一个数字,总是感觉生硬.对比如下: 是不是瞬间高大上了 ...

  9. 那些H5用到的技术(4)——弹幕

    前言思路实现模式无限循环模式时间线模式停止显示弹幕 前言 以前玩卷轴射击游戏的时候,大量的BOSS子弹让我们无路可逃的时候,让我见识到了真正弹幕的威力,可自从A站B站火了之后,大量评论留言参与到了视频 ...

随机推荐

  1. winsock的io模型(终极篇)

    最近在看服务器框架的搭建,看了不少,都是零零碎碎的,觉得看的差不多了,可以写点最后的总结了,然后,竟然发现了这篇文章,总结做的特别好,肯定比我总结写要好多了,所以我也就不写了,直接转吧...... 套 ...

  2. Linq转换操作之ToArray,ToList,ToDictionary源码分析

    Linq转换操作之ToArray,ToList,ToDictionary源码分析 一:linq中的转换运算符 1. ToArray 我们经常用在linq查询上吧. linq只能运用在IEnumerab ...

  3. 使用Go客户端访问MongoDB

    1.安装MongoDB 1.1 到官网:www.mongodb.org/downloads下载windows最新版本,解压到目标目录下. 1.2 创建数据存储目录 mongodb需要一个数据文件夹来保 ...

  4. Elasticsearch(1.1.1)基础教程pdf

    基础概念 Elasticsearch有几个核心概念.从一开始理解这些概念会对整个学习过程有莫大的帮助. 接近实时(NRT)        Elasticsearch是一个接近实时的搜索平台.这意味着, ...

  5. python版本selenium定位方式(不止八种哦)

    除了大家熟知的8种定位方式之外 1.id定位:find_element_by_id(self, id_)2.name定位:find_element_by_name(self, name)3.class ...

  6. Cntlm

    SourceForge页面 作用是转发请求到代理 可以同时加上域验证信息(为各种NTLM认证?) gradle.cmd.Terminal等工具或软件可能无法或者说没有使用系统/浏览器设置的代理,因为可 ...

  7. MySQL不带where条件的UPDATE和DELETE 限制操作说明

    本文来自 网易云社区 . 数据安全是业务的基石,但是DBA 总会遇到救火情况,业务误删除全表或者误更新错全表业务数据,导致服务不可用 sql_safe_updates参数可以限制不带where条件的u ...

  8. SP16580 QTREE7 - Query on a tree VII(LCT)

    题意翻译 一棵树,每个点初始有个点权和颜色(输入会给你) 0 u:询问所有u,v路径上的最大点权,要满足u,v路径上所有点颜色相同 1 u:反转u的颜色 2 u w:把u的点权改成w 题解 Qtree ...

  9. ArchLinux下shadow服务报错

    用着Linux蓦然开机就报错了.我是个对报错很敏感的,而是是开机报错. 这个的严重性,听一位前辈说过:如果开机报错你都不理它,慢慢的它就会宕机. 报错内容: shadow服务是Linux下用于校队pa ...

  10. javascript 私有化属性,和公共属性

    function TestClassA(name, number) { this.name = name; //public this.number = number; //public var ac ...