我正在参加跨端技术专题征文活动,详情查看:juejin.cn/post/710123…
前两天看到了一篇写如何在uni-app项目中使用微软智能文字转语音服务,所以作为曾经在微软的项目组中实现过一套SDK的,想要讲一讲微软智能文字转语音服务的实现方案的细节。其实为什么微软的智能语音服务能在各端实现录音、播放而不需要其他的权限呢?其实问题就在与window对。曾经尝试在小程序中使用智能语音的时候,我一直以为是需要通过微信的授权系统才能进行录音和播放。但是在做调研的时候发现,能真正绕过或者并不是真的需要微信一系列授权的操作。
为什么各端能实现录音、播放功能
这个问题在于使用的方案,或者调用的方案。推荐使用iframe(web-view)嵌入,因为在小程序端、或者通过App壳运行H5页面的项目中,每一个iframe(web-view)都会有一个window对象,而现在的window对象都能直接调用设备的AudioRecord/AudioPlay。
window中的mediaDevices对象
MediaDevices 接口是由window提供的对象以访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。它可以使你取得任何硬件资源的媒体数据。
废话不多说,直接上代码:
// 用作承接录音收到的字节流
let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// createBufferSource()方法用于创建一个新的AudioBufferSourceNode接口,该接口可以通过AudioBuffer对象来播放音频数据
let source = audioCtx.createBufferSource();
// 为安全起见,最好先判断是否支持调用音视频设备,navigator.mediaDevices是window提供的只读属性,返回一个MeidiaDevices对象,该对象可提供对相机和麦克风等媒体输入设备的连接访问,也包括屏幕共享。
if (navigator.mediaDevices) {
console.log('getUserMedia supported.');
// constraints对象设置获取哪些权限
// 可以通过此设置,增加相机的权限:{ audio: true, video: true }
// 可以通过此设置,设置相机的分辨率:{ audio: true, video: { width: 1280, height: 720 } }
var constraints = {audio: true};
// 保存字节流
var chunks = [];
// getUserMedia方法通过constraints对象调用对应的设备权限,返回包含字节流的promise对象
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
// MediaRecorder是调用audio设备进行录音的接口,需要通过实例化后使用
mediaRecorder = new MediaRecorder(stream);
// 当结束录制之后的回调方法
mediaRecorder.onstop = function(e) {
console.log("data available after MediaRecorder.stop() called.");
var clipName = prompt('Enter a name for your sound clip');
var soundClips = document.getElementById('soundClips');
var clipContainer = document.createElement('article');
var clipLabel = document.createElement('p');
var audio = document.createElement('audio');
var deleteButton = document.createElement('button');
clipContainer.classList.add('clip');
audio.setAttribute('controls', '');
deleteButton.innerHTML = "Delete";
clipLabel.innerHTML = clipName;
clipContainer.appendChild(audio);
clipContainer.appendChild(clipLabel);
clipContainer.appendChild(deleteButton);
soundClips.appendChild(clipContainer);
// source = audioCtx.createMediaStreamSource(stream);
var blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
chunks = [];
var audioURL = URL.createObjectURL(blob);
audio.src = audioURL;
deleteButton.onclick = function(e) {
evtTgt = e.target;
evtTgt.parentNode.parentNode.removeChild(evtTgt.parentNode);
}
}
mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data);
}
})
.catch(function(err) {
console.log('The following error occurred: ' + err);
})
}
MDN中关于constraints对象的详细设置 MDN中关于MediaRecorder接口的详细介绍
通过window中的AudioContext对象播放语音
上面已经说了如何进行录音,保存,但是并没有说明如何播放语音,下面就是播放语音的方法
// 创建二阶滤波器
var biquadFilter = audioCtx.createBiquadFilter();
// 定义字节流的解析算法
biquadFilter.type = "lowshelf";
// 定义滤波算法的频率
biquadFilter.frequency.value = 1000;
// 定义滤波算法的资源
biquadFilter.gain.value = chunks[0];
// 把AudioBufferSourceNode连接到gainNode
// gainNode连接到目的地, 所以我们可以播放
// 音乐并用鼠标调节音量
source.connect(biquadFilter);
biquadFilter.connect(audioCtx.destination);