Streaming MP3 audio via socket communication using OpenSL ES on Android

advertisements

I'm trying to stream an MP3 from an Android phone to another Android phone using WiFi via an access point. The problem is that OpenSL ES appears to only support PCM audio buffers as the source (unless using a URI). Rather than decoding a potentially huge file on the "Master" side before sending I would prefer to let the "Client" decode the MP3 into PCM. Keep in mind that this has to occur AS the file streams rather than simply sending the whole file and then decoding. Is there any way to accomplish this using OpenSL ES? AudioTrack? It seems like it would be a fairly common request.


You are correct that opensl doesn't appear to take a simple buffer queue with mp3 source. That being said, you should be able to use an SLDataLocator_URI instead. Now, I understand that you don't have the full file available when you start (since you are streaming), but there is a way around this. If you create an empty file, and use it as the source for the opensl URI player everything should work. As you get data (bits of the mp3 file), just add this data to the empty file you created. You can have OpenSL start playing from this file before you are finished appending data to it.

Create an empty file with:

RandomAccessFile raf = new RandomAccessFile(new File(mFileUri), "rw");
raf.setLength(audioFileSize);

Create your audio source as:

SLDataLocator_URI loc_uri = {SL_DATALOCATOR_URI, (SLchar *) fileLoc};
SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};
SLDataSource audioSrc = {&loc_uri, &format_mime};

Load buffers with:

for (int i = 0; i < BUFFER_COUNT; i++) {
    // get byte[] data from stream
    raf.seek(i*Constants.BUFFER_SIZE);
    raf.write(data);
}

Start playing audio at any time with OpenSL and then continue loading buffers. As long as you stay ahead of the curve in your streaming process, you should be fine.