<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Best Android apps - Androidapps.org - Your source for technology news &#187; media streaming with mediaplayer</title>
	<atom:link href="http://www.androidapps.org/tag/media-streaming-with-mediaplayer/feed" rel="self" type="application/rss+xml" />
	<link>http://www.androidapps.org</link>
	<description>Android apps and Tech News</description>
	<lastBuildDate>Fri, 03 Feb 2012 20:42:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Android Tutorial 3: Custom Media Streaming with MediaPlayer</title>
		<link>http://www.androidapps.org/android-tutorial-3-custom-media-streaming-with-mediaplayer</link>
		<comments>http://www.androidapps.org/android-tutorial-3-custom-media-streaming-with-mediaplayer#comments</comments>
		<pubDate>Tue, 25 Mar 2008 00:49:17 +0000</pubDate>
		<dc:creator>Admin</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[media streaming with mediaplayer]]></category>

		<guid isPermaLink="false">http://www.androidapps.org/?p=163</guid>
		<description><![CDATA[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 [...]]]></description>
			<content:encoded><![CDATA[<p>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 <a title="Android Challenge" href="http://code.google.com/android/adc.html">Google’s Android Challenge</a></p>
<p>This tutorial will show how to roll your own streaming media utility for <a title="Android's MediaPlayer" href="http://code.google.com/android/toolbox/apis/media.html">Android’s MediaPlayer</a>. 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.</p>
<p>Here’s the <a title="Source Code" href="http://www.pocketjourney.com/downloads/pj/tutorials/tutorial3.zip">source code</a> 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.</p>
<p>Here are a few screenshots of what we’ll be creating:</p>
<p><img src="http://pocketjourney.files.wordpress.com/2008/04/tutorial-3-results-screenshots.gif" border="0" alt="Tutorial #3 results screenshots" /></p>
<p><strong>Basic Layout</strong></p>
<p>The tutorial consists of just two classes:</p>
<p style="padding-left: 30px;"><strong>Tutorial3: </strong>Contains the UI layout and process button clicks<br />
<strong>StreamingMediaPlayer:</strong> Connects to the server, downloads audio into the buffer, and controls the functionality to ensure the audio continues to play seamlessly.</p>
<p>We’ll assume you know about UI layout using Android’s XML resource files and will instead jump right into the audio streaming code.</p>
<p><strong>Start Your Streaming</strong></p>
<p>Upon clicking the “Start Streaming” button, Tutorial3 creates an instance of StreamingMediaPlayer.</p>
<blockquote><p><em>new StreamingMediaPlayer(textStreamed, playButton, streamButton,progressBar);</em></p></blockquote>
<p>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 &amp; cleaner code in this tutorial however, StreamingMediaPlayer will be directly updating the UI.</p>
<p>Tutorial3 then calls StreamingMediaPlayer.startStreaming():</p>
<p style="padding-left: 30px;"><em>audioStreamer.startStreaming(”http://www.pocketjourney.com/audio.mp3?,1444, 180);</em></p>
<p>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.</p>
<p>AudioStreamer.startStreaming() creates a new thread for streaming the content so we can immediately return control back to the user interface.</p>
<p style="padding-left: 30px;"><em>public void startStreaming(final String mediaUrl, long mediaLengthInKb, long mediaLengthInSeconds) throws IOException {</em></p>
<p style="padding-left: 60px;"><em>this.mediaLengthInKb = mediaLengthInKb;<br />
this.mediaLengthInSeconds = mediaLengthInSeconds;</em></p>
<p style="padding-left: 60px;"><em>Runnable r = new Runnable() {</em></p>
<p style="padding-left: 90px;"><em>public void run() { </em></p>
<p style="padding-left: 120px;"><em>try { </em></p>
<p style="padding-left: 150px;"><em>downloadAudioIncrement(mediaUrl);</em></p>
<p style="padding-left: 120px;"><em>} catch (IOException e) {</em></p>
<p style="padding-left: 150px;"><em>Log.e(getClass().getName(), “Initialization error for fileUrl=” + mediaUrl, e);<br />
return;</em></p>
<p style="padding-left: 120px;"><em>} </em></p>
<p style="padding-left: 90px;"><em>} </em></p>
<p style="padding-left: 60px;"><em>};<br />
new Thread(r).start();</em></p>
<p style="padding-left: 30px;"><em>}</em></p>
<p><strong>Incremental Media Download </strong></p>
<p>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.</p>
<p>Things get a little tricky here because:</p>
<p style="padding-left: 30px;"><em>(a) The MediaPlayer seems to lock the file so we can’t simply append our content to the existing file.<br />
(b) Pausing the MediaPlayer to load the new content takes awhile so we only want to interrupt it when absolutely necessary.<br />
(c) Accessing the MediaPlayer from a separate thread causes it to crash.</em></p>
<p>So with those caveats in mind, here’s the method that bufferes the media content to a temporary file:</p>
<p style="padding-left: 30px;"><em>public void downloadAudioIncrement(String mediaUrl) throws IOException {</em></p>
<p style="padding-left: 60px;"><em><span style="color: #008000;">// First establish connection to the media provider</span><br />
URLConnection cn = new URL(mediaUrl).openConnection();<br />
cn.connect();<br />
InputStream stream = cn.getInputStream();<br />
if (stream == null) {</em></p>
<p style="padding-left: 90px;"><em>Log.e(getClass().getName(), “Unable to create InputStream for mediaUrl:” + mediaUrl);</em></p>
<p style="padding-left: 60px;"><em>}</em></p>
<p style="padding-left: 60px;"><em><span style="color: #008000;">// Create the temporary file for buffering data into</span><br />
downloadingMediaFile = File.createTempFile(”downloadingMedia”, “.dat”);<br />
FileOutputStream out = new FileOutputStream(downloadingMediaFile);</em></p>
<p style="padding-left: 60px;"><em><span style="color: #008000;">// Start reading data from the URL stream<br />
</span>byte buf[] = new byte[16384];<br />
int totalBytesRead = 0, incrementalBytesRead = 0;<br />
do {</em></p>
<p style="padding-left: 90px;"><em>int numread = stream.read(buf);<br />
if (numread &lt;= 0) {</em></p>
<p style="padding-left: 120px;"><em><span style="color: #008000;">// Nothing left to read so quit</span><br />
break; </em></p>
<p style="padding-left: 90px;"><em>} else {</em></p>
<p style="padding-left: 120px;"><em>out.write(buf, 0, numread);<br />
totalBytesRead += numread;<br />
incrementalBytesRead += numread;<br />
totalKbRead = totalBytesRead/1000;</em></p>
<p style="padding-left: 120px;"><span style="color: #008000;">// Test whether we need to transfer buffered data to the MediaPlayer</span><br />
testMediaBuffer();<br />
<span style="color: #008000;"><br />
// Update the status for ProgressBar and TextFields<br />
</span>fireDataLoadUpdate();</p>
<p style="padding-left: 90px;"><em>}</em></p>
<p style="padding-left: 60px;"><em>} while (true); </em></p>
<p style="padding-left: 60px;"><em><span style="color: #008000;">// Lastly transfer fully loaded audio to the MediaPlayer and close the InputStream</span><br />
fireDataFullyLoaded();<br />
<em>stream.close();</em></em></p>
<p style="padding-left: 30px;"><em>}</em></p>
<p><strong>What’s up with testMediaBuffer()?</strong></p>
<p>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.</p>
<p><span style="color: #ff0000;">Before we jump into that, please take note that interacting with a MediaPlayer on non-main UI thread can cause crashes so we always ensure we are interacting with the UI 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.</span></p>
<p style="padding-left: 30px;"><em>private void testMediaBuffer() {</em></p>
<p style="padding-left: 60px;"><em><span style="color: #008000;">// We’ll place our following code into a Runnable so the Handler can call it for running<br />
// on the main UI thread</span><br />
Runnable updater = new Runnable() {</em></p>
<p style="padding-left: 90px;"><em>public void run() {</em></p>
<p style="padding-left: 120px;"><em>if (mediaPlayer == null) {</em></p>
<p style="padding-left: 150px;"><em><span style="color: #008000;">// The MediaPlayer has not yet been created so see if we have<br />
// the minimum buffered data yet.<br />
// For our purposes, we take the minimum buffered requirement to be:<br />
// INTIAL_KB_BUFFER = 96*10/8;//assume 96kbps*10secs/8bits per byte</span><br />
if ( totalKbRead &gt;= INTIAL_KB_BUFFER) {</em></p>
<p style="padding-left: 180px;"><em>try {</em></p>
<p style="padding-left: 210px;"><em><span style="color: #008000;">// We have enough buffered content so start the MediaPlayer</span><br />
startMediaPlayer(bufferedFile);</em></p>
<p style="padding-left: 180px;"><em>} catch (Exception e) {</em></p>
<p style="padding-left: 210px;"><em>Log.e(getClass().getName(), “Error copying buffered conent.”, e);</em></p>
<p style="padding-left: 180px;"><em>}</em></p>
<p style="padding-left: 150px;"><em>}</em></p>
<p style="padding-left: 120px;"><em>} else if ( mediaPlayer.getDuration() – mediaPlayer.getCurrentPosition() &lt;= 1000 ){</em></p>
<p style="padding-left: 150px;"><em><span style="color: #008000;">// The MediaPlayer has been started and has reached the end of its buffered<br />
// content. We test for &lt; 1second of data (i.e. 1000ms) because the media<br />
// player will often stop when there are still a few milliseconds of data left to play</span><br />
transferBufferToMediaPlayer();</em></p>
<p style="padding-left: 120px;"><em>}</em></p>
<p style="padding-left: 90px;"><em>}</em></p>
<p style="padding-left: 60px;"><em>};<br />
handler.post(updater);</em></p>
<p style="padding-left: 30px;"><em>}</em></p>
<p><strong>Starting the MediaPlayer with Initial Content Buffer</strong></p>
<p>Starting the MediaPlayer is very straightforward now. We simply copy all the currently buffered content<br />
into a new Ffile and start the MediaPlayer with it.</p>
<p style="padding-left: 30px;"><em>private void startMediaPlayer(File bufferedFile) {</em></p>
<p style="padding-left: 60px;"><em>try {</em></p>
<p style="padding-left: 90px;"><em>File bufferedFile = File.createTempFile(”playingMedia”, “.dat”);<br />
FileUtils.copyFile(downloadingMediaFile,bufferedFile);</em><em>} catch (IOException e) {</em></p>
<p style="padding-left: 90px;">mediaPlayer = new MediaPlayer();<br />
mediaPlayer.setDataSource(bufferedFile.getAbsolutePath());<br />
mediaPlayer.prepare();<br />
fireDataPreloadComplete();</p>
<p style="padding-left: 60px;">
<p style="padding-left: 90px;"><em>Log.e(getClass().getName(), “Error initializing the MediaPlaer.”, e);<br />
return;</em></p>
<p style="padding-left: 60px;"><em>}</em></p>
<p style="padding-left: 30px;"><em>}</em></p>
<p><strong>Transferring Buffered Content to a MediaPlayer That is Already Playing</strong></p>
<p>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.</p>
<p style="padding-left: 30px;"><em>private void transferBufferToMediaPlayer() {</em></p>
<p style="padding-left: 60px;"><em>try {</em></p>
<p style="padding-left: 90px;"><em><span style="color: #008000;">// Determine if we need to restart the player after transferring data (e.g. perhaps the user<br />
// pressed pause) &amp; also store the current audio position so we can reset it later. </span><br />
boolean wasPlaying = mediaPlayer.isPlaying();<br />
int curPosition = mediaPlayer.getCurrentPosition();<br />
mediaPlayer.pause();</em></p>
<p style="padding-left: 90px;"><em><span style="color: #008000;">// Copy the current buffer file as we can’t download content into the same file that<br />
// the MediaPlayer is reading from.</span><br />
File bufferedFile = File.createTempFile(”playingMedia”, “.dat”);<br />
FileUtils.copyFile(downloadingMediaFile,bufferedFile);</em></p>
<p style="padding-left: 90px;"><em><span style="color: #008000;">// Create a new MediaPlayer. We’ve tried reusing them but that seems to result in<br />
// more system crashes than simply creating new ones.</span><br />
mediaPlayer = new MediaPlayer();<br />
mediaPlayer.setDataSource(bufferedFile.getAbsolutePath());<br />
mediaPlayer.prepare();<br />
mediaPlayer.seekTo(curPosition);</em></p>
<p style="padding-left: 90px;"><em><span style="color: #008000;">// Restart if at end of prior beuffered content or mediaPlayer was previously playing.<br />
// NOTE: We test for &lt; 1second of data because the media player can stop when there is still<br />
// a few milliseconds of data left to play</span><br />
boolean atEndOfFile = mediaPlayer.getDuration() – mediaPlayer.getCurrentPosition() &lt;= 1000;<br />
if (wasPlaying || atEndOfFile){</em></p>
<p style="padding-left: 120px;"><em>mediaPlayer.start();</em></p>
<p style="padding-left: 90px;"><em>}</em></p>
<p style="padding-left: 60px;"><em>}catch (Exception e) {</em></p>
<p style="padding-left: 90px;"><em>Log.e(getClass().getName(), “Error updating to newly loaded content.”, e);</em></p>
<p style="padding-left: 60px;"><em>}</em></p>
<p style="padding-left: 30px;"><em>}</em></p>
<p><strong>Conclusion</strong></p>
<p>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&amp;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.</p>
<p style="text-align: center;"><img class="size-full wp-image-19" src="http://pocketjourney.files.wordpress.com/2008/04/edge-settings-in-eclipse.gif" alt="EDGE settings in Eclipse" width="378" height="237" /></p>
<p>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 <a title="Android Challenge" href="http://code.google.com/android/adc.html">Android Challenge</a> submissions.</p>
<p>And of course, here’s the <a title="Source Code" href="http://www.pocketjourney.com/downloads/pj/tutorials/tutorial3.zip">source code</a>. 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.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.androidapps.org/android-tutorial-3-custom-media-streaming-with-mediaplayer/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

