prism-media icon indicating copy to clipboard operation
prism-media copied to clipboard

How to save opus stream to a file?

Open OnkelTem opened this issue 3 years ago • 7 comments

Is there a way to save an Opus stream into a file using prism-media?

OnkelTem avatar Mar 20 '21 18:03 OnkelTem

https://github.com/amishshah/prism-media#what-is-it

// This example will demux and decode an Opus-containing OGG file, and then write it to a file.
const prism = require('prism-media');
const fs = require('fs');

fs.createReadStream('./audio.ogg')
  .pipe(new prism.opus.OggDemuxer())
  .pipe(new prism.opus.Decoder({ rate: 48000, channels: 2, frameSize: 960 }))
  .pipe(fs.createWriteStream('./audio.pcm')); // <--

Mesteery avatar Mar 20 '21 20:03 Mesteery

@Mesteery's solution is the closest thing you can do at the moment. I have plans to add an Ogg containeriser (is that a word?) stream to let you save Opus streams in .ogg files, but that will have to wait until the TypeScript refactor.

amishshah avatar Mar 20 '21 20:03 amishshah

Thanks @Mesteery, but I meant Opus stream, not raw/pcm. @amishshah

I have plans to add an Ogg containeriser (is that a word?)

Ogg Muxer?

but that will have to wait until the TypeScript refactor?

Could you please elaborate? Why TypeScript?

OnkelTem avatar Mar 21 '21 11:03 OnkelTem

@OnkelTem at the moment I'm prioritising refactoring the library to TypeScript to make it easier for me to maintain and add new features. I'd much rather write the Ogg muxer once in TypeScript, than have to port it from JavaScript to TypeScript.

However, I think I have a solution for this use-case in the meantime, see https://gist.github.com/amishshah/1f7e202dfb8f5595ebb19b9338a4d8f2

This will allow you to send your Opus streams to some other place (e.g. send them across processes, write to filesystem) and then recover them safely. Example usage:

Saving an Opus stream to filesystem:

createReadStream('file.ogg')
  .pipe(new prism.opus.OggDemuxer())
  .pipe(new Serialiser())
  .pipe(createWriteStream('file.nodestream'))

Later re-reading the Opus stream:

createReadStream('file.nodestream')
  .pipe(new Deserialiser())
  // now you have the original Opus packet object stream back

Essentially, it is a very lightweight alternative to the .ogg format and so it doesn't contain support for metadata, it stores only the Opus packets. Until I get the time to write the Ogg Muxer (I'm reluctant to call it this, since I'm planning on only supporting one input stream anyway), I think that this is a more than adequate solution.

amishshah avatar Mar 21 '21 12:03 amishshah

It's nice to hear that you support TypeScript, you have my vote on this!

I think I got the idea of your proposition of dumping packets. Well, in my case I'm implementing a history writer for an audio channel in Zello and I would want to have just normal OGG files at the end of course. Maybe it wouldn't be that difficult to package raw packets in a subset of OGG after all? You said "one input stream"? Maybe that would be enough.

OnkelTem avatar Mar 21 '21 13:03 OnkelTem

This is now being implemented in https://github.com/amishshah/prism-media/pull/70 :tada:

amishshah avatar Mar 24 '21 22:03 amishshah

Cool, gonna test it!

OnkelTem avatar Mar 25 '21 10:03 OnkelTem