Exemplos de captura e reprodução de áudio e vídeo WebRTC e análise de fluxo de mídia MediaStream
Índice
- Código de amostra - abra a câmera e o microfone ao mesmo tempo, exiba a tela e reproduza o som capturado na página
- análise de API
- dispositivos de mídia
- Fluxo de mídia MediaStream
1. Código de amostra - abra a câmera e o microfone ao mesmo tempo, exiba a tela e reproduza o som capturado na página
- o código
<!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>
- Efeito
2. Análise de API
1. dispositivos de mídia
- mediaDevices é uma propriedade somente leitura do Navigator que retorna um objeto MediaDevices que fornece acesso de conexão a dispositivos de entrada de mídia, como câmeras e microfones, incluindo compartilhamento de tela.
- gramática:
var mediaDevices = navigator.mediaDevices;
- MediaDevices é um objeto singleton e os membros desse objeto podem ser usados diretamente, por exemplo, chamando navigator.mediaDevices.getUserMedia().
2. Fluxo de mídia MediaStream
- navigator.mediaDevices.getUserMedia() solicitará ao usuário permissão para usar a entrada de mídia, e a entrada de mídia gerará um MediaStream (fluxo de mídia), que é o portador de informações e representa o fluxo de conteúdo de um dispositivo de mídia.
- Fluxos de mídia podem ser coletados, transmitidos e reproduzidos. Normalmente, um fluxo de mídia contém várias faixas de mídia, como faixas de áudio e faixas de vídeo.
- Os fluxos de mídia são gerenciados usando a interface MediaStream.Geralmente, existem várias maneiras de obter fluxos de mídia.
a. Obtenha o objeto de transmissão da câmera ou do microfone.
b. Obtenha o objeto de fluxo do compartilhamento de tela.
c. Obtenha o objeto de fluxo do conteúdo da tela (HTMLCanvasElement).
d. Obtenha o objeto de fluxo do elemento de mídia (HTMLMediaElement). - Os fluxos de mídia obtidos pelos métodos acima podem ser transmitidos por meio do WebRTC e compartilhados entre vários pares.
- Retorne um objeto Promise e resolver chamará de volta um objeto MediaStream após o sucesso.
- Se o usuário negar a permissão ou a fonte de mídia necessária não estiver disponível, a promessa rejeitará e chamará de volta um PermissionDeniedError ou NotFoundError.
- Uso comum:
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
/* 使用这个 stream stream */
})
.catch(function(err) {
/* 处理 error */
});
- Definição de 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. Propriedade MediaStream
1. ativo somente leitura
- Retorna o estado do MediaStream, o tipo é Boolean, true significa que está ativo, false significa que está inativo.
2. id é somente leitura
- Retorna o UUID do MediaStream, o tipo é string e o comprimento é 36 caracteres.
2. Método MediaStream
1. Método addTrack(): adiciona uma nova faixa de mídia ao fluxo de mídia.
stream.addTrack(track);
参数:Track,媒体轨道,类型为MediaStreamTrack。
返回值:无。
2. método clone(): retorna uma cópia do fluxo de mídia atual, e a cópia tem um identificador diferente e exclusivo.
const newstream = stream.clone();
// sameId为false
const sameId = newstream.id === stream.id? true : false
参数:无。
返回值:一个新的媒体流对象。
3. Método getAudioTracks(): retorna uma matriz de objetos de rastreamento de mídia cujo tipo de mídia é áudio e cujo tipo de membro é MediaStreamTrack.
- Observe que a ordem da matriz é indeterminada e pode variar de chamada para chamada.
const mediaStreamTracks = mediaStream.getAudioTracks()
参数:无。
返回值:mediaStreamTracks,媒体轨道对象数组,如果当前媒体流没有音频轨道,则返回数组为空。
- Exemplo: use o método getUserMedia() para obter o fluxo de mídia contendo faixas de vídeo e áudio. Se a chamada for bem-sucedida, anexe o fluxo de mídia ao elemento < >, defina um cronômetro e chame o método getAudioTracks() para obter
video
todos faixas de áudio após 5 segundos e, finalmente, pare de reproduzir a primeira faixa de áudio.
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. Método getVideoTracks(): retorna uma matriz de objetos de rastreamento de mídia cujo valor de atributo kind é video e o tipo do objeto de rastreamento de mídia é MediaStream Track.
- Observe que a ordem dos objetos no array é indeterminada e pode variar de chamada para chamada.
const mediaStreamTracks = mediaStream.getVideoTracks()
参数:无。
返回值:mediaStreamTracks是媒体轨道对象数组。如果当前媒体流没有视频轨道,则返回数组为空。
- Exemplo: O método getUserMedia() obtém o fluxo de vídeo, se a chamada for bem-sucedida, anexe o fluxo de mídia ao
video
elemento < > e, em seguida, obtenha a primeira faixa de vídeo e capture uma imagem da faixa de vídeo.
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. Método getTrackById(): retorna o objeto track com o ID especificado.
- Se nenhum parâmetro for fornecido ou o valor do ID não corresponder, null será retornado; se houver várias faixas com o mesmo ID, o método retornará a primeira faixa correspondente.
const track = MediaStream.getTrackById(id);
参数:id,类型为字符串。
返回值:如果输入参数id与MediaStreamTrack.id匹配,则返回相应的MediaStream-Track对象,否则返回null。
- Exemplo: obtenha a faixa de mídia com o ID especificado e aplique restrições para ajustar o volume para 0,5.
stream.getTrackById("primary-audio-track").applyConstraints({
volume: 0.5 });
6. Método getTracks(): retorna um array de todos os objetos de trilha de mídia, incluindo todas as trilhas de vídeo e áudio.
- A ordem dos objetos no array é indeterminada e pode variar de chamada para chamada.
const mediaStreamTracks = mediaStream.getTracks()
参数:无。
返回值:媒体轨道对象数组。
- Use o método getUserMedia() para obter o fluxo que contém a faixa de vídeo. Se a chamada for bem-sucedida, anexe o fluxo ao
video
elemento < >, defina o cronômetro, obtenha todas as faixas de mídia após 5 segundos e pare de reproduzir a primeira faixa de mídia (ou seja, a faixa de vídeo).
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. Evento MediaStream
1. evento addtrack: Este evento é acionado quando uma nova faixa de mídia (MediaStreamTrack) é adicionada, correspondendo ao manipulador de eventos onaddtrack
- Observe que esse evento só será acionado nas seguintes condições e não será acionado se o método MediaStream.addTrack() for chamado ativamente.
- Renegociação de RTCPeerConnection.
- HTMLMediaElement.captureStream() retorna uma nova faixa de mídia.
- Exemplo: quando uma nova faixa de mídia é adicionada ao fluxo de mídia, exiba o tipo e o rótulo da nova faixa de mídia.
// 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);
};
- Além disso, você também pode usar o método addEventListener() para ouvir o evento addtrack.
2. evento removetrack: Este evento é acionado quando uma faixa de mídia é removida, correspondendo ao manipulador de eventos onremovetrack
- Observe que esse evento só será acionado nas seguintes situações e não será acionado se o método MediaStream.removeTrack() for chamado ativamente.
- Renegociação de RTCPeerConnection.
- HTMLMediaElement.captureStream() retorna uma nova faixa de mídia.
- Exemplo: Quando uma faixa de mídia é excluída de um fluxo de mídia, registre as informações da faixa de mídia.
// 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);
};
- Além disso, você também pode usar o método addEventListener() para ouvir o evento removetrack.
4. Restrições de parâmetros
-
restrições, como um objeto MediaStreamConstraints, especifica o tipo de mídia solicitado e os parâmetros correspondentes.
-
O parâmetro constraints é um objeto MediaStreamConstraints que contém dois membros, vídeo e áudio, para descrever o tipo de mídia solicitado.
- Pelo menos um tipo ou ambos devem ser especificados.
- Se o navegador não conseguir encontrar o tipo de mídia especificado ou não atender aos requisitos de parâmetro correspondentes, o objeto Promise retornado estará no estado rejeitado [com falha] e NotFoundError será usado como o parâmetro do retorno de chamada rejeitado [com falha].
-
O seguinte solicita áudio e vídeo sem nenhum parâmetro:
{
audio: true, video: true }
-
Se true for definido para um determinado tipo de mídia, o fluxo resultante precisará ter esse tipo de faixa. Se um deles não puder ser obtido por algum motivo, getUserMedia() gerará um erro.
-
Quando as informações da câmera e do microfone do usuário não podem ser acessadas por motivos de proteção de privacidade, o aplicativo pode usar o parâmetro de restrições adicionais para solicitar os recursos de câmera e microfone de que precisa ou deseja.
-
O seguinte demonstra que o aplicativo deseja usar uma resolução de câmera de 1280x720:
{
audio: true,
video: {
width: 1280, height: 720 }
}
- O navegador tentará atender a esse parâmetro de solicitação, mas se não puder atender com precisão aos requisitos de parâmetro nessa solicitação ou se o usuário optar por substituir o parâmetro na solicitação, ele poderá retornar outras resoluções.
- Ao forçar um tamanho específico, você pode usar as palavras-chave min, max ou exact (isto é, min == max).
- Os seguintes parâmetros indicam que é necessária uma resolução mínima de 1280x720.
{
audio: true,
video: {
width: {
min: 1280 },
height: {
min: 720 }
}
}
- Se a câmera não suportar a resolução solicitada ou superior, o Promise retornado estará em estado rejeitado, NotFoundError será passado como parâmetro do retorno de chamada rejeitado e a autorização do usuário não será solicitada.
- A razão para o desempenho diferente é que, em comparação com o valor de solicitação simples e a palavra-chave ideal, as palavras-chave min, max e exact têm coercividade intrínseca, como:
{
audio: true,
video: {
width: {
min: 1024, ideal: 1280, max: 1920 },
height: {
min: 776, ideal: 720, max: 1080 }
}
}
- Quando a requisição contém um valor ideal, este valor tem um peso maior, ou seja, o navegador tentará primeiro encontrar a configuração ou câmera (caso o dispositivo possua mais de uma câmera) que esteja mais próximo do valor ideal especificado.
- Um simples valor de requisição também pode ser entendido como um valor ideal para a aplicação, então nossa primeira requisição para especificar uma resolução também pode ser escrita da seguinte forma:
{
audio: true,
video: {
width: {
ideal: 1280 },
height: {
ideal: 720 }
}
}
- Nem todas as restrições são números. Por exemplo, em um dispositivo móvel, o exemplo a seguir indica que a câmera frontal deve ser usada primeiro (se disponível):
{
audio: true, video: {
facingMode: "user" } }
- Para forçar o uso da câmera traseira, use:
{
audio: true, video: {
facingMode: {
exact: "environment" } } }
- Em alguns casos, como ao usar um transporte de largura de banda limitada em WebRTC, uma taxa de quadros baixa pode ser mais apropriada.
{
video: {
frameRate: {
ideal: 10, max: 15 } } };
5. Valor de retorno
var promise = navigator.mediaDevices.getUserMedia(constraints);
- Retorna um Promise, a função de retorno de chamada quando o Promise é bem-sucedido usa um objeto MediaStream como seu parâmetro.
6. Outliers
- Retorna um Promise em um estado de falha e a função de retorno de chamada após a falha do Promise usa um objeto DOMException como seu parâmetro. As possíveis exceções são:
- AbortError [erro de cancelamento]
- Embora o usuário e o sistema operacional tenham concedido acesso ao hardware do dispositivo e não haja problemas de hardware que gerem uma exceção NotReadableError, ainda existem alguns problemas que tornam o dispositivo inutilizável.
- NotAllowedError [erro negado]
- O usuário nega a solicitação de acesso da instância atual do navegador; ou o usuário nega o acesso da sessão atual; ou o usuário nega todas as solicitações de acesso à mídia globalmente.
- Versões mais antigas da especificação usavam SecurityError, mas SecurityError recebeu um novo significado em versões mais recentes.
- NotFoundError [Erro não encontrado]
- Não foi possível encontrar um tipo de mídia que satisfaça os parâmetros solicitados.
- NotReadableError[Não foi possível ler o erro]
- Embora o usuário tenha autorizado o uso do dispositivo correspondente, um erro de hardware, navegador ou nível da web no sistema operacional impede o acesso ao dispositivo.
- OverconstainedError[Erro de não atender aos requisitos]
- O requisito especificado não pode ser atendido pelo dispositivo. Essa exceção é um objeto do tipo OverconstainedError, que possui um atributo de restrição, que contém o objeto de restrição que não pode ser satisfeito no momento, e um atributo de mensagem, que contém uma string de fácil leitura para Explique a situação.
- NotFoundError [Erro não encontrado]
- Não foi possível encontrar um tipo de mídia que satisfaça os parâmetros solicitados.
- NotReadableError[Não foi possível ler o erro]
- Embora o usuário tenha autorizado o uso do dispositivo correspondente, um erro de hardware, navegador ou nível da web no sistema operacional impede o acesso ao dispositivo.
- OverconstainedError[Erro de não atender aos requisitos]
- O requisito especificado não pode ser atendido pelo dispositivo. Essa exceção é um objeto do tipo OverconstainedError, que possui um atributo de restrição, que contém o objeto de restrição que não pode ser satisfeito no momento, e um atributo de mensagem, que contém uma string de fácil leitura para Explique a situação.
- SecurityError [Erro de segurança]
- O uso de mídia do dispositivo está desabilitado no documento no qual getUserMedia() é chamado. A ativação ou desativação desse mecanismo depende das preferências individuais do usuário.
- TypeError [erro de tipo]
- O objeto de restrições não está definido como [nulo] ou ambos estão definidos como false.