Reputation: 6289
this code uses an opus encoded stream as input to cloud speech recognition ( options: contentType: 'OGG_OPUS', sampleRateHertz: 48000, ) and working fine.
However, a bufferCopy of the same stream sent to the Cloud storage api following sample, binary upload code causes error where the audio does not play after a download. Also on download, using both 'ogg' and 'opus' filetypes, ffprobe will not correctly detect the encoding as it should.
console and output from the upload to GCS looks ok - binary file about correct size gets up there and is downloadable using gsutils.
An opus stream that is ok for the google cloud recognition api is not good for the cloud storage api as a simple file-sink for an audio stream . I use gsutil to get the audio file from the cloud but it does not play in any player and ffprobe doesnt detect the encoding.
I dont know how to debug the issue. The original audio blob on the client plays fine, its size in bytes is very close but not equal to the size of the file uploaded to / downloaded from GCS api.
code details below: socket-io used to get data from js layer to this express server instance....
client.on('startGoogleCloudStream', function (data) {
// startRecognitionStream(this, data);
console.log('STRMbeg ' + typeof recognizeStream);
rs = new stream.Readable();
rs._read = function () {};
readStream1 = new ReadableStreamClone(rs);
readStream2 = new ReadableStreamClone(rs);
startRecognitionStream(this);
let rfil = 'audio/' +uuidv4() + '.ogg'; //typ '.opus' same error
const file = myBucket.file(rfil);
var otstrm = file.createWriteStream({
metadata: {
contentType: 'audio/ogg'
},
gzip: false,
resumable: false
});
readStream1.pipe(recognizeStream);// works fine
readStream2.pipe(otstrm) // gets a corrupted binary up on cloud
.on('error', function(err) {
console.log('second strm ' + err);
})
.on('finish', function() {
console.log('Done BcketFilaudio local');
});
});
client.on('endGoogleCloudStream', function (data) {
console.log('STRMend');
// stopRecognitionStream();
rs.push(null); // null is Stream.END
recognizeStream = null;
});
client.on('binaryData', function (data) {
console.log('data ' + data.length ); // log binary data
if (recognizeStream !== null) {
let _bfr = Buffer.from(data.buffer);
rs.push(_bfr);
}
});
function startRecognitionStream (client, data) {
recognizeStream = speechClient.streamingRecognize(request)
.on('error', console.error)
.on('data', (data) => { // back to client on socket.io
// Dev only logging
process.stdout.write(
(data.results[0] && data.results[0].alternatives[0])
? `Transcription: ${data.results[0].alternatives[0].transcript}\n`
: `\n\nReached transcription time limit, press Ctrl+C\n`
);
client.emit('speechData', data);
if (data.results[0] && data.results[0].isFinal) {
postRecSpeech(data.results[0].alternatives[0].transcript);
}
});
}
Upvotes: 1
Views: 416
Reputation: 6289
for some reason, GCS does NOT accept a copy of the stream working with Cloud Speech and the reuse of the server-side stream as input to multiple API's did not work.
-- workaround
even though the stream ( audio recorder ) was already server-side as a stream, the streams chunks had to be concated to a blob on the client and then posted AGAIN to express like doing curl/POST ...
curl -X POST --header "Transfer-Encoding: chunked" --header "Content-Type: audio/ogg; rate=48000" --data-binary @myaudio.opus "https://localhost${PORT}/audio/upload"
based on this code
my express code below worked fine and the GCS audio plays fine for downloads.
app.post("/audio/upload", gcsAudio);
const gcsAudio = (req, res) => {
const type = req.get('Content-Type');
let gcsname = 'audio/' +uuidv4() + '.opus';
const files = myBucket.file(gcsname);
const stream = files.createWriteStream({
metadata: {
contentType: type
},
resumable: false
});
req
.pipe(stream)
.on("error", (err) => {
restify.InternalServerError(err);
})
.on('finish', () => {
res.json({
success: true,
fileUrl: `https://storage.googleapis.com/${_bucket}/${gcsname}`
})
});
};
Upvotes: 1