Robert Rowntree
Robert Rowntree

Reputation: 6289

GCS binary upload - audio file not playing upon download

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

Answers (1)

Robert Rowntree
Robert Rowntree

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

Related Questions