navigator.mediaDevices.getUserMedia
和 MediaStream
是实时音视频处理的重要 API。通过这些 API,可以从摄像头、麦克风或其他设备捕获音视频流,应用于视频通话、录制等场景。本文将介绍 navigator.mediaDevices.getUserMedia
的参数配置、MediaStream
的传参、属性和方法,配合详细的代码示例,特别是如何动态添加和移除音视频轨道,以及轨道的处理。
目录
navigator.mediaDevices.getUserMedia
传参配置
getUserMedia()
方法接受一个参数对象,用于定义所需的媒体类型和具体约束。它的语法如下:
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
// 处理成功的媒体流
})
.catch(function(error) {
// 处理错误
});
布尔值与对象配置
constraints
参数用于定义音频和视频的需求,既可以是布尔值,也可以是一个详细的对象。
1. 布尔值配置
audio: true
:请求音频轨道。video: true
:请求视频轨道。
这种简单配置仅表示是否请求音频或视频轨道,而不指定任何具体属性。
const constraints = {
audio: true,
video: true
};
2. 对象配置
如果需要更加精细地控制音视频流的特性,可以将 audio
和 video
设置为对象,指定详细的参数。
音频参数
音频配置对象可包含以下参数:
echoCancellation
:是否启用回声消除(布尔值)。noiseSuppression
:是否启用噪声抑制(布尔值)。autoGainControl
:是否启用自动增益控制(布尔值)。
示例:
const audioConstraints = {
audio: {
echoCancellation: true, // 启用回声消除
noiseSuppression: true, // 启用噪声抑制
autoGainControl: false // 关闭自动增益控制
}
};
视频参数
视频配置对象可以包含以下参数:
width
:定义视频宽度,可以是具体值或理想值(ideal
、min
、max
)。height
:定义视频高度,同样可以是具体值或理想值。frameRate
:帧率控制。facingMode
:定义使用前置或后置摄像头(“user” 为前置,“environment” 为后置)。
示例:
const videoConstraints = {
video: {
width: { ideal: 1280 }, // 理想宽度
height: { ideal: 720 }, // 理想高度
frameRate: { max: 30 }, // 最大帧率 30fps
facingMode: "user" // 前置摄像头
}
};
综合示例
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
:设备硬件故障,无法读取数据。
处理示例:
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
动态添加新的音视频轨道。示例如下:
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
中移除指定的音视频轨道:
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
<!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
<!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"
,表示该轨道是音频还是视频。track.kind; // 'audio' 或 'video'
-
id
:轨道的唯一标识符,通常在流的不同上下文中用于识别不同的轨道。track.id; // 一个唯一的字符串
-
label
:轨道的标签,通常是设备的名称(如摄像头或麦克风的名称)。track.label; // 例如 'Integrated Camera' 或 'Microphone'
-
enabled
:布尔值,表示轨道是否启用。如果设置为false
,轨道的数据将不会传递,但轨道仍然存在于流中。track.enabled = false; // 暂停轨道传输
-
muted
:布尔值,表示轨道是否被静音。该属性通常由浏览器控制,当轨道没有数据或用户禁用了权限时会自动设置为true
。if (track.muted) { console.log('轨道被静音'); }
-
readyState
:轨道的当前状态,可能的值为:"live"
:轨道正在传输数据。"ended"
:轨道不再传输数据,例如设备已被移除。
console.log(track.readyState); // 'live' 或 'ended'
方法
-
clone()
:返回当前轨道的一个副本。新轨道与原轨道相同,但可以独立控制。const clonedTrack = track.clone();
-
stop()
:停止轨道传输,并将readyState
设置为"ended"
。停止后,该轨道将不再传输数据。track.stop();
-
applyConstraints(constraints)
:应用指定的约束条件(如分辨率或帧率)来控制轨道的参数。适用于视频轨道。const constraints = { width: { min: 640, ideal: 1280 }, height: { ideal: 720 } }; track.applyConstraints(constraints) .then(() => console.log('应用约束成功')) .catch(err => console.error('应用约束失败', err));
-
getCapabilities()
:返回轨道的能力信息,表明该轨道支持的各种参数范围(如宽度、高度、帧率等)。const capabilities = track.getCapabilities(); console.log(capabilities);
-
getConstraints()
:返回当前应用到该轨道的约束。const constraints = track.getConstraints(); console.log(constraints);
-
getSettings()
:返回当前轨道的设置(如分辨率、帧率等),这些设置通常是在调用applyConstraints
方法时应用的。const settings = track.getSettings(); console.log(settings);
事件
MediaStreamTrack
可以触发多个事件,帮助开发者处理轨道的状态变化:
-
ended
:当轨道停止传输(如设备被移除或调用了stop()
方法)时触发。track.addEventListener('ended', () => { console.log('轨道结束'); });
-
mute
:当轨道由于某种原因静音时触发(例如用户拒绝权限或设备被禁用)。track.addEventListener('mute', () => { console.log('轨道被静音'); });
-
unmute
:当轨道恢复传输音频或视频数据时触发。track.addEventListener('unmute', () => { console.log('轨道恢复传输'); });
实例代码
下面的示例,展示了如何通过 getUserMedia
获取媒体流,并操作 MediaStreamTrack
以控制轨道的启用和禁用。
<!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>