原创

MediaDevices.getUserMedia()实现WebRTC简单的视频音频采集输出到本地

MediaDevices.getUserMedia()
https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia

使用谷歌adapter.js适配浏览器
https://webrtc.github.io/adapter/adapter-latest.js

兼容获取navigator.getUserMedia属性

navigator.getUserMedia =  navigator.mediaDevices.getUserMedia || 
    navigator.getUserMedia ||
    navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia ||
    navigator.msGetUserMedia;

MediaTrackConstraints参数属性
https://developer.mozilla.org/zh-CN/docs/Web/API/MediaTrackConstraints

  • Properties of video tracks
参数 含义 取值示例
groupId 分组ID string
deviceId 获取设备ID string
with 宽度 long(640)
height 高度 long(480)
aspectRatio 长宽比 double(1.1)
frameTate 帧率 double(30)
facingMode 摄像头 string(user:前置,environment:后置,left:前置左侧,right:前置右侧)
resizeMode 调整视频大小 string(none:无,crop-and-scale:裁剪)
  • Properties of audio tracks
参数 含义 取值示例
groupId 分组ID string
deviceId 获取设备ID string
volume 音量 double(取值0~1.0)
sampleRate 采样率 long(59)
sampleSize 采样大小 long(59)
echoCancellation 回声消除 bool(true|false)
autoGainControl 自动增益控制 bool(true|false)
noiseSuppression 噪声抑制 bool(true|false)
latency 延迟大小(延迟大的话直播比较好,延迟小的话实时通讯比较好) double
channelCount 声道 1 用于单声道声音,2用于立体声...

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebRTC</title>
    <style>
        .none {
            -webkit-filter: none;
        }

        .blur {
            -webkit-filter: blur(3px);
        }

        .grayscale {
            -webkit-filter: grayscale(1);
        }

        .invert {
            -webkit-filter: invert(1);
        }

        .sepia {
            -webkit-filter: sepia(1);
        }

        .saturate {
            -webkit-filter: saturate(1);
        }

        .hue-rotate {
            -webkit-filter: hue-rotate(90deg);
        }

        .opacity {
            -webkit-filter: opacity(0.8);
        }

        .brightness {
            -webkit-filter: brightness(0.8);
        }

        .contrast {
            -webkit-filter: contrast(0.8);
        }

        .drop-shadow {
            -webkit-filter: drop-shadow(5px 5px 10px black);
        }
    </style>
</head>
<body>
<div>
    <label>audioInput:</label>
    <select id="audioInput"></select>
</div>
<div>
    <label>audioOutput:</label>
    <select id="audioOutput"></select>
</div>
<div>
    <label>videoInput:</label>
    <select id="videoInput"></select>
</div>
<div>
    <label>other:</label>
    <select id="other"></select>
</div>
<div>
    <label>Filter特效:</label>
    <select id="filter">
        <option value="none">无</option>
        <option value="grayscale">灰度</option>
        <option value="sepia">褐色</option>
        <option value="saturate">饱和度</option>
        <option value="hue-rotate">色相旋转</option>
        <option value="invert">反色</option>
        <option value="opacity">透明度</option>
        <option value="brightness">亮度</option>
        <option value="contrast">对比度</option>
        <option value="blur">模糊</option>
        <option value="drop-shadow">阴影</option>
    </select>
</div>
<div>
    <audio hidden id="audio"></audio>
    <table>
        <tr>
            <td><video autoplay playsinline id="player"></video></td>
            <td>
                <div id="constraints" class="output"></div>
            </td>
        </tr>
    </table>
</div>
<div>
    <button id="snapshot">快照</button>
</div>
<div>
    <canvas width="640" height="480" id="photo"></canvas>
</div>
</body>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="client.js" type="application/javascript"></script>
</html>

client.js

'use strict';

