| Android Tutorial 3: Custom Media Streaming with MediaPlayer |
|
|
|
|
Introduction This is a long tutorial, but for those of you that have been struggling with streaming of media to Google’s Android’s MediaPlayer, then I hope this tutorial proves useful as you finalize your entries into Google’s Android Challenge This tutorial will show how to roll your own streaming media utility for Android’s MediaPlayer. We will buffer 10 seconds of audio and start playing that audio while the rest of the audio loads in the background. We store the streamed audio locally so you could cache it on device for later use or simply let it be garbage collected. Here’s the source code for those that just want to jump in. You’ll also notice code for the other tutorials as I didn’t have time to strip them out. Here are a few screenshots of what we’ll be creating:
Basic Layout The tutorial consists of just two classes: Tutorial3: Contains
the UI layout and process button clicks We’ll assume you know about UI layout using Android’s XML resource files and will instead jump right into the audio streaming code. Start Your Streaming Upon clicking the “Start Streaming” button, Tutorial3 creates an instance of StreamingMediaPlayer.
All UI elements are passed to StreamingMediaPlayer so it can perform UI update itself. In a more robust implementation, StreamingMediaPlayer would fire relevant update events and Tutorial3 would handle the UI updates. For simplicity & cleaner code in this tutorial however, StreamingMediaPlayer will be directly updating the UI. Tutorial3 then calls StreamingMediaPlayer.startStreaming(): audioStreamer.startStreaming(”http://www.pocketjourney.com/audio.mp3″,1444, 180); Three variables are passed to startStreaming(): a url for the media to stream (link to an .mp3 file in this tutorial), the length in kilobytes of the media file, and the lenght in seconds of the media file. These last two values will be used when updating the progress bar. AudioStreamer.startStreaming() creates a new thread for streaming the content so we can immediately return control back to the user interface. public void startStreaming(final String mediaUrl, long mediaLengthInKb, long mediaLengthInSeconds) throws IOException { this.mediaLengthInKb = mediaLengthInKb; Runnable r = new Runnable() { public void run() { try { downloadAudioIncrement(mediaUrl); } catch (IOException e) { Log.e(getClass().getName(), “Initialization
error for fileUrl=” + mediaUrl, e); } } }; } Incremental Media Download This is where the magic happens as we download media content from the the url stream until we have enough content buffered to start the MediaPlayer. We then let the MediaPlayer play in the background while we download the remaining audio. If the MediaPlayer reaches the end of the buffered audio, then we transfer any newly downloaded audio to the MediaPlayer and let it start playing again. Things get a little tricky here because: (a) The MediaPlayer seems to lock the file so
we can’t simply append our content to the existing file. So with those caveats in mind, here’s the method that bufferes the media content to a temporary file: public void downloadAudioIncrement(String mediaUrl) throws IOException { // First
establish connection to the media provider Log.e(getClass().getName(), “Unable to create InputStream for mediaUrl:” + mediaUrl); } // Create
the temporary file for buffering data into // Start
reading data from the URL stream int numread = stream.read(buf); // Nothing
left to read so quit } else { out.write(buf, 0, numread); // Test whether
we need to transfer buffered data to the MediaPlayer } } while (true); // Lastly
transfer fully loaded audio to the MediaPlayer and close the InputStream } What’s up with testMediaBuffer()? So if you were paying attention, an important piece of functionality must reside in the testMediaBuffer() method. You’re right. That’s the method where we determine whether we need to transfer buffered data to the MediaPlayer because we have enough to start the MediaPlayer or because the MediaPlayer has already played out its previous buffer content. Before we jump into that, please take note that interacting with a MediaPlayer on non-main UI thread can causes crashes to we always ensure we are interacting on the main-UI Thread by using a Handler when necessary. For example, we must do so in the following method because it is being called by the media streaming Thread. private void testMediaBuffer() { // We’ll
place our following code into a Runnable so the Handler can call it for running public void run() { if (mediaPlayer == null) { // The
MediaPlayer has not yet been created so see if we have try { // We have
enough buffered content so start the MediaPlayer } catch (Exception e) { Log.e(getClass().getName(), “Error copying buffered conent.”, e); } } } else if ( mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000 ){ // The
MediaPlayer has been started and has reached the end of its buffered } } }; } Starting the MediaPlayer with Initial Content Buffer Starting the MediaPlayer is very straightforward now. We simply
copy all the currently buffered content private void startMediaPlayer(File bufferedFile) { try { File bufferedFile = File.createTempFile(”playingMedia”,
“.dat”); mediaPlayer = new MediaPlayer();
Log.e(getClass().getName(), “Error initializing
the MediaPlaer.”, e); } } Transferring Buffered Content to a MediaPlayer That is Already Playing This is a little trickier but not much. We simply pause the MediaPlayer if it was playing (i.e. the user had not pressed pause), copy over the currently downloaded media content (which may be all of it by now) and then restart the MediaPlayer if it was previously running or had hit the end of its buffer due to a slow network. private void transferBufferToMediaPlayer() { try { // Determine
if we need to restart the player after transferring data (e.g. perhaps the user // Copy
the current buffer file as we can’t download content into the same file that // Create
a new MediaPlayer. We’ve tried reusing them but that seems to result in // Restart
if at end of prior beuffered content or mediaPlayer was previously playing. mediaPlayer.start(); } }catch (Exception e) { Log.e(getClass().getName(), “Error updating to newly loaded content.”, e); } } Conclusion To get the real feel for how your audio will download, make sure to set it to a slower network speed. I recommend setting to AT&T’s EDGE network setting as it should give a lower limit on expected performance. You can make these setting’s easy in Eclipse by setting going into your Run or Debug setting’s dialog and making these selections.
Well that’s it. I’ve inluded additional code for handling the ProgressBar and TextField updates but that should all be sufficiently easy to understand once you understand the rest of the code. Good luck during the next week as you finish your Android Challenge submissions. And of course, here’s the source code. Please post a comment below if I need to explain anything in more detail. You’ll also notice code for the other tutorials as I didn’t have time to strip them out.
Source: http://blog.pocketjourney.com/2008/04/04/tutorial-custom-media-streaming-for-androids-mediaplayer/
Set as favorite
Bookmark
Email This
Hits: 18050 Comments (25)
![]() tiffany jewelry
written by tiffany jewelry , May 22, 2010 Well that’s it. I’ve inluded additional code for handling the ProgressBar and TextField updates but that should all be sufficiently easy to understand once you understand the rest of the code. Good luck during the next week as you finish your Android Challenge submissions.
report abuse
vote down
vote up
Votes: -1
adidas
written by adidas , May 22, 2010 The designers hid the cheap Adidas shoes sneakers among the plants, keeping them one with nature.The adidas shoes
report abuse
vote down
vote up
Votes: -1
adidas
written by adidas , May 22, 2010 sneaker pack was launched in style, complete the Adidas superstar with a green house preview in Japan. If you really want to buy a Gucci handbags
report abuse
vote down
vote up
Votes: +0
adidas
written by adidas , May 22, 2010 and you do not want to wait for years, you can shop for a custom Gucci wallets at Gucci outlet .
report abuse
vote down
vote up
Votes: +0
Cheap ghd hair straighteners
written by Cheap ghd hair straighteners , June 05, 2010 i just need these,thank you
report abuse
vote down
vote up
Votes: +0
Blue ghd
written by Blue ghd , June 06, 2010 thx you,thank you......
report abuse
vote down
vote up
Votes: +0
Red ghd straighteners
written by Red ghd straighteners , June 06, 2010 The designers hid the
report abuse
vote down
vote up
Votes: +0
new ghds
written by new ghds , June 06, 2010 Well that’s it. I’ve inluded additional code for handling the ProgressBar and TextField updates
report abuse
vote down
vote up
Votes: +0
blue ghd
written by blue ghd , June 08, 2010 I like it,it is very great ,if you play the online game cheap ghd hair straighteners
you will knowmetin2 goldis the game gold.in the gameghd red straightenersQuickly come here. report abuse
vote down
vote up
Votes: +0
new ghds
written by new ghds , June 09, 2010 it is very great ,if you play the online game blue ghdyou will knowmetin2 goldis the game gold.in the gamegreen ghdsQuickly come here.
report abuse
vote down
vote up
Votes: +0
green ghds
written by green ghds , June 10, 2010 if you play the online game blue ghdyou will knowmetin2 goldis the game gold.in the gameghd red straightenersQuickly come here.
report abuse
vote down
vote up
Votes: +0
led flashing bracelet
written by led flashing bracelet , June 17, 2010 want something special, come here
led flashing bracelets, cheap bakugan toys finger skate, power balance ddung, barbie girls led flashing bracelets at http://www.toptoys2trade.com report abuse
vote down
vote up
Votes: +0
...
written by mbt , June 18, 2010 "list" is a reference to an object implementing the List interface. Each element in this list is an object implementing the Map
report abuse
vote down
vote up
Votes: +0
sdfsadf
written by fivefingers , June 25, 2010 There are many different kinds products of Gucci outlet for your selection, including Gucci handbags,
report abuse
vote down
vote up
Votes: +0
sdfsf
written by fivefingers , June 25, 2010 Gucci wallets. The month of October brought on a new Vibram FiveFingers
report abuse
vote down
vote up
Votes: +0
adsfasd
written by fivefingers , June 25, 2010 offering for men the black Vibram Five Fingers, orange, and gray FiveFingers, which has been a hit.
report abuse
vote down
vote up
Votes: +0
product
written by user-me , July 06, 2010 good!
http://www.so-sports.com/nike-shox-r4-c-34.html report abuse
vote down
vote up
Votes: +0
2
written by Joey Dempster , July 08, 2010 First, thank you for sharing this code; it has been very helpful to me.
My nexus 1 updated to 2.2 the other day, and the streaming app immediately stopped working. The following error is observed: 07-07 11:48:45.414: ERROR/MediaPlayer(11269): Unable to to create media player 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): Error initializing the MediaPlayer. 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): java.io.IOException: setDataSourceFD failed.: status=0x80000000 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at android.media.MediaPlayer.setDataSource(Native Method) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at android.media.MediaPlayer.setDataSource(MediaPlayer.java:749) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at com.pocketjourney.media.StreamingMediaPlayer.createMediaPlayer(StreamingMediaPlayer.java:21 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at com.pocketjourney.media.StreamingMediaPlayer.startMediaPlayer(StreamingMediaPlayer.java:191) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at com.pocketjourney.media.StreamingMediaPlayer.access$2(StreamingMediaPlayer.java:176) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at com.pocketjourney.media.StreamingMediaPlayer$2.run(StreamingMediaPlayer.java:160) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at android.os.Handler.handleCallback(Handler.java:587) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at android.os.Handler.dispatchMessage(Handler.java:92) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at android.os.Looper.loop(Looper.java:123) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at android.app.ActivityThread.main(ActivityThread.java:4627) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at java.lang.reflect.Method.invokeNative(Native Method) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at java.lang.reflect.Method.invoke(Method.java:521) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:86 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) 07-07 11:48:45.414: ERROR/com.pocketjourney.media.StreamingMediaPlayer(11269): at dalvik.system.NativeStart.main(Native Method) Have you seen this as well? Any ideas about what is causing it and how to adapt to the change? Thanks! report abuse
vote down
vote up
Votes: +1
...
written by Joey Dempster , July 08, 2010 By the way, it works when streaming a file, but not when accessing a streaming audio file. I'm at a loss as to why.
report abuse
vote down
vote up
Votes: +0
... written by Abercrombie fitch outlet , July 29, 2010 led flashing bracelets, cheap bakugan toys
finger skate, power balance ddung, barbie girls led flashing bracelets report abuse
vote down
vote up
Votes: +0
Write comment
|