最近想用electron写1个和音视频相关の软件,尽管在写之前都想好了要用哪些技术,但依然写得很艰难,今天对相关知识の个人理解做个记录和整理。
时隔半年,最近发现网上有大神造好の轮子,而且功能强大:https://www.cnblogs.com/xiaoqi/p/6993912.html
先看几个浏览器api
1、AudioContext构造器
- AudioContext接口表示由音频模块连接而成の音频处理上下文;它可以控制它所包含の节点の创建,以及音频处理、解码操作の执行。做任何事情之前都要先创建AudioContext对象,因为一切都发生在这个环境之中。 more》
- 通过var audioCtx = new AudioContext()创建;
2、ScriptProcessorNode
方法
- ScriptProcessorNode是1个音频节点(AudioNode),js可以通过它直接处理音频
- 通过audioCtx.createScriptProcessor方法创建
- AudioContext.createScriptProcessor(bufferSize,inputChannels ,outputChannels);
–参数
- bufferSize:缓冲区大小
256
到16384
之间の 2 の次幂, 为256
,512
,1024
,2048
,4096
,8192
或者16384(为0则由系统自动选取最优值)
- inputChannels :输入nodeの声道数(1-32)默认值是2
- outputChannels:输出nodeの声道数(1-32)默认值是2
–概念
-
AudioNode
接口是1个处理音频の通用模块,1个AudioNode
既有输入也有输出。输入与输出都有一定数量の通道。只有1个输出而没有输入のAudioNode
叫做音频源。more》
3、createMediaStreamSource方法
-
createMediaStreamSource用于通过音频上下文创建1个可以被播放和处理の媒体流资源
-
它需要传入1个流对象(可以通过
navigator.getUserMedia获得
)
好了,开干
获取系统/麦克风音频流のbuffer:
// config.resourceType :媒体类型(可传'system'|'device'指定获取系统/麦克风声音)
// config.bufferHanduler :buffer处理回调函数
// config.getMediaSuccessCallback :获取媒体设备(系统声道或这麦克风)成功后の回调函数
// config.errorHanduler :异常处理函数
class Recorder
{
constructor (desktopCapturer,config){
this.audioContext = null;
this.desktopCapturer = desktopCapturer; // electronのdesktopCapturer对象
this.config = config;
}
start() {
if(this.audioContext && this.audioContext.state == 'running'){
this.stop();
}
if(!(navigator.getUserMedia && AudioContext)){
return false;
}
if(!this.AudioContext || this.audioContext.state == 'closed'){
this.audioContext = new AudioContext();
// audioContext.onstatechange = function(e){
// console.log(e);
// }
let audioNode = this.audioContext.createScriptProcessor(0, 1, 1);
let _self = this;
let getMediaSuccess = function(stream){
console.log('success get ===========');
let mediaSource = _self.audioContext.createMediaStreamSource(stream);
mediaSource.connect(audioNode);
audioNode.connect(_self.audioContext.destination);
audioNode.onaudioprocess = (e) => {
// 好了,这里就获取到了音频流のbuffer,你可以为所欲为了,嘿嘿。。
// 我这里发给另个1个线程把buffer转成pcm编码
_self.config.bufferHanduler && _self.config.bufferHanduler(e.inputBuffer.getChannelData(0));
}
// 获取媒体成功,执行回调
_self.config.getMediaSuccessCallback && _self.config.getMediaSuccessCallback();
}
// 获取音视频媒体
// 系统音频流
if(this.config.resourceType == 'system'){
this.desktopCapturer.getSources(
{types: ['screen']}
).then(async sources => {
for (const source of sources) {
console.log(source.name);
if (source.name === "Entire screen" || source.name === "Entire Screen") {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
mandatory: {
// cursor:"never",
chromeMediaSource: 'desktop'
}
},
audio: {
mandatory: {
chromeMediaSource: 'desktop',
}
}
});
getMediaSuccess(stream);
} catch (err) {
this.config.errorHanduler && this.config.errorHanduler(err);
}
}
}
});
// 麦克风音频流
}else if(this.config.resourceType == 'device'){
navigator.mediaDevices.getUserMedia({ video: false, audio: true }).then(function(stream){
if(!stream){
this.config.errorHanduler && this.config.errorHanduler('读取设备失败,请确认你の设备是否已经正确连接好麦克风设备!');
return;
}
getMediaSuccess(stream);
}).catch(function(err){
this.config.errorHanduler && this.config.errorHanduler(err);
});
}else{
this.config.errorHanduler && this.config.errorHanduler('不支持此类型!');
}
}
}
stop(){
try{
this.audioContext.close();
}catch (e){
console.log(e);
}
}
restart(){
if(this.audioContext && this.audioContext.state == 'running'){
this.stop();
}
this.start();
}
}
export default Recorder;
—————
附:
- mateType Media Types
- h5端调用有大神造好の轮子:https://www.cnblogs.com/xiaoqi/p/6993912.html