views:

3114

answers:

4

As I understand it, Android will only play AAC format audio if it's encoded as MPEG-4 or 3GPP.

I'm able to play AAC audio encoded as M4A when it's local to the app, but it fails when obtaining it from a server.

The following works, as the m4a file is held locally in the res/raw directory.

MediaPlayer mp = MediaPlayer.create(this, R.raw.*file*);
mp.start();

The following doesn't work. (But does with MP3's).

Uri uri = Uri.parse("http://*example.com*/blah.m4a");
MediaPlayer mp = MediaPlayer.create(this, uri);
mp.start();

Can anyone shed any light on why it fails when the m4a audio file is not local?

Here's (some of) the error...

ERROR/PlayerDriver(542): Command PLAYER_INIT completed with an error or info UNKNOWN PVMFStatus
ERROR/MediaPlayer(769): error (200, -32)  
WARN/PlayerDriver(542): PVMFInfoErrorHandlingComplete  
DEBUG/MediaPlayer(769): create failed:  
DEBUG/MediaPlayer(769): java.io.IOException: Prepare failed.: status=0xC8  
DEBUG/MediaPlayer(769):     at android.media.MediaPlayer.prepare(Native Method)  
DEBUG/MediaPlayer(769):     at android.media.MediaPlayer.create(MediaPlayer.java:530)  
DEBUG/MediaPlayer(769):     at android.media.MediaPlayer.create(MediaPlayer.java:507)   
...

I'm targeting SDK 1.6.

A: 

This is a wild shot in the dark, but I have seen similar behavior with the flash player where it actually ignores the file name and only relies on the MIME type sent by the server. Any idea what headers are being sent down from example.com? You might want to try wrapping your blah.m4a in a page that can set the headers and then stream the binary data. Give these types a shot and the community would appreciate a confirmation of what works:

audio/mpeg audio/mp4a audio/mp4a-latm audio/aac audio/x-aac

Goyuix
A good suggestion - thanks. Unfortunately I've had no luck trying an array of possible content-types. For reference, I've listed the ones that have not worked below. It's still possible it's something to do with HTTP headers - or something - it might be that it's very fussy about what it can be fed.`audio/m4a audio/aac audio/aacp audio/x-aac audio/mpeg audio/mp4a audio/mp4a-latm audio/mp4`
bdls
I definitely experienced an issue with this. For our streaming purposes, the MediaPlayer would not play the streaming file unless the Http header content-type was set correctly. Interestingly, the content length was not required though.
greg7gkb
A: 

This work-around allows you to play M4A files from the net (and AAC files in other containers such as MP4 & 3GP). It simply downloads the file and plays from the cache.

private File mediaFile;

private void playAudio(String mediaUrl) {
    try {
     URLConnection cn = new URL(mediaUrl).openConnection();
        InputStream is = cn.getInputStream();

        // create file to store audio
        mediaFile = new File(this.getCacheDir(),"mediafile");
        FileOutputStream fos = new FileOutputStream(mediaFile);   
        byte buf[] = new byte[16 * 1024];
        Log.i("FileOutputStream", "Download");

        // write to file until complete
        do {
         int numread = is.read(buf);   
            if (numread <= 0)  
                break;
            fos.write(buf, 0, numread);
        } while (true);
        fos.flush();
        fos.close();
        Log.i("FileOutputStream", "Saved");
        MediaPlayer mp = new MediaPlayer();

        // create listener to tidy up after playback complete
     MediaPlayer.OnCompletionListener listener = new MediaPlayer.OnCompletionListener() {
      public void onCompletion(MediaPlayer mp) {
       // free up media player
       mp.release();
       Log.i("MediaPlayer.OnCompletionListener", "MediaPlayer Released");
      }
     };
        mp.setOnCompletionListener(listener);

        FileInputStream fis = new FileInputStream(mediaFile);
        // set mediaplayer data source to file descriptor of input stream
        mp.setDataSource(fis.getFD());
        mp.prepare();
        Log.i("MediaPlayer", "Start Player");
        mp.start();
    } catch (Exception e) {
     e.printStackTrace();
    }
}
bdls
Good idea but of course this requires the entire file to be downloaded first before it can be played. Could be useful for some situations but obviously not suitable as a streaming solution.
greg7gkb
That's true, though this code can be built on to create a streaming solution using a local file or files as a makeshift circular buffer. It's unfortunate that the MediaPlayer cannot receive from an InputStream or you'd be able to do a circular buffer in the standard way.
bdls
A: 

try --

1) MP.prepareAsync

2) onPrepared() { mp.start() }

subbarao
Thanks for your response. The Async version doesn't appear to work either. The following (not very helpful) errors occur when I try to start the player after an asynchronous prepare for a static AAC+ M4A/3gp/MP4 file, then an HE-AACv2 stream. `ERROR/PlayerDriver(51): Command PLAYER_INIT completed with an error or info UNKNOWN PVMFStatus ERROR/MediaPlayer(12116): error (200, -32)` `ERROR/PlayerDriver(51): Command PLAYER_INIT completed with an error or info PVMFErrCorrupt ERROR/MediaPlayer(10700): error (1, -10)`
bdls
A: 

I wrote a smal blog on a cloud-based solution I use for a music player I'm developing. It's based on the young Android Cloud Services (ACS) project, which isn't available yet, but still, it shows a potential solution using cloud-based transcoding to stream any media files. Have a look : http://positivelydisruptive.blogspot.com/2010/08/streaming-m4a-files-using-android-cloud.html

Joel

jgrenon
Hi Joel. It's a possible option, however it removes the advantages of AAC over other formats (higher perceived quality at a lower bitrate) as you're just streaming MP3 in the end.
bdls