filoe / cscore

An advanced audio library, written in C#. Provides tons of features. From playing/recording audio to decoding/encoding audio streams/files to processing audio data in realtime (e.g. applying custom effects during playback, create visualizations,...). The possibilities are nearly unlimited.
Other
2.15k stars 451 forks source link

Help needed: Play PCM from MemoryStream #403

Closed oo-dev17 closed 3 years ago

oo-dev17 commented 4 years ago

Hi ! (my question about this in another thread was not seen, so I repeat here in a own issue)

First a BIG THANK YOU to the contributor(s) of this library.

I am getting audio PCM from a bluetooth device by its API and want to play it on the speakers. I tried already with RawDataReader as IWaveSource, but ISoundOut stops immediately, I guess the stream is not continuous / buffer is empty - or bluetooth lags :-( In this approach I see no way to set FillWithZeros.

And when I see other examples with SoundInSource I have no idea where I could specify the WaveFormat (it is write protected)?

Any help is welcome, best regards

cPlayStream = new MemoryStream();
IWaveSource soundSource = new CSCore.Codecs.RAW.RawDataReader(cPlayStream, new CSCore.WaveFormat(4000, 16, 1));
outDevice = new CSCore.SoundOut.DirectSoundOut() { Device = DirectSoundDevice.DefaultDevice.Guid };
outDevice.Initialize(soundSource);
outDevice.Stopped += (a, b) => logger( "CSCore player stopped");
outDevice.Play();

somewhere else

// when bluetooth audio comes in
cPlayStream.Write(received.Message, 0, received.Message.Length);
filoe commented 4 years ago

What is the format of the received data?

oo-dev17 commented 4 years ago

Signed 16-Bit per sample, Mono, 4kHz, PCM, Little Endian, I see about 128 samples coming per event

filoe commented 4 years ago

Use the WriteableBufferingSource. Initialize the source with the mentioned format. Set WriteableBufferingSource to true. Write all data to the source and play it.

Pseudo:

var source = new WriteableBufferingSource(new WaveFormat(4000, 16, 1)){ FillWithZeros = true };
var soundOut = new WasapiOut();
soundOut.Initialize(source);
soundOut.Play();

//somewhere else
cPlayStream.Write(received.Message, 0, received.Message.Length);
filoe commented 4 years ago

What do you mean with "Write all data to the source and play it"? Shall I use the source its methods like WriteToStream()? Or: I don't see where the memory stream is connected to the source

You don't need the memory stream. The source is your MemoryStream. It behaves the same as a MemoryStream but can be played by cscore and automatically recyles data and has a circular buffer inside which prevents flooding memory.

oo-dev17 commented 4 years ago

This worked like a charm. Thank you a lot!

oo-dev17 commented 4 years ago

Restructured my code (maybe a thread issue), now I am getting

Frameworkversion: v4.0.30319
Beschreibung: Der Prozess wurde aufgrund einer unbehandelten Ausnahme beendet.
Ausnahmeinformationen: System.ArgumentNullException
   bei System.Threading.Monitor.Enter(System.Object)
   bei CSCore.Codecs.WAV.WaveFileReader.Dispose(Boolean)
   bei CSCore.Codecs.WAV.WaveFileReader.Finalize()

(working with Cscore from Nuget 1.2.1.2)

Maybe it is simple to guide me avoiding this? I tried to load and debug the Cscore code, but I cannot compile the Core 3 code (I guess because I am on VS2017)

filoe commented 4 years ago

Why do you need the WaveFileReader?

Regarding the issue: Looks like _lockObj is null. Can't figure out why. _lockObj is readonly and gets set to new object() when initializing the instance. Anyway, do you Dispose the WaveFileReader?

oo-dev17 commented 4 years ago

Don't worry, I will change my calls to avoid this, Thanks!

agaertner commented 3 years ago

Hey, I am also trying todo the same with youtube-dl

snip

~~I am currently piping it like this but I am not sure how or where to handle the basestream Should I put this in a background thread and wait for enough data to be written to the basestream? How do you handle this?~~

See issue: https://github.com/filoe/cscore/issues/437

oo-dev17 commented 3 years ago

I am sorry cause I don't understand your approach at all, but I will reopen the issue, maybe @filoe can help....

agaertner commented 3 years ago

@oo-dev17 Oh sorry. I forgot to delete this comment. I opened a new issue with more code as reference. See issue: https://github.com/filoe/cscore/issues/437 I was able to playback from the stream but the stream makes cracking noises after two or three readings. (Please reply in said issue not here.)