webrtc 入门第一章 基本设备操作

一、介绍

1、webrtc是什么

webrtc是一个由google发起的开源实时通信方案,其中包括视频/音频采集、编解码、数据传输、音视频展示的功能。在浏览器,桌面应用,移动设备或者lot设备上都有可以运行的api接口,均可实现实时通信能力。web开发者可以基于web api开发基于视频、音频的实时通信应用,如视频会议,远程教育,视频通话,视频直播,游戏直播,远程协助,互动游戏,实时人脸识别等功能。

2、优点是什么

webrtc主要应用在实时通信方面,其优点总结为如下几点。

1、跨平台:可以在Web,Android,iOS,Windows,MacOS、Linux等环境下运行

2、实时传输:传输速度快,低延迟,适合实时性要求较高的场景

3、音视频引擎:有强大的音视频处理能力

4、免插件:不需要安装任何插件,兼容性高,打开浏览器即可使用,并且免费开源

5、强大的打洞能力:webrtc技术包含了使用STUN、ICE、TURN、RTP-over-TCP的关键NAT和防火墙穿透技术

本次将通过webrtc实现一对一视频对话的功能,首先要进行本地媒体资源的操作

二、实践

1、打开摄像头
<body>
  <input type="button" title="开启摄像头" value="开启前置摄像头" v-on:click="getMedia(0)"/>
  <input type="button" title="开启摄像头" value="开启后置摄像头" v-on:click="getMedia(1)"/>
   <video height="120px" autoplay="autoplay" :src="video_1_url" crossOrigin="anonymous" muted="muted" controls></video>
    <hr/>
 </body>
  <script src="/static/js/Vue.2.5.3.js"></script>
<script type="text/javascript"> 
 // 兼容版本
  navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
    window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
getMedia: function (a) {
    let that = this;
    if (that.exArray.length <= a) {
        alert("设备不存在")
        return
    }


    if (navigator.getUserMedia) {
    	// 获取用户媒体数据,
        navigator.getUserMedia({
            'video': {
                'optional': [{
                    'sourceId': that.exArray[a] //0为前置摄像头,1为后置
                }]
            },
            'audio': true // 不需要音频的话为false
        }, that.successFunc, that.errorFunc); //success是获取成功的回调函数,也可以使用await来处理异步
    } else {
        alert('Native device media streaming (getUserMedia) not supported in this browser.');
    }
},
        // 摄像头加载成功
            successFunc: function (stream) {
                if (this.video.mozSrcObject !== undefined) {
                    //Firefox中,video.mozSrcObject最初为null,而不是未定义的,我们可以靠这个来检测Firefox的支持
                    this.video.mozSrcObject = stream;
                } else {
                	// 将流媒体复制给video标签进行播放 
                    this.video.srcObject = stream 
                }
                this.stream = stream


                // 获取track  视频轨道
                let deviceInfo = stream.getVideoTracks()
                let tracks = deviceInfo[0]
                // 可以对轨道进行操作
                console.log(tracks.getConstraints())
                this.deviceName = deviceInfo[0].label
                this.video.play();


                // 音频
                this.audio = new Audio();
                this.audioType = this.getAudioType(this.audio);
                if (this.audioType) {
                    this.audio.src = 'polaroid.' + this.audioType;
                    this.audio.play();
                }
            }
             loadDevice: function () {
                let that = this;

                navigator.mediaDevices.enumerateDevices()
                    .then(function (sourceInfos) {
                            // 获取设备列表
                            console.log(sourceInfos)
                            for (let i = 0; i != sourceInfos.length; ++i) {
                                let sourceInfo = sourceInfos[i];
                                //这里会遍历audio,video,所以要加以区分
                                if (sourceInfo.kind === 'videoinput') {
                                    that.exArray.push(sourceInfo.deviceId);
                                }
                            }
                        }
                    ).catch(function (err) {
                    alert("获取设备列表错误")
                });
            },
            
<script type="text/javascript">

本次只展示部分重要代码,部分代码可以自行补充,打开摄像头流程如下

1先使用getUserMedia 约束条件获取到媒体, 其中 ‘audio’: true 表示获取视频,video:turn 表示获取声音

2.使用navigator.mediaDevices.enumerateDevices 方法获取到设备

3.获取到媒体资源后使用video标签进行播放

4.在媒体流中通过getVideoTracks 方法可以获取到当前流媒体的轨道即正在使用的设备。
在这里插入图片描述

2、打开麦克风
<body>
	<input type="button" value="开启麦克风" v-on:click="checkVoice()"/>
