WebRTC オーディオとビデオのキャプチャと再生、および MediaStream メディア ストリーム分析の例
目次
- サンプルコード - カメラとマイクを同時に開き、画面を表示し、キャプチャしたサウンドをページで再生します
- API分析
- メディアデバイス
- MediaStream メディア ストリーム
1. サンプルコード - カメラとマイクを同時に開き、画面を表示し、キャプチャしたサウンドをページで再生します
- コード
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebRTC Demo</title>
</head>
<body>
<video id="local-video" autoplay playsinline></video>
<button id="showVideo">打开音视频</button>
</body>
<script>
const constraints = {
audio: true,
video: {
width: 640, height: 480}
}
// 处理打开摄像头成功
function handleSuccess(mediaStream) {
const video = document.querySelector("#local-video");
video.srcObject = mediaStream;
}
// 异常处理
function handleError(error) {
console.error("getUserMedia error: " + error)
}
function onOpenAV(e) {
navigator.mediaDevices.getUserMedia(constraints).then(handleSuccess).catch(handleError);
}
document.querySelector("#showVideo").addEventListener("click", onOpenAV)
</script>
</html>
- 効果
2.原薬分析
1.メディアデバイス
- mediaDevices は、ナビゲーターの読み取り専用プロパティであり、画面共有を含む、カメラやマイクなどのメディア入力デバイスへの接続アクセスを提供する MediaDevices オブジェクトを返します。
- 文法:
var mediaDevices = navigator.mediaDevices;
- MediaDevices はシングルトン オブジェクトであり、このオブジェクトのメンバーは、navigator.mediaDevices.getUserMedia() を呼び出すなどして直接使用できます。
2. MediaStream メディア ストリーム
- navigator.mediaDevices.getUserMedia() は、メディア入力を使用する許可を与えるようにユーザーに促し、メディア入力は、情報のキャリアであり、メディア デバイスのコンテンツ ストリームを表す MediaStream (メディア ストリーム) を生成します。
- メディア ストリームは、収集、送信、および再生できます。通常、メディア ストリームには、オーディオ トラックやビデオ トラックなどの複数のメディア トラックが含まれます。
- Media Stream are managed using the MediaStream interface. 通常、メディア ストリームを取得するにはいくつかの方法があります。
a. カメラまたはマイクからストリーム オブジェクトを取得します。
b. 画面共有からストリーム オブジェクトを取得します。
c. キャンバス (HTMLCanvasElement) コンテンツからストリーム オブジェクトを取得します。
d. メディア要素 (HTMLMediaElement) からストリーム オブジェクトを取得します。 - 上記の方法で取得したメディア ストリームは、WebRTC を介して送信し、複数のピア間で共有できます。
- Promise オブジェクトを返し、resolve は成功後に MediaStream オブジェクトをコールバックします。
- ユーザーが許可を拒否した場合、または必要なメディア ソースが利用できない場合、promise は拒否され、PermissionDeniedError または NotFoundError がコールバックされます。
- 一般的な使用法:
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
/* 使用这个 stream stream */
})
.catch(function(err) {
/* 处理 error */
});
- MediaStream の定義
interface MediaStream : EventTarget {
constructor();
constructor(MediaStream stream);
constructor(sequence<MediaStreamTrack> tracks);
readonly attribute DOMString id;
sequence<MediaStreamTrack> getAudioTracks();
sequence<MediaStreamTrack> getVideoTracks();
sequence<MediaStreamTrack> getTracks();
MediaStreamTrack? getTrackById(DOMString trackId);
void addTrack(MediaStreamTrack track);
void removeTrack(MediaStreamTrack track);
MediaStream clone();
readonly attribute boolean active;
attribute EventHandler onaddtrack;
attribute EventHandler onremovetrack;
};
1. MediaStream プロパティ
1.アクティブな読み取り専用
- MediaStream の状態を返します。型はブール値です。true はアクティブであることを意味し、false は非アクティブであることを意味します。
2. id は読み取り専用です
- MediaStream の UUID を返します。タイプは文字列で、長さは 36 文字です。
2.MediaStream メソッド
1. addTrack() メソッド: 新しいメディア トラックをメディア ストリームに追加します。
stream.addTrack(track);
参数:Track,媒体轨道,类型为MediaStreamTrack。
返回值:无。
2. clone() メソッド: 現在のメディア ストリームのコピーを返します。コピーには異なる一意の識別子があります。
const newstream = stream.clone();
// sameId为false
const sameId = newstream.id === stream.id? true : false
参数:无。
返回值:一个新的媒体流对象。
3. getAudioTracks() メソッド: メディア タイプがオーディオで、メンバー タイプが MediaStreamTrack であるメディア トラック オブジェクトの配列を返します。
- 配列の順序は不定であり、呼び出しごとに異なる場合があることに注意してください。
const mediaStreamTracks = mediaStream.getAudioTracks()
参数:无。
返回值:mediaStreamTracks,媒体轨道对象数组,如果当前媒体流没有音频轨道,则返回数组为空。
- 例: getUserMedia() メソッドを使用して、ビデオ トラックとオーディオ トラックを含むメディア ストリームを取得します。呼び出しが成功した場合は、メディア ストリームを < > 要素にアタッチし、タイマーを設定し、getAudioTracks() メソッドを呼び出してすべてを取得します
video
。 5 秒後にオーディオ トラックを再生し、最後に最初のオーディオ トラックの再生を停止します。
navigator.mediaDevices.getUserMedia({
audio: true, video: true})
.then(mediaStream => {
document.querySelector('video').srcObject = mediaStream;
// 5s后,停止播放第一个音频轨道
setTimeout(() => {
const tracks = mediaStream.getAudioTracks()
tracks[0].stop()
}, 5000)
})
4. getVideoTracks() メソッド: kind 属性値が video で、メディア トラック オブジェクトのタイプが MediaStream Track であるメディア トラック オブジェクトの配列を返します。
- 配列内のオブジェクトの順序は不定であり、呼び出しごとに異なる場合があることに注意してください。
const mediaStreamTracks = mediaStream.getVideoTracks()
参数:无。
返回值:mediaStreamTracks是媒体轨道对象数组。如果当前媒体流没有视频轨道,则返回数组为空。
- 例: getUserMedia() メソッドはビデオ ストリームを取得します。呼び出しが成功した場合は、メディア ストリームを <
video
> 要素にアタッチし、最初のビデオ トラックを取得して、ビデオ トラックから画像をキャプチャします。
navigator.mediaDevices.getUserMedia({
video: true})
.then(mediaStream => {
document.querySelector('video').srcObject = mediaStream;
const track = mediaStream.getVideoTracks()[0];
// 截取图片
const imageCapture = new ImageCapture(track);
return imageCapture;
})
5. getTrackById() メソッド: 指定された ID を持つトラック オブジェクトを返します。
- パラメータが指定されていない場合、または ID 値が一致しない場合は null が返されます。同じ ID を持つトラックが複数ある場合、メソッドは最初に一致したトラックを返します。
const track = MediaStream.getTrackById(id);
参数:id,类型为字符串。
返回值:如果输入参数id与MediaStreamTrack.id匹配,则返回相应的MediaStream-Track对象,否则返回null。
- 例: 指定された ID のメディア トラックを取得し、制約を適用して音量を 0.5 に調整します。
stream.getTrackById("primary-audio-track").applyConstraints({
volume: 0.5 });
6. getTracks() メソッド: すべてのビデオおよびオーディオ トラックを含む、すべてのメディア トラック オブジェクトの配列を返します。
- 配列内のオブジェクトの順序は不定であり、呼び出しごとに異なる場合があります。
const mediaStreamTracks = mediaStream.getTracks()
参数:无。
返回值:媒体轨道对象数组。
- getUserMedia() メソッドを使用して、ビデオ トラックを含むストリームを取得します。呼び出しが成功した場合は、ストリームを < > 要素にアタッチし、タイマーを設定して、5 秒後にすべての
video
メディア トラックを取得し、最初のメディア トラックの再生を停止します。 (つまり、ビデオ トラック) .
navigator.mediaDevices.getUserMedia({
audio: false, video: true})
.then(mediaStream => {
document.querySelector('video').srcObject = mediaStream;
// 5s后,停止播放第一个媒体轨道
setTimeout(() => {
const tracks = mediaStream.getTracks()
tracks[0].stop()
}, 5000)
})
3.MediaStream イベント
1. addtrack イベント: このイベントは、イベント ハンドラー onaddtrack に対応する新しいメディア トラック (MediaStreamTrack) が追加されたときにトリガーされます。
- このイベントは、次の条件下でのみトリガーされ、MediaStream.addTrack() メソッドがアクティブに呼び出された場合はトリガーされないことに注意してください。
- RTCPeerConnection の再ネゴシエーション。
- HTMLMediaElement.captureStream() は、新しいメディア トラックを返します。
- 例: 新しいメディア トラックがメディア ストリームに追加された場合、新しいメディア トラックのタイプとラベルを表示します。
// event类型为MediaStreamTrackEvent
// event.track类型为MediaStreamTrack
stream.onaddtrack = (event) => {
let trackList = document.getElementById("tracks");
let label = document.createElement("li");
label.innerHTML = event.track.kind + ": " + event.track.label;
trackList.appendChild(label);
};
- さらに、addEventListener() メソッドを使用してイベント addtrack をリッスンすることもできます。
2. removetrack イベント: このイベントは、メディア トラックが削除されたときにトリガーされ、イベント ハンドラー onremovetrack に対応します。
- このイベントは、次の状況でのみトリガーされ、MediaStream.removeTrack() メソッドがアクティブに呼び出された場合はトリガーされないことに注意してください。
- RTCPeerConnection の再ネゴシエーション。
- HTMLMediaElement.captureStream() は、新しいメディア トラックを返します。
- 例: メディア トラックがメディア ストリームから削除された場合、メディア トラック情報を記録します。
// event类型为MediaStreamTrackEvent
// event.track类型为MediaStreamTrack
stream.onremovetrack = (event) => {
let trackList = document.getElementById("tracks");
let label = document.createElement("li");
label.innerHTML = "Removed: " + event.track.kind + ": " + event.track.label;
trackList.appendChild(label);
};
- さらに、addEventListener() メソッドを使用してイベント removetrack をリッスンすることもできます。
4. パラメータの制約
-
制約は、MediaStreamConstraints オブジェクトとして、要求されたメディア タイプと対応するパラメーターを指定します。
-
制約パラメーターは、要求されたメディアの種類を記述するために、ビデオとオーディオの 2 つのメンバーを含む MediaStreamConstraints オブジェクトです。
- 少なくとも 1 つまたは両方のタイプを指定する必要があります。
- ブラウザーが指定されたメディア タイプを見つけられない場合、または対応するパラメーター要件を満たすことができない場合、返された Promise オブジェクトは拒否された [失敗] 状態になり、NotFoundError が拒否された [失敗] コールバックのパラメーターとして使用されます。
-
以下は、パラメータなしでオーディオとビデオの両方をリクエストします。
{
audio: true, video: true }
-
特定のメディア タイプに対して true が設定されている場合、結果のストリームにはそのタイプのトラックが含まれている必要があります。何らかの理由でそれらのいずれかを取得できない場合、getUserMedia() はエラーを発生させます。
-
プライバシー保護の理由により、ユーザーのカメラとマイクの情報にアクセスできない場合、アプリケーションは追加の制約パラメーターを使用して、必要または必要とするカメラとマイクの機能を要求できます。
-
以下は、アプリが 1280x720 のカメラ解像度を使用することを示しています。
{
audio: true,
video: {
width: 1280, height: 720 }
}
- ブラウザーはこの要求パラメーターを満たそうとしますが、この要求のパラメーター要件を正確に満たすことができない場合、またはユーザーが要求のパラメーターをオーバーライドすることを選択した場合、他の解決策が返されることがあります。
- 特定のサイズを強制する場合は、キーワード min、max、exact (つまり、min == max) を使用できます。
- 次のパラメータは、1280x720 の最小解像度が必要であることを示しています。
{
audio: true,
video: {
width: {
min: 1280 },
height: {
min: 720 }
}
}
- カメラが要求された解像度またはそれ以上の解像度をサポートしていない場合、返された Promise は拒否された状態になり、拒否されたコールバックのパラメーターとして NotFoundError が渡され、ユーザーは承認を求められません。
- 異なるパフォーマンスの理由は、単純なリクエスト値と理想的なキーワードと比較して、キーワード min、max、および exact には次のような固有の強制性があるためです。
{
audio: true,
video: {
width: {
min: 1024, ideal: 1280, max: 1920 },
height: {
min: 776, ideal: 720, max: 1080 }
}
}
- 要求に理想的な値が含まれている場合、この値の重みが高くなります。つまり、ブラウザーは最初に、指定された理想的な値に最も近い設定またはカメラ (デバイスに複数のカメラがある場合) を見つけようとします。
- 単純なリクエスト値もアプリケーションの理想的な値として理解できるため、解像度を指定する最初のリクエストは次のように書くこともできます。
{
audio: true,
video: {
width: {
ideal: 1280 },
height: {
ideal: 720 }
}
}
- すべての制約が数値であるとは限りません。たとえば、モバイル デバイスでは、次の例は、前面カメラを最初に使用する必要があることを示しています (使用可能な場合)。
{
audio: true, video: {
facingMode: "user" } }
- 背面カメラの使用を強制するには、次を使用してください。
{
audio: true, video: {
facingMode: {
exact: "environment" } } }
- WebRTC で帯域幅が制限されたトランスポートを使用する場合など、場合によっては、低いフレーム レートがより適切な場合があります。
{
video: {
frameRate: {
ideal: 10, max: 15 } } };
5.戻り値
var promise = navigator.mediaDevices.getUserMedia(constraints);
- Promise を返します。Promise が成功したときのコールバック関数は、MediaStream オブジェクトをパラメーターとして受け取ります。
6.外れ値
- 失敗した状態の Promise を返します。Promise が失敗した後のコールバック関数は、そのパラメーターとして DOMException オブジェクトを受け取ります。考えられる例外は次のとおりです。
- AbortError [中止エラー]
- ユーザーとオペレーティング システムの両方がデバイスのハードウェアへのアクセスを許可しており、NotReadableError 例外をスローするハードウェアの問題はありませんが、デバイスが使用できなくなる問題がまだいくつかあります。
- NotAllowedError [拒否エラー]
- ユーザーが現在のブラウザー インスタンスのアクセス要求を拒否するか、ユーザーが現在のセッションのアクセスを拒否するか、ユーザーがすべてのメディア アクセス要求をグローバルに拒否します。
- 古いバージョンの仕様では SecurityError を使用していましたが、新しいバージョンでは SecurityError に新しい意味が与えられました。
- NotFoundError [エラーが見つかりません]
- 要求されたパラメータを満たすメディア タイプが見つかりませんでした。
- NotReadableError[エラーを読み取れません]
- ユーザーは対応するデバイスの使用を承認しましたが、オペレーティング システムのハードウェア、ブラウザー、または Web レベルのエラーにより、デバイスにアクセスできません。
- OverconstrainedError[要件を満たすことができませんエラー]
- 指定された要件をデバイスで満たすことができません。この例外は、OverconstrainedError 型のオブジェクトであり、現在満たすことができない制約オブジェクトを含む制約属性と、読み取り可能な文字列を含むメッセージ属性を持ちます。状況を説明します。
- NotFoundError [エラーが見つかりません]
- 要求されたパラメータを満たすメディア タイプが見つかりませんでした。
- NotReadableError[エラーを読み取れません]
- ユーザーは対応するデバイスの使用を承認しましたが、オペレーティング システムのハードウェア、ブラウザー、または Web レベルのエラーにより、デバイスにアクセスできません。
- OverconstrainedError[要件を満たすことができませんエラー]
- 指定された要件をデバイスで満たすことができません。この例外は、OverconstrainedError 型のオブジェクトであり、現在満たすことができない制約オブジェクトを含む制約属性と、読み取り可能な文字列を含むメッセージ属性を持ちます。状況を説明します。
- SecurityError [セキュリティ エラー]
- getUserMedia() が呼び出されたドキュメントでは、デバイス メディアの使用が無効になっています。このメカニズムを有効にするか無効にするかは、個々のユーザー設定によって異なります。
- TypeError [型エラー]
- 制約オブジェクトが [null] に設定されていないか、両方が false に設定されています。