Web前端MP3的播放(多浏览器实现)

前端开发项目职责 前端实战项目开发 web前端小型开发项目流程

一、MP3文件在各浏览器中支持情况

1.1 HTML5 Audio大家可能都知道,在HTML5中有一个标签:audio,他的作用就是播放音频文件,那么对MP3格式文件支持情况如何呢?

据度娘告诉我的,大概是酱紫情况:
Chrome, IE9+, Safari

但是还是有点担心,万一漏了,肿么办呢?
所以第一步,我们需要检测MP3文件的播放情况。

如下代码所示,我们可以通过Audio对象的创建、canPlayType方法,监听[backcolor=rgb(247, 247, 247)]canPlaythrough、error事件来判断MP3是否可以播放。[/bgcolor]使用代码检测后,发现度娘的描述中确实漏掉了几个浏览器:Opera,Edge,还有各式各样的使用webkit内核的PC/Mobile浏览器,可见这一番功夫并没有白费!
[code]//默认可以播放
var audioMp3Flag = true;

//执行检查方法
canPlayAudioMP3(function(flag){audioMp3Flag = flag;})

/**

  • 检测浏览器是否能使用Audio对象播放mp3文件
    */
    function canPlayAudioMP3(callback){
    try {
    var audio = new Audio();

    //1、利用canPlayType方法,检测浏览器是否有MP3解码器,回调true
    if(audio.canPlayType('audio/mpeg') == "probably")
        callback(true);
    
    //2、利用canPlaythrough事件,监听音频是否可以加载成功,回调true
    audio.addEventListener('canplaythrough', function(e){
        callback(true);
    }, false);
    
    //3、利用error事件,监听音频播放是否会出现异常,回调false
    audio.addEventListener('error', function(e){
        callback(false);
    }, false);
    
    //base64编码最小的MP3文件
    audio.src = "data:audio/mpeg;base64,/+MYxAAAAANIAAAAAExBTUUzLjk4LjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    audio.load();

    }
    catch(e){
    4、Audio对象异常,回调false
    callback(false);
    }
    }[/code]

1.2 再谈谈Flash

由于flash的安全漏洞,放弃flash的声音越来越多了。
但是作为一个功能研究,还是希望能够兼容尽可能多的浏览器的,优雅降级、渐进增强是每个开发者都想做到的事情吧!

尽管网页上嵌入flash有很多现成的js文件,比方说swfobject.js等,但作为一个小demo,还是自己练习一下嵌入flash所需的html

1.2.1 object与embed
网上同类的科普文章有很多,如OBJECT和EMBED标签
OBJECT 标签是用于windows IE3.0及以后浏览器或者其它支持Activex控件的浏览器。
EMBED标签是用于Netscape Navigator2.0及以后的浏览器或其它支持Netscape插件的浏览器。

