目录
2.7 轨道的能力 MediaTrackCapabilities
2.8 轨道的约束 MediaTrackConstraints
1 源(Sources)与 接收器(Sinks)
-
Media pipeline
浏览器提供了多媒体数据从源(sources)流向消费者或接收器(sinks)的媒体管线(media pipeline)。 -
Sources
源是一个理论上的实体,浏览器可以基于可用的设备以任意方式提供源。源本身是一个提供媒体数据的“东西”。大致可以将源分为两大类:
1)静态源:传统的源(sources)包括 流式的内容(内存中的数据),本地文件,网络资源。传统源所提供的的媒体数据一般是不随时间而变化的,这些源可以认为是静态的源。
2)动态源:getUserMedia API使得用户可以访问动态的源,比如 摄像头,麦克风。这些源的特征是可以响应应用程序的需求进行改变,这些源可以被认为是天然动态的。
“源” 本身没有约束 ,而轨道有约束。当源连接到轨道时,它必须生成符合该轨道上存在的约束的媒体。多个轨道可以连接到同一个源。WebRTC不能直接访问或控制源,对源的一切控制都通过轨道实施。对轨道应用约束,并且应用约束时可能会影响到隐藏在轨道背后的源。更改或应用轨道约束的行为可能会影响共享该源(source)的所有轨道的设置,从而影响共享该源的所有下层消费者(sinks)。 有些消费者(sinks)可能能够适配这种更改,例如<video>元素或RTCPeerConnection。 其他像Recorder API可能会因源设置更改而失败。 - Sinks
在浏览器中,接收器(sinks)一般是<img>, <video>, <audio> 这些标签,也可以是RTCPeerConnection对等对象。
sinks显示静态源提供的媒体内容时,可以对内容进行多种方式的操控。比如,<img>标签可以将源提供的高分辨率图片(1600x1200像素)scale到适合标签大小(400x300)的图片进行显示。一个<video>标签显示动态源所提供的内容时,既可以像上述的对待静态源的方式进行scale,crop等操作,也可以通过媒体管线(media pipeline)将信息反馈给源(source),让源(source)提供更合适的内容进行显示。这种反馈机制是一个很大的优化,可以节省电源,可以减少网络拥塞。 - RTCPeerConnection
RTCPeerConnection是个有趣的对象,因为其既可以作为网络媒体流的source,又可以作为sink。作为sink,它具有对源提供的媒体内容进行转换功能(例如,降低比特率,放大/缩小分辨率和调整帧速率);作为源(source),它可以拥有自己的设置。
2 MediaStreamTrack(轨道)
2.1 轨道的基本概念
- MediaStreamTack是WebRTC中基本的媒体单元。代表一种设备或录制内容(“源”)可返回的单一类型的媒体,比如摄像头所提供的视频流。单个立体声源或者5.1声道环绕声音频信号均可各自视为一个轨,尽管二者都是由多个音频声道组成。注意一点,虽然规范中粗略规定了各声道“彼此具有公认的关系”,但并未定义在声道级别的访问或者操作媒体的方式。
- 轨道的内容“将在一起编码,以便作为某种有效负载类型,比如RTP的某种负载类型,进行传输”。换句话说,在使用对等连接进行媒体传输时,音频轨道的各个声道将被视为一个单元,即使其在本地处于启用/禁用或者是静音状态,也不例外。
- 每个轨道都有一个“源”与之关联,WebRTC不能直接访问或者控制源,对源的一切控制都通过轨道来实施。MediaStreamTrack与源之间的关系可能会发生一些变化:轨道不仅可以是来自源的原始媒体,也可能是浏览器提供的经过转换的版本,例如,轨道可以代表由摄像头以较高本机分辨率录制的视频的低采样率版本。
- 不同的MediaStreamTrack对象可以绑定同一媒体源
- 轨道输出的数据不需要是统一二进制格式。比如,可以是从用户摄像头采集来的原始视频数据。这允许用户代理以用户平台上最适合的方式操作媒体。
2.2 轨道的生存周期(life-cycle)
- 轨道有生命期有两种状态:"live" 和 "ended"。新创建的轨道的状态可以是二者之一,取决于轨道的创建方式。比如,克隆一个ended的轨道而生成的新轨道也是ended状态。轨道当前状态通过轨道的只读属性readyState来获取。
- "live"状态的轨道,表示这个轨道是活动的,媒体对于消费者(比如<video>标签)是可用的,意即轨道所关联的源会尽可能提供实时的媒体数据。但请注意,"live"状态的轨道若是被静音或者被禁用,媒体源所提供的媒体数据可能会被 "零信息内容(zero-information-content)"替代,此时,对于消费者(<video>标签)来说媒体仍是播放状态,只是渲染音频为静音(silence),视频渲染出黑屏(black frames)。
- "ended"状态的轨道,表示这个轨道所关联的源将不再向外提供媒体数据,也将不再给轨道提供媒体数据。一旦轨道进入ended状态,那么将不会从这个状态退出,一直会保持在ended状态。当绑定同一源的所有轨道都进入ended状态,那么源也将停止。轨道进入'''ended'状态可能的原因:
1)当轨道与所绑定的源失去连接,例如,当用户拔下用作媒体源的USB网络摄像机时;
2)当源无法再提供更多媒体数据,比如,源是本地磁盘的音视频文件,文件读到最后无更多媒体数据可提供;
3)当轨道请求使用本地摄像头权限而被拒绝时;
4)当应用程序调用轨道的MediaStreamTrack.stop()方法
如果导致轨道进入"ended"状态的原因不是由应用程序调用MediaStreamTrack.stop()方法所引发,那么用户代理将往队列中投递一个任务去执行如下步骤:
1)如果MediaStreamTrack.readyState属性已经是ended状态,则终止以下步骤;
2)设置MediaStreamTrack.readyState为ended;
3)通知轨道所绑定的源,轨道已经终止,此时源也将停止,除非还有其他轨道对象绑定在该源上;
4)触发轨道的ended事件。
2.3 轨道上的媒体流(Media Flow)
- 对于"live"状态的轨道,轨道上的媒体流(Media Flow)有两个维度的状态变量去刻画:muted/unmuted 和 enabled/disabled。
- "muted/unmuted "状态对应着轨道的输入,反应的是源当前是否提供媒体数据。若源当前无法给轨道提供媒体数据,那么轨道将处于"muted"状态。"muted/unmuted "状态由用户操作来引发,由浏览器的用户代理最终实施,比如出现以下三种情况时,用户代理(UA)将使得轨道状态变为muted。
1)用户在物理媒体设备层面进行了操作,比如,在麦克风上按下了静音按钮;
2)用户在操作系统层面进行了设备的静音操作;
3)用户在浏览器上点击了静音按钮,比如,chrome的某个网页进行着音乐播放,可以对标签页点击静音。
但是该状态的改变,不受运行的用户应用程序控制,该状态对应用程序来说是只读的,可以通过读取MediaStreamTrack.muted属性获取到,应用程序也能通过监听轨道对象关联的mute和unmute事件观察到"muted/unmuted "状态变化。不管何时,用户代理对轨道"muted/unmuted "状态进行改变时,将投递一个任务到队列,任务中执行步骤:
1)让该轨道为带疑问的轨道(目前还未懂啥意思,英文原话为,MediaStreamTrack
in question);
2)设置轨道的muted属性到新状态,若新状态为muted,则为true;否则为false;
3)若新状态为true,则产生新事件名为mute,否则为unmute;
4)触发轨道上的该新事件。 - "enabled/disabled"状态对应着轨道的输出,决定了轨道中的媒体数据是否输出到消费者(比如<video>标签)。这个是受用户应用程序控制的,可以通过设置MediaStreamTrack.enabled来实现。应用程序通过该属性来阻止轨道中来自于源的媒体数据被渲染到消费者。
- 总结:只有当轨道处于life-cycle的"live"周期,并且处于"unmuted" and "enable"状态时,媒体数据从源出发,经由轨道流动,流入消费者(consumer or sink,such as <video>)进行渲染,这整个媒体数据流动(Media Flow)才是通畅的。处于"live"生命周期的轨道,以消费者的视角来看,轨道是"muted"状态亦或者是"disable"状态并没有区别,其得到的数据是"零信息内容(zero-information -content)",此时,消费者仍可以是播放状态,但是渲染静音或者是黑屏(render silence and darkness)
2.4 轨道接口相关的API
MediaStreamTrack的属性:
- id(readonly,DOMString):该值唯一表征了一个轨道对象,在MediaStreamTrack创建时被确定,一般是36个字符的UUID值。
- kind(readonly,DOMString):这个属性只有两种类型的值,"video"表示该轨道为视频轨,"audio"表示该轨道为音频轨。
- label(readonly,DOMString):用户代理(UA,UserAgent)一般会给音频,视频源贴一些用户可读的标签,比如“内部音频设备”,“外部USB摄像头”等等。轨道的label属性应该返回其关联的源的标签,如果源的label为空,那么轨道的label也应该返回空的字符串。
- readyState(readonly,MediaStreamTrackState):该值反应了轨道所处生命周期状态,必须返回UA设置的最新值。该属性是MediaStreamTrackState枚举类型:
- muted(readonly,boolean):如果轨道处于"muted"状态,则为true,否则为false。
- enabled(boolean):这个属性控制着轨道的"enabled"状态。当读取该属性时,返回最后一次该属性被设置的值;当设置该属性时,该属性将被设置为新的值。特别注意一点,如果轨道的生命周期已到ended,该属性仍然可以被设置,只是该值已经不会产生其他的影响。
- onmute(EventHandler):该事件处理函数句柄对应的事件是"mute"。
- onunmute(EventHandler):该事件处理函数句柄对应的事件是"unmute"。
- onended(EventHandler):该事件处理函数句柄对应的事件是"ended"。
MediaStreamTrack的方法:
- clone():UA将执行如下动作克隆出该轨道的一个副本:
1)创建一个新的MediaStreamTrack对象;
2)初始化新轨道对象的id属性,保证唯一性;
3)通过复制原轨道的属性值来初始化新轨道对象的kind,label,readyState,enabled属性;
4)让原轨道所关联的源成为新轨道的源;
5)根据原轨道的约束值来设置新轨道上的约束,但注意新旧轨道上的约束是分离的,互不干扰的;
6)返回新创建的轨道。 - stop():当应用程序调用轨道的stop方法时,UA将执行如下步骤:
1)如果轨道的readyState属性已经是"ended",那么终止以下步骤;
2)通知源其绑定的轨道已经处于"ended"状态,可引发源停止运行,除非还有其他轨道绑定到该源;
3)设置轨道的readyState属性为"ended"。
注意一点,由其他原因导致源进入"ended"状态和调用stop方法是有一些区别的,调用stop方法内部处理时,步骤2与3是与其他方式的顺序是相反的,另外一个重要之处是其他方式导致源进入'ended"状态最终会触发"ended"事件,而stop方法不会。 - getCapabilities():获取轨道所关联的源的能力,该能力由一些可约束的属性值组成,有些属性是一个非离散范围值,比如aspectRatio: {max: 1280, min: 0.0010416666666666667};有些属性是离散枚举值,比如echoCancellation: [true, false]。具体详情会在后文详细阐述
- getConstraints():获取应用在轨道上的约束;具体详情会在后文详细阐述。
- getSettings():获取在轨道应用约束后形成的设置;具体详情会在后文详细阐述。
- applyConstraints():该方法允许应用程序在创建轨道之后,运行时对轨道再次应用约束。具体详情会在后文详细阐述。
2.5 轨道所支持的约束
MediaTrackSupportedConstraints字典代表了用户代理(UA,User Agent)当前能识别的所有可约束属性,UA通过这些属性来控制轨道对象的capabilities,未来规范可以通过partial关键字来扩展该字典的boolean成员以支持更多的属性。
2.6 可约束的属性
上述UA所能识别的可约束属性可分为3类:
- 音频轨道和视频轨道同时支持的可约束属性
Property Name | Values | Notes |
---|---|---|
deviceId | DOMString | 该属性指定了为轨道提供媒体数据的源,该值与媒体设备MediaDeviceInfo.deviceId属性相匹配。该约束值可用于getUserMedia()方法,在获取用户媒体流时,指定设备. 但是,不要在运行时,调用applyConstraints()方法中使用该属性,因为该值在创建轨道,并与源绑定时就已经确定下来,无法更改,如果进行这种尝试只会导致一个无法满足的约束设置。如果在调用getUserMedia()方法,对该约束值设置为空字符串,则会被认定为该约束没有被指定。 |
groupId | DOMString | 该属性与deviceId,二者唯一指定了为轨道提供媒体数据的源,比如一个既可以提供音频,又可以提供视频的摄像头物理设备,在进行设备枚举时,会得到两个代表设备的MediaDeviceInfo对象,这两个对象的groupId相同,因为是同一物理设备,而两个MediaDeviceInfo对象的deviceId不同,分别代表音频输入设备和视频输入设备。与deviceId一样,可约束属性groupId也只用在getUserMedia()方法中指定提供媒体流的物理设备,一旦指定,成功生成媒体流后,与媒体流所关联的源就无法更改,也即在对轨道调用applyConstraints()方法时,不能再提供该属性的约束。 |
-
视频轨道独有的可约束属性
Property Name | Values | Notes |
---|---|---|
width |
| 指定单个宽度值或宽度范围,以像素为单位。作为一种能力,范围应该跨越视频源的预设高度值,其中min是最小高度,max是最大高度。 |
height |
| 指定单个高度值或高度范围,以像素为单位。 作为一种能力,范围应该跨越视频源的预设高度值,其中min是最小高度,max是最大高度。 |
frameRate |
| 指定单个帧率值或帧率的范围。如果帧率无法确定下来(比如,源不提供这种帧率,或者无法从源流确定帧率),则此值必须指代用户代理的vsync显示速率。 |
aspectRatio |
| 指定单个宽高比值或宽高比范围(以像素为单位的宽度除以以像素为单位的高度,表示为二次四舍五入到小数点后十位)。 |
facingMode |
| 此字符串(当为字符串列表时,每个字符串)应该是VideoFacingModeEnum的成员之一("user", "left","right","environment")。 从用户的角度来看,成员描述了相机可以面对的方向。
|
resizeMode |
| 此字符串(当为字符串列表时,每个字符串)应该是VideoResizeModeEnum的成员之一("none","crop-and-scale"),描述了是否允许UA对相机输出使用裁剪(crop)和缩小(downscaled )。如果是"none",那么分辨率只能是camera,驱动程序,os来提供的那些;如果是"crop-and-sacle",那么UA就可以通过对摄像头提供的高分辨率图像使用裁剪,缩小的手段来提供低分辨率的图像。 |
-
音频轨道独有的可约束属性
Property Name | Values | Notes |
---|---|---|
sampleRate |
| 指定单个音频采样率值,每秒采样点数。 |
sampleSize |
| 指定单个采样点所占位数,即线性样本大小(以位为单位),只有生成线性样本的音频设备才能满足此约束。 |
echoCancellation |
| 是否启用回声消除 |
autoGainControl |
| 是否启用自动增益 |
noiseSuppression |
| 是否启用噪声抑制 |
latency |
| 指定单个延迟值或延迟范围,以秒为单位。 延迟是处理开始(例如,当现实世界中发生声音时)与可用于该过程中下一步骤的数据之间的时间。 低延迟对某些应用至关重要; 高延迟对于其他应用程序可能是可接受的,因为它有助于功率限制。 该数字预计将是配置的目标延迟; 实际的延迟可能与目标延迟有一定的差别。 |
channelCount |
| 指定通道数 |
2.7 轨道的能力 MediaTrackCapabilities
轨道对象的getCapabilities()方法返回MediaTrackCapabilities对象,该对象描述了轨道的能力Capabilities,绑定到同一个源的轨道,他们的Capabilities是相同的。
- 轨道的Capabilities其实是通过一堆属性值来进行描述的;
- 从字典中Capabilities所包含的属性值来看,与2.1.5中UA能识别的约束属性是一致的;
- 根据属性的类型来说,可以简单分为3类(前两类是重点):
1)ULongRange,DoubleRange这类范围值属性;
2)sequence<DOMString>,sequence<boolean>这类离散值属性;
3)DOMSring这类单纯字符串属性 - 每个属性所代表的含义将在后文以表格形式提供。
2.8 轨道的约束 MediaTrackConstraints
轨道对象的getConstraints()方法返回MediaTrackConstraints对象,该对象描述了应用到轨道上的约束。
- 轨道上的约束由MediaTrackConstraintSet的序列构成;
- MediaTrackConstraintSet的每个成员的类型
2.9 轨道的设置 MediaTrackSettings
轨道对象的getSettings()方法返回MediaTrackSettings对象,该对象描述了应用到轨道上的设置。
3 MediaStream(流)
3.1 流的基本概念
- MediaStream是MediaStreamTrack对象的集合,集合中可以包含0个或者多个MediaStreamTrack,这些轨道在集合中的顺序是由用户代理决定的,所有的API都不依赖轨道在集合中的排列顺序,从集合中查找特定轨道的合理方式是通过轨道的id进行查找。
- MediaStream将多个MediaStreamTrack对象组合成一个整体,这个整体可以用来录制或者在一个媒体元素上进行渲染。同一个MediaStream中的多个轨道在渲染时,将会进行同步。但注意这不是硬性的规定,不同的轨道可能就是无法进行同步的,因为他们的时钟是不同的。不同的MediaStream对象之间不需要进行同步。
- MediaStream可以使用 MediaStream() 构造函数从现有媒体流或轨道创建新对象 。构造函数参数可以是现有MediaStream对象,在这种情况下,给定流的所有轨道都将添加到新MediaStream对象中,或构造函数参数是MediaStreamTrack对象数组。后一种参数形式使得可以组成来自不同源的流。
- MediaStream和 MediaStreamTrack对象均可以被克隆。克隆MediaStream包含来自原始流的所有成员轨道的克隆。克隆MediaStreamTrack具有一组约束,这组约束独立于被克隆的MediaStreamTrack中的约束,这允许来自相同源的MediaStreamTrack的不同对象具有不同约束 。
- 从MediaStream的输出读取数据的对象称为MediaStream消费者。MediaStream消费者列表中目前包括媒体元素(如
<video>
和<audio>,可以将
MediaStream赋值给标签的srcObject属性),Web实时通信(WebRTC的RTCPeerConnection
),媒体录制(MediaRecorder
),图像捕获(ImageCapture
),和网络音频(MediaStreamAudioSourceNode
)。
3.2 流相关API
MediaStream的构造函数
MediaStream提供3类构造函数:
- 无参:MediaStream中包含0个MediaStreamTrack
- 入参为已经存在的MediaStream对象:给定流的所有轨道对象都将添加到新MediaStream对象中,注意轨道对象并没有克隆,还是原来的那个轨道对象。
- 入参为MediaStreamTrack的序列:序列中的所有轨道都将添加到新的MediaStream中,注意轨道对象并没有克隆,还是原来的那个轨道对象。
MediaStream的属性
-
id(readonly,DOMString):当MediaStream被创建时,用户代理生成一个标识符字符串并赋值给id,一个好的做法是使用UUID,它的规范形式长度为36个字符;
-
active(readonly,boolean):如果MediaStream是活动的,那么该值为true,否则为false;而MediaStream是否为active状态,取决于MediaStream所包含的MediaStreamTrack集合中是否存在一个MediaStreamTrack为非ended状态;若MediaStream集合中不存在MediaStreamTrack或者所有的MediaStreamTrack均为ended状态,那么该MediaStream为inactive状态,active属性为false。
-
onaddtrack(EventHandler):事件处理函数句柄,当MediaStream调用addTrack()方法,成功添加新的track时,触发addtrack事件。
-
onremovetrack(EventHandler):事件处理函数句柄,,当MediaStream调用removeTrack()方法,成功删除MediaStream中已存在的一个track时,触发removetrack事件。
MediaStream的方法
-
getAudioTracks():返回流的轨道集合中所有表征音频轨道的MediaStreamTrack序列。MediaStreamTrack的kind属性为"audio",并且在两次调用getAudioTracks()返回的序列中轨道的排列顺序可能是不一致的。
-
getVideoTracks():返回流的轨道集合中所有表征视频轨道的MediaStreamTrack序列。MediaStreamTrack的kind属性为"video",并且在两次调用getVideoTracks()返回的序列中轨道的排列顺序可能是不一致的。
-
getTracks():返回流的轨道集合中所有轨道的列表,不管轨道的kind属性是"video"还是"audio",并且在两次调用getTracks()返回的序列中轨道的排列顺序可能是不一致的。
-
getTrackById():返回流的轨道集合中MediaStreamTrack的id属性与入参trackId相匹配的MediaStreamTrack,或者返回bull,如果没找到匹配的MediaStreamTrack。
-
addTrack():添加一个指定的MediaStreamTrack到MediaStream对象中,当该方法被调用时,内部将按如下步骤进行处理:
1) 如果指定的轨道已经在流中,则停止处理;
2)添加轨道到流中的集合中;
3)触发addtrack事件。 -
removeTrack():从MediaStream对象的轨道集合中删除指定的MediaStreamTrack,当该方法被调用时,内部将按如下步骤进行处理:
1) 如果指定的轨道不在流中,则停止处理;
2)删除轨道集合中指定的轨道;
3)触发removetrack事件。 -
clone方法:克隆流以及流中的所有轨道,该方法被调用时,内部将按如下步骤处理:
1)让克隆出的新的流对象streamClone是一个新构建的MediaStream对象;
2)让streamClone的id属性是一个新生成的值,与原来的流相区别;
3)克隆原来的流中的每个轨道,并将克隆的轨道添加到streamClone的轨道集合中;
4)返回这个新的MediaStream对象streamClone。
3.3 流与媒体标签元素
一个MediaStream对象可以赋给一个网页的media元素。MediaStream对象是不可预加载,不可seek的,表现为一个简单的,无无限时长的,线性媒体时间线。时间线从0开始,并随着MediaStream的播放而实时的线性递增。当MediaStream的播出暂停时,时间线不会递增。支持本规范的UA,HTMLMediaElement接口必须支持srcObject属性,该属性可以为播放MediaStream对象提供支持。以下几点为HTMLMediaElement元素的媒体提供者是MediaStream时所呈现出来的特性:
- UA必须播放MediaStream中获取的当前数据,而不能采用缓冲
- 由于没有规定MediaStream中轨道集合的轨道的排序,因此HTMLMediaElement元素中的AudioTrackList和VideoTrackList也没有规定轨道的顺序。
- 当标签为HTMLVideoElement时,当MediaStream状态从active变为inactive,HTMLVideoElement元素会设置其ended状态为true,并触发ended事件。一旦HTMLVideoElement的ended状态变为true,标签将不再播放媒体,即使有新的轨道加入到MediaStream对象中(引发MediaStream对象变为active状态),除非HTMLVideoElement的autoplay属性为true或者应用程序通过调用标签的paly()方法重启了标签。
- 当标签为HTMLAudioElement时,当MediaStream状态从audible变为inaudible,HTMLAudioElement元素会设置其ended状态为true,并触发ended事件。一旦HTMLAudioElement的ended状态变为true,标签将不再播放媒体,即使有新的轨道加入到MediaStream对象中(引发MediaStream对象变为active状态),除非HTMLVideoElement的autoplay属性为true或者应用程序通过调用标签的paly()方法重启了标签。
- 调用HTMLMediaElement的fastSeek()方法会被忽略掉。
MediaStream的性质对关联HTMLMediaElement的属性行为以及可对其执行的操作施加了某些限制,如下所示:
Attribute Name | Attribute Type | Setter/Getter Behavior When Provider is a MediaStream | Additional considerations |
---|---|---|---|
preload | DOMString | 读取: none . 设置: 忽略. | MediaStream不支持预加载。 |
buffered | TimeRanges | buffered.length返回0 . | MediaStream不支持预加载。因此,缓存保持为空的TimeRange |
currentTime | double | 任意非负整数。初始化值为0,当媒体在播放时,实时地线性增加该值 | 该值为播放位置,单位s。任何尝试修改该值将被忽略。 |
seeking | boolean | false | MediaStream不支持seek。因此该属性一直返回false。 |
defaultPlaybackRate | double | 读取: 1.0 . 设置: ignored. | MediaStream不支持seek。因此,该属性(倍速播放)一直返回1.0,任何尝试修改此属性会被忽略。因此不会触发ratechange事件 |
playbackRate | double | 读取: 1.0 . 设置: ignored. | MediaStream不支持seek。因此,该属性(倍速播放)一直返回1.0,任何尝试修改此属性会被忽略。因此不会触发ratechange事件 |
played | TimeRanges | played.length 返回1 .played.start(0)返回 0 .played.end(0)返回最新的 currentTime . | MediaStream时间线总是由单个范围值组成,0~currentTime |
seekable | TimeRanges | seekable.length返回 0 . | MediaStream不支持seek |
loop | boolean | true , false | 设置loop属性没有任何作用,因为MediaStream没有定义媒体数据的结尾,因此无法循环播放。 |
4 关于模型的应用示例
4.1 示例情景一
为了说明给定源(source)的更改如何影响各种Sinks,请考虑以下示例。 此示例仅使用宽度和高度这两个约束属性,但相同的原则适用于本规范中公开的所有约束属性。 图中,本地客户端从其本地摄像机获得了视频源, 源的宽度和高度设置分别为800像素和600像素。 本地客户端上的三个MediaStream对象包含使用同一deviceId的轨道(MediaStreamTrack),三个媒体流连接到三个不同的sink:<video>元素A,另一个<video>元素B 和对等连接C。 对等连接C将源视频流式传输到远程客户端。 在远程客户端上,有两个媒体流对象MediaStream,其中包含使用对等连接作为源的轨道MediaStreamTrack。 这两个媒体流连接到两个<video>元素sinks(Y,Z)。
请注意,此时,本地客户端上的所有 Sinks 必须对源所提供的内容进行维度转换:Sink B缩小(scale down)视频,Sink A放大(scaling up)视频(导致质量下降),而Sink C也在略微缩放视频以便通过网络发送。 在远程客户端上,Sink Y缩小(scale down)视频,而Sink Z不应用任何缩放。
当本地客户端上的三个MediaStream中与该源(Home client video source)绑定的某个MediaStreamTrack需要更高的分辨率图像(1920x1200像素),从而调用轨道的applyConstraints()方法时,这个源的设置将受到影响,从而设置为1920x1200。如下图所示:
此时,请注意,源更改会立即影响本地客户端上的与该源关联的所有轨道和Sinks,但不会影响远程客户端上的Sinks(或Sources)。 变化如下:随着本地客户端源视频尺寸的增加,Sink A不再需要执行任何缩放,而Sink B必须比以前更进一步缩小。 Sink C(对等连接)现在必须按比例缩小视频到1024x768,以使传输保持与远程客户端不变。
上述示例没有展示的一种情况是:相等的合法设置请求可以发生在远程客户端这一侧。除了Sink Y和Sink Z会受到像上述Sink A,B,C一样受到的影响外,还会导致对等媒体对象之间(Remote client video source与Home client video sinks)重新进行媒体协商,从而改变Home client video sinks在其应用在本地客户端视频源上的转换(比如由缩小变为扩大)。这种改变并不会改变Sink A,Sink B和本地客户端的视频源的任何东西。
注意:规范并没有定义这样一个机制:远程客户端视频源(图中remote client's video source)的改变自动触发本地客户端视频源的改变。实现可能会选择这种source-to-sink的优化,但是仅在应用之间建立的约束范围之内,就像下面将要介绍的这个示例。
4.2 示例情景二
情景一描述了某个指定源上的改变将会影响到相关的Sinks消费者。然而,在某些情形下,对于Sink的改变会引发实现去调整源的设置。如下图所示,本地客户端视频源发送的视频流分辨率为1920x1200,并且视频源是未受约束的,因此就应用而言,确切的源尺寸是灵活可变的。两个媒体流对象MediaStream包含使用同一deviceId的轨道MediaStreamTrack,并且这两个媒体流对象MediaStream关联到两个不同的<video>标签Sink A和Sink B。Sink A的大小为1920x1200,显示源提供的视频内容不需要做任何转换;而Sink B的大小为320x200,因此,需要对源提供的视频内容进行缩放展示。
当应用改变Sink A的大小到1200x768时,浏览器的媒体管线(media pipeline)将会识别到没有Sinks需要更高的视频源分辨率,此时,若不进行调整,不仅是源还是Sink A需要做一些不必要的工作。在此种情况下,如果没有其他约束强制源继续提供高分辨率的视频流,那么媒体管线(media pipeline)可能会去改变源的分辨率(如下图所示)。
如上图,本地客户端视频源的分辨率将改变为Sink A和Sink B中的较大者以优化播放。
然后上述没有展示的情况是,对于PeerConnections和其他类型的Sinks,也会执行相同的行为。
4.3 示例情景三
可能会出现这么一个情况:对一个轨道应用关联的源无法满足的约束,这种无法满足,可能是因为源本身无法满足约束,也可能是源已经被应用了相冲突的约束。当此种情况发生时,applyConstraints()返回的Promise将是rejected,并且任何新的约束将不会被应用,此时,源本身也就不需要做任何改变。
示例如下,两个媒体流对象MediaStream各自含有一个视频轨绑定同一个源。第一个轨道初始时没有应用任何约束,其连接到Sink N。Sink N大小为800x600,将源所提供的1024x768的视频流转换成800x600进行展示。另外一个轨道包含一个强制性的约束条件,即强制源关闭其补光模式。该轨道连接到Sink P,其宽高与源相同。
现在,第一个轨道添加一个强制约束,即源的补光模式强制开启。此时,源无法同时满足这两个强制性约束(补光模式无法同时开启又关闭)。这个状态是在第一个轨道上应用产生冲突的约束导致,因此,这个约束将应用失败,并且源上的设置不会改变,应用在另一个轨道上的约束也不会改变。