精华内容
下载资源
问答
  • Android 设置多媒体静音

    千次阅读 2019-07-01 09:26:06
    最近因为开发了一个音量进度条的seekbar,客户要求点击音量图标能够使正在播放的多媒体静音,百度上找的方法基本上都是设置系统铃声静音的,可以通过下面的方法设置当前多媒体静音。 booleanmuteFlag=audioManager....

    最近因为开发了一个音量进度条的seekbar,客户要求点击音量图标能够使正在播放的多媒体静音,百度上找的方法基本上都是设置系统铃声静音的,可以通过下面的方法设置当前多媒体静音。

     

    boolean muteFlag = audioManager.isStreamMute(AudioManager.STREAM_MUSIC);//获取当前音乐多媒体是否静音
     if(muteFlag){
          audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC,AudioManager.ADJUST_UNMUTE, 0);//取消静音
     }else{
          audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_MUTE , 0);//设为静音
     }

     

    展开全文
  • AudioManager用来对音量、模式(静音,震动,震动加声音等模式)等进行管理。可以用Vibrator、HapticFeedback进行管理手机震动。本人带着案例进行讲解,先温柔点讲控制系统音量,再说撩人的震动棒...呸..是振荡器。 一...

    导读:

    Android提供了可以进行对原生系统进行控制API。AudioManager用来对音量、模式(静音,震动,震动加声音等模式)等进行管理。可以用Vibrator、HapticFeedback进行管理手机震动。本人带着案例进行讲解,先温柔点讲控制系统音量,再说撩人的震动棒...呸..是振荡器。


    一、AudioManager (音频管理)

    1、音乐的播放方式

    //1、自定义音频文件test
     MediaPlayer player = MediaPlayer.create(getApplicationContext(), R.raw.test);
    
    //2、系统电话铃声TYPE_RINGTONE\系统通知铃声TYPE_NOTIFICATION 
    Uri  uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);  
    
    MediaPlayer  mMediaPlayer = new MediaPlayer();
    mMediaPlayer.setDataSource(PlayerService.this, uri);
    
    ————————————————————————————————————————————————————————————————               
     mMediaPlayer.setLooping(true); // 设置循环播放
                   
     mMediaPlayer.prepare();//准备
                   
     mMediaPlayer.start();//播放


    2、修改音量方式

    首先,拿到音频管理实例对象。 AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);

    然后,设置音量。例如 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, 30, 0);

    (1)修改音量

    adjustVolume(int direction , int  flag) //修改音量

    direction(方向):顾名思义,就是点击事件发生,往上增加音量,往下减少音量,和保持音量不变。

    •  AudioManager.ADJUST_LOWER(降低) 
    •  AudioManager.ADJUST_RAISE(升高) 
    •  AudioManager.ADJUST_SAME(锁定不变)  

    (2) 修改类型、音量

    adjustStreamVolume(int  streamType ,int direction , int flag) //修改类型、音量
    

    streamType(音频流类型):即指定声音类型,有下述几种声音类型:

    STREAM_ALARM:手机闹铃     STREAM_MUSIC:手机音乐
    
    STREAM_RING:电话铃声      STREAM_SYSTEAM:手机系统
    
    STREAM_DTMF:音调         STREAM_NOTIFICATION:系统提示
    
    STREAM_VOICE_CALL:语音电话

    flag(标志):其实是点击事件发生后,音量的表现形式。

    • AudioManager.FLAG_SHOW_UI :会弹出调节音量的界面
    • AudioManager.FLAG_ALLOW_RINGER_MODES :最低声音会振动

    (3)设置音量大小 

    setStreamVolume(int streamType, int index, int flags)//直接设置音量大小

    index(音量的值) ,int类型。

     

    4、实用小案例

    XML 写一个SeekBar控件

    <android.support.v7.widget.AppCompatSeekBar
        android:id="@+id/play_volume"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"/>

    Activiy中的代码

    声明变量

    private MediaPlayer player;//测试音乐
    private int maxVolume, currentVolume;//音量值
    private AudioManager audioManager;//音频管理类
    private SeekBar mView_sb_play_volume; //控件

    初始化操作

            mView_sb_play_volume = (SeekBar) findViewById(R.id.play_volume);//滑动进度条
    
            myRegisterReceiver();//注册同步更新的广播
            player = MediaPlayer.create(getApplicationContext(), R.raw.test);//自定义音频文件test
            audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);//实例
            maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  //获取系统最大音量
            mView_sb_play_volume.setMax(maxVolume);
            currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);  //获取当前值
            mView_sb_play_volume.setProgress(currentVolume);
    
            player.setLooping(true);
            mView_sb_play_volume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    player.pause();
                }
    
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                    player.start();
                }
    
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);
                    seekBar.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
    //                seekBar.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
    //                seekBar.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
    
    //HapticFeedbackConstants的常量值,我们要用到的有三个触摸震动方式:
    // 一个是LONG_PRESS(长按),
    // 第二个是FLAG_IGNORE_VIEW_SETTING(不受Xml里view的属性设置影响,即不受isHapticFeedbackEnabled()的影响),
    // 第三个是FLAG_IGNORE_GLOBAL_SETTING(不受系统设置的影响,即不受是否开启震动反馈的影响)
                }
            });

     广播监听音量变化

        //注册当音量发生变化时接收的广播
        private void myRegisterReceiver(){
            MyVolumeReceiver mVolumeReceiver = new MyVolumeReceiver() ;
            IntentFilter filter = new IntentFilter() ;
            filter.addAction("android.media.VOLUME_CHANGED_ACTION") ;
            registerReceiver(mVolumeReceiver, filter) ;
        }
    
        //处理音量变化时的界面显示
        private class MyVolumeReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                //如果音量发生变化则更改seekbar的位置
                if(intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")){
    //AudioManager mAm = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);                
                    // 当前的媒体音量
                    currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) ;
                    mView_sb_play_volume.setProgress(currentVolume) ;
                }
            }
        }

    二、HapticFeedback(震动反馈)

     

    首先,说明该震动方式不需要设置震动权限!!不需要设置震动权限!!不需要设置震动权限!!重要的事情说三遍。

    从上面案例中所见,在SeekBar设置改变监听里自定义触发震动,下面先看一下源码讲解。

     

    如下文所示,点击也会触发震动反馈了:

          click.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
    
                }
            });

    现在我们就去performHapticFeedback源码看下,都执行了什么。View.performHapticFeedback源码:

    /**
         * BZZZTT!!1!
         *
         * <p>Provide haptic feedback to the user for this view.
         *
         * <p>The framework will provide haptic feedback for some built in actions,
         * such as long presses, but you may wish to provide feedback for your
         * own widget.
         *
         * <p>The feedback will only be performed if
         * {@link #isHapticFeedbackEnabled()} is true.
         *
         * @param feedbackConstant One of the constants defined in
         * {@link HapticFeedbackConstants}
         */
        public boolean performHapticFeedback(int feedbackConstant) {
            return performHapticFeedback(feedbackConstant, 0);
        }

    这里解释三个知识点:

    1、只有在isHapticFeedbackEnabled()为true的情况下,才会触发震动。之后会解释在为false的情况下,为何不会触发震动。

          在xml里,可以通过android:hapticFeedbackEnabled=”false|true”来进行设置

          在java代码里,可以通过view.setHapticFeedbackEnabled(boolean)来设置,不过默认是true哦。

    2、HapticFeedbackConstants的常量值,我们要用到的有三个:

     

    • LONG_PRESS(长按);
    • FLAG_IGNORE_VIEW_SETTING(不受view的设置影响,即不受isHapticFeedbackEnabled()的影响);
    • FLAG_IGNORE_GLOBAL_SETTING(不受系统设置的影响,即不受是否开启震动反馈的影响);

     

    3、最终是返回的performHapticFeedback(int feedbackConstant, int flags)这个方法。

        View.performHapticFeedback(int feedbackConstant, int flags)源码:

    /**
         * BZZZTT!!1!
         *
         * <p>Like {@link #performHapticFeedback(int)}, with additional options.
         *
         * @param feedbackConstant One of the constants defined in
         * {@link HapticFeedbackConstants}
         * @param flags Additional flags as per {@link HapticFeedbackConstants}.
         */
        public boolean performHapticFeedback(int feedbackConstant, int flags) {
            if (mAttachInfo == null) {
                return false;
            }
            //noinspection SimplifiableIfStatement
            if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0
                    && !isHapticFeedbackEnabled()) {
                return false;
            }
            return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant,
                    (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0);
        }

     

    看第15行的if语句,当flags=0时,flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING为0,又isHapticFeedbackEnabled()为false,整个条件为真,所以会执行17行,直接return。这也是为什么performHapticFeedback(int feedbackConstant)方法一定要在isHapticFeedbackEnabled()为ture的情况下才会触发震动。 在这里说一下,&是按位与,返回数值,&&逻辑与,返回布尔值。 第19-20行,就是触发底层震动的代码了,之后代码不做分析。

    案例:

    在单击事件,会触发震动:

    click.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);//长按
                }
            });

    如果xml加上 android:hapticFeedbackEnabled=”false”这句话,单击事件没有震动效果了。如下所示:

    <Button
            android:layout_width="wrap_content"
            android:id="@+id/click"
            android:layout_height="wrap_content"
            android:hapticFeedbackEnabled="false"
            android:text="make" />

    如果这时,想让其震动,可以用如下方法来做:

    click.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS
    			 ,HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);//忽略view属性设置
                }
            });

    还记得本篇文章之前,说去设置里打开触摸时震动的开关吗,其实,用户不打开,照样可以让其震动,只需要用如下的方法:

    click.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    v.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS
    			 ,HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
                }
            });

     

    三、Vibrator(振荡器)

    震动的系统权限

    <uses-permission android:name="android.permission.VIBRATE"/>

    获取实例:

     Vibrator  vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);

    两种震动方式:

    1、按照指定的模式去震动:

     vibrator.vibrate(new long[]{100,1000,1000,1000}, -1);

    数组参数意义:

    • 第一个参数为等待指定时间后开始震动,震动时间为第二个参数; 后边的参数依次为等待震动和震动的时间;
    • 第二个参数为重复次数,-1为不重复,0为一直震动;

    2、指定震动的时间,数据类型long,单位为毫秒,一毫秒为1/1000秒

      vibrator.vibrate(2000);


    取消震动:

    注意:震动为一直震动的话,如果不取消震动,就算退出,也会一直震动

    vibrator.cancel();

    案例:

    XML 

    <Button
        android:id="@+id/vibrator1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="35dp"
        android:text="震动模式一间断性"/>
    
    
    <Button
        android:id="@+id/vibrator2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="震动模式二独立性"/>

    Activity

    private Button vibrator1,vibrator2;//控件
    private Vibrator vibrator;//震动
    vibrator1 = (Button) findViewById(R.id.vibrator1);
     vibrator2 =(Button)findViewById(R.id.vibrator2);
     vibrator1.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View view) {
             vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
             vibrator.vibrate(new long[]{100,1000,1000,1000}, -1);
             //按照指定的模式去震动。数组参数意义:
             // 第一个参数为等待指定时间后开始震动,震动时间为第二个参数; 后边的参数依次为等待震动和震动的时间;
             // 第二个参数为重复次数,-1为不重复,0为一直震动;
         }
     });
     vibrator2.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View view) {
             vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
             vibrator.vibrate(2000);//震动指定时间 ,数据类型long,单位为毫秒,一毫秒为1/1000秒
         }
     });
    // vibrator.cancel();//取消震动,立即停止震动震动为一直震动的话,如果不取消震动,就算退出,也会一直震动

     

    源码:安卓系统音频震动demohttp://download.csdn.net/download/csdn_aiyang/9970166

     

     

    加群一起学习,我们不是一个人战斗:

     

     

     

     

    展开全文
  • 蓝牙音乐静音

    2020-11-04 10:00:59
    蓝牙音乐静音的实现方案从上图也就非常明了,当前的安卓系统主要是在音频数据上报到 SNK 端的蓝牙协议栈时不进行保存,从而没有解码后的音频数据送入安卓多媒体系统 AudioTrack 来实现的。 上述方案的实现主要依赖...

    蓝牙音乐静音

    在这里插入图片描述

    大家想必对静音功能不陌生,相关场景下该功能很实用。现在的终端设备上有整个音频系统的静音,当然也有局部功能的静音,其中的蓝牙音乐也是提供静音操作的,本期和大家简单分享下蓝牙音乐静音在安卓系统中的实现。

    蓝牙音乐的音频数据基本按照如下流程从 SRC 传送到 SNK:

    在这里插入图片描述

    蓝牙音乐静音的实现方案从上图也就非常明了,当前的安卓系统主要是在音频数据上报到 SNK 端的蓝牙协议栈时不进行保存,从而没有解码后的音频数据送入安卓多媒体系统 AudioTrack 来实现的。

    上述方案的实现主要依赖协议栈 btif_a2dp_sink.cc 中定义的全局变量 btif_a2dp_sink_cb 中的两个基本变量:
    在这里插入图片描述

    rx_focus_state 变量受蓝牙服务层控制,变量含义顾名思义表示当前的蓝牙音乐是否具有音频焦点,而布尔值的 rx_flush 表示接收到的音频数据是否保存,其和 rx_focus_state 是一 一对应的关系:
    在这里插入图片描述

    这样蓝牙服务也就间接通过 rx_flush 在函数btif_a2dp_sink_enqueue_buf()中实现了蓝牙音乐静音。

    蓝牙服务层中的接口为A2dpSinkStateMachine.informAudioFocusStateNative(),还需在framework层中添加接口函数才能打通应用层到蓝牙服务的调用,相信大家都可以轻松实现。

    蓝牙音乐静音功能遇到的问题:
    静音成功后再解除静音,重新播放蓝牙音乐往往会伴随着一声pop音

    针对该问题首先需要分析下蓝牙协议栈将解码后的音频数据送入AudioTrack是否异常,打开宏变量 DUMP_PCM_DATA 记录蓝牙音乐音频数据PCM流,使用PCM流查看工具打开发现送给系统的PCM流很正常啊。

    最后请教系统音频的同事后才了解其中的缘由,蓝牙协议栈在静音时是停止往系统AudioFlinger写数据,AudioFlinger会检测通道内是否有数据,这样超过一定时间没有数据后,AudioFlinger会关闭蓝牙协议栈对应的音频通道。然后再解除静音系统会重新打开音频通道,由于打开通道需要时间,但蓝牙协议栈是在解除静音后就开始往送AudioTrack中写数据了,由于存在这样的时序问题才会伴随着一声pop音。

    基于AudioFlinger会检测是否有数据这一特性,理想的修复方案就是蓝牙协议栈在静音后往给AudioFlinger 写入空数据,从而避免 AudioFlinger 检测通道一定时间没有送数据后关闭通道。

    解决方案:SNK 端的蓝牙协议栈还是正常接收音频数据加入 btif_a2dp_sink_cb.rx_audio_queue 队列保存,只需在音频数据解码完成的处理函数 btif_a2dp_sink_on_decode_complete()中加以判断,如果当前处于静音状态,则将解码后的数据直接memset重置为0的空数据即可。

    蓝牙音乐静音的分享到这里就结束了,感兴趣的小伙伴欢迎私信留言一起讨论,共同学习,一起进步!

    更多互联互通技术,欢迎关注微信公众号:Connectivity
    在这里插入图片描述

    展开全文
  • 多媒体

    千次阅读 2016-07-12 23:56:22
    本章将结合Web前端的发展历程和未来的发展前景详解现在HTML5中引入的多媒体技术HTML5的多媒体支持在HTML5规范出来之前,网页对视频和音频播放的支持基本上是靠Flash插件来实现,在HTML5之后,同文字和图片一样,音频...
    本章将结合Web前端的发展历程和未来的发展前景详解现在HTML5中引入的多媒体技术

    HTML5的多媒体支持

    在HTML5规范出来之前,网页对视频和音频播放的支持基本上是靠Flash插件来实现,在HTML5之后,同文字和图片一样,音频和视频直接变成HTML一系列规范中第一等公民,首先是JavaScript接口的支持,开发者可以使用JavaScript接口来方便的控制音视频的播放,实现例如播放、停止和记录等功能,其次HTML5中多媒体与图片一样可以用其他技术来进行操作,例如使用CSS技术来修改它的样式,例如3D变形,Web开发者可以将视频同Canvas2D或者WebGL结合在一起,而Flash插件中的视频是不能做到的。在HTML5中,对于多媒体的支持大致可以包括一下几个部分:第一是HTML的元素“video”,他用于音视频的播放;第二是“audio”,它用于单纯的音频播放;第三是可以将多个声音合成处理的WebAudio技术;第四是将照相机、麦克分与视频、音频和通信结合起来使用的最新技术WebRTC(网络实时通信),这使得Web领域使用视频对话和视频网络会议成为了现实。

    视频

    HTML5视频

    在HTML5规范定义中,Web开发者可以使用“video”元素来播放视频资源,其中视频涉及到视频编码格式,目前标准中包含了三种编码格式:Ogg、MPEG4和WebM,其中Ogg使用Theora作为视频编码格式和Vorbis作为音频编码格式,MPEG4使用H.264作为视频编码格式和AAC作为音频编码格式,WebM是有Google研发的标准,使用VP8作为视频编码格式和Vorbis作为音频编码格式。HTML提供了一些属性让开发者来使用JavaScript代码检查和操作视频,HTML5在“video”和“audio”元素之间抽象了一个基类元素“media”,结合它提供的能力,大致有一下几个方面的JavaScript编程接口,首先是资源加载和信息方面的接口,开发者可以通过特定接口检查游览器支持什么格式,如Metadata和海报(Poster)等,其次是缓冲(Buffering)处理,包括缓冲区域、进度等信息,然后是播放方面的状态,包括播放、暂停、终止等。再次是搜寻(Seeking)方面的信息,包括设置当前时间、“Timeupdate”事件,以及两个状态“Seeking”和“seeked”,最后是音量方面的设置,包括获取和设置音量、静音和音量变换等事件。

    WebKit基础设施

    WebKit提供了支持多媒体规范的基础框架,如音视频元素、JavaScript接口和视频播放等,根据WebKit的一般设计思想,它主要是提供标准的实现框架,而具体的实现有各个移植类来完成,因为音视频需要平台的支持,下图显示了各个类和它们之间的关系,也包括了Chromium移动的几个基础类:
    这里写图片描述
    首先WebKit是支持规范定义的编程接口,图中左侧的HTMLMediaElement和HTMLVideoElement类是DOM树中的节点类,包括众多的DOM接口,这些接口可以被JavaScript代码访问;其次是MediaPlayer和MediaPlayerClient两个类,MediaPlayer类是一个公共标准累,被HTMLMediaElement类使用来播放音频和视频,它本身支持提供抽象接口,具体实现依赖于不同的WebKit移植,同时一些播放器中的状态信息需要通知到HTMLMediaElement类,这里使用MediaPlayerClient类来定义这些有关状态信息的接口,HTMLMediaElement类需要继承MediaPlayerClient类并接收这些状态信息,根据前面的描述,规范要求将事件派发到JavaScript代码中,而这个实现在HTMLMediaElement类完成,然后是不同移植对MediaPlayer类的实现,其中包括MediaPlayerPrivateInterface类和WebMediaPlayerClientImpl类,前者是除了Chromium移植之外使用的标准接口也是一个抽象接口,由不同移植来实现,后者是Chromium移植的实现类,因为Chromium将WebKit复制出Blink之后就将MediaPlayerPrivateInterface类直接移除了,而在MediaPlayer类中直接调用它,WebMediaPlayerClientImpl类会使用Chromium移植自己定义的WebMediaPlayer接口类来作为实际的播放器,而真正的播放器则是在Chromium项目的代码中来实现,最后同渲染有关,这里就是之前介绍的RenderObject树和RenderLayer树,图中的RenderMedia类和RenderVideo类是RenderObject的子类,用于表示Media节点和Video节点。

    Chromium视频机制
    资源获取

    由于视频资源相对其他资源而言比较大,当用户播放视频的时候需要连续性播放以获得较好的体验,但是网络可能并不是移植都稳定和告诉,所以资源的获取对用户体验很重要,需要使用缓存机制或者其他机制来预先获取视频资源。下图是Chromium中的缓存资源类,BufferedDataSource类表示资源数据,它是一个简单的数据表示类,内存包含一个较小的内存空间(32K),实际的缓冲机制由BufferedResourceLoader类完成,在Chromium的设置中,最小的缓存空间是2M内存,最大的缓存空间是20M,并没有使用磁盘来缓存视频资源:
    这里写图片描述

    基础设施

    下图是chromium中支持硬件加速机制的视频播放所需基础设施的总体架构图,基于Chromium的多进程结构:
    这里写图片描述
    根据多进程架构的设计原则,Chromium的媒体播放器的实现应该在Renderer进程,而对于资源的获取则是在Browser进程,其中WebKit基础设施需要每个移植的具体实现,因此WebKit的Chromium移植部分提供了桥接接口,并且实现则是在Chromium代码中来完成,Chromium支持媒体播放器的具体实现涉及到不同的操作系统,目前Chromium在不同操作系统上实现的媒体播放器也不一样,下图显示了Chromium的基础类:
    这里写图片描述
    上半部分是WebKit和WebKit的Chromium移植中的相关类,下半部分是Chromium中使用硬件加速机制来实现视频播放的基础设施类,从做到分开来看,左边部分是播放器的具体实现类,右边部分是支持视频在合成器中工作的相关类。
    首先看下这些类和对象的创建过程,WebMediaPlayerClientImpl类是WebKit在创建HTMLMediaElement对象之后创建MediaPlayer对象的时候有MediaPlayer对象来创建的,当视频资源开始加载时,WebKit创建一个WebMediaPlayer对象,当然就是Chromium中的具体实现类WebMediaPlayerImpl对象,同时WebMediaPlayerClientImpl类也实现了WebMediaPlayerClient类,所以WebMediaPlayerImpl在播放视频的过程中需要向该WebMediaPlayerClient类更新各种状态,这些状态信息最终会传递到HTMLMediaElement类中,最终可能成为JavaScript事件,之后WebMediaPlayerImpl对象会创建一个WebLayerImpl对象,海湖同时创建VideoLayer对象,根据合成器的设计,Chromium还有一个LayerImpl树,在同步的时候,VideoLayer对象对应的VideoLayerImpl对象会被创建,之后Chromium需要创建VideoFrameProviderClientImpl对象,该对象将合成器的Video层同视频播放器联系起来并将合成器绘制一帧的请求转给提供视频内容的VideoFrameProvider类,这实际上是调用Chromium的媒体播放器WebMediaPlayerImpl,因为它是一个VideoFrameProvider类的实现子类,然后是Chromium如何使用这些类来生成和显示每一帧,当合成器调用每一层来绘制下一帧的时候,VideoFrameProviderClientImpl::AcquireLockAndCurrentFrame()函数会被调用,然后该函数调用WebMediaPlayerImpl类的GetCurrentFrame函数返回当前一帧的数据,VideoLayerImpl类根据需要会将这一帧数据上传到GPU的纹理对象中,当绘制完这一帧之后,VideoLayerImpl调用VidelFrameProviderClientImpl::PutCurrentFrame来通知播放器这一帧已绘制完成,并释放掉相应的资源,同时,媒体播放器也可以通知合成器有一些新帧生成,需要绘制出来,它会首先调用播放器的VideoFrameProvider::DidReceiveFrame()函数,该函数用来检查当前有没有一个VideoLayerImpl对象,如果有对象存在,需要设置它的SetNeedsRedraw标记位,这样合成器就知道需要重新生成新的一帧,最后是有关视频播放对象的销毁过程,有多种情况使Chromium需要销毁媒体播放器和相关的资源,如“video”元素被移除或者设置为隐藏等,这样视频元素对应的各种层对象以及WebKit和Chromium中的这些设施都会被销毁,WebMediaPalyerImpl类是多媒体播放器的具体实现类,在Chromium项目中,随着对Android系统的支持,Chromium既能支持左面系统也能支持移动系统,而这两者对视频和音频的支持很不一样,所以在不同系统上WebMediaPlayerImpl是如何实现和工作的也很不一样。

    桌面系统

    在桌面系统中,Chroimum使用了一套多媒体播放框架,而不是直接使用系统或者第三方库的完整解决方案,下图是Chromium在桌面系统上采用的多媒体播放引擎的工作模块和过程,这一框架称为多媒体管线化引擎,图中主要的模块四号多路分配器、音视频解码器、音视频渲染器,这些部分主要被WebMediaPlayerImpl类调用:
    这里写图片描述
    在处理音视频的管线化过程中,需要解码器和渲染其来分别处理视频和音频数据,它们均采用一种叫做“拉”而不是“推”的方式进行,也就是说有视频或者音频渲染器根据声卡或者时钟控制器,按需求来请求解码器解码数据,然后解码器和渲染器又向前请求“拉”数据,直到请求从视频资源文件读入数据,根据之前的多进程架构和Chromium的安全机制,整个管线化引擎虽然在Render进程中,但是由于Render进程不能访问声卡,所以渲染器需要通过IPC将数据或者消息同Browser进程通信,由Browser进程来访问声卡。虽然FFmpeg多媒体库拥有上述管线化的能力,但Chromium并不是将其作为一个黑盒来使用,而是分别使用FFmpeg的不同模块来实现自己的管线化引擎,目的是由自身来控制这一整个过程。Chromum使用并行FFmpeg解码技术,也就是说FFmpeg能够在帧这个层面上并行解码,当然不是针对所有格式的视频文件,目前主要针对H.264这个格式的视频。

    Android系统

    Chromium使用的是Android系统所提供的android.media.MediaPlayer类,也就是使用系统提供的音视频的渲染框架,在减少了管线化引擎带来复杂性的同时,也引入了一些额外的复杂问题。Android中的Chromium彻底抛弃了FFmpeg,直接使用系统自带的多媒体功能,因而,Android系统支持什么样的音视频格式,Chromium就只能支持什么样的相应格式,同时由于Android多媒体框架的优点使得视频元素仍然能够同HTML5中的其他技术一起工作。
    Ⅰ Android媒体播放框架
    Android中使用一个名为“MediaService”的服务进程来为应用程序提供音频和视频的播放功能,对于每一个使用多媒体播发功能的应用程序来说,“MediaService”服务是透明的,因为Android系统提供了“MediaService”的封装接口,这些接口隐藏了“MediaService”服务内部的细节,应用程序只是使用了简单的播放接口。MediaService能够为多个播放器提供服务,对于播放器来说,它的主要设置为两个参数,其一是输入的URL,第二是输出结果的绘制目标,下图描述了Android的播放器类和相关类:
    这里写图片描述
    当应用程序使用播放器的时候,Chromium可以创建MediaPlayer类的对象,调用setDataSource函数来设置待播放视频文件,并调用setSurface来设置视频结果绘制的目标-SurfaceTexture对象,这是一个GL的纹理对象,实际的解码和绘制是在MediaService进程中完成,这需要该纹理对象能够被多个不同的GL上下文对象所访问,支持多个GL上下文对象访问的GL纹理对象的类型GL_TEXTURE_EXTERNAL_OES,由此可以看到Chromium使用Android系统提供的音视频播放功能,表示Chromium使用Android系统的音视频解码器,所以Chromium是依赖与Android系统支持的音视频编码格式,而不像Chromium桌面版独立与操作系统的音视频编码格式。
    Ⅱ Chromium的视频解决方案
    在Android系统上,因为Chromium使用系统的多媒体框架,所以没有自己的管线化引擎,主要的工作是将Chromium的架构同Android多媒体框架结合起来以完成对网页中视频和音频的播放。下图是Chromium的Android系统上支持音频和视频播放的播放器主要类,因为Chromium的多进程架构,所以这里面包括两大部分,首先是右侧的Render进程的相关类,根据前面Chromium的桌面版上支持多媒体的相关类,可以看到WebKit::WebMediaPlayer类和WebMediaPlayerClient类来自于WebKit的Chromium移植,这两个类在所有平台上的定义都是一样的:
    这里写图片描述
    上图中右侧的Render进程,从上向下首先是WebMediaPlayerAndroid类,它同之前的WebMediaPlayerImpl类相似,表示的是Android系统上网页中的播放器,同video元素是一一对应的,与桌面系统不一样的是,Android系统使用RendeerMediaPlayerManager类来管理所有的WebMediaPlayerAndroid对象,因为一个网页中可能包含多个播放器实例,而WebMediaPlayerProxyAndroid则是同Browser进程来通信的,因为真正的Android播放器是在Browser进程中,主要请求Browser进程创建实际的Android的MediaPlayer类并设置播放文件的信息,左侧则是实际的播放器,在JNI(Java Native Interface)之上的是Java类,该播放器就是使用Android系统的android.media.MediaPlayer及其相关类来工作的,从下向上看首先是BrowserMediaPlayerManager类,该类不仅负责同Render进程的播放器类进行通信,而且自身又是一个播放器的管理类,它包含当前全部网页中的所有播放器对象,因为可能会有多个Render进程,所以只能通过播放器的唯一标记来区分这些播放器,BrowserMediaPlayerManager类管理称为MediaPlayerAndroid类的多个对象,而MediaPlayerAndroid的子类MediaPlayerBridge则是具体实现类,该子类能够与Java层中相同名字类通过JNI调用来控制Android系统的播放器类,以上的基本过程就是如何在网页中创建一个播放器,从右向左直到android.media.MediaPlayer对象被创建,同时Chromium获取网页中设置的视频文件的URL字符串然后传递并设置该URL字符串到Android的媒体播放器作为输入,对于输出Chrome使用SurfaceTexture对象作为输出目标,当Chromium调用WebMediaPlayerAndroid类的play函数时,该函数发起请求从Render进程到Browser进程来创建输出目标,也就是SurfeceTexture对象,下图描述了这个过程中使用到的主要类和之间的关系:
    这里写图片描述
    右侧的Render进程,最上面的StreamTexureFactoryImpl是创建目标结果存储空间的类,它被WebMediaPlayerAndroid类使用来创建所需要的结果存储对象StreamTexture,由于实际的对象是在Browser进程中创建的,所以Render进程中的StreamTextureProxy类就是一个代理类,最后的请求是通过GPUChannelHost类传递给Browser进程。在Browser进程中,负责处理上述请求的是GPU线程,该线程有StreamTextureManagerAndroid类处理所有创建StreamTexture对象的请求,StreamTexture对象的直接使用者是GPU线程,Render进程需要区分和标识这些StreamTexture对象,具体的方法是使用整形标记符来表示Browser进程中的各个StreamTexture对象,StreamTexture和StreamTextureManager是基础抽象类,在Android系统上,StreamTextureAndroid和StreamTextureManagerAndroid是实际的实现类,StreamTextureAndroid表示的是C++端的桥接类,它包含一个SurfaceTexture对象,该对象会在Java端创建一个android.graphics.SurfaceTexture对象,Chromium设置该对象到MediaPlayer对象作为播放器的输出目标,当视频播放器将解码后的结果写入到SurfaceTexture中后,播放器需要告诉Chromium游览器这一信息,Chroimum游览器需要执行合成操作而合成器在Render进程中,同之前创建SurfaceTexture对象的调用过程正好相反,这里需要使用回调机制,这就是Java层SurfaceTextureListener类的作用,该回调类注册Java层的回调对象到创建好的SurfaceTexture对象,当该对象被写入新的帧的时候,Chromium首先从Browse进程中的Java层将这一回调动作通过JNI到C++层的SurfaceTextureListener类的FrameAvailable函数,该函数经过StreamTextureAndroid和StreamTextureManagerAndroid类最后发送到Render进程,Render进程的调用过程如下:
    这里写图片描述
    网页中的视频播放有两种模式,其一是嵌入式模式,其二是全屏模式,这两种模式在解码后结果的处理上是不一样的,下图描述了全屏模式创建视频结果的绘制目标的相关类和过程:
    这里写图片描述
    当播放器进入全屏模式的时候,Chromium使用ContentVideoView类来管理,该类会创建一个SurfaceView对象并将对象传递给C++端的ContentVideoView类,因为统一时刻只有一个播放器是全屏模式,而且BrowserMediaPlayerManager管理所有的MediaPlayer对象,该管理类能够知道哪个对象是全屏模式,并将该SurfaceView对象设置到相应的MediaPlayer对象中去。

    字幕

    视频需要字母的支持,W3C组织已经开始定义支持字幕的“trace”元素,而字幕文件采用的格式是WebVTT格式,该格式看起来比较直观,简单的例子就是时间戳区间加上相应的字母文字,一下是使用字母的视频元素,因为语言的问题,每个“video”元素可以有多个“trace”元素,每个“trace”元素可以用来表示一个语言:

    <video controls="controls">
      <source src="video.mp4" type="video/mp4">
      <trace src="trace.vtt" kind="subtitles" srclang="en" label="English"></trace>
    </video>

    字幕文件的解释工作不依赖与各个WebKit移植,WebCore模块支持“track”元素解析、字幕文件解析等功能,下图是WebKit支持字幕功能的主要类:
    这里写图片描述
    “track”本身是一个HTML元素,因此它在DOM中有相应的节点元素,这就是HTMLTrackElement类,根据规范,“track“元素有一个重要的属性”src“,该属性指定了字幕文件的URL,WebKit使用LoadableTextTrack类来负责解析字幕文件并使用TextTrack类来存储解析后的结果,目前WebKit只支持WebVTT格式的字幕,使用WebVTTParser解析器来解释它们。
    下面一部分是提供接口,这里的接口是WebKit的Chromium移植所定义的接口不同额移植所定义的接口可能不一样,接口有两个类,WebInbandTextTrack和WebInbandTextTrackClient类,且是公开接口,WebInbandTextTrack类是有Chromium实现由WebKit调用,而WebInbandTextTrackClient则是有WebKit实现,实现类就是InbandTextTrackPrivateImpl,它实现WebInbandTextTrackClient的接口,然后后调用解析后的字幕并返回给Chromium。上述需要将一些消息传递给JavaScript代码,因为规范提供了JavaScript接口,开发者可以让JavaScript代码控制或者获取字幕信息,下面是Chromium中支持框架,下图描述了Chromium是如何将WebKit中的字幕信息桥接到多媒体管线化引擎中的:
    这里写图片描述
    在Chromium中,WebMediaPlayerImpl类创建继承类的对象,并设置WebInbandTextTrackClient对戏那个到该对象,该对象实际上是InTextTrack,它包含解析后的字幕内容,这样TextTrackImpl就可以获取字幕的内容,而TextTrack对象会被多媒体的管线化引擎多调用并渲染在视频的结果中。

    音频

    音频元素

    音频支持不仅指对声音的播放,还包括对音频的编辑和合成以及对乐器数字接口等的支持。

    HTML5 Audio元素

    在HTML5中使用”audio“元素来表示,同视频类似,HTML5标准中定义了三种格式:Ogg、MP3和Wav,因为视频内容通常包含音频数据,所以不仅仅是”audio“元素才会使用音频播放,同时,音频的字幕同视频一样,”track“元素也可以用在”audio“元素的字母中,用来显示字幕。

    基础设施

    音频的支持方面还是从输入和输出两个方面着手,对于输入,同视频类似,WebKit使用资源加载器先加载音频文件,之后建立音频元素、管线话引擎相关类,如MediaPlayer类,HTMLAudioElement和WebMediaPlayer类等,同视频不一样的是,视频的输出是GPU中的纹理对象,而音频需要输出到声卡,因此需要打开声卡设备,由于Chromium的沙箱模型机制,所以只能靠Browser进程来打开和关闭声卡设备,下图描述了多进程中如何将音频从Render进程传输到Browser进程,以及WebKit和Chromium中相应的基础设施:
    这里写图片描述
    首先看Render进程,从上玩下介绍如下:

    • WebKit::WebAudioSourceProvider和WebKit::WebAudioSourceProviderClient:最上面两个类是WebKit的Chromium移植接口类,前者提供音频原数据,也就是音频文件中的数据,这里采用“拉”的方式,也就是在ResourceLoader加载数据之后,当且仅当渲染引擎需要新的数据的时候,主动从加载后的数据中拉出数据来进行解码,“provideInput”函数由Chromium实现,由WebKit引擎调用,WebKit::WebAudioSourceProviderClient提供“setFormat”函数,用于让Chromium的媒体播放器设置频道数量、采样率等信息,WebAudioSourceProviderImpl是WebKit::WebAudioSourceProvider的实现类
    • AudioRendererImpl:该类是音频渲染器的实现,并使用AudioRenderSink将音频解码的结果输出到音频设备
    • AudioRendererSink:一个抽象类,用于表示一个音频终端店,能够接收解码后的音频信息,典型的例子就是音频设备
    • AudioRendererMixer:渲染器中的调用类
    • AudioOutputDevice:音频的输出设备,当然只是一个桥接层,因为实际的调用请求是通过下面两个类传送给Browser进程的
    • AudioOutputIPCImpl和AudioMessageFilter:前者将数据和指令通过IPC发送给Browser进程,后者就是执行消息发送机制的类

    下面是Browser进程,从下向上一次介绍:

    • AudioRendererHost:Browser进程端同Renderer进程通信并调度管理输出视频流的功能,对于每个输出流,有相应的AudioOutputStream对象对应,并且通过AudioOutputController类处理和优化输出
    • AudioOutputController:该类控制一个AudioOutputStream对象并提供数据给该对象,提供play、pause、stop等功能,因为它控制这音频的输出结果
    • AudiOutputStream和AudioOutputProxy:音频的输出流类和其子类,AudioOutputProxy是一个使用优化算法的类,它仅在Start()和Stop()函数之间打开音频设备,其他情况下音频设备都是关闭的,AudioOutputProxy使用AudioOutputDispatcher打开和关闭实际的物理音频设备
    • AudioOutputDispatcher和AudioOutputDispatcherImpl:控制音频设备的接口类和实际实现类

    由此可以得出当WebKit和Chromium需要输出解码后的音频数据是,通过从侧自上向下、左侧自下向上的过程,然后使用共享内存的方式将解码后的数据输出到实际的物理设备中。

    Web Audio

    Audio元素能够用来播放各种格式的音频,但是HTML5还拥有更强大的能力来处理声音,这就是Web Audio,该规范提供了搞层次的JavaScript接口,用来处理和合成声音,整个思路就是提供一张图,giant图中的每个节点称为AudioNode,这些节点构成处理的整个过程,虽然实际的处理是使用C/C++来完成,但是Web Audio也提供了一些接口来让Web前端开发者使用JavaScript代码来调用C/C++的实现,WebAudio对于很多Web应用很有帮助,例如它呢能够帮助开发者设计和实时合成出各种音效,根据W3C的Web Audio规范的定义,整个处理过程可以看成一个拓扑图,该图有一个或多个输入源,称为Source节点,中间的所有点都可以看成各种处理过程,它们组成复杂的网,图中有一个最终节点称为“Destination”,它可以表示实际的音频设备,每个图只能有一个该类型的节点,上述图中的所有节点都是工作在一个上下文中,称为AudioContext:
    这里写图片描述
    对于Source1节点,它没有输入节点,hi有输出节点,对于中间的这些节点,它们既包含输入节点也包含输出节点,而对应Destination节点,它只有输入节点,没有输出节点,图中的其他节点都是可以任意定义的,这些即诶但每一个都可以代表一种处理算法,开发者可以根据需要设置不同的节点以处理出不同效果的音频输出,中间这些节点有很多类型,它们的作用也不一样,这些节点的实现通常由C或者C++代码来完成以达到高性能,当然这里提供的接口都是JavaScript接口。Web Audio的绝大多数处理都是在WebKi中完成的,而不需要Chromium过多的参与,除了输入源和输出结果到实际设备,其他同前面的多媒体数据源是一致的。下图的上半部分主要是支持规范中的标准接口,例如AudioBufferSourceNode、AudioContext、DestinationNode和OscillatorNode等类,它们对应上图中规范定义的接口,还有众多类没有绘出,以下重点关注OsicllatorNode类,它需要对音频数据进行大量计算,包括向量的加法、乘法等,同时该节点类需要使用PeriodicWave来计算周期性波形,这里面需要使用到FFT(快速傅立叶变换)算法,因为音频的及时性,网页对性能有非常高的要求,对于Chromium移植,不同平台采用不同的加速算法,在Windows和Linux中使用FFMpeg中的高性能算法,在Android上使用OpenMax DL提供的接口来加速,而在Mac上又是不同的算法:
    这里写图片描述

    MIDI和Web MIDI

    MIDI是一个通信标准,它是电子乐器之间,以及电子乐器与电脑之间的统一交流协议,用以确定电脑音乐程序、合成器和其他电子音响设备互相交换信息与控制信息的方法,同其他的声音格式不同,MIDI不是记录采样信息,而是记录乐器的演奏指令。音频也可以以MIDI格式来存储,但是该格式不是HTML5的标准,所以游览器并没有内置支持它们,为了让MIDI格式的音乐播放出来,可以使用JavaScript代码,这就是MIDI.js,它使用上面提到的WebAudio技术和Audio元素来实现音乐的播放。Web MIDI规范中定义了输入和输出的MIDI设备,如MIDIInput和MIDIOutput,通过MIDIAccess接口分那会到所有枚举的输入和输出设备,MIDIInput主要包含一个接收指令的函数“onMessage”,而MIDIOutput包含一个发送指令的函数“send”,而发送的数据指令就是MIDIEvent,该指令包含一个时间戳和数据,WebKIt和Chromium对于Web MIDI的支持主要包括三个部分,第一是加入JavaScript的绑定,第二是将对MIDI接口的支持从Redner进程桥接到Browser进程,第三是Chromium的具体实现。

    WebRTC

    WebRTC(Web Real Time Communication)技术,中文全称为Web实时通信技术,是一种提供实时视频通信的规范,目前是W3C推荐的规范。

    原理和规范

    构建网络视频通信需要三种类型的技术,其一是视频,其二是音频,其三是网络传输

    • 音视频输入和输出设备:同音视频播放不同,因为它们只是需要输出设备,这里需要输入和输出设备,同时输入使用getUserMedia技术,而输出基本上可以采用音视频播放的基本框架
    • 网络连接的建立:因为视频通信需要不停的传送大量数据,所以需要建立一种可靠的网络连接来让各个参与方传输数据
    • 数据捕获、比那吗和发送:当用户打开设备之后,需要捕获这些数据并对它们进行编码,因为原始数据的数据量太大,然后需要将编码后的数据通过连接传输出去
    • 数据接收、解码和显示:接收来自其他方的数据流并进行解码,然后显示出来,这个跟播放媒体文件的需求比较类似

    下图结合主要组成部分构建一个比较完整的音视频通信过程:
    这里写图片描述
    下面了解一下规范中如何针对上面的描述来定义相应的JavaScript接口,根据W3C推荐的规范草案,主要包括一下几个部分:

    • Media Capture and Streams 规范和WebRTC对它的扩展,这个主要是依赖摄像头和麦克风来捕获多媒体流,WebRTC对它进行扩展,使得多媒体流可以满足网络传输用途,也就是“video”元素可以来源与多媒体流而不仅仅是资源文件
    • 点到点的连接,也就是规范中的RTCPeerConnection接口,它能够建立端到端的连接,两者直接通过某种方式传输控制信息,至于方式并没有进行规定
    • RTCDataChannel接口,通过该接口,通信双方可以发哦是那个任何类型的信息,例如文本或者二进制数据,这个不是必须的,不过这个功能极大的方便了开发者,其主要思想来源与WebSocket
    WebKit和Chromium的实现

    首先了解下WebRTC技术的内部框架和功能模块,下图主要包括三大方面,即语言、视频和传输,它们三个构成WebRTC的主要组成部分,其中iSAC(internet Speech Audio Codec)和iLBC(internet Low Bitrate Codec)是两种不同的音频编码格式,是为了适应互联网的语言传输要求而存在的,前者是针对带宽比较大的情况,后者是针对带宽较小的情况,其中VP8同样是Google提供免费视频格式,传输部分主要是加入了对前面协议的支持模块,在会话管理中,主要使用一个开源项目libjingle来管理,下面部分主要是WebRTC工作时依赖的下层功能的接口,在Chromium游览器中,它会提供相应接口和功能给WebRTC使用:
    这里写图片描述
    上图是WebRTC开源项目的架构图,在Chromium中,通常使用WebRTC项目来完成WebRTC规范的功能,并使用libjingle项目来建立点到点的连接,所有Chromium主要的目的是将WebRTC和libjingle的能力桥接到游览器中来,先看WebRTC规范中建立连接所需要的相关的技术设备,下图是WebKit、Chromium及Chromium中使用libjingle的类的层次图:
    这里写图片描述
    基础设备分成三个层次,首先是WebKit,该部分最上面的类是RTCPeerConnection,该类是对WebRTC连接的接口类,实际上它是从规范中定义的RTCPeerConnection接口文件生成的基本框架,实际真正和JavaScript引擎打交道还需要一个桥接类,该桥接类包含一个实际实现的连接类句柄m_peerHandler,它是这个连接所包含的本地多媒体流和远端对方的多媒体流,场景大致是首先WebKit需要将本地的多媒体流收集起来,通过连接传输给对方,本地可以选择是否通过“video”播放,同时需要接收从对方传输过来的多媒体流,接下来是WebKit的实现类,该类能够满足RTCPeerConnection的功能要求,但是它需要通过不同移植的实现才能完成,因为本身WebKit的WebCore并没有这样的能力,在WebKit的Chromium中同样定义了两个类WebRTCPeerConnectionHandler和WebRTCPeerCOnnectionHandlerClient,根据WebKit的类名定义方式,前者是需要Chroimum来实现,后者则由Chromium调用,并由WebKit来实现,这里主要是应用连接事件的监听函数,所以WebKit能够将它们传递给JavaScript引擎,之后是Chromium的实现类,RTCPeerCOnnectionHandler类继承自WebKit的Chromium移植的接口类,并做了具体的实现,也就是content::RTCPeerConnectionHandler,它同时集成自PeerConnectionHandleBase类,而该类拥有了支持建立连接所需的能力,当然它是依赖于libjingle项目提供的连接能力,libjingle提供了建立和管理连接的能力,支持透过NAT和防火墙设备、代理等建立连接,libjingle不仅支持点到点的连接,也支持多用户连接,同时还包含了连接所使用的MediaStream接口,这是因为Chromium本身不直接使用WebRTC项目提供的接口,而是调用libjingle来建立连接,并使用libjingle提供的MediaStream接口,而libjingle本身则会使用WebRTC项目的音视频处理引擎。
    下面总结下多媒体流,先看下WebKit是怎样支持getUserMedia这个接口的,下图描述了WebKit,以及WebKit的Chroimum移植中所定义的接口:
    这里写图片描述
    最上层的是WebKit支持多媒体流编程接口提供的具体实现类,如NavigatorMediaStream类,而直接同V8JavaScript引擎桥接的类是V8NavigatorUserMediaSuccessCallback,它是一个绑定类,因为getUserMedia接口主要是返回一个MediaStream对象,而MediaStream类可以提供众多访问数据流的接口,而连接的目的就是需要将MediaStream对应的多媒体流传输出去,UserMediaRequest类负责请求创建一个MediaStream对象,在WebKit的Chromium移植中,定义WebUserMediaClient为一个接口类,Chromium需要新建子类来实现这一功能,这就是Chromium中的MediaStreamImpl类。WebKit使用MediaStreamRegistry类来注册和管理对应的类,管理类根据ID信息来识别各个多媒体数据流,在接口层中,Chromium移植使用WebMediaStream类来表示多媒体流,使用WebMediaStreamRegistry类来表示注册管理类,下面的问题是MediaStream接口需要提供各种事件给网页,因为很多实际的工作是在Chromium中来完成的,所以MediaStreamImpl会将这些事件从Chromium传递给WebKit,同时因为Chromium的多进程和沙箱模型,一些工作需要在Browser进程中完成,下图是所描述的跨进程的基础设施:
    这里写图片描述
    IPC左侧部分是Browser进程中的两个主要类,分别是消息处理类和MediaSrteam的管理类,该管理类知道MediaStream对应的网页是什么,并将事件(如创建和销毁等)传回Render进程,右侧是消息派发类,主要帮助MediaStreamImpl类来完成与Browser进程相关的MediaStream消息的传递,MediaStream可以表示本地的多媒体流也可以表示远端的多媒体流,对于本地的多媒体流,需要音频和视频的捕获机制,同时使用上面建立的连接传输给远端,对于远端的多媒体流,需要使用连接来接收数据,并使用到音频和视频的解码能力,下面分成四个部分来分别介绍,首先是音频的捕获机制,下图描述了该机制使用的主要类,当我那工业需要创建多媒体流的时候,MediaStreamImpl会创建音频捕获类WebRtcAudioCapturer类,因为捕获音频需要音频输入设备,所以使用AudioDeviceFactory工厂类创建一个逻辑上的AudioInputDevice对象,另外一个重要的类是WebRtcAudioDeviceImpl,用来表示音频的设备,该类继承自WebRtcAudioDeviceNotImpl类,这其实是继承自libjingle和WebRTC项目中的抽象接口的一个桥接类,用来表示它们需要的音频设备,包括输入鼠辈,同样因为Render进程不能访问音频输入设备,所以需要IPC来完成一个功能,Browser进程的AudioInputController会控制和访问设备,而AudioInputDeviceManager可以管理和控制所有输入设备:
    这里写图片描述
    其次是处理远程多媒体流中的音频解码和播放功能,下图是Chromium处理远端音频流所需要的一些主要类及关系图,这里不涉及连接如何接收传输的数据,因为Chromium是使用libjingle和WebRTC项目来完成连接的功能,Chromium使用WebRtcAudioRender类来完成音频渲染,该桥接类会被WebMediaPlayer作为渲染音频的实现类,其作用主要是将MediaStream的数据同实际的音频渲染类结合起来:
    这里写图片描述
    再次是从视频输入设备请求捕获本地视频流,下图是该功能依赖的一些主要类:
    这里写图片描述
    实线右侧Render进程中的设施,同样是MediaStreamImpl类发起,有辅助工厂类MediaStreamDependencyFactory帮助创建一个RtcVideoCapaturer,用来获取视频,该类有两个作用,其一是是吸纳linjingle和WebRTC项目中的接口类,因为需要薯片输入的实现,这个同音频部分类似,另外就是将调用请求交割一个代理类来完成(RtcVideoCaptureDelegate类),分别是管理类VideoCaptureImplManager和视频捕获类VideoCaptureImpl,并包括一个发送消息到Browser进程的辅助类,在Browser进程使用控制类VideoCaptureController来获取VideoCaptureDevice,该类会使用摄像头等视频输入设备。最后是处理远端多媒体流中的视频解码和播放功能,当MediaStreamImpl对象接收到远端的多媒体流之后,它会使用WebRTC来会视频数据进行解码,因为可以使用硬件来解码,提供了处理的性能:
    这里写图片描述
    把WebRTC整个过程综合起来分析如下图,可以有一种更为整体和直观的感受:
    这里写图片描述

    展开全文
  • 手机来源识别已成为多媒体取证领域重要的热点问题。提出了一种基于语音静音段特征的手机来源识别方法,该方法先通过使用自适应端点检测算法得到语音的静音段;然后将静音段的梅尔频谱系数(MFC)的均值作为分类特征...
  • HTML 多媒体

    2018-10-19 10:07:31
    Web 上的多媒体指的是音效、音乐、视频和动画。多媒体来自多种不同的格式。它可以是您听到或看到的任何内容,文字、图片、音乐、音效、录音、电影、动画等等 二、audio标签 1、作用 播放音频 2、语法格式 格式1 &...
  • 播放多媒体

    2019-09-23 12:27:48
    浏览器在安装Flash插件后才能播放多媒体。使用HTML5提供的新标签<audio>和<video>可以很方便地在网页中播放音频和视频。 1、HTML5音频 HTML5提供了在网页中播放音频的标准,支持<audio>标签的...
  • 网页静音

    千次阅读 2006-03-05 11:24:00
    包括网页中的Flash文件,背景音乐等等(注意: 一些网页多媒体插件直接使用DirectSound进行发声的不能被静音). 这样您就可以自由的关闭网页中或Flash文件中那些令你厌烦的声音了.2. 使用方法软件成功安装后
  • Dephi 音量调节及静音

    2014-11-02 16:49:34
    在进行多媒体软件开发时,经常要调整各种设备的音量和设置静音,本人编写了一个单元,四个函数,分别用于获取音量(GetVolume(DN))、设置音量(SetVolume(DN,Value))、获取静音(GetVolumeMute(DN))及设置静音...
  • IOS多媒体

    千次阅读 2015-03-12 15:43:12
    --iOS多媒体 概览 随着移动互联网的发展,如今的手机早已不是打电话、发短信那么简单了,播放音乐、视频、录音、拍照等都是很常用的功能。在iOS中对于多媒体的支持是非常强大的,无论是音视频播放、录制,还是...
  • 多媒体按钮

    2017-04-21 16:34:39
    有暂停按钮,播放按钮,快进按钮,快退按钮,音量加按钮,音量减按钮,静音按钮,下一个按钮,上一个按钮等等
  • 易语言MCI多媒体播放类源码,MCI多媒体播放类,模块_关闭所有媒体,模块_取错误信息文本,取短路径名,模块_毫秒到时间,打开媒体,播放媒体,关闭媒体,取媒体状态,停止媒体,系统静音,继续媒体,暂停媒体,置视频区域,置视频...
  • 黄忠现【摘 要】多媒体教室设备的普及满足了教育工作者的需求,但也带来了技术上的麻烦——多媒体教室设备故障。本文主要阐述和分析了常见音响故障、常见投影机故障的具体情况及处理方法。【关键词】多媒体教室设备 ...
  • 多媒体播放

    2015-03-08 21:59:24
    Media and CameraMedia PlaybackAndroid的多媒体框架支持各种格式的媒体类型,你可以很容易的集成音频,视频,图像到你的应用中,通过 MediaPlayer的API,你可以从你的应用资源的媒体文件,或者文件系统的文件,或者...
  • H5多媒体

    2019-10-01 10:11:10
    高版本浏览器需要加上muted属性能让视频自动播放并且静音 poster 给视频添加海报(广告) loop 让视频循环播放 音频及常用属性 前言 音频的格式是mp3 视频的格式是mp4 audio 可以在页面中插入一个音频 音频在...
  • 多媒体定时播放系统

    2007-03-28 11:39:05
    3、根据播放列表,在指定的时间实行静音或播音,也可随时强制播音与静音! 4、支持的多媒体格式众多! 5、带有预览功能,可以对下一个多媒体视频文件进行截图预览,同时通过文字对文件名、播放时刻等信息进行提示...
  • HTML:多媒体元素

    2019-08-27 22:28:46
    多媒体元素 video 视频 audio 音频 video controls: 控制控件的显示,取值只能为controls 某些属性,只有两种状态:1. 不写 2. 取值为属性名,这种属性叫做布尔属性 布尔属性,在HTML5中,可以不用书写属性值 ...
  • 多媒体标签

    2019-09-06 22:53:42
    多媒体 audio HTML5通过<audio>标签来解决音频播放的问题。 并且可以通过附加属性可以更友好控制音频的播放,如: autoplay 自动播放 controls 是否显不默认播放控件 多媒体 video 同音频播放一样,&...
  • 音量调节及静音

    千次阅读 2003-03-04 08:56:00
    在进行多媒体软件开发时,经常要调整各种设备的音量和设置静音,本人编写了一个单元,四个函数,分别用于获取音量(GetVolume(DN))、设置音量(SetVolume(DN,Value))、获取静音(GetVolumeMute(DN))及设置静音...
  • 多媒体格式

    2020-12-14 17:08:56
    muted:静音 preload:auto (自动)metadta(加载元数据)none(不加载) video html5中video标签用于定义播放器视频文件的标准 支持三种音频格式:ogg、mpeg4(mp4)和webm <video controls="cont
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此楼5.2文本素材的获取 在著作工具中直接...利用手写体识别技术(需要手写板的支持)5.3音频素材的获取与创作声音是多媒体的又一重要方面,它除了给多媒体带来令人惊奇的...
  • Android 静音控制 音量控制 减小增大音量的实例源代码,如示图所示,音量控制时候,适时显示音量进度条:  ToggleButton tbMute = (ToggleButton)findViewById(R.id.tbMute);//获得ToggleButton对象  tbMute....
  • 多媒体元素

    2020-06-08 21:28:43
    muted属性:布尔属性,静音播放 loop属性:布尔属性,循环播放 audio 音频元素 和上面的video一样 旧版本浏览器不支持这两个元素(用flash) 不同浏览器支持的音频格式可能不同 我们可以把src属性拿下来,用source...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,887
精华内容 1,954
关键字:

多媒体静音