下面分享一下我的方法[code]/*

  • 生成嵌入网页的flash代码
  • @param {Object} movieName 元素Id
  • @param {Object} src swf文件
  • @param {Object} data 需要传入的参数
    /
    function flashHtml(movieName, src, data) {
    var attr = {
    width: 1,
    height: 1,
    quality: ‘high’,
    style: ”,
    wmode: ‘opaque’ /
    window|transparent|opaque/
    };
    if (exports.name == “ie” && exports.version<=7) {
    //旧版IE加载flash需要添加随机数,随机数取值0-999
    src += ‘?rnd=’ + Math.floor(Math.random()
    1000);
    }
    /* 1、IE6-10: object标签 + classid + codebase

    • 2、IE11浏览器:object标签 + type=application/x-shockwave-flash
    • 3、其他浏览器(Chrome|Firefox|Opera)等:embed标签 + type=application/x-shockwave-flash
      */
      return exports.name == “ie” && exports.version<11 ? [
      ‘<object id=”‘, movieName, ‘” name=”‘, movieName, ‘” width=”‘, attr.width, ‘” height=”‘, attr.height, ‘” style=”‘, attr.style, ‘” classid=”clsid:D27CDB6E-AE6D-11cf-96B8-444553540000″ codebase=”https://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,28″>’,
      ‘<param name=”wmode” value=”‘, attr.wmode, ‘” />’,
      ‘<param name=”movie” value=”‘, src, ‘” />’,
      ‘<param name=”allowscriptaccess” value=”always” />’,
      ‘<param name=”flashvars” value=”‘, data , ‘” />’,
      ‘</object>’
      ].join(”) :
      exports.name == “ie” && exports.version==11 ? [
      ‘<object id=”‘, movieName, ‘” name=”‘, movieName, ‘” data=”‘, src, ‘” width=”‘, attr.width, ‘” height=”‘, attr.height, ‘” style=”‘, attr.style, ‘” type=”application/x-shockwave-flash”>’,
      ‘<param name=”wmode” value=”‘, attr.wmode, ‘”/>’,
      ‘<param name=”movie” value=”‘, src, ‘”/>’,
      ‘<param name=”quality” value=”‘,attr.quality,'”/>’,
      ‘<param name=”allowscriptaccess” value=”always”/>’,
      ‘<param name=”flashvars” value=”‘, data , ‘”/>’,
      ‘</object>’
      ].join(”) : [
      ‘<embed id=”‘, movieName, ‘” name=”‘, movieName, ‘” src=”‘ + src + ‘” width=”‘, attr.width, ‘” height=”‘, attr.height, ‘” style=”‘, attr.style, ‘” flashvars=”‘,data, ‘” wmode=”‘, attr.wmode, ‘” allowscriptaccess=”always” pluginspage=”https://www.macromedia.com/go/getflashplayer” type=”application/x-shockwave-flash” >’,
      ‘</embed>’
      ].join(”);
      }[/code][color=#666666]

      1.2.2 编写as脚本,用于和js交互[/color]

下面脚本借鉴了这位大神的代码 https://github.com/breily/jquery.player.js/blob/master/version_0.2/music.as

同时吸取了记ie8及以下版本ie的flash的addCallback的一坑这位大哥的as脚本编写的经验,减少了addcallback的数量,成功消灭了IE8以下版本的bug

编写好as文件后,可以利mtasc编译为swf文件,
[code]import flash.external.ExternalInterface;

class Music {
static var app:Music;
var sound:Sound;
var paused:Number;

// Constructor, plus adds all the js callbacks
function Music() {
    this.sound = new Sound();
            paused = 0;
    ExternalInterface.addCallback("emit",  this, emit);
            ExternalInterface.addCallback("getPaused",  this, getPaused);
}

    public function emit(action:String, arg:String) {
            switch(action){
                    case 'load':
                            this.load(arg);
                            break;
                    case 'play':
                            this.play();
                            break;
                    case 'stop':
                            this.stop();
                            break;
            }
    }

    public function getPaused() {
            return paused;
    }

private function load(url:String) {
    this.sound.loadSound(url, true);
    this.sound.onSoundComplete = function() {
            this.paused = 0;
        ExternalInterface.call("v_stop");
    };
}

private function play() {
        this.paused = 1;
    this.sound.start(0);
}

private function stop() {
        this.paused = 0;
    this.sound.stop();
}

static function main(mc:MovieClip) {
    app = new Music();
}

}[/code]
####二、Music对象的编写

捋顺了外部依赖,下面可以编写Music对象了,我的思路大概是:

Music: 1、构造函数
2、init 初始化方法
3、emit (根据音乐状态play或stop音乐)

为了实现播放逻辑与视图显示的分离,在初始化方法中传入了逻辑层完成后需要回调的方法。
2.1 构造函数

[code]/**

  • Music对象的构造函数
  • @param {Object} url 音乐文件地址
  • @param {Object} type 音乐类型、暂时只支持audio/mpeg,加一个参数便于拓展
  • @param {Object} viewCallback 音乐初始化、播放逻辑完成后的视图回调
  • @param {Object} eventCallback 音乐初始化、播放逻辑完成后的事件回调
    */
    function Music(url, type, viewCallback, eventCallback){
    this.url = url;
    this.type = type;
    this.viewCallback = viewCallback;
    this.eventCallback = eventCallback;
    this.isSupportAudio = isSupportAudio(this.type);
    }[/code]
    2.2 init初始化方法

分别调用了createAudioPlayer()和createSwfPlayer()来创建音乐播放的载体
[code]/**

  • init初始化方法
  • 在支持audio标签且能正常解码MP3的情况下创建audio标签
  • 否则使用flash的方式
  • 完成后,进行初始化方法的视图及事件回调
    */
    Music.prototype.init = function(){
    var self = this;
    if (this.isSupportAudio) {
    this.createAudioPlayer();
    } else {
    try{this.createSwfPlayer()}catch(e){};
    }
    this.viewCallback[‘init’].call(this);
    this.eventCallback[‘init’].call(this);
    }[/code]
    createAudioPlayer和createSwfPlayer的目的只有一个,封装一个this.musicEl对象,让对象在audio|flash的模式下,都能支持play(播放)、stop(停止),getPaused(获取音乐状态)
    createSwfPlayer的实现方式中有一点要注意:IE6,7需要使用window[id]才能获取到object对象,其他浏览器可以使用document[id][code]Music.prototype.createAudioPlayer = function(){
    var self = this;
    this.musicEl = document.createElement(‘audio’);
    this.musicEl.src = this.url;
    this.musicEl.type = this.type;
    this.musicEl.stop = function(){
    this.pause();
    this.currentTime = 0.0;
    }
    addEvent(this.musicEl, ‘ended’, function(){
    m_console(‘播放结束停止MP3’);
    self.viewCallback[‘stop’].call();
    });
    this.musicEl.getPaused = function(){
    return this.paused;
    }
    }

Music.prototype.createSwfPlayer = function(){
var self =this;
var musicId = ‘swfPlayer’;
var id = ‘player_hidden’;
var swf = ‘music.swf’;
var html = flashHtml(id, swf, ‘id=’+id);
this.musicEl = document.createElement(‘div’);
this.musicEl.innerHTML += html;
this.musicEl.id = musicId;
document.body.innerHTML += this.musicEl.outerHTML;

var flashEl = (exports.name == 'ie' && exports.version <= 7) ? window[id] : document[id]; 

setTimeout(function(){
        flashEl.emit('load', self.url);
        flashEl.emit('stop');
        self.musicEl.play = function(){
                flashEl.emit('play');
        }
        self.musicEl.stop = function(){
                flashEl.emit('stop');
        }
        self.musicEl.getPaused = function(){
                return flashEl.getPaused() == 0;
        }
}, 250);

}[/code]
2.3 emit播放控制方法

emit的作用就是在音乐停止状态下,执行播放。播放状态下,执行停止。
play、stop,getPaused方法的具体实现原理(在createAudioPlayer和createSwfPlayer有代码说明)
HTML5 Audio
play方法:调用Audio对象的play方法
stop方法:调用Audio对象的pause方法,并将currentTime设为0
getPaused方法:调用Audio对象的paused属性
Flash
play方法:调用flash Sound类的start方法
stop方法:######调用flash Sound类的stop方法
getPaused方法:在as代码中设置了一个变量paused,在播放时设为1,停止时设为0,js中调用flash接口读取此变量判断是否为0

[code]Music.prototype.play = function(){
m_console(‘播放MP3’);
this.musicEl.play();
this.viewCallback[‘play’].call();
}[/code][code]Music.prototype.stop = function(){
m_console(‘手动停止MP3’);
this.musicEl.stop();
this.viewCallback[‘stop’].call();
}[/code][code]Music.prototype.emit = function(){
if (this.musicEl.getPaused()) {
this.play();
} else {
this.stop();
}
}[/code]

前端开发项目架构 前端开发项目功能描述 前端开发项目经验描述

» 本文来自:前端开发者 » 《Web前端MP3的播放(多浏览器实现)》
» 本文链接地址:https://www.rokub.com/5908.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!