/*
* Copyright (C) 2010 Josh Guilfoyle <jasta@devtcg.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package org.devtcg.five.activity;
import java.io.IOException;
import org.devtcg.five.R;
import org.devtcg.five.util.streaming.DownloadManager;
import org.devtcg.five.util.streaming.DownloadTailStream;
import org.devtcg.five.util.streaming.StreamMediaPlayer;
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.Toast;
public class StreamMediaPlayerTest extends Activity
{
public static final String TAG = "StreamMediaPlayerTest";
private static final String STREAM_URI = "http://www.theyellowstereo.com/Daily%20Graboid/Kings%20of%20Leon%20-%20Sex%20on%20Fire.mp3";
private static final String CACHE_PATH = "/sdcard/Kings_of_Leon-Sex_on_Fire.mp3";
private ProgressHandler mHandler = new ProgressHandler();
private final StreamMediaPlayer mPlayer = new StreamMediaPlayer();
private boolean mPlaying = false;
private SeekBar mPlayInfo;
private Button mDownload;
private Button mPlay;
@Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.stream_media_player_test);
mPlayInfo = (SeekBar)findViewById(R.id.playback_info);
mPlayInfo.setOnSeekBarChangeListener(mSeeked);
mPlayInfo.setThumb(null);
mDownload = (Button)findViewById(R.id.download);
mDownload.setOnClickListener(mDownloadClick);
mPlay = (Button)findViewById(R.id.playstop);
mPlay.setOnClickListener(mPlayClick);
}
@Override
protected void onDestroy()
{
mPlayer.stop();
mPlayer.reset();
mPlayer.release();
super.onDestroy();
}
private void setPlaying(boolean playing)
{
if (playing == true)
{
mPlay.setText("Stop");
mPlay.setOnClickListener(mStopClick);
mPlayInfo.setEnabled(true);
}
else
{
mPlay.setText("Play");
mPlay.setOnClickListener(mPlayClick);
mPlayInfo.setEnabled(false);
mPlayInfo.setProgress(0);
mPlayInfo.setSecondaryProgress(0);
mHandler.stopPlaybackMonitoring();
}
mPlaying = playing;
}
private final OnClickListener mDownloadClick = new OnClickListener()
{
public void onClick(View v)
{
DownloadManager.Download d;
if ((d = mManager.lookupDownload(STREAM_URI)) == null)
{
try {
mManager.startDownload(STREAM_URI, CACHE_PATH, 0, 0);
} catch (IOException e) {
Log.e(TAG, "Crap", e);
}
}
else
{
Toast.makeText(StreamMediaPlayerTest.this,
"Download already in progress...", Toast.LENGTH_SHORT)
.show();
}
}
};
private final OnClickListener mPlayClick = new OnClickListener()
{
public void onClick(View v)
{
StreamMediaPlayer player = mPlayer;
/* I don't understand why this is necessary. I am cleanly invoking
* reset() each time the MediaPlayer is to be returned to
* its initial state however it doesn't seem to matter for the case
* where it's reset before it had even started playing. */
player.reset();
player.setOnBufferingUpdateListener(mBufferListener);
player.setOnPreparedListener(mPreparedListener);
player.setOnErrorListener(mErrorListener);
player.setOnCompletionListener(mCompletionListener);
DownloadManager.Download dl =
mManager.lookupDownload(STREAM_URI);
if (dl == null)
{
try {
dl = mManager.startDownload(STREAM_URI, CACHE_PATH, 0, 0);
} catch (IOException e) {
Log.e(TAG, "Crap", e);
}
}
try {
player.setDataSource(new DownloadTailStream(dl));
} catch (Exception e) {
Log.e(TAG, "Damnit", e);
Toast.makeText(StreamMediaPlayerTest.this,
"Fatal MediaPlayer error: " + e.toString(), Toast.LENGTH_LONG)
.show();
mManager.stopDownload(dl);
player.reset();
return;
}
setPlaying(true);
player.prepareAsync();
Log.i(TAG, "Should be buffering...");
}
};
private final OnClickListener mStopClick = new OnClickListener()
{
public void onClick(View v)
{
setPlaying(false);
mManager.stopAllDownloads();
if (mPlayer.isPlaying() == true)
mPlayer.stop();
mPlayer.reset();
}
};
private final SeekBar.OnSeekBarChangeListener mSeeked = new SeekBar.OnSeekBarChangeListener()
{
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromTouch)
{
if (fromTouch == false)
return;
assert mPlaying == true;
int dur = mPlayer.getDuration();
int target = (int)((progress / 100f) * dur);
mPlayer.seekTo(target);
}
public void onStartTrackingTouch(SeekBar seekBar)
{
}
public void onStopTrackingTouch(SeekBar seekBar)
{
}
};
private final MediaPlayer.OnBufferingUpdateListener mBufferListener =
new MediaPlayer.OnBufferingUpdateListener()
{
public void onBufferingUpdate(MediaPlayer mp, int percent)
{
Log.i(TAG, "onBufferingUpdate: percent=" + percent);
}
};
private final MediaPlayer.OnPreparedListener mPreparedListener =
new MediaPlayer.OnPreparedListener()
{
public void onPrepared(MediaPlayer mp)
{
Log.i(TAG, "Should be playing...");
mp.start();
mHandler.startPlaybackMonitoring();
}
};
private final MediaPlayer.OnErrorListener mErrorListener =
new MediaPlayer.OnErrorListener()
{
public boolean onError(MediaPlayer mp, int what, int extra)
{
Log.i(TAG, "onError: what=" + what + ", extra=" + extra);
mManager.stopAllDownloads();
if (mp.isPlaying() == true)
mp.stop();
mp.reset();
setPlaying(false);
return true;
}
};
private final MediaPlayer.OnCompletionListener mCompletionListener =
new MediaPlayer.OnCompletionListener()
{
public void onCompletion(MediaPlayer mp)
{
Log.i(TAG, "Should be finished.");
mp.reset();
setPlaying(false);
}
};
private final DownloadManager mManager = new DownloadManager(this)
{
@Override
public void onStateChange(String url, int state, String message)
{
Log.i(TAG, "State change for: " + url + " [state=" + state + ", msg=" + message +"]");
}
@Override
public void onFinished(String url)
{
Log.i(TAG, "Download finished for: " + url + "...");
}
@Override
public void onAborted(String url)
{
super.onAborted(url);
}
@Override
public void onError(String url, int state, final String err)
{
super.onError(url, state, err);
mHandler.post(new Runnable() {
public void run() {
Toast.makeText(StreamMediaPlayerTest.this,
"Fatal download error: " + err, Toast.LENGTH_LONG)
.show();
if (mPlaying == true)
{
if (mErrorListener.onError(mPlayer, 0, 0) == false)
mCompletionListener.onCompletion(mPlayer);
}
}
});
}
@Override
public void onProgressUpdate(String url, int percent)
{
mHandler.sendDownloadProgress(percent);
}
};
private class ProgressHandler extends Handler
{
private static final int MSG_DOWNLOAD_PROGRESS = 1;
private static final int MSG_PLAYBACK_PROGRESS = 2;
public int mLastDownloadProgress = -1;
public void handleMessage(Message msg)
{
switch (msg.what)
{
case MSG_DOWNLOAD_PROGRESS:
mPlayInfo.setSecondaryProgress(msg.arg1);
break;
case MSG_PLAYBACK_PROGRESS:
mPlayInfo.setProgress((int)
(((float)mPlayer.getCurrentPosition() /
(float)mPlayer.getDuration()) * 100f));
sendMessageDelayed(obtainMessage(MSG_PLAYBACK_PROGRESS),
1000);
break;
default:
super.handleMessage(msg);
break;
}
}
public void startPlaybackMonitoring()
{
removeMessages(MSG_PLAYBACK_PROGRESS);
sendMessage(obtainMessage(MSG_PLAYBACK_PROGRESS));
}
public void stopPlaybackMonitoring()
{
removeMessages(MSG_PLAYBACK_PROGRESS);
}
public void sendDownloadProgress(int progress)
{
sendMessage(obtainMessage(MSG_DOWNLOAD_PROGRESS, progress, -1));
}
}
}