I am streaming the audio from microphone using javascript and sending the audio stream from frontend to backend via websocket. In my websocket handle message i can see float array recieving from front end but as soon as i write the float array to a file it does contatin any audio. here is link of generated audio file.
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
// TODO Auto-generated method stub
byte [] bb =getByteArrayFromByteBuffer((ByteBuffer)message.getPayload());
System.out.println(Arrays.toString(bb));
FileUtils.writeByteArrayToFile(file,bb,true);
}
private static byte[] getByteArrayFromByteBuffer(ByteBuffer byteBuffer) {
byte[] bytesArray = new byte[byteBuffer.remaining()];
byteBuffer.get(bytesArray, 0, bytesArray.length);
return bytesArray;
}
below is javascript streaming code:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<button onclick="stop()">stop</button>
<script>
const AudioContext = window.AudioContext// Safari and old versions of Chrome
var context;
var source;
var bufferDetectorNode ;
jssocket= new WebSocket("ws://localhost:8080/websocket/name?user_id="+ generateRandomInteger(0, 3));
jssocket.onopen = function(e) {
console.log("[open] Connection established");
};
jssocket.onmessage = function(event) {
console.log(`[message] Data received from server: ${event.data}`);
};
jssocket.onclose = function(event) {
if (event.wasClean) {
console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
// e.g. server process killed or network down
// event.code is usually 1006 in this case
console.log('[close] Connection died');
}
};
jssocket.onerror = function(error) {
console.log(`[error] ${error.message}`);
};
try {
navigator.getUserMedia = navigator.getUserMedia
|| navigator.webkitGetUserMedia
|| navigator.mozGetUserMedia;
microphone = navigator.getUserMedia({
audio : true,
video : false
}, onMicrophoneGranted, onMicrophoneDenied);
} catch (e) {
alert(e)
}
async function onMicrophoneGranted(stream) {
console.log(stream)
context = new AudioContext();
source = context.createMediaStreamSource(stream);
await context.audioWorklet.addModule('/assets/js/buffer-detector.js');
// Create our custom node.
bufferDetectorNode= new AudioWorkletNode(context, 'buffer-detector');
bufferDetectorNode.port.onmessage = (event) => {
// Handling data from the processor.
jssocket.send(event.data)
// const byteArr = Int8Array.from(event.data)
//const original = Array.from(byteArr)
// console.log(original);
// jssocket.send( Buffer.from(byteArr, 'base64').toString('utf8'));
};
source.connect(bufferDetectorNode);
bufferDetectorNode.connect(context.destination);
//source.connect(context.destination);
}
function _base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
function onMicrophoneDenied() {
console.log('denied')
}
function stop(){
bufferDetectorNode.disconnect(context.destination)
source.disconnect(bufferDetectorNode)
}
function generateRandomInteger(min, max) {
return Math.floor(min + Math.random() * (max - min + 1))
}
</script>
</body>
</html>
AudioWorklet
class BufferProcessor extends AudioWorkletProcessor {
bufferSize = 256
_bytesWritten = 0
// 2. Create a buffer of fixed size
_buffer = new Float32Array(this.bufferSize)
initBuffer() {
this._bytesWritten = 0
}
isBufferEmpty() {
return this._bytesWritten === 0
}
isBufferFull() {
return this._bytesWritten === this.bufferSize
}
process (inputs) {
this.append(inputs[0][0])
return true;
}
append(channelData) {
if (this.isBufferFull()) {
this.flush()
}
if (!channelData) return
for (let i = 0; i < channelData.length; i++) {
this._buffer[this._bytesWritten++] = channelData[i]
}
}
flush() {
// trim the buffer if ended prematurely
this.port.postMessage(
this._bytesWritten < this.bufferSize
? this._buffer.slice(0, this._bytesWritten)
: this._buffer
)
this.initBuffer()
}
static get parameterDescriptors() {
return [{
name: 'Buffer Detector',
}]
}
constructor() {
super();
this._socket = null;
this._isRecording = true;
this.initBuffer()
}
get socket() {
return this._socket;
}
set socket(value) {
if (value instanceof WebSocket) {
this._socket = value;
}
}
get recording() {
return this._isRecording;
}
set recording(value) {
if ('boolean' === typeof value) {
this._isRecording = value;
}
}
}
registerProcessor('buffer-detector',BufferProcessor );