</body>
<script type="text/javascript">
    // 开启声音
  checkVoice: function () {
      
      
                if (navigator.getUserMedia) {
      
      
                    window.audioContext = new AudioContext()
                    navigator.getUserMedia({
      
      
                        'video': false,
                        'audio': true
                    }, this.onVoice, this.errorFunc); //success是获取成功的回调函数
                } else {
      
      
                    alert('Native device media streaming (getUserMedia) not supported in this browser.');
                }

            },
  // 获取到媒体声音后 音量展示 stream表示流媒体              
  onVoice: function (stream) {
      
            
                let that = this;
       			//创建一个管理、播放声音的对象
                let audioContext = new AudioContext()
                let analyser = audioContext.createAnalyser()
                liveSource = audioContext.createMediaStreamSource(stream); //将麦克风的声音输入这个对象\
                // 音频连入分析器
                liveSource.connect(analyser)
                // 分析器再将音频连入麦克风-这样播放的音频就会通过分析器
                analyser.connect(audioContext.destination)

                analyser.fftSize = 128


                setInterval(() => {
      
      
                    let dataArray = new Uint8Array(analyser.frequencyBinCount)
                    analyser.getByteFrequencyData(dataArray)
                    // console.log(dataArray)
                    let maxVal = 0;
                    for (let i = 0; i < dataArray.length; i++) {
      
      
                        if (maxVal < dataArray[i]) {
      
      
                            maxVal = dataArray[i];
                        }
                    }
                    that.voiceWidth = Math.round(maxVal) + "px"
                    that.drow(dataArray)
                }, 50)
            },
                // 画图案
            drow: function (array) {
      
      
                var canvas = document.getElementById('canvas3'),
                    cwidth = canvas.width,
                    cheight = canvas.height - 2,
                    meterWidth = 10, //能量条的宽度
                    gap = 2, //能量条间的间距
                    capHeight = 2,
                    meterNum = 800 / (10 + 2), //计算当前画布上能画多少条
                    ctx = canvas.getContext('2d')
                var step = Math.round(array.length / meterNum);
                ctx.clearRect(0, 0, cwidth, cheight); //清理画布准备画画
                gradient = ctx.createLinearGradient(0, 0, 0, 300);
                gradient.addColorStop(1, '#0f0');
                gradient.addColorStop(0.5, '#ff0');
                gradient.addColorStop(0, '#f00');
                ctx.fillStyle = gradient;
                for (var i = 0; i < meterNum; i++) {
      
      
                    var value = array[i * step];
                    ctx.fillRect(i * 12, cheight - value + capHeight, meterWidth, cheight);
                }
            },
</script>

和打开视频流程一样,

1.同样使用getUserMedia()方法 约束条件’audio’: true , 即可请求麦克风。

2.当获取到音频流后传递给audio对象的srcObject方法即可。

3.音频可视化,audioContext 方法可以创建一个音频分析器,将音频流载入后就能展示音频的大小

在这里插入图片描述

3、截屏及下载图片
<body>
	<input type="button" title="截屏" value="截屏" v-on:click="getPhoto()"/><br/>
	<canvas id="canvas1" height="120px"></canvas>
</body>
<script>
    
         getPhoto: function () {
      
      
             	// 创建canvas画布
                 this.canvas1 = document.getElementById('canvas1');
            this.context1 = this.canvas1.getContext('2d');
                //将video对象内指定的区域捕捉绘制到画布上指定的区域,实现拍照。
                this.context1.drawImage(this.video, 0, 0, 90, 120);
             
             
             	// 转图片下载
                // 抓取照片数据
                let imgData = this.canvas1.toDataURL(); //将图像转换为base64数据
                let base64Data = imgData.substr(22); //在前端截取22位之后的字符串作为图像数据

          
                imgData = imgData.replace(this.changeImageType("png"), 'image/octet-stream');
                let save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
                save_link.href = imgData;
                save_link.download = (new Date()).getTime() + '.' + "png";

                let event = document.createEvent('MouseEvents');
                event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                save_link.dispatchEvent(event);
            }
    		// 修改图片类型操作
            changeImageType: function (type) {
      
      
                type = type.toLowerCase().replace(/jpg/i, 'jpeg');
                let r = type.match(/png|jpeg|bmp|gif/)[0];
                return 'image/' + r;
            },
      
</script>

在摄像头正常可以播放的时候,可以使用canvas进行图像捕捉

1.使用媒体约束条件,调用getUserMedia()方法,实现摄像头播放正常

2.获取到媒体流时,传递给video的srcObject对象进行播放

3.创建canvas 标签,调用canvas的drawImage 方法,传递video对象可以生成一张2d图片。

4.将canvas 图转换格式实现本地下载

4.视频同步与
<body>
    <input type="button" title="视频" value="视频" v-on:click="getVideo()"/><br/>
	<canvas id="canvas2" height="120px"></canvas>
</body>
<script>
			//视频
           getVideo: function () {
      
      
                this.canvas2 = document.getElementById('canvas2');
            	this.context2 = this.canvas2.getContext('2d');
                this.drawVideoAtCanvas(this.video, this.context2);
            },
             // 将视频帧绘制到Canvas对象上,Canvas每60ms切换帧,形成肉眼视频效果
            drawVideoAtCanvas: function (video, context) {
      
      
                window.setInterval(function () {
      
      
                    context.drawImage(video, 0, 0, 90, 120);
                }, 60);
            },
</script>

在摄像头正常可以播放的时候,可以使用canvas进行图像捕捉

1.使用媒体约束条件,调用getUserMedia()方法,实现摄像头播放正常

2.获取到媒体流时,传递给video的srcObject对象进行播放

3.将video的视频源载入canvas ,实现图案绘制,最后每隔60毫秒,绘制一张图片实现视频的同步

三、总结

1.访问相关设备API

方法名 参数 说明
getUserMedia 定义约束对象,是否调用音频或者视频 采集摄像头或者麦克风设备
getDisplayMedia 定义约束对象,设置视频采集宽高,是否调用视频 捕获计算机屏幕的方法(本章未用到)
MediaStreamConstanints video,audio 调用getUserMedia和getDisplayMedia方法的约束条件,ture表示采集,false表示不采集

2.在本章学习使用媒体设备的基本操作,首先我们要解决的兼容性,因为不同的浏览器的不同版本对webrtc的兼容性不同,因此在使用前首先要解决兼容性。

3.再次我们学回了如何访问媒体设备,使用设置约束调剂调用音频或者视频流。

4.最后我们将媒体流以不同的形式进行了展示,做到了可视化。每一步都很有意思

5.在使用webrtc的时候需要我们部署https服务访问,否则可能会因为安全问题而操作失败
6.当然在后面还有一些分享桌面,捕捉等操作没在本次示例中演示。具体可以查看代码仓库。

四、感谢

感谢作者 亢少军老师的 《WebRTC音视频开发 》 课本指导

猜你喜欢

转载自blog.csdn.net/weixin_42547619/article/details/123106757