let videoPlay = document.querySelector('video#player');
let audio = document.querySelector('audio#audio');
let audioInput = document.querySelector('select#audioInput');
let videoInput = document.querySelector('select#videoInput');
let audioOutput = document.querySelector('select#audioOutput');
let other = document.querySelector('select#other');
let filter = document.querySelector('select#filter');
let snapshot = document.querySelector('button#snapshot');
let photo = document.querySelector('canvas#photo');
let divConstraints = document.querySelector('div#constraints');

navigator.getUserMedia = navigator.getUserMedia ||
    navigator.webkitGetUserMedia ||
    navigator.mozGetUserMedia ||
    navigator.msGetUserMedia ||
    navigator.mediaDevices.getUserMedia
;

function start() {
    if (navigator.getUserMedia) {
        // MediaTrackConstraints参数属性
        // https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints

        // 参数可以为范围 min~max
        let videoDeviceId = videoInput.value;
        let audioDeviceId = audioInput.value;
        const constraints = {
            // video: false,
            video: {
                // 获取设备ID
                deviceId: videoDeviceId ? videoDeviceId : undefined,
                // groupIp  获取分组ID
                width : {
                    min : 300,
                    max : 640
                },
                height : 480,
                // 长宽比
                // aspectRatio : 1.1,
                // 帧率
                frameRate : 30,
                // 摄像头
                //  user         前置
                //  environment  后置
                //  left         前置左侧
                //  right        前置右侧
                // facingMode : "user",
                // 调整视频大小
                //  none
                //  crop-and-scale
                resizeMode : "ideal"
            },
            audio: {
                deviceId: audioDeviceId ? videoDeviceId : undefined,
                // 音量          0~1.0
                volume: 0.8,
                // 采样率
                sampleRate: 59,
                // 采样大小
                sampleSize: 59,
                // 回声消除(true | false)
                echoCancellation: true,
                // 自动增益控制(true | false)
                autoGainControl: false,
                // 噪声抑制(true | false)
                noiseSuppression: true,
                // 延迟大小(延迟大的话直播比较好,延迟小的话实时通讯比较好)
                latency: 8000,
                // 声道
                //  1 用于单声道声音
                //  2用于立体声
                //  ...
                channelCount: 1
            }
        };
        navigator.getUserMedia(constraints, getStream, handleError);

    } else {
        window.alert("不支持");
    }
}


function getDevices(devicesInfos) {
    devicesInfos.forEach(function (deviceInfo) {
        let option = document.createElement('option');
        option.text = deviceInfo.label;
        option.value = deviceInfo.deviceId;
        console.log(deviceInfo);
        switch (deviceInfo.kind) {
            case "function":
            case "table":
            case "memory":
            case "global":
                other.appendChild(option);
                break;
            case "audiooutput":
                audioOutput.appendChild(option);
                break;
            case "videoinput":
                videoInput.appendChild(option);
                break;
            case "audioinput":
                audioInput.appendChild(option);
        }
    });

}

function getStream(stream) {
    window.stream = stream;
    let videoTrack = stream.getVideoTracks()[0];
    let videoConstraints = videoTrack.getSettings();
    divConstraints.textContent = JSON.stringify(videoConstraints, null, 2);
    if (window.URL) {
        // Chrome浏览器
        videoPlay.srcObject = stream;
        audio.srcObject = stream;
    } else {
        // Firefox和Opera: 可以直接把视频源设置为stream
        videoPlay.src = stream;
        audio.src = stream;
    }
    // 获取用户可用的设备类型和数量
    navigator.mediaDevices.enumerateDevices().then(getDevices);
}

function handleError(err) {
    console.log(err);
}

videoInput.onchange = start;
audioInput.onchange = start;
filter.onchange = function () {
    videoPlay.className = filter.value;
};
snapshot.onclick = function () {
    photo.className = filter.value;
    photo.getContext('2d').drawImage(videoPlay, 0, 0, photo.width, photo.height);
};
start();
正文到此结束
本文目录