音视频采集getUserMedia 与设备管理实时通信第一步是采集音视频。getUserMedia 怎么用分辨率、帧率、码率怎么设多个摄像头怎么切换麦克风怎么选这篇讲音视频采集的详细用法和常见坑。大家好我是黒漂技术佬。WebRTC 的第一步就是采集音视频——打开摄像头、获取麦克风。看起来简单就一个 getUserMedia但里面细节不少分辨率怎么设、帧率怎么控、前后摄像头怎么切、设备权限怎么处理。这篇讲音视频采集的完整用法从基础参数到设备管理再到常见坑。一、getUserMedia 基础最简单的调用conststreamawaitnavigator.mediaDevices.getUserMedia({video:true,// 要视频audio:true// 要音频});返回一个 MediaStream 对象里面包含视频轨和音频轨。显示到页面constvideodocument.querySelector(video);video.srcObjectstream;video 标签加上autoplay playsinline属性就能自动播放。只开音频/只开视频// 只要音频语音通话conststreamawaitnavigator.mediaDevices.getUserMedia({audio:true});// 只要视频conststreamawaitnavigator.mediaDevices.getUserMedia({video:true});二、视频参数控制分辨率设置conststreamawaitnavigator.mediaDevices.getUserMedia({video:{width:1280,height:720}});常用分辨率分辨率名称适用场景320×240QVGA低带宽、小窗口640×480VGA普通视频通话1280×720720P高清通话1920×10801080P高清会议、直播3840×21604K超高画质设备支持才行理想值 vs 最小值/最大值不一定能拿到你要的分辨率摄像头不一定支持。可以设范围video:{width:{min:640,ideal:1280,max:1920},height:{min:480,ideal:720,max:1080}}ideal理想值尽量满足min/max范围超出就报错只写数字 理想值帧率控制video:{width:1280,height:720,frameRate:30// 30帧}或者设范围frameRate:{min:15,ideal:30,max:60}常见帧率15、24、30、60。一般视频通话 30 帧足够60 帧更流畅但码率高。宽高比video:{aspectRatio:1.777,// 16:9width:1280}前置/后置摄像头移动端// 前置摄像头默认video:{facingMode:user}// 后置摄像头video:{facingMode:environment}移动端切换前后摄像头常用。三、音频参数控制基础设置audio:true// 默认配置详细参数audio:{echoCancellation:true,// 回声消除开noiseSuppression:true,// 降噪开autoGainControl:true,// 自动增益开sampleRate:48000,// 采样率sampleSize:16,// 采样位数channelCount:1// 声道数1单声道2立体声}三个重要的音频处理回声消除AEC作用对方的声音从扬声器出来不会又被麦克风录回去视频通话必须开不然有回声降噪NS作用去掉背景噪音键盘声、空调声一般都开通话质量好很多自动增益AGC作用声音小自动放大声音大自动缩小保持音量稳定这三个默认都是开的一般不用改。四、设备管理枚举所有设备constdevicesawaitnavigator.mediaDevices.enumerateDevices();devices.forEach(device{console.log(device.kind,device.label,device.deviceId);// kind: audioinput / videoinput / audiooutput});按设备 ID 指定摄像头/麦克风知道设备 ID 后可以指定用哪个设备conststreamawaitnavigator.mediaDevices.getUserMedia({video:{deviceId:cameraDeviceId},audio:{deviceId:micDeviceId}});切换摄像头asyncfunctionswitchCamera(deviceId){// 关掉旧的stream.getTracks().forEach(tracktrack.stop());// 打开新的constnewStreamawaitnavigator.mediaDevices.getUserMedia({video:{deviceId:deviceId},audio:true});// 更新显示video.srcObjectnewStream;streamnewStream;}设备变化监听插拔摄像头/麦克风时触发navigator.mediaDevices.ondevicechange(){console.log(设备列表变化了);// 重新枚举设备更新UI};注意没权限时 label 是空的用户没授权摄像头/麦克风权限前enumerateDevices 返回的设备 label 是空的只能看到数量看不到名字。授权后才能看到设备名称。五、屏幕共享采集屏幕conststreamawaitnavigator.mediaDevices.getDisplayMedia({video:true,audio:true// 可选采集系统音频});会弹出系统的屏幕选择窗口用户选共享整个屏幕、某个窗口、还是某个浏览器标签页。屏幕共享参数getDisplayMedia({video:{cursor:always// 显示鼠标always / motion / never},audio:true// 共享系统音频注意不是所有平台都支持});屏幕共享 摄像头可以同时采集摄像头和屏幕两个流constcameraStreamawaitgetUserMedia({video:true,audio:true});constscreenStreamawaitgetDisplayMedia({video:true});然后可以把摄像头画到屏幕流上做成画中画或者两路都推给对方。注意getDisplayMedia 必须用户主动触发点击按钮不能自动弹共享结束用户可以手动停止页面也能监听停止事件移动端支持有限六、轨道操作获取轨道// 视频轨constvideoTracksstream.getVideoTracks();constvideoTrackvideoTracks[0];// 音频轨constaudioTracksstream.getAudioTracks();constaudioTrackaudioTracks[0];// 所有轨道consttracksstream.getTracks();开关摄像头/麦克风// 关闭摄像头画面变黑videoTrack.enabledfalse;// 打开videoTrack.enabledtrue;// 静音audioTrack.enabledfalse;enabled false 时还在采集只是数据是黑的/静音的带宽还占着。要完全停止用 stop()。停止采集// 停止某个轨道videoTrack.stop();// 停止所有轨道挂断时用stream.getTracks().forEach(tracktrack.stop());stop 之后轨道就废了要重新采集得再调用 getUserMedia。动态修改参数采集过程中改分辨率、帧率awaitvideoTrack.applyConstraints({width:640,height:480,frameRate:15});网络不好的时候降低画质网络好的时候升回去。七、权限处理权限状态constpermissionsawaitnavigator.permissions.query({name:camera});console.log(permissions.state);// granted / denied / promptpermissions.onchange(){console.log(权限状态变了:,permissions.state);};常见错误错误原因NotAllowedError用户拒绝了权限NotFoundError没有摄像头/麦克风NotReadableError设备被其他程序占用了OverconstrainedError设置的参数设备不支持SecurityError非 HTTPS 环境错误处理try{conststreamawaitnavigator.mediaDevices.getUserMedia({video:true});}catch(err){switch(err.name){caseNotAllowedError:alert(请允许摄像头权限);break;caseNotFoundError:alert(没有找到摄像头);break;caseNotReadableError:alert(摄像头被占用了请关闭其他使用摄像头的程序);break;default:alert(打开摄像头失败err.message);}}八、兼容性处理adapter.js不同浏览器 API 有前缀差异Google 官方的 adapter.js 可以抹平scriptsrchttps://webrtc.github.io/adapter/adapter-latest.js/script引入之后直接用标准 API 就行不用管前缀。功能检测if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert(您的浏览器不支持 WebRTC);}HTTPS 要求正式环境必须 HTTPSlocalhost 本地开发例外。HTTP 环境下 getUserMedia 是 undefined。九、实际场景视频通话的采集配置普通视频通话conststreamawaitnavigator.mediaDevices.getUserMedia({video:{width:{ideal:1280},height:{ideal:720},frameRate:30},audio:{echoCancellation:true,noiseSuppression:true,autoGainControl:true}});720P 30帧音频处理全开平衡画质和带宽。语音通话conststreamawaitnavigator.mediaDevices.getUserMedia({video:false,audio:{echoCancellation:true,noiseSuppression:true,autoGainControl:true,sampleRate:48000}});高清直播conststreamawaitnavigator.mediaDevices.getUserMedia({video:{width:1920,height:1080,frameRate:30},audio:{echoCancellation:false,// 直播不用回声消除noiseSuppression:true,sampleRate:48000,channelCount:2// 立体声}});十、常见坑坑 1HTTP 环境用不了必须 HTTPSlocalhost 除外。本地开发用 localhost 没问题部署上线要配 HTTPS。坑 2iOS Safari 限制多必须用户点击才能播放autoplay 没用第一次 getUserMedia 要用户手势触发playsinline 属性一定要加不然会全屏播放坑 3分辨率设太高拿不到写死 1080P有些摄像头不支持就报错。用 ideal 不要写死或者给个范围。坑 4设备被占用摄像头被其他应用占了打开失败。提示用户关闭其他程序。坑 5移动端前后摄像头切换facingMode 不是所有浏览器都支持最好用 deviceId 的方式切换更可靠。坑 6静音用 enabled false 不省带宽只是不发送数据内容轨道还在带宽和连接都保持着。要省带宽得移除轨道或者降低码率。坑 7屏幕共享不能自动弹必须用户点击按钮触发不能页面加载自动弹浏览器会拦截。十一、本篇小结getUserMedia 是音视频采集的入口video 和 audio 两个参数控制视频参数分辨率、帧率、宽高比、前后摄像头音频参数回声消除、降噪、自动增益默认都开enumerateDevices 枚举设备deviceId 指定设备getDisplayMedia 采集屏幕支持共享整个屏幕/窗口/标签页轨道操作enabled 开关、stop 停止、applyConstraints 动态改参数注意权限处理和错误提示用户体验很重要必须 HTTPS 环境注意移动端和 Safari 兼容性下一篇讲媒体流与轨道MediaStream 和 MediaTrack 的详细用法怎么添加移除轨道、怎么克隆流。我是黒漂技术佬。
音视频采集:getUserMedia 与设备管理
发布时间:2026/7/7 3:04:18
音视频采集getUserMedia 与设备管理实时通信第一步是采集音视频。getUserMedia 怎么用分辨率、帧率、码率怎么设多个摄像头怎么切换麦克风怎么选这篇讲音视频采集的详细用法和常见坑。大家好我是黒漂技术佬。WebRTC 的第一步就是采集音视频——打开摄像头、获取麦克风。看起来简单就一个 getUserMedia但里面细节不少分辨率怎么设、帧率怎么控、前后摄像头怎么切、设备权限怎么处理。这篇讲音视频采集的完整用法从基础参数到设备管理再到常见坑。一、getUserMedia 基础最简单的调用conststreamawaitnavigator.mediaDevices.getUserMedia({video:true,// 要视频audio:true// 要音频});返回一个 MediaStream 对象里面包含视频轨和音频轨。显示到页面constvideodocument.querySelector(video);video.srcObjectstream;video 标签加上autoplay playsinline属性就能自动播放。只开音频/只开视频// 只要音频语音通话conststreamawaitnavigator.mediaDevices.getUserMedia({audio:true});// 只要视频conststreamawaitnavigator.mediaDevices.getUserMedia({video:true});二、视频参数控制分辨率设置conststreamawaitnavigator.mediaDevices.getUserMedia({video:{width:1280,height:720}});常用分辨率分辨率名称适用场景320×240QVGA低带宽、小窗口640×480VGA普通视频通话1280×720720P高清通话1920×10801080P高清会议、直播3840×21604K超高画质设备支持才行理想值 vs 最小值/最大值不一定能拿到你要的分辨率摄像头不一定支持。可以设范围video:{width:{min:640,ideal:1280,max:1920},height:{min:480,ideal:720,max:1080}}ideal理想值尽量满足min/max范围超出就报错只写数字 理想值帧率控制video:{width:1280,height:720,frameRate:30// 30帧}或者设范围frameRate:{min:15,ideal:30,max:60}常见帧率15、24、30、60。一般视频通话 30 帧足够60 帧更流畅但码率高。宽高比video:{aspectRatio:1.777,// 16:9width:1280}前置/后置摄像头移动端// 前置摄像头默认video:{facingMode:user}// 后置摄像头video:{facingMode:environment}移动端切换前后摄像头常用。三、音频参数控制基础设置audio:true// 默认配置详细参数audio:{echoCancellation:true,// 回声消除开noiseSuppression:true,// 降噪开autoGainControl:true,// 自动增益开sampleRate:48000,// 采样率sampleSize:16,// 采样位数channelCount:1// 声道数1单声道2立体声}三个重要的音频处理回声消除AEC作用对方的声音从扬声器出来不会又被麦克风录回去视频通话必须开不然有回声降噪NS作用去掉背景噪音键盘声、空调声一般都开通话质量好很多自动增益AGC作用声音小自动放大声音大自动缩小保持音量稳定这三个默认都是开的一般不用改。四、设备管理枚举所有设备constdevicesawaitnavigator.mediaDevices.enumerateDevices();devices.forEach(device{console.log(device.kind,device.label,device.deviceId);// kind: audioinput / videoinput / audiooutput});按设备 ID 指定摄像头/麦克风知道设备 ID 后可以指定用哪个设备conststreamawaitnavigator.mediaDevices.getUserMedia({video:{deviceId:cameraDeviceId},audio:{deviceId:micDeviceId}});切换摄像头asyncfunctionswitchCamera(deviceId){// 关掉旧的stream.getTracks().forEach(tracktrack.stop());// 打开新的constnewStreamawaitnavigator.mediaDevices.getUserMedia({video:{deviceId:deviceId},audio:true});// 更新显示video.srcObjectnewStream;streamnewStream;}设备变化监听插拔摄像头/麦克风时触发navigator.mediaDevices.ondevicechange(){console.log(设备列表变化了);// 重新枚举设备更新UI};注意没权限时 label 是空的用户没授权摄像头/麦克风权限前enumerateDevices 返回的设备 label 是空的只能看到数量看不到名字。授权后才能看到设备名称。五、屏幕共享采集屏幕conststreamawaitnavigator.mediaDevices.getDisplayMedia({video:true,audio:true// 可选采集系统音频});会弹出系统的屏幕选择窗口用户选共享整个屏幕、某个窗口、还是某个浏览器标签页。屏幕共享参数getDisplayMedia({video:{cursor:always// 显示鼠标always / motion / never},audio:true// 共享系统音频注意不是所有平台都支持});屏幕共享 摄像头可以同时采集摄像头和屏幕两个流constcameraStreamawaitgetUserMedia({video:true,audio:true});constscreenStreamawaitgetDisplayMedia({video:true});然后可以把摄像头画到屏幕流上做成画中画或者两路都推给对方。注意getDisplayMedia 必须用户主动触发点击按钮不能自动弹共享结束用户可以手动停止页面也能监听停止事件移动端支持有限六、轨道操作获取轨道// 视频轨constvideoTracksstream.getVideoTracks();constvideoTrackvideoTracks[0];// 音频轨constaudioTracksstream.getAudioTracks();constaudioTrackaudioTracks[0];// 所有轨道consttracksstream.getTracks();开关摄像头/麦克风// 关闭摄像头画面变黑videoTrack.enabledfalse;// 打开videoTrack.enabledtrue;// 静音audioTrack.enabledfalse;enabled false 时还在采集只是数据是黑的/静音的带宽还占着。要完全停止用 stop()。停止采集// 停止某个轨道videoTrack.stop();// 停止所有轨道挂断时用stream.getTracks().forEach(tracktrack.stop());stop 之后轨道就废了要重新采集得再调用 getUserMedia。动态修改参数采集过程中改分辨率、帧率awaitvideoTrack.applyConstraints({width:640,height:480,frameRate:15});网络不好的时候降低画质网络好的时候升回去。七、权限处理权限状态constpermissionsawaitnavigator.permissions.query({name:camera});console.log(permissions.state);// granted / denied / promptpermissions.onchange(){console.log(权限状态变了:,permissions.state);};常见错误错误原因NotAllowedError用户拒绝了权限NotFoundError没有摄像头/麦克风NotReadableError设备被其他程序占用了OverconstrainedError设置的参数设备不支持SecurityError非 HTTPS 环境错误处理try{conststreamawaitnavigator.mediaDevices.getUserMedia({video:true});}catch(err){switch(err.name){caseNotAllowedError:alert(请允许摄像头权限);break;caseNotFoundError:alert(没有找到摄像头);break;caseNotReadableError:alert(摄像头被占用了请关闭其他使用摄像头的程序);break;default:alert(打开摄像头失败err.message);}}八、兼容性处理adapter.js不同浏览器 API 有前缀差异Google 官方的 adapter.js 可以抹平scriptsrchttps://webrtc.github.io/adapter/adapter-latest.js/script引入之后直接用标准 API 就行不用管前缀。功能检测if(!navigator.mediaDevices||!navigator.mediaDevices.getUserMedia){alert(您的浏览器不支持 WebRTC);}HTTPS 要求正式环境必须 HTTPSlocalhost 本地开发例外。HTTP 环境下 getUserMedia 是 undefined。九、实际场景视频通话的采集配置普通视频通话conststreamawaitnavigator.mediaDevices.getUserMedia({video:{width:{ideal:1280},height:{ideal:720},frameRate:30},audio:{echoCancellation:true,noiseSuppression:true,autoGainControl:true}});720P 30帧音频处理全开平衡画质和带宽。语音通话conststreamawaitnavigator.mediaDevices.getUserMedia({video:false,audio:{echoCancellation:true,noiseSuppression:true,autoGainControl:true,sampleRate:48000}});高清直播conststreamawaitnavigator.mediaDevices.getUserMedia({video:{width:1920,height:1080,frameRate:30},audio:{echoCancellation:false,// 直播不用回声消除noiseSuppression:true,sampleRate:48000,channelCount:2// 立体声}});十、常见坑坑 1HTTP 环境用不了必须 HTTPSlocalhost 除外。本地开发用 localhost 没问题部署上线要配 HTTPS。坑 2iOS Safari 限制多必须用户点击才能播放autoplay 没用第一次 getUserMedia 要用户手势触发playsinline 属性一定要加不然会全屏播放坑 3分辨率设太高拿不到写死 1080P有些摄像头不支持就报错。用 ideal 不要写死或者给个范围。坑 4设备被占用摄像头被其他应用占了打开失败。提示用户关闭其他程序。坑 5移动端前后摄像头切换facingMode 不是所有浏览器都支持最好用 deviceId 的方式切换更可靠。坑 6静音用 enabled false 不省带宽只是不发送数据内容轨道还在带宽和连接都保持着。要省带宽得移除轨道或者降低码率。坑 7屏幕共享不能自动弹必须用户点击按钮触发不能页面加载自动弹浏览器会拦截。十一、本篇小结getUserMedia 是音视频采集的入口video 和 audio 两个参数控制视频参数分辨率、帧率、宽高比、前后摄像头音频参数回声消除、降噪、自动增益默认都开enumerateDevices 枚举设备deviceId 指定设备getDisplayMedia 采集屏幕支持共享整个屏幕/窗口/标签页轨道操作enabled 开关、stop 停止、applyConstraints 动态改参数注意权限处理和错误提示用户体验很重要必须 HTTPS 环境注意移动端和 Safari 兼容性下一篇讲媒体流与轨道MediaStream 和 MediaTrack 的详细用法怎么添加移除轨道、怎么克隆流。我是黒漂技术佬。