我正在实施getUserMedia()
来录制音频消息。我想录制音频,然后使用websocket将其传递给另一个对等方。我如何做到这一点?我在SO上进行了搜索,但只发现了一个有趣的问题,但没有什么可以指导我找到可行的解决方案。我正在为应用程序的websocket部分使用Pusher API。
这是我正在测试的代码。
$(document).on("click", ".audio-chat",function(){
console.log('clicked');
var channel = $('input[name="channelName"]').val();
navigator.mediaDevices.getUserMedia({
audio: true
})
.then(function(stream){
var mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start();
console.log(mediaRecorder.state);
console.log("recorder started");
mediaRecorder.ondataavailable = function(e) {
chunks.push(e.data);
console.log(chunks);
}
setTimeout(function(){
mediaRecorder.stop();
console.log(mediaRecorder.state);
console.log("recorder stopped");
var blob = new Blob(chunks, {'type':'audio/webm; codecs=opus'});
//console.log(blob);
chunks = [];
const audioUrl = window.URL.createObjectURL(blob);
var data = {channel:channel,message:audioUrl,socketId:socketId}
$.post('api/message.php', data);
}, 10000);
});
});
答案 0 :(得分:1)
而不是依靠Blob / CreateObjectURL,而是像https://github.com/Ivan-Feofanov/ws-audio-api那样,依靠arrayBuffer进行二进制传输。
您还需要一个编码器和一个_resampler。
要查看的相关代码
https://github.com/Ivan-Feofanov/ws-audio-api/blob/master/src/ws-audio-api.js
Streamer: function(config, socket) {
navigator.getUserMedia = (navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
this.config = {};
this.config.codec = this.config.codec || defaultConfig.codec;
this.config.server = this.config.server || defaultConfig.server;
this.sampler = new Resampler(44100, this.config.codec.sampleRate, 1, this.config.codec.bufferSize);
this.parentSocket = socket;
this.encoder = new OpusEncoder(this.config.codec.sampleRate, this.config.codec.channels, this.config.codec.app, this.config.codec.frameDuration);
var _this = this;
this._makeStream = function(onError) {
navigator.getUserMedia({ audio: true }, function(stream) {
_this.stream = stream;
_this.audioInput = audioContext.createMediaStreamSource(stream);
_this.gainNode = audioContext.createGain();
_this.recorder = audioContext.createScriptProcessor(_this.config.codec.bufferSize, 1, 1);
_this.recorder.onaudioprocess = function(e) {
var resampled = _this.sampler.resampler(e.inputBuffer.getChannelData(0));
var packets = _this.encoder.encode_float(resampled);
for (var i = 0; i < packets.length; i++) {
if (_this.socket.readyState == 1) _this.socket.send(packets[i]);
}
};
_this.audioInput.connect(_this.gainNode);
_this.gainNode.connect(_this.recorder);
_this.recorder.connect(audioContext.destination);
}, onError || _this.onError);
}
}
流媒体开始
WSAudioAPI.Streamer.prototype.start = function(onError) {
var _this = this;
if (!this.parentSocket) {
this.socket = new WebSocket('wss://' + this.config.server.host + ':' + this.config.server.port);
} else {
this.socket = this.parentSocket;
}
this.socket.binaryType = 'arraybuffer';
if (this.socket.readyState == WebSocket.OPEN) {
this._makeStream(onError);
} else if (this.socket.readyState == WebSocket.CONNECTING) {
var _onopen = this.socket.onopen;
this.socket.onopen = function() {
if (_onopen) {
_onopen();
}
_this._makeStream(onError);
}
} else {
console.error('Socket is in CLOSED state');
}
var _onclose = this.socket.onclose;
this.socket.onclose = function() {
if (_onclose) {
_onclose();
}
if (_this.audioInput) {
_this.audioInput.disconnect();
_this.audioInput = null;
}
if (_this.gainNode) {
_this.gainNode.disconnect();
_this.gainNode = null;
}
if (_this.recorder) {
_this.recorder.disconnect();
_this.recorder = null;
}
_this.stream.getTracks()[0].stop();
console.log('Disconnected from server');
};
};
播放器
WSAudioAPI.Player.prototype.start = function() {
var _this = this;
this.audioQueue = {
buffer: new Float32Array(0),
write: function(newAudio) {
var currentQLength = this.buffer.length;
newAudio = _this.sampler.resampler(newAudio);
var newBuffer = new Float32Array(currentQLength + newAudio.length);
newBuffer.set(this.buffer, 0);
newBuffer.set(newAudio, currentQLength);
this.buffer = newBuffer;
},
read: function(nSamples) {
var samplesToPlay = this.buffer.subarray(0, nSamples);
this.buffer = this.buffer.subarray(nSamples, this.buffer.length);
return samplesToPlay;
},
length: function() {
return this.buffer.length;
}
};
this.scriptNode = audioContext.createScriptProcessor(this.config.codec.bufferSize, 1, 1);
this.scriptNode.onaudioprocess = function(e) {
if (_this.audioQueue.length()) {
e.outputBuffer.getChannelData(0).set(_this.audioQueue.read(_this.config.codec.bufferSize));
} else {
e.outputBuffer.getChannelData(0).set(_this.silence);
}
};
this.gainNode = audioContext.createGain();
this.scriptNode.connect(this.gainNode);
this.gainNode.connect(audioContext.destination);
if (!this.parentSocket) {
this.socket = new WebSocket('wss://' + this.config.server.host + ':' + this.config.server.port);
} else {
this.socket = this.parentSocket;
}
//this.socket.onopen = function () {
// console.log('Connected to server ' + _this.config.server.host + ' as listener');
//};
var _onmessage = this.parentOnmessage = this.socket.onmessage;
this.socket.onmessage = function(message) {
if (_onmessage) {
_onmessage(message);
}
if (message.data instanceof Blob) {
var reader = new FileReader();
reader.onload = function() {
_this.audioQueue.write(_this.decoder.decode_float(reader.result));
};
reader.readAsArrayBuffer(message.data);
}
};
//this.socket.onclose = function () {
// console.log('Connection to server closed');
//};
//this.socket.onerror = function (err) {
// console.log('Getting audio data error:', err);
//};
};
答案 1 :(得分:1)
二进制数据远比JSON更有效,我不建议您采用这种方式
答案 2 :(得分:0)
您可以使用棘轮 php websocket
或者如果你想使用 laravel 框架,你可以使用带有 Echo 的 laravel websockets