navigator.mediaDevices.getUserMedia 和 MediaStream 是实时音视频处理的重要 API。通过这些 API,可以从摄像头、麦克风或其他设备捕获音视频流,应用于视频通话、录制等场景。本文将介绍 navigator.mediaDevices.getUserMedia 的参数配置、MediaStream 的传参、属性和方法,配合详细的代码示例,特别是如何动态添加和移除音视频轨道,以及轨道的处理。
目录
- navigator.mediaDevices.getUserMedia
- MediaStream
- 实例代码
- [流媒体轨道 (MediaStreamTrack)](#流媒体轨道 (MediaStreamTrack) "MediaStreamTrack")
navigator.mediaDevices.getUserMedia
传参配置
getUserMedia() 方法接受一个参数对象,用于定义所需的媒体类型和具体约束。它的语法如下:
javascript
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
// 处理成功的媒体流
})
.catch(function(error) {
// 处理错误
});
布尔值与对象配置
constraints 参数用于定义音频和视频的需求,既可以是布尔值,也可以是一个详细的对象。
1. 布尔值配置
audio: true:请求音频轨道。video: true:请求视频轨道。
这种简单配置仅表示是否请求音频或视频轨道,而不指定任何具体属性。
javascript
const constraints = {
audio: true,
video: true
};
2. 对象配置
如果需要更加精细地控制音视频流的特性,可以将 audio 和 video 设置为对象,指定详细的参数。
音频参数
音频配置对象可包含以下参数:
echoCancellation:是否启用回声消除(布尔值)。noiseSuppression:是否启用噪声抑制(布尔值)。autoGainControl:是否启用自动增益控制(布尔值)。
示例:
javascript
const audioConstraints = {
audio: {
echoCancellation: true, // 启用回声消除
noiseSuppression: true, // 启用噪声抑制
autoGainControl: false // 关闭自动增益控制
}
};
视频参数
视频配置对象可以包含以下参数:
width:定义视频宽度,可以是具体值或理想值(ideal、min、max)。height:定义视频高度,同样可以是具体值或理想值。frameRate:帧率控制。facingMode:定义使用前置或后置摄像头("user" 为前置,"environment" 为后置)。
示例:
javascript
const videoConstraints = {
video: {
width: { ideal: 1280 }, // 理想宽度
height: { ideal: 720 }, // 理想高度
frameRate: { max: 30 }, // 最大帧率 30fps
facingMode: "user" // 前置摄像头
}
};
综合示例
javascript
const constraints = {
audio: {
echoCancellation: true,
noiseSuppression: true
},
video: {
width: { min: 640, ideal: 1280, max: 1920 },
height: { min: 480, ideal: 720, max: 1080 },
frameRate: { ideal: 30, max: 60 },
facingMode: "user"
}
};
错误处理
getUserMedia() 调用失败时会返回一个 Promise,并触发错误。常见错误类型包括:
NotAllowedError:用户拒绝授予摄像头/麦克风访问权限。NotFoundError:找不到满足请求的设备。OverconstrainedError:指定的约束条件无法满足。NotReadableError:设备硬件故障,无法读取数据。
处理示例:
javascript
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
// 成功处理
})
.catch(function(error) {
console.error("错误: ", error.name);
});
兼容性
| 浏览器 | 支持情况 |
|---|---|
| Chrome | 完全支持 |
| Firefox | 完全支持 |
| Edge | 完全支持 |
| Safari | 仅 HTTPS 支持 |
| Internet Explorer | 不支持 |
| 移动端浏览器 | 部分支持 |
MediaStream
MediaStream 是由多条 MediaStreamTrack(音轨或视频轨)组成的媒体流。它允许开发者动态操控音视频轨道,包括添加、移除轨道,或将媒体流传递给其他 API 进行处理(如 WebRTC)。
MediaStream 接口代表一个媒体数据流,由多个轨道(MediaStreamTrack)组成。这些轨道可以是音频或视频轨道。MediaStream 可用于:
- 获取用户的摄像头和麦克风输入。
- 处理和修改媒体数据。
- 通过 WebRTC 进行实时通信。
属性
id:流的唯一标识符(只读)。active:指示流是否处于活动状态的布尔值(只读)。
方法
getTracks():返回流中所有的音视频轨道。getAudioTracks():返回流中的所有音轨。getVideoTracks():返回流中的所有视频轨道。addTrack(track):向MediaStream添加音频或视频轨道。removeTrack(track):从MediaStream中移除指定轨道。clone():克隆当前的媒体流,生成一个相同的MediaStream。
事件
addtrack:当轨道被添加时触发。removetrack:当轨道被移除时触发。
如何动态添加和移除音视频轨道
添加轨道
可以通过 addTrack() 方法向 MediaStream 动态添加新的音视频轨道。示例如下:
javascript
const videoElement = document.querySelector('video');
// 请求媒体流
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function(stream) {
videoElement.srcObject = stream;
// 获取视频轨道
const videoTrack = stream.getVideoTracks()[0];
// 添加新的视频轨道(假设你有一个新的视频轨道)
const newVideoTrack = /* 假设从其他源获取 */;
stream.addTrack(newVideoTrack);
})
.catch(function(error) {
console.error("错误: ", error);
});
移除轨道
可以通过 removeTrack() 方法从 MediaStream 中移除指定的音视频轨道:
javascript
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function(stream) {
const audioTrack = stream.getAudioTracks()[0]; // 获取音频轨道
// 从流中移除音频轨道
stream.removeTrack(audioTrack);
})
.catch(function(error) {
console.error("错误: ", error);
});
实例代码
下面是一个完整的示例,展示如何通过 getUserMedia 获取摄像头和麦克风,添加和移除轨道。
- 实例1
html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>MediaStream 示例</title>
<style>
video {
width: 640px;
height: 480px;
background-color: black;
}
</style>
</head>
<body>
<h1>MediaStream 示例</h1>
<video id="video" autoplay playsinline></video>
<script>
// 检查浏览器是否支持
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
const constraints = {
audio: true,
video: {
width: { ideal: 1280 },
height: { ideal: 720 },
facingMode: 'user' // 使用前置摄像头
}
};
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
const video = document.getElementById('video');
video.srcObject = stream;
video.onloadedmetadata = function(e) {
video.play();
};
})
.catch(function(err) {
console.error('发生错误: ' + err.name + ': ' + err.message);
});
} else {
alert('您的浏览器不支持 getUserMedia API');
}
</script>
</body>
</html>
- 实例2
html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>MediaStream 示例</title>
<style>
video {
width: 640px;
height: 480px;
background-color: black;
}
</style>
</head>
<body>
<h1>MediaStream 示例</h1>
<video id="video" autoplay playsinline></video>
<button id="addTrack">添加视频轨道</button>
<button id="removeTrack">移除音轨</button>
<script>
const video = document.getElementById('video');
let mediaStream;
// 获取音视频流
navigator.mediaDevices.getUserMedia({
audio: { echoCancellation: true },
video: { width: 1280, height: 720 }
})
.then(function(stream) {
mediaStream = stream;
video.srcObject = mediaStream;
})
.catch(function(err) {
console.error('错误: ' + err);
});
// 添加视频轨道
document.getElementById('addTrack').addEventListener('click', () => {
const newVideoTrack = /* 获取新的视频轨道 */;
mediaStream.addTrack(newVideoTrack);
});
// 移除音频轨道
document.getElementById('removeTrack').addEventListener('click', () => {
const audioTrack = mediaStream.getAudioTracks()[0];
mediaStream.removeTrack(audioTrack);
});
</script>
流媒体轨道 (MediaStreamTrack)
概述
MediaStreamTrack 代表 MediaStream 中的音频或视频轨道。每个轨道独立于其他轨道,可以单独控制、启用、禁用、或通过 clone() 方法复制。
通常,轨道通过调用 navigator.mediaDevices.getUserMedia() 返回的 MediaStream 对象获取。例如,一个 MediaStream 可以包含一条音频轨道和一条视频轨道。
属性
-
kind:轨道的类型,值为"audio"或"video",表示该轨道是音频还是视频。javascripttrack.kind; // 'audio' 或 'video' -
id:轨道的唯一标识符,通常在流的不同上下文中用于识别不同的轨道。javascripttrack.id; // 一个唯一的字符串 -
label:轨道的标签,通常是设备的名称(如摄像头或麦克风的名称)。javascripttrack.label; // 例如 'Integrated Camera' 或 'Microphone' -
enabled:布尔值,表示轨道是否启用。如果设置为false,轨道的数据将不会传递,但轨道仍然存在于流中。javascripttrack.enabled = false; // 暂停轨道传输 -
muted:布尔值,表示轨道是否被静音。该属性通常由浏览器控制,当轨道没有数据或用户禁用了权限时会自动设置为true。javascriptif (track.muted) { console.log('轨道被静音'); } -
readyState:轨道的当前状态,可能的值为:"live":轨道正在传输数据。"ended":轨道不再传输数据,例如设备已被移除。
javascriptconsole.log(track.readyState); // 'live' 或 'ended'
方法
-
clone():返回当前轨道的一个副本。新轨道与原轨道相同,但可以独立控制。javascriptconst clonedTrack = track.clone(); -
stop():停止轨道传输,并将readyState设置为"ended"。停止后,该轨道将不再传输数据。javascripttrack.stop(); -
applyConstraints(constraints):应用指定的约束条件(如分辨率或帧率)来控制轨道的参数。适用于视频轨道。javascriptconst constraints = { width: { min: 640, ideal: 1280 }, height: { ideal: 720 } }; track.applyConstraints(constraints) .then(() => console.log('应用约束成功')) .catch(err => console.error('应用约束失败', err)); -
getCapabilities():返回轨道的能力信息,表明该轨道支持的各种参数范围(如宽度、高度、帧率等)。javascriptconst capabilities = track.getCapabilities(); console.log(capabilities); -
getConstraints():返回当前应用到该轨道的约束。javascriptconst constraints = track.getConstraints(); console.log(constraints); -
getSettings():返回当前轨道的设置(如分辨率、帧率等),这些设置通常是在调用applyConstraints方法时应用的。javascriptconst settings = track.getSettings(); console.log(settings);
事件
MediaStreamTrack 可以触发多个事件,帮助开发者处理轨道的状态变化:
-
ended:当轨道停止传输(如设备被移除或调用了stop()方法)时触发。javascripttrack.addEventListener('ended', () => { console.log('轨道结束'); }); -
mute:当轨道由于某种原因静音时触发(例如用户拒绝权限或设备被禁用)。javascripttrack.addEventListener('mute', () => { console.log('轨道被静音'); }); -
unmute:当轨道恢复传输音频或视频数据时触发。javascripttrack.addEventListener('unmute', () => { console.log('轨道恢复传输'); });
实例代码
下面的示例,展示了如何通过 getUserMedia 获取媒体流,并操作 MediaStreamTrack 以控制轨道的启用和禁用。
html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>MediaStreamTrack 示例</title>
</head>
<body>
<h1>MediaStreamTrack 示例</h1>
<video id="video" autoplay playsinline></video>
<button id="toggleVideo">禁用/启用视频轨道</button>
<button id="stopVideo">停止视频轨道</button>
<script>
let videoTrack;
// 获取媒体流
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then(function(stream) {
document.getElementById('video').srcObject = stream;
// 获取视频轨道
videoTrack = stream.getVideoTracks()[0];
})
.catch(function(err) {
console.error('无法获取媒体流:', err);
});
// 切换视频轨道的启用/禁用状态
document.getElementById('toggleVideo').addEventListener('click', () => {
if (videoTrack) {
videoTrack.enabled = !videoTrack.enabled;
console.log(`视频轨道 ${videoTrack.enabled ? '启用' : '禁用'}`);
}
});
// 停止视频轨道
document.getElementById('stopVideo').addEventListener('click', () => {
if (videoTrack) {
videoTrack.stop();
console.log('视频轨道已停止');
}
});
</script>
</body>
</html>