当前位置: 首页 > news >正文

媒体流与轨道:MediaStream 与 MediaStreamTrack

媒体流与轨道:MediaStream 与 MediaStreamTrack

采集到的音视频用 MediaStream 封装,里面包含多个 MediaStreamTrack。这篇讲流和轨道的关系、怎么操作轨道、怎么合并分流、怎么处理轨道事件,以及实际开发中的常用技巧。

大家好,我是黒漂技术佬。

getUserMedia 返回的是 MediaStream 对象,里面装着视频轨、音频轨。流和轨道是 WebRTC 里最基础的数据结构,搞懂它们才能灵活处理音视频。

这篇讲 MediaStream 和 MediaStreamTrack 的详细用法:添加移除轨道、克隆、事件、常用操作技巧。


一、基本概念

MediaStream(媒体流)

一个媒体流对象,可以包含多个轨道(Track)。

MediaStream ├─ MediaStreamTrack(视频轨) ├─ MediaStreamTrack(音频轨) └─ ... 更多轨道

MediaStreamTrack(媒体轨道)

单一类型的媒体轨道,要么是视频,要么是音频。

  • 一个摄像头 = 一个视频轨
  • 一个麦克风 = 一个音频轨
  • 屏幕共享 = 一个视频轨(+可选的系统音频轨)

轨道的属性

每个轨道有:

  • kind:‘video’ 或 ‘audio’
  • id:唯一标识
  • label:设备名称
  • enabled:是否启用(true/false)
  • readyState:‘live’ 或 ‘ended’
  • muted:是否静音(只读,由系统决定)

二、MediaStream 常用操作

创建空流

conststream=newMediaStream();// 空流,后面加轨道

从已有轨道创建

conststream=newMediaStream([videoTrack,audioTrack]);

获取轨道

// 所有轨道constallTracks=stream.getTracks();// 只视频轨constvideoTracks=stream.getVideoTracks();// 只音频轨constaudioTracks=stream.getAudioTracks();// 按 ID 取consttrack=stream.getTrackById(trackId);

添加轨道

stream.addTrack(videoTrack);stream.addTrack(audioTrack);

移除轨道

stream.removeTrack(videoTrack);

克隆流

constnewStream=stream.clone();

克隆出的新流和原流独立,轨道也是克隆的,互不影响。

流的活跃状态

if(stream.active){console.log('流是活跃的');}

所有轨道都结束了,流就变成 inactive。


三、MediaStreamTrack 常用操作

开关轨道

// 关闭(画面变黑/静音)track.enabled=false;// 打开track.enabled=true;

enabled = false 时轨道还在,还占带宽,只是发空数据。

停止轨道

track.stop();

完全停止,释放设备。停止后轨道就废了,不能再用。

获取轨道信息

console.log(track.kind);// 'video' / 'audio'console.log(track.id);// 唯一IDconsole.log(track.label);// 设备名,比如'FaceTime HD Camera'console.log(track.readyState);// 'live' / 'ended'console.log(track.muted);// 是否被系统静音

获取能力(Capabilities)

设备支持什么参数:

constcapabilities=videoTrack.getCapabilities();console.log(capabilities);// {// width: { min: 320, max: 1920 },// height: { min: 240, max: 1080 },// frameRate: { min: 1, max: 60 },// ...// }

获取当前约束(Constraints)

当前用的什么参数:

constconstraints=videoTrack.getConstraints();

获取当前设置(Settings)

实际生效的参数:

constsettings=videoTrack.getSettings();console.log(settings.width,settings.height,settings.frameRate);

注意:getConstraints 是你请求的参数,getSettings 是实际生效的参数,可能不一样(设备不支持的话会降级)。

应用新约束

动态修改参数:

awaittrack.applyConstraints({width:640,height:480,frameRate:15});

网络不好时降画质,网络好时升回去,都用这个。

克隆轨道

constnewTrack=track.clone();

克隆一个一样的轨道,独立控制。


四、轨道事件

onmute / onunmute

轨道被系统静音/取消静音时触发:

track.onmute=()=>{console.log('轨道被静音了');};track.onunmute=()=>{console.log('轨道恢复了');};

比如摄像头被其他程序占用了,就会 mute。

onended

轨道结束时触发:

track.onended=()=>{console.log('轨道结束了');};

用户拔掉摄像头、调用 stop()、页面关闭都会触发。

onoverconstrained

约束条件设备满足不了时触发。


五、流的事件

onaddtrack / onremovetrack

流里添加/移除轨道时触发:

stream.onaddtrack=(event)=>{console.log('添加了轨道:',event.track.kind);};stream.onremovetrack=(event)=>{console.log('移除了轨道:',event.track.kind);};

