PortAudio (MBS) to play an existing file

Hi,

My goal is to read an encrypted file, decrypt it and play its content as a sound (the original file being an mp3 or m4a audio file). I want to avoid saving to a temporary file, so the data must stay in memory.

I’m stuck at playing the data. I’ve checked the MBS “PortAudio” examples, but they play only generated sounds or just-in-time recorded audio (not existing files). Trying anyway to fill the buffer of the examples with the data obtained from the decrypted file leads to random noise.

So I’m wondering: can PortAudio play mp3/m4a files (if so, how)?
Is there a better way I’m missing?

MacOS or Windows?

WindowsPlayerMBS class can play MP3 from memory for Windows.
AVAudioPlayerMBS should do the same for macOS

1 Like

Both. I was hoping to use the same code for Mac and Windows, hence why I avoided AVAudioPlayer and WindowsPlayer (which I knew) and tried with PortAudio instead.

Can’t PortAudio play audio files? That would be simpler to maintain code.

Thank you.

The AVAudioPlayer class can play files correctly, but I can’t find a way to make it working by passing the binary data.

This works:

  '“File” is an existing audio file
  Var e As NSErrorMBS
  
  AVPlayer=new AVAudioPlayerMBS(File,e)
  
  if e<>nil then return e.Code
  if not AVPlayer.play then return -1

This doesn’t:

'“File” is an existing audio file

Var b As BinaryStream=BinaryStream.Open(File)
Var Data As String=b.Read(b.Length)
b.close

Var e As NSErrorMBS
  
AVPlayer=new AVAudioPlayerMBS(Data,e)
  
if e<>nil then return e.Code
if not AVPlayer.play then return -1

In the latter case, e is not nil and e.Code=-10875 (kAudioUnitErr_FailedInitialization).
Adding a hint (new AVAudioPlayerMBS(Data,e,“com.apple.m4a-audio”)) doesn’t work either.

So it seems like passing the file is not treated the same way as reading its content.
Help welcome, please. I don’t know what to look for.

Using AVPlayer=AVAudioPlayerMBS.audioPlayerWithData(Data,e) instead of passing by the constructor worked. That’s a subtle difference to be aware of with this class.

(I can’t edit my previous post)

The constructor taking string expects an URL.
if you like to pass data, use a memory block.

or the helper function there.

That’s confusing, as in Xojo, strings and MemoryBlocks are interchangeable (provided the string equals to a valid MemoryBlock). Therefore, in my point of view, the constructor taking a MemoryBlock could very well take the string data (i.e. “the MemoryBlock data”).

That looks especially more true since both the constructor and the AudioPlayerWithData methods have the data parameter as a MemoryBlock (in other words, they look the same but aren’t).

And the URL signature is already separated, so I strongly expected the version with “Data As MemoryBlock” could take the file’s binary content, not only in AudioPlayerWithData, but also with the similar constructor.

But well, it’s working now :slightly_smiling_face:.
Thanks for your support.

1 Like