媒体流与轨道:MediaStream 与 MediaStreamTrack

📅 2026/7/7 1:09:04
媒体流与轨道:MediaStream 与 MediaStreamTrack
媒体流与轨道MediaStream 与 MediaStreamTrack采集到的音视频用 MediaStream 封装里面包含多个 MediaStreamTrack。这篇讲流和轨道的关系、怎么操作轨道、怎么合并分流、怎么处理轨道事件以及实际开发中的常用技巧。大家好我是黒漂技术佬。getUserMedia 返回的是 MediaStream 对象里面装着视频轨、音频轨。流和轨道是 WebRTC 里最基础的数据结构搞懂它们才能灵活处理音视频。这篇讲 MediaStream 和 MediaStreamTrack 的详细用法添加移除轨道、克隆、事件、常用操作技巧。一、基本概念MediaStream媒体流一个媒体流对象可以包含多个轨道Track。MediaStream ├─ MediaStreamTrack视频轨 ├─ MediaStreamTrack音频轨 └─ ... 更多轨道MediaStreamTrack媒体轨道单一类型的媒体轨道要么是视频要么是音频。一个摄像头 一个视频轨一个麦克风 一个音频轨屏幕共享 一个视频轨可选的系统音频轨轨道的属性每个轨道有kind‘video’ 或 ‘audio’id唯一标识label设备名称enabled是否启用true/falsereadyState‘live’ 或 ‘ended’muted是否静音只读由系统决定二、MediaStream 常用操作创建空流conststreamnewMediaStream();// 空流后面加轨道从已有轨道创建conststreamnewMediaStream([videoTrack,audioTrack]);获取轨道// 所有轨道constallTracksstream.getTracks();// 只视频轨constvideoTracksstream.getVideoTracks();// 只音频轨constaudioTracksstream.getAudioTracks();// 按 ID 取consttrackstream.getTrackById(trackId);添加轨道stream.addTrack(videoTrack);stream.addTrack(audioTrack);移除轨道stream.removeTrack(videoTrack);克隆流constnewStreamstream.clone();克隆出的新流和原流独立轨道也是克隆的互不影响。流的活跃状态if(stream.active){console.log(流是活跃的);}所有轨道都结束了流就变成 inactive。三、MediaStreamTrack 常用操作开关轨道// 关闭画面变黑/静音track.enabledfalse;// 打开track.enabledtrue;enabled false 时轨道还在还占带宽只是发空数据。停止轨道track.stop();完全停止释放设备。停止后轨道就废了不能再用。获取轨道信息console.log(track.kind);// video / audioconsole.log(track.id);// 唯一IDconsole.log(track.label);// 设备名比如FaceTime HD Cameraconsole.log(track.readyState);// live / endedconsole.log(track.muted);// 是否被系统静音获取能力Capabilities设备支持什么参数constcapabilitiesvideoTrack.getCapabilities();console.log(capabilities);// {// width: { min: 320, max: 1920 },// height: { min: 240, max: 1080 },// frameRate: { min: 1, max: 60 },// ...// }获取当前约束Constraints当前用的什么参数constconstraintsvideoTrack.getConstraints();获取当前设置Settings实际生效的参数constsettingsvideoTrack.getSettings();console.log(settings.width,settings.height,settings.frameRate);注意getConstraints 是你请求的参数getSettings 是实际生效的参数可能不一样设备不支持的话会降级。应用新约束动态修改参数awaittrack.applyConstraints({width:640,height:480,frameRate:15});网络不好时降画质网络好时升回去都用这个。克隆轨道constnewTracktrack.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){// 移除旧的constoldTrackstream.getVideoTracks()[0];if(oldTrack){stream.removeTrack(oldTrack);oldTrack.stop();}// 添加新的stream.addTrack(newVideoTrack);// 如果已经在 PeerConnection 里还要替换发送的轨道// sender.replaceTrack(newVideoTrack);}2. 静音/取消静音// 静音麦克风functionmuteAudio(stream){constaudioTrackstream.getAudioTracks()[0];if(audioTrack){audioTrack.enabledfalse;}}// 取消静音functionunmuteAudio(stream){constaudioTrackstream.getAudioTracks()[0];if(audioTrack){audioTrack.enabledtrue;}}3. 开关摄像头functiontoggleCamera(stream){constvideoTrackstream.getVideoTracks()[0];if(videoTrack){videoTrack.enabled!videoTrack.enabled;returnvideoTrack.enabled;}}4. 合并两个流把摄像头和屏幕共享合并到一个流functionmergeStreams(cameraStream,screenStream){constmergednewMediaStream();// 屏幕视频screenStream.getVideoTracks().forEach(tmerged.addTrack(t));// 摄像头音频或者两个都加看需求cameraStream.getAudioTracks().forEach(tmerged.addTrack(t));returnmerged;}5. 只取视频/只取音频// 从流里只提取视频轨生成新流functionvideoOnly(stream){returnnewMediaStream(stream.getVideoTracks());}// 只提取音频functionaudioOnly(stream){returnnewMediaStream(stream.getAudioTracks());}6. 拍照从视频轨抓帧functiontakePhoto(videoTrack){constcanvasdocument.createElement(canvas);constvideodocument.createElement(video);video.srcObjectnewMediaStream([videoTrack]);// 等视频就绪returnnewPromise(resolve{video.onloadedmetadata(){canvas.widthvideo.videoWidth;canvas.heightvideo.videoHeight;canvas.getContext(2d).drawImage(video,0,0);resolve(canvas.toDataURL(image/png));};});}七、视频轨道的特殊操作摄像头切换移动端asyncfunctionswitchCamera(currentStream){constcurrentTrackcurrentStream.getVideoTracks()[0];constfacingModecurrentTrack.getSettings().facingMode;constnewFacingModefacingModeuser?environment:user;constnewStreamawaitnavigator.mediaDevices.getUserMedia({video:{facingMode:newFacingMode},audio:true});// 停掉旧的currentStream.getTracks().forEach(tt.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){constaudioContextnewAudioContext();constsourceaudioContext.createMediaStreamSource(newMediaStream([audioTrack]));constanalyseraudioContext.createAnalyser();source.connect(analyser);constdataArraynewUint8Array(analyser.frequencyBinCount);functiongetVolume(){analyser.getByteFrequencyData(dataArray);letsum0;for(leti0;idataArray.length;i){sumdataArray[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 是关联的流对方收到时轨道会在同一个流里。替换轨道切换摄像头时用通话中切换摄像头不用重新协商constsenderpc.getSenders().find(ss.track.kindvideo);awaitsender.replaceTrack(newVideoTrack);replaceTrack 不用重新协商 SDP切换很快很平滑。接收端拿到轨道pc.ontrack(event){conststreamevent.streams[0];remoteVideo.srcObjectstream;};对方添加轨道后这边触发 ontrack 事件。十、常见坑坑 1enabled false 不省带宽很多人以为静音就不发数据了其实还在发只是发静音帧/黑屏帧。要省带宽得移除轨道或者用码率限制。坑 2stop 之后轨道就废了调用 stop() 后轨道就结束了不能再启用。要重新开得再 getUserMedia。坑 3克隆的轨道也要手动 stopclone() 出来的轨道是独立的原轨道 stop 了克隆的还在跑记得都要释放。坑 4流里可以有多个视频轨一个流可以加多个视频轨但不是所有播放器都支持显示多个。一般一个流一个视频轨一个音频轨。坑 5replaceTrack 不需要重新协商切换摄像头用 replaceTrack 就行不用重新 createOffer/Answer体验好很多。坑 6iOS 上轨道行为不一样iOS Safari 上页面切后台后视频轨会暂停回来可能要重新处理。十一、本篇小结MediaStream 容器装多个 MediaStreamTrackMediaStreamTrack 单个音/视频轨道是最小操作单元轨道操作enabled 开关、stop 停止、applyConstraints 改参数、clone 克隆流操作addTrack/removeTrack、clone、getTracks常用技巧切换摄像头、静音、合并流、分流、拍照、音量检测PeerConnection 中用 addTrack 添加replaceTrack 替换ontrack 接收注意enabled 不省带宽stop 后不可恢复克隆的轨道要手动释放下一篇讲RTCPeerConnection 连接建立SDP 协商、ICE 候选、完整的连接建立流程。我是黒漂技术佬。