onactive / oninactive

流变成活跃/不活跃时触发。


六、常用操作技巧

1. 替换视频轨(切换摄像头)

functionreplaceVideoTrack(stream,newVideoTrack){// 移除旧的constoldTrack=stream.getVideoTracks()[0];if(oldTrack){stream.removeTrack(oldTrack);oldTrack.stop();}// 添加新的stream.addTrack(newVideoTrack);// 如果已经在 PeerConnection 里,还要替换发送的轨道// sender.replaceTrack(newVideoTrack);}

2. 静音/取消静音

// 静音麦克风functionmuteAudio(stream){constaudioTrack=stream.getAudioTracks()[0];if(audioTrack){audioTrack.enabled=false;}}// 取消静音functionunmuteAudio(stream){constaudioTrack=stream.getAudioTracks()[0];if(audioTrack){audioTrack.enabled=true;}}

3. 开关摄像头

functiontoggleCamera(stream){constvideoTrack=stream.getVideoTracks()[0];if(videoTrack){videoTrack.enabled=!videoTrack.enabled;returnvideoTrack.enabled;}}

4. 合并两个流

把摄像头和屏幕共享合并到一个流:

functionmergeStreams(cameraStream,screenStream){constmerged=newMediaStream();// 屏幕视频screenStream.getVideoTracks().forEach(t=>merged.addTrack(t));// 摄像头音频(或者两个都加,看需求)cameraStream.getAudioTracks().forEach(t=>merged.addTrack(t));returnmerged;}

5. 只取视频/只取音频

// 从流里只提取视频轨,生成新流functionvideoOnly(stream){returnnewMediaStream(stream.getVideoTracks());}// 只提取音频functionaudioOnly(stream){returnnewMediaStream(stream.getAudioTracks());}

6. 拍照(从视频轨抓帧)

functiontakePhoto(videoTrack){constcanvas=document.createElement('canvas');constvideo=document.createElement('video');video.srcObject=newMediaStream([videoTrack]);// 等视频就绪returnnewPromise(resolve=>{video.onloadedmetadata=()=>{canvas.width=video.videoWidth;canvas.height=video.videoHeight;canvas.getContext('2d').drawImage(video,0,0);resolve(canvas.toDataURL('image/png'));};});}

七、视频轨道的特殊操作

摄像头切换(移动端)

asyncfunctionswitchCamera(currentStream){constcurrentTrack=currentStream.getVideoTracks()[0];constfacingMode=currentTrack.getSettings().facingMode;constnewFacingMode=facingMode==='user'?'environment':'user';constnewStream=awaitnavigator.mediaDevices.getUserMedia({video:{facingMode:newFacingMode},audio:true});// 停掉旧的currentStream.getTracks().forEach(t=>t.stop());returnnewStream;}

画质动态调整

根据网络情况动态改:

// 降画质asyncfunctionlowerQuality(track){awaittrack.applyConstraints({width:640,height:480,frameRate:15});}// 升画质asyncfunctionraiseQuality(track){awaittrack.applyConstraints({width:1280,height:720,frameRate:30});}

配合 WebRTC 的带宽估计,自动调画质。


八、音频轨道的特殊操作

音量检测

用 Web Audio API 检测麦克风音量:

functiongetVolumeLevel(audioTrack){constaudioContext=newAudioContext();constsource=audioContext.createMediaStreamSource(newMediaStream([audioTrack]));constanalyser=audioContext.createAnalyser();source.connect(analyser);constdataArray=newUint8Array(analyser.frequencyBinCount);functiongetVolume(){analyser.getByteFrequencyData(dataArray);letsum=0;for(leti=0;i<dataArray.length;i++){sum+=dataArray[i];}returnsum/dataArray.length;}return{getVolume,audioContext};}

可以做音量条、说话检测等功能。

音频处理

用 Web Audio API 可以加各种效果:

  • 混响
  • 均衡器
  • 变声
  • 降噪

处理完再通过 WebRTC 发出去。


九、PeerConnection 中的轨道

添加流

旧 API(还能用但不推荐):

pc.addStream(stream);

添加轨道(推荐)

新 API,逐个轨道加:

pc.addTrack(videoTrack,stream);pc.addTrack(audioTrack,stream);

第二个参数 stream 是关联的流,对方收到时轨道会在同一个流里。

替换轨道(切换摄像头时用)

通话中切换摄像头,不用重新协商:

constsender=pc.getSenders().find(s=>s.track.kind==='video');awaitsender.replaceTrack(newVideoTrack);

replaceTrack 不用重新协商 SDP,切换很快很平滑。

接收端拿到轨道

pc.ontrack=(event)=>{conststream=event.streams[0];remoteVideo.srcObject=stream;};

对方添加轨道后,这边触发 ontrack 事件。


十、常见坑

坑 1:enabled = false 不省带宽

很多人以为静音就不发数据了,其实还在发,只是发静音帧/黑屏帧。要省带宽得移除轨道或者用码率限制。

坑 2:stop 之后轨道就废了

调用 stop() 后轨道就结束了,不能再启用。要重新开得再 getUserMedia。

坑 3:克隆的轨道也要手动 stop

clone() 出来的轨道是独立的,原轨道 stop 了克隆的还在跑,记得都要释放。

坑 4:流里可以有多个视频轨

一个流可以加多个视频轨,但不是所有播放器都支持显示多个。一般一个流一个视频轨+一个音频轨。

坑 5:replaceTrack 不需要重新协商

切换摄像头用 replaceTrack 就行,不用重新 createOffer/Answer,体验好很多。

坑 6:iOS 上轨道行为不一样

iOS Safari 上,页面切后台后视频轨会暂停,回来可能要重新处理。


十一、本篇小结

  • MediaStream = 容器,装多个 MediaStreamTrack
  • MediaStreamTrack = 单个音/视频轨道,是最小操作单元
  • 轨道操作:enabled 开关、stop 停止、applyConstraints 改参数、clone 克隆
  • 流操作:addTrack/removeTrack、clone、getTracks
  • 常用技巧:切换摄像头、静音、合并流、分流、拍照、音量检测
  • PeerConnection 中用 addTrack 添加,replaceTrack 替换,ontrack 接收
  • 注意:enabled 不省带宽,stop 后不可恢复,克隆的轨道要手动释放

下一篇讲RTCPeerConnection 连接建立:SDP 协商、ICE 候选、完整的连接建立流程。

我是黒漂技术佬。

http://www.jsqmd.com/news/1138107/

相关文章:

  • 实用Windows风扇控制软件:FanControl让你的电脑安静又高效
  • 免费开源字幕编辑神器:Subtitle Edit 5分钟上手完全指南
  • XSS攻击实战:从Cookie窃取到会话劫持的攻防解析
  • literally 加强语气,≈简直、真的、实在是,无“字面”含义,纯感叹
  • Claude Code 的可恢复性机制
  • 15个实用的API文档生成工具,自动化
  • 基于STM32单片机车载儿童防窒息 车载儿童滞留检测安全座椅系统312(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_
  • Understat Python库:构建专业级足球数据分析系统的完整指南
  • FlashAttention 收益边界:注意力优化不是所有模型都能白赚
  • 极简工作流引擎设计:基于状态机的轻量级编排内核实现——不依赖重型框架,用500行代码搭建可控的业务流程引擎
  • AI商业洞察动态简报(2026.07.06)
  • REPENTOGON:如何为《以撒的结合:悔改》安装终极脚本扩展器?
  • 黑苹果配置革命:OpCore-Simplify如何让复杂技术变得像搭积木一样简单?
  • 小龙虾身份配置完整指南
  • 「 简记往来」第二十八篇:从0到被大模型推荐——完整复盘
  • KES 监控与运维自动化实战:性能指标采集、告警体系与智能运维
  • 深入解析Playwright HTML报告源码:定制化与性能优化指南
  • 终极ROS机器人仿真教程:从零开始掌握WPR系列虚拟测试环境
  • 还在手撕XML?个人微信API二次开发如何优雅攻克多模态数据的解析壁垒?
  • 连接器SI仿真精度提升:CST背景材料与边界条件3大关键参数设置
  • 当 GPT-4o 的眼睛遇上 UI 截图:自动检测视觉异常,为何比像素对比更懂页面
  • OpenEuler workflowkits对比分析:与其他命令编排工具的10个关键差异
  • 2026顶尖EMBA含金量排名:国际化商科项目深度评测
  • 高性能火箭仿真架构设计:从六自由度动力学到模块化组件系统
  • Windows下使用Docker搭建SQL注入靶场SQLi-labs的完整指南
  • WS2812与PIC18F87J50嵌入式灯光控制实战指南
  • 拯救你的B站缓存视频:m4s-converter无损转换工具使用指南
  • 免费开源数据库工具 DBeaver 26.1.2 发布,新增 AI 聊天与 Timeplus 数据库支持!
  • 【计算机Java毕业设计案例】基于 SpringBoot 的学生学业过程跟踪考核系统的设计与实现 基于 SpringBoot+Vue 的教师形成性评分管理系统(程序+文档+讲解+定制)
  • 当断点成为战略选择:Mobile First 与 Desktop First 的选型依据,为何不只是代码习惯