I need to play a live stream video. I am trying to play the video by using MediaPlayer & SurfaceView. The URL is redirected from http with .mov to rtsp with .3gp extension. Vide plays efficiently in OS v2.3.x, but it does not play in any other OS version from 2.1 onward. Any suggestions?
public class StreamingAudioActivity extends Activity {
/** Called when the activity is first created. */
private Button streamButton;
private ImageButton playButton;
private TextView textStreamed;
private boolean isPlaying;
private StreamingMediaPlayer audioStreamer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// }
//
// private void initControls() {
textStreamed = (TextView) findViewById(R.id.text_kb_streamed);
streamButton = (Button) findViewById(R.id.button_stream);
streamButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Log.v("click","streaming on");
startStreamingAudio();
}
});
playButton = (ImageButton) findViewById(R.id.button_play);
playButton.setEnabled(false);
playButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (audioStreamer.getMediaPlayer().isPlaying()) {
audioStreamer.getMediaPlayer().pause();
playButton.setImageResource(R.drawable.button_play);
} else {
audioStreamer.getMediaPlayer().start();
audioStreamer.startPlayProgressUpdater();
playButton.setImageResource(R.drawable.button_pause);
}
isPlaying = !isPlaying;
}
});
}
private void startStreamingAudio() {
try {
final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
if (audioStreamer != null) {
audioStreamer.interrupt();
}
audioStreamer = new StreamingMediaPlayer(this, textStreamed,
playButton, streamButton, progressBar);
Log.v("aaa", "sdaa");
// audioStreamer.startStreaming("http://www.pocketjourney.com/downloads/pj/tutorials/audio.mp3",1717,
// 214);
audioStreamer.startStreaming(
"http://vprbbc.streamguys.net:80/vprbbc24.mp3",
1717, 216);
// http://rkmania.me/playlistAction.php?action=addTrack&trck=115976
streamButton.setEnabled(false);
} catch (IOException e) {
Log.e(getClass().getName(), "Error starting to stream audio.", e);
}
}
public class StreamingMediaPlayer {
private static final int INTIAL_KB_BUFFER = 96*10/8;//assume 96kbps*10secs/8bits per byte
private TextView textStreamed;
private ImageButton playButton;
private ProgressBar progressBar;
// Track for display by progressBar
private long mediaLengthInKb, mediaLengthInSeconds;
private int totalKbRead = 0;
// Create Handler to call View updates on the main UI thread.
private final Handler handler = new Handler();
private MediaPlayer mediaPlayer;
private File downloadingMediaFile;
private boolean isInterrupted;
private Context context;
private int counter = 0;
public StreamingMediaPlayer(Context context,TextView textStreamed, ImageButton playButton, Button streamButton,ProgressBar progressBar)
{
this.context = context;
this.textStreamed = textStreamed;
this.playButton = playButton;
this.progressBar = progressBar;
}
/**
* Progressivly download the media to a temporary location and update the MediaPlayer as new content becomes available.
*/
public void startStreaming(final String mediaUrl, long mediaLengthInKb, long mediaLengthInSeconds) throws IOException {
this.mediaLengthInKb = mediaLengthInKb;
this.mediaLengthInSeconds = mediaLengthInSeconds;
Runnable r = new Runnable() {
public void run() {
try {
downloadAudioIncrement(mediaUrl);
} catch (IOException e) {
Log.e(getClass().getName(), "Unable to initialize the MediaPlayer for fileUrl=" + mediaUrl, e);
return;
}
}
};
new Thread(r).start();
}
/**
* Download the url stream to a temporary location and then call the setDataSource
* for that local file
*/
public void downloadAudioIncrement(String mediaUrl) throws IOException {
URLConnection cn = new URL(mediaUrl).openConnection();
cn.connect();
InputStream stream = cn.getInputStream();
if (stream == null) {
Log.e(getClass().getName(), "Unable to create InputStream for mediaUrl:" + mediaUrl);
}
downloadingMediaFile = new File(context.getCacheDir(),"downloadingMedia.dat");
// Just in case a prior deletion failed because our code crashed or something, we also delete any previously
// downloaded file to ensure we start fresh. If you use this code, always delete
// no longer used downloads else you'll quickly fill up your hard disk memory. Of course, you can also
// store any previously downloaded file in a separate data cache for instant replay if you wanted as well.
if (downloadingMediaFile.exists()) {
downloadingMediaFile.delete();
}
FileOutputStream out = new FileOutputStream(downloadingMediaFile);
byte buf[] = new byte[16384];
int totalBytesRead = 0, incrementalBytesRead = 0;
do {
int numread = stream.read(buf);
if (numread <= 0)
break;
out.write(buf, 0, numread);
totalBytesRead += numread;
incrementalBytesRead += numread;
totalKbRead = totalBytesRead/1000;
testMediaBuffer();
fireDataLoadUpdate();
} while (validateNotInterrupted());
stream.close();
if (validateNotInterrupted()) {
fireDataFullyLoaded();
}
}
private boolean validateNotInterrupted() {
if (isInterrupted) {
if (mediaPlayer != null) {
mediaPlayer.pause();
//mediaPlayer.release();
}
return false;
} else {
return true;
}
}
/**
* Test whether we need to transfer buffered data to the MediaPlayer.
* Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler.
*/
private void testMediaBuffer() {
Runnable updater = new Runnable() {
public void run() {
if (mediaPlayer == null) {
// Only create the MediaPlayer once we have the minimum buffered data
if ( totalKbRead >= INTIAL_KB_BUFFER) {
try {
startMediaPlayer();
} catch (Exception e) {
Log.e(getClass().getName(), "Error copying buffered conent.", e);
}
}
} else if ( mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000 ){
// NOTE: The media player has stopped at the end so transfer any existing buffered data
// We test for < 1second of data because the media player can stop when there is still
// a few milliseconds of data left to play
transferBufferToMediaPlayer();
}
}
};
handler.post(updater);
}
private void startMediaPlayer() {
try {
File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");
// We double buffer the data to avoid potential read/write errors that could happen if the
// download thread attempted to write at the same time the MediaPlayer was trying to read.
// For example, we can't guarantee that the MediaPlayer won't open a file for playing and leave it locked while
// the media is playing. This would permanently deadlock the file download. To avoid such a deadloack,
// we move the currently loaded data to a temporary buffer file that we start playing while the remaining
// data downloads.
moveFile(downloadingMediaFile,bufferedFile);
Log.e(getClass().getName(),"Buffered File path: " + bufferedFile.getAbsolutePath());
Log.e(getClass().getName(),"Buffered File length: " + bufferedFile.length()+"");
mediaPlayer = createMediaPlayer(bufferedFile);
// We have pre-loaded enough content and started the MediaPlayer so update the buttons & progress meters.
mediaPlayer.start();
startPlayProgressUpdater();
playButton.setEnabled(true);
} catch (IOException e) {
Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e);
return;
}
}
private MediaPlayer createMediaPlayer(File mediaFile)
throws IOException {
MediaPlayer mPlayer = new MediaPlayer();
mPlayer.setOnErrorListener(
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(getClass().getName(), "Error in MediaPlayer: (" + what +") with extra (" +extra +")" );
return false;
}
});
// It appears that for security/permission reasons, it is better to pass a FileDescriptor rather than a direct path to the File.
// Also I have seen errors such as "PVMFErrNotSupported" and "Prepare failed.: status=0x1" if a file path String is passed to
// setDataSource(). So unless otherwise noted, we use a FileDescriptor here.
FileInputStream fis = new FileInputStream(mediaFile);
mPlayer.setDataSource(fis.getFD());
mPlayer.prepare();
return mPlayer;
}
/**
* Transfer buffered data to the MediaPlayer.
* NOTE: Interacting with a MediaPlayer on a non-main UI thread can cause thread-lock and crashes so
* this method should always be called using a Handler.
*/
private void transferBufferToMediaPlayer() {
try {
// First determine if we need to restart the player after transferring data...e.g. perhaps the user pressed pause
boolean wasPlaying = mediaPlayer.isPlaying();
int curPosition = mediaPlayer.getCurrentPosition();
// Copy the currently downloaded content to a new buffered File. Store the old File for deleting later.
File oldBufferedFile = new File(context.getCacheDir(),"playingMedia" + counter + ".dat");
File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");
// This may be the last buffered File so ask that it be delete on exit. If it's already deleted, then this won't mean anything. If you want to
// keep and track fully downloaded files for later use, write caching code and please send me a copy.
bufferedFile.deleteOnExit();
moveFile(downloadingMediaFile,bufferedFile);
// Pause the current player now as we are about to create and start a new one. So far (Android v1.5),
// this always happens so quickly that the user never realized we've stopped the player and started a new one
mediaPlayer.pause();
// Create a new MediaPlayer rather than try to re-prepare the prior one.
mediaPlayer = createMediaPlayer(bufferedFile);
mediaPlayer.seekTo(curPosition);
// Restart if at end of prior buffered content or mediaPlayer was previously playing.
// NOTE: We test for < 1second of data because the media player can stop when there is still
// a few milliseconds of data left to play
boolean atEndOfFile = mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000;
if (wasPlaying || atEndOfFile){
mediaPlayer.start();
}
// Lastly delete the previously playing buffered File as it's no longer needed.
oldBufferedFile.delete();
}catch (Exception e) {
Log.e(getClass().getName(), "Error updating to newly loaded content.", e);
}
}
private void fireDataLoadUpdate() {
Runnable updater = new Runnable() {
public void run() {
textStreamed.setText((totalKbRead + " Kb read"));
float loadProgress = ((float)totalKbRead/(float)mediaLengthInKb);
progressBar.setSecondaryProgress((int)(loadProgress*100));
}
};
handler.post(updater);
}
private void fireDataFullyLoaded() {
Runnable updater = new Runnable() {
public void run() {
transferBufferToMediaPlayer();
// Delete the downloaded File as it's now been transferred to the currently playing buffer file.
downloadingMediaFile.delete();
textStreamed.setText(("Audio full loaded: " + totalKbRead + " Kb read"));
}
};
handler.post(updater);
}
public MediaPlayer getMediaPlayer() {
return mediaPlayer;
}
public void startPlayProgressUpdater() {
float progress = (((float)mediaPlayer.getCurrentPosition()/1000)/mediaLengthInSeconds);
progressBar.setProgress((int)(progress*100));
if (mediaPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
startPlayProgressUpdater();
}
};
handler.postDelayed(notification,1000);
}
}
public void interrupt() {
playButton.setEnabled(false);
isInterrupted = true;
validateNotInterrupted();
}
/**
* Move the file in oldLocation to newLocation.
*/
public void moveFile(File oldLocation, File newLocation)
throws IOException {
if ( oldLocation.exists( )) {
BufferedInputStream reader = new BufferedInputStream( new FileInputStream(oldLocation) );
BufferedOutputStream writer = new BufferedOutputStream( new FileOutputStream(newLocation, false));
try {
byte[] buff = new byte[8192];
int numChars;
while ( (numChars = reader.read( buff, 0, buff.length ) ) != -1) {
writer.write( buff, 0, numChars );
}
} catch( IOException ex ) {
throw new IOException("IOException when transferring " + oldLocation.getPath() + " to " + newLocation.getPath());
} finally {
try {
if ( reader != null ){
writer.close();
reader.close();
}
} catch( IOException ex ){
Log.e(getClass().getName(),"Error closing files when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
}
}
} else {
throw new IOException("Old location does not exist when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
}
}
}
Related
I'm downloading MP4 files from a Web app to a file on my mobile device. Since the files tend to be large, I want to start playing them as soon as I get some data, rather than wait until the whole file has been downloaded, so I've come up with the following scheme:
Download the first 1 MB of data to a file on my SD card.
Start the video player.
Download the remaining data in 1 MB chunks, appending the new data to the original file.
More precisely, the code does the following:
Create a FileOutputstream named out that writes to "/storage/sdcard/tmpAttachment"
Fetch up to 1 MB from the server and write it to /storage/sdcard/tmpAttachment
start the video player and have it start playing from the beginning of /storage/sdcard/tmpAttachment
while (more data)
Fetch next 1 MB chunk and write to out
endwhile
The actual code is as follows:
File file = new File(Environment.getExternalStorageDirectory() + "/tmpAttachment");
if (file.exists() && !file.delete()) { //Delete the old file if it exists
postRes = mContext.getString(R.string.message_view_dynamic_content_delete_error);
mHandler.post(mUpdateResults);
return;
}
FileOutputStream out = new FileOutputStream(file);
reply = Utility.doFetchSegment(mAccount, mMessage.getFrom()[0].getAddress() + Utility.BLANK + contentPointers[i] + Utility.BLANK + "0", "https://" + contentServerName + ":" + contentServerPort, mAccount.getEmail(), contentServerPassword, true, out, null);
if (reply[0].equals("13")) {
Uri attachmentUri = Uri.fromFile(file);
attachmentViewIntent = new Intent(mContext, ECSVideoViewer.class);
try {
ECSVideoViewer.actionECSVideoViewer(mContext, attachmentUri);
} catch (Exception e) {
postRes = mContext.getString(R.string.message_view_dynamic_content_fetch_error) + e;
mHandler.post(mUpdateResults);
e.printStackTrace();
}
while (!fPtr.equals(contentLen)) {
reply = Utility.doFetchSegment(mAccount, mMessage.getFrom()[0].getAddress() + Utility.BLANK + contentPointers[i] + Utility.BLANK + fPtr, "https://" + contentServerName + ":" + contentServerPort, mAccount.getEmail(), contentServerPassword, true, out, null);
if (reply[0].equals("13")) {
fPtr = reply[1].substring(reply[1].indexOf("pointer=") + "pointer=".length(), reply[1].indexOf(", t"));
} else {
postRes = reply[1];
mHandler.post(mUpdateResults);
out.close();
return;
}
}
The code for ECSVideoViewer.java is as follows:
public class ECSVideoViewer extends Activity {
private static final String EXTRA_PATH = "path";
/**
* TODO: Set the path variable to a streaming video URL or a local media
* file path.
*/
private static VideoView mVideoView;
public static void actionECSVideoViewer(Context context, Uri uri) {
Intent i = new Intent(context, ECSVideoViewer.class);
i.putExtra(EXTRA_PATH, uri.getEncodedPath());
context.startActivity(i);
}
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.videoview);
mVideoView = (VideoView) findViewById(R.id.surface_view);
String path = getIntent().getStringExtra(EXTRA_PATH);
mVideoView.setVideoURI(Uri.parse(path));
mVideoView.setMediaController(new MediaController(this));
mVideoView.setOnErrorListener(new OnErrorListener() {
public boolean onError (MediaPlayer mp, int what, int extra) {
mVideoView.getCurrentPosition();
mVideoView.getBufferPercentage();
mVideoView.getDuration();
return true;
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion (MediaPlayer mp) {
mVideoView.pause();
}
});
mVideoView.requestFocus();
mVideoView.start();
}
public static void resume() {
mVideoView.resume();
}
public static void play() {
mVideoView.start();
}
public static int getCurrentPosition() {
return mVideoView.getCurrentPosition();
}
public static int getBufferPercentage() {
return mVideoView.getBufferPercentage();
}
public static int getDuration() {
return mVideoView.getDuration();
}
public static boolean isPlaying() {
return mVideoView.isPlaying();
}
}
The video starts playing OK, after loading the first block and while the next one is getting loaded, but for some reason, the player stops and throws an error when it tries to read the second 1 MB block of downloaded data, returning MEDIA_ERROR_UNKNOWN and MEDIA_ERROR_IO. Can anyone see what I'm doing wrong?
I'm building, inside my existing app, a player using the AudioTrack class,in MODE_STATIC, because i want to implement the timestretch and the loop points features.
The code is ok for start() and stop(), but when paused, if i try to resume, calling play() again, the status bar remain fixed and no audio is played.
Now, from the docs :
Public void pause ()Pauses the playback of the audio data. Data that has not been played >back will not be discarded. Subsequent calls to play() will play this data back. See >flush() to discard this data.
It seems so easy to understand but there is something that escapes me.
Can some one help me?
Is it necessary to create boolean variables like start, play, pause, stopAudio etc?
If yes, where is the utility of the methods inherited from the AudioTrack class?
In MODE_STREAM i have realized the project, using the above boolean variables., but i need the MODE_STATIC.
This is the code, thanks:
Button playpause, stop;
SeekBar posBar;
int sliderval=0;
int headerOffset = 0x2C;
File file =new File(Environment.getExternalStorageDirectory(), "raw.pcm");
int fileSize = (int) file.length();
int dataSize = fileSize-headerOffset ;
byte[] dataArray = new byte[dataSize];
int posValue;
int dataBytesRead = initializeTrack();
AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, dataBytesRead , AudioTrack.MODE_STATIC);
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
playpause= (Button)(findViewById(R.id.playpause));
stop= (Button)(findViewById(R.id.stop));
posBar=(SeekBar)findViewById(R.id.posBar);
// create a listener for the slider bar;
OnSeekBarChangeListener listener = new OnSeekBarChangeListener() {
public void onStopTrackingTouch(SeekBar seekBar) { }
public void onStartTrackingTouch(SeekBar seekBar) { }
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) { sliderval = progress;}
}
};
// set the listener on the slider
posBar.setOnSeekBarChangeListener(listener); }
public void toggleButtonSound(View button)
{
switch (button.getId())
{
case R.id.playpause:
play();
break;
case R.id.stop:
stop();
break;
}
}
private void stop() {
if(audioTrack.getState()==AudioTrack.PLAYSTATE_PLAYING ||
audioTrack.getState()==AudioTrack.PLAYSTATE_PAUSED || audioTrack.getState()==AudioTrack.PLAYSTATE_STOPPED)
{ audioTrack.stop();
resetPlayer();}
}
Context context;
private double actualPos=0;
public void pause() {}
public void play()
{
if (audioTrack.getPlayState()==AudioTrack.PLAYSTATE_PLAYING)
{ //Log.i("", "Play pressed in state "+audioTrack.getPlayState());
audioTrack.pause();
}
else if (audioTrack.getPlayState()==AudioTrack.PLAYSTATE_PAUSED)
{ //Log.i("", "Play pressed in state "+audioTrack.getPlayState());
audioTrack.play();
}
else if (audioTrack.getPlayState()==AudioTrack.PLAYSTATE_STOPPED)
{ //Log.i("", "Play pressed in state "+audioTrack.getPlayState());
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, dataSize, AudioTrack.MODE_STATIC);
audioTrack.write(dataArray, 0, dataBytesRead);
audioTrack.play();
}
posBar.setMax((int) (dataBytesRead/2)); // Set the Maximum range of the
audioTrack.setNotificationMarkerPosition((int) (dataSize/2));
audioTrack.setPositionNotificationPeriod(1000);
audioTrack.setPlaybackPositionUpdateListener(new OnPlaybackPositionUpdateListener() {
#Override
public void onPeriodicNotification(AudioTrack track) {
posBar.setProgress(audioTrack.getPlaybackHeadPosition());
Log.i("", " " + audioTrack.getPlaybackHeadPosition() + " " + dataBytesRead/2);
}
#Override
public void onMarkerReached(AudioTrack track) {
Log.i("", " End reached ");
audioTrack.pause();
audioTrack.flush();
audioTrack.release();
posBar.setProgress(0);
resetPlayer();}
});
}
private int initializeTrack() {
InputStream is;
BufferedInputStream bis;
DataInputStream dis;
int temp = 0;
try {
is = new FileInputStream(file);
bis = new BufferedInputStream(is);
dis = new DataInputStream(bis);
temp = dis.read(dataArray, 0, dataSize);
dis.close();
bis.close();
is.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return temp;
}
public void resetPlayer() {
audioTrack.flush();
audioTrack.release();
posBar.setProgress(0);
sliderval=0;
}
You see, you did implement AudioTrack so that even when its paused the contents of file still uploads to AudioTrack:
I don't know how it manage it but in my case I also pause data uploading to AT. Like:
while (byteOffset < fileLengh) {
if(isPaused)
continue;
ret = in.read(byteData, 0, byteCount);
if (ret != -1) { // Write the byte array to the track
audioTrack.write(byteData, 0, ret);
byteOffset += ret;
} else
break;
}
So then I unpause the AT the file uploading while cycle resumes too. I guess that's it. Also I have to mention that even when AT is playing the following:
if (audioTrack.getPlayState()==AudioTrack.PLAYSTATE_PLAYING)
and
if (audioTrack.getPlayState()==AudioTrack.PLAYSTATE_PAUSED)
doesn't work for me and getPlayState() always returns 1 (AudioTrack.PLAYSTATE_STOPPED) for me, no matter if its playing or has been paused.
I am trying to run Android's MediaPlayer using runOnUiThread. I did not caught any exception with setDataSource. But after that, nothing happens with MediaPlayer. It should give callback as surface changed and onPrepared.
It seems MediaPlayer doesn't support this way.
If it is true, are there any workarounds ?
I need this kind of logic because I need to get info with network query which is blocked. I need to run onSuccess from that.
What is your suggestion for this? Thanks very much!
onResume()
{
getInfo(xxx);
}
void getInfo(url, new DataListener() {
#Override
public void onDataSuccess(xxx) {
playVideoOnSuccess(xxx);
}
}
public void playVideoOnSuccess(xxx)
{
myBaseActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
try {
mPlayerListener = new VideoPlayerListener(null, content);
// create new mediaplayer
mVideoPlayer = VideoPlayer.getInstance();
mVideoPlayer.setVideoPlayerListener(mPlayerListener);
// setDataSource
mVideoPlayer.consumeContent(content);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
Here is a sample code that i used to play video hope this might help you in some way
public class VideoViewDemo extends Activity {
private static final String TAG = "VideoViewDemo";
private String current;
/**
* TODO: Set the path variable to a streaming video URL or a local media
* file path.
*/
private String path = "http://www.boisestatefootball.com/sites/default/files/videos/original/01%20-%20coach%20pete%20bio_4.mp4";
private VideoView mVideoView;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.videoview);
mVideoView = (VideoView) findViewById(R.id.surface_view);
runOnUiThread(new Runnable() {
public void run() {
playVideo();
}
});
}
private void playVideo() {
try {
// final String path = path;
Log.v(TAG, "path: " + path);
if (path == null || path.length() == 0) {
Toast.makeText(VideoViewDemo.this, "File URL/path is empty",
Toast.LENGTH_LONG).show();
} else {
// If the path has not changed, just start the media player
if (path.equals(current) && mVideoView != null) {
mVideoView.start();
mVideoView.requestFocus();
return;
}
current = path;
mVideoView.setVideoPath(getDataSource(path));
mVideoView.start();
mVideoView.setMediaController(new MediaController(this));
mVideoView.requestFocus();
}
} catch (Exception e) {
Log.e(TAG, "error: " + e.getMessage(), e);
if (mVideoView != null) {
mVideoView.stopPlayback();
}
}
}
private String getDataSource(String path) throws IOException {
if (!URLUtil.isNetworkUrl(path)) {
return path;
} else {
URL url = new URL(path);
URLConnection cn = url.openConnection();
cn.connect();
InputStream stream = cn.getInputStream();
if (stream == null)
throw new RuntimeException("stream is null");
File temp = File.createTempFile("mediaplayertmp", "dat");
temp.deleteOnExit();
String tempPath = temp.getAbsolutePath();
FileOutputStream out = new FileOutputStream(temp);
byte buf[] = new byte[128];
do {
int numread = stream.read(buf);
if (numread <= 0)
break;
out.write(buf, 0, numread);
} while (true);
try {
stream.close();
} catch (IOException ex) {
Log.e(TAG, "error: " + ex.getMessage(), ex);
}
return tempPath;
}
}
}
This work for me
I am in need of simple audio recording and playing example using AudioRecorder in android. I tried with MediaRecorder, it works fine.
You mean AudioRecord? Search e.g. "AudioRecord.OnRecordPositionUpdateListener" using Google Code Search. Btw, AudioRecord does recording, not playing.
See also:
Improve Android Audio Recording quality?
Android AudioRecord class - process live mic audio quickly, set up callback function
here is the sample code for audio record.
private Runnable recordRunnable = new Runnable() {
#Override
public void run() {
byte[] audiodata = new byte[mBufferSizeInBytes];
int readsize = 0;
Log.d(TAG, "start to record");
// start the audio recording
try {
mAudioRecord.startRecording();
} catch (IllegalStateException ex) {
ex.printStackTrace();
}
// in the loop to read data from audio and save it to file.
while (mInRecording == true) {
readsize = mAudioRecord.read(audiodata, 0, mBufferSizeInBytes);
if (AudioRecord.ERROR_INVALID_OPERATION != readsize
&& mFos != null) {
try {
mFos.write(audiodata);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// stop recording
try {
mAudioRecord.stop();
} catch (IllegalStateException ex) {
ex.printStackTrace();
}
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mRecordLogTextView.append("\n Audio finishes recording");
}
});
// close the file
try {
if (mFos != null)
mFos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
};
then you need two buttons (or one acts as different function in the different time) to start and stop the record thread.
mRecordStartButton = (Button) rootView
.findViewById(R.id.audio_record_start);
mRecordStartButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// initialize the audio source
int recordChannel = getChoosedSampleChannelForRecord();
int recordFrequency = getChoosedSampleFrequencyForRecord();
int recordBits = getChoosedSampleBitsForRecord();
Log.d(TAG, "recordBits = " + recordBits);
mRecordChannel = getChoosedSampleChannelForSave();
mRecordBits = getChoosedSampleBitsForSave();
mRecordFrequency = recordFrequency;
// set up the audio source : get the buffer size for audio
// record.
int minBufferSizeInBytes = AudioRecord.getMinBufferSize(
recordFrequency, recordChannel, recordBits);
if(AudioRecord.ERROR_BAD_VALUE == minBufferSizeInBytes){
mRecordLogTextView.setText("Configuration Error");
return;
}
int bufferSizeInBytes = minBufferSizeInBytes * 4;
// create AudioRecord object
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
recordFrequency, recordChannel, recordBits,
bufferSizeInBytes);
// calculate the buffer size used in the file operation.
mBufferSizeInBytes = minBufferSizeInBytes * 2;
// reset the save file setup
String rawFilePath = WaveFileWrapper
.getRawFilePath(RAW_PCM_FILE_NAME);
try {
File file = new File(rawFilePath);
if (file.exists()) {
file.delete();
}
mFos = new FileOutputStream(file);
} catch (Exception e) {
e.printStackTrace();
}
if (mInRecording == false) {
mRecordThread = new Thread(recordRunnable);
mRecordThread.setName("Demo.AudioRecord");
mRecordThread.start();
mRecordLogTextView.setText(" Audio starts recording");
mInRecording = true;
// enable the stop button
mRecordStopButton.setEnabled(true);
// disable the start button
mRecordStartButton.setEnabled(false);
}
// show the log info
String audioInfo = " Audio Information : \n"
+ " sample rate = " + mRecordFrequency + "\n"
+ " channel = " + mRecordChannel + "\n"
+ " sample byte = " + mRecordBits;
mRecordLogTextView.setText(audioInfo);
}
});
mRecordStopButton = (Button) rootView
.findViewById(R.id.audio_record_stop);
mRecordStopButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (mInRecording == false) {
Log.d(TAG, "current NOT in Record");
} else {
// stop recording
if (mRecordThread != null) {
Log.d(TAG, "mRecordThread is not null");
mInRecording = false;
Log.d(TAG, "set mInRecording to false");
try {
mRecordThread.join(TIMEOUT_FOR_RECORD_THREAD_JOIN);
Log.d(TAG, "record thread joins here");
} catch (InterruptedException e) {
e.printStackTrace();
}
mRecordThread = null;
// re-enable the start button
mRecordStartButton.setEnabled(true);
// disable the start button
mRecordStopButton.setEnabled(false);
} else {
Log.d(TAG, "mRecordThread is null");
}
}
}
});
then you can save the pcm data into a WAV file.
I am using SurfaceView to play streaming video and Media Player for streaming video. Can any one tell me how can I place media controller in surfaceview?
Here's my code:
package com.menu.donationvideos;
import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer.OnVideoSizeChangedListener;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.MediaController;
import android.widget.MediaController.MediaPlayerControl;
import android.widget.Toast;
import android.widget.VideoView;
import com.menu.R;
public class VideoPlay extends Activity implements OnBufferingUpdateListener, OnCompletionListener,
OnPreparedListener, OnVideoSizeChangedListener, SurfaceHolder.Callback
{
private static final String TAG = "MediaPlayerDemo";
private int mVideoWidth;
private int mVideoHeight;
SurfaceHolder holder;
VideoInfo videoInfo;
String pos,videoURL;
private MediaPlayer mMediaPlayer;
private SurfaceView mPreview;
private String path;
private boolean mIsVideoSizeKnown = false;
private boolean mIsVideoReadyToBePlayed = false;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.video_play);
Bundle bundle=new Bundle();
bundle=this.getIntent().getExtras();
pos=bundle.getString("position");
videoInfo=VideoList.m_video.get(Integer.parseInt(pos));
videoURL=videoInfo.getVideoFile();
try
{
mPreview = (SurfaceView)findViewById(R.id.mySurfaceView);
holder=mPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
catch(Exception e)
{
e.printStackTrace();
}
}
private void playVideo()
{
doCleanUp();
try
{
path = videoURL;
if (path == "")
{
Toast.makeText(VideoPlay.this,"URL Not found", Toast.LENGTH_LONG).show();
}
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setDataSource(path);
mMediaPlayer.setDisplay(holder);
mMediaPlayer.prepare();
mMediaPlayer.setOnBufferingUpdateListener(this);
mMediaPlayer.setOnCompletionListener(this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setScreenOnWhilePlaying(true);
mMediaPlayer.setOnVideoSizeChangedListener(this);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void onBufferingUpdate(MediaPlayer arg0, int percent)
{
Log.d(TAG,"Buffering:"+percent);
}
public void onCompletion(MediaPlayer arg0)
{
Log.d(TAG, "onCompletion called");
finish();
}
public void onVideoSizeChanged(MediaPlayer mp, int width, int height)
{
Log.v(TAG, "onVideoSizeChanged called");
if (width == 0 || height == 0)
{
Log.e(TAG, "invalid video width(" + width + ") or height(" + height + ")");
return;
}
mIsVideoSizeKnown = true;
mVideoWidth = width;
mVideoHeight = height;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown)
{
startVideoPlayback();
}
}
public void onPrepared(MediaPlayer mediaplayer)
{
Log.d(TAG, "onPrepared called");
mIsVideoReadyToBePlayed = true;
if (mIsVideoReadyToBePlayed && mIsVideoSizeKnown)
{
startVideoPlayback();
}
}
public void surfaceChanged(SurfaceHolder surfaceholder, int i, int j, int k)
{
Log.d(TAG, "surfaceChanged called");
}
public void surfaceDestroyed(SurfaceHolder surfaceholder)
{
Log.d(TAG, "surfaceDestroyed called");
}
public void surfaceCreated(SurfaceHolder holder)
{
Log.d(TAG, "surfaceCreated called");
playVideo();
}
#Override
protected void onPause()
{
super.onPause();
releaseMediaPlayer();
doCleanUp();
}
#Override
protected void onDestroy()
{
super.onDestroy();
releaseMediaPlayer();
doCleanUp();
}
private void releaseMediaPlayer()
{
if (mMediaPlayer != null)
{
mMediaPlayer.release();
mMediaPlayer = null;
}
}
private void doCleanUp()
{
mVideoWidth = 0;
mVideoHeight = 0;
mIsVideoReadyToBePlayed = false;
mIsVideoSizeKnown = false;
}
private void startVideoPlayback()
{
Log.v(TAG, "startVideoPlayback");
holder.setFixedSize(mVideoWidth, mVideoHeight);
mMediaPlayer.start();
}
}
do {
numread = stream.read(buf);
if (numread <= 0)
break;
totalBytesRead += numread;
totalKbRead = totalBytesRead/1000;
Log.e(getClass().getName(),"Buffered byte: " +totalBytesRead+"");
if(totalBytesRead>=100000){
if(mediaPlayer!=null){
int dura = mediaPlayer.getDuration();
if(mediaPlayer.getDuration()>=90000){
isInterrupted =false;
stream.close();
out.close();
out.flush();
break;
}
}
}
This is my code but I realized that media player doesnt start until streaming in progress.
I would suggest you take a look at the source code of VideoView, which combines everything at first place (or use VideoView instead of MediaPlayer itself)
hey nirav this code try it for media streaming
package com.pocketjourney.media;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Handler;
import android.util.Log;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* MediaPlayer does not yet support streaming from external URLs so this class provides a pseudo-streaming function
* by downloading the content incrementally & playing as soon as we get enough audio in our temporary storage.
*/
public class StreamingMediaPlayer {
private static final int INTIAL_KB_BUFFER = 96*10/8;//assume 96kbps*10secs/8bits per byte
private TextView textStreamed;
private ImageButton playButton;
private ProgressBar progressBar;
// Track for display by progressBar
private long mediaLengthInKb, mediaLengthInSeconds;
private int totalKbRead = 0;
// Create Handler to call View updates on the main UI thread.
private final Handler handler = new Handler();
private MediaPlayer mediaPlayer;
private File downloadingMediaFile;
private boolean isInterrupted;
private Context context;
private int counter = 0;
public StreamingMediaPlayer(Context context,TextView textStreamed, ImageButton playButton, Button streamButton,ProgressBar progressBar)
{
this.context = context;
this.textStreamed = textStreamed;
this.playButton = playButton;
this.progressBar = progressBar;
}
/**
* Progressivly download the media to a temporary location and update the MediaPlayer as new content becomes available.
*/
public void startStreaming(final String mediaUrl, long mediaLengthInKb, long mediaLengthInSeconds) throws IOException {
this.mediaLengthInKb = mediaLengthInKb;
this.mediaLengthInSeconds = mediaLengthInSeconds;
Runnable r = new Runnable() {
public void run() {
try {
downloadAudioIncrement(mediaUrl);
} catch (IOException e) {
Log.e(getClass().getName(), "Unable to initialize the MediaPlayer for fileUrl=" + mediaUrl, e);
return;
}
}
};
new Thread(r).start();
}
/**
* Download the url stream to a temporary location and then call the setDataSource
* for that local file
*/
public void downloadAudioIncrement(String mediaUrl) throws IOException {
URLConnection cn = new URL(mediaUrl).openConnection();
cn.connect();
InputStream stream = cn.getInputStream();
if (stream == null) {
Log.e(getClass().getName(), "Unable to create InputStream for mediaUrl:" + mediaUrl);
}
downloadingMediaFile = new File(context.getCacheDir(),"downloadingMedia.dat");
// Just in case a prior deletion failed because our code crashed or something, we also delete any previously
// downloaded file to ensure we start fresh. If you use this code, always delete
// no longer used downloads else you'll quickly fill up your hard disk memory. Of course, you can also
// store any previously downloaded file in a separate data cache for instant replay if you wanted as well.
if (downloadingMediaFile.exists()) {
downloadingMediaFile.delete();
}
FileOutputStream out = new FileOutputStream(downloadingMediaFile);
byte buf[] = new byte[16384];
int totalBytesRead = 0, incrementalBytesRead = 0;
do {
int numread = stream.read(buf);
if (numread <= 0)
break;
out.write(buf, 0, numread);
totalBytesRead += numread;
incrementalBytesRead += numread;
totalKbRead = totalBytesRead/1000;
testMediaBuffer();
fireDataLoadUpdate();
} while (validateNotInterrupted());
stream.close();
if (validateNotInterrupted()) {
fireDataFullyLoaded();
}
}
private boolean validateNotInterrupted() {
if (isInterrupted) {
if (mediaPlayer != null) {
mediaPlayer.pause();
//mediaPlayer.release();
}
return false;
} else {
return true;
}
}
/**
* Test whether we need to transfer buffered data to the MediaPlayer.
* Interacting with MediaPlayer on non-main UI thread can causes crashes to so perform this using a Handler.
*/
private void testMediaBuffer() {
Runnable updater = new Runnable() {
public void run() {
if (mediaPlayer == null) {
// Only create the MediaPlayer once we have the minimum buffered data
if ( totalKbRead >= INTIAL_KB_BUFFER) {
try {
startMediaPlayer();
} catch (Exception e) {
Log.e(getClass().getName(), "Error copying buffered conent.", e);
}
}
} else if ( mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000 ){
// NOTE: The media player has stopped at the end so transfer any existing buffered data
// We test for < 1second of data because the media player can stop when there is still
// a few milliseconds of data left to play
transferBufferToMediaPlayer();
}
}
};
handler.post(updater);
}
private void startMediaPlayer() {
try {
File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");
// We double buffer the data to avoid potential read/write errors that could happen if the
// download thread attempted to write at the same time the MediaPlayer was trying to read.
// For example, we can't guarantee that the MediaPlayer won't open a file for playing and leave it locked while
// the media is playing. This would permanently deadlock the file download. To avoid such a deadloack,
// we move the currently loaded data to a temporary buffer file that we start playing while the remaining
// data downloads.
moveFile(downloadingMediaFile,bufferedFile);
Log.e(getClass().getName(),"Buffered File path: " + bufferedFile.getAbsolutePath());
Log.e(getClass().getName(),"Buffered File length: " + bufferedFile.length()+"");
mediaPlayer = createMediaPlayer(bufferedFile);
// We have pre-loaded enough content and started the MediaPlayer so update the buttons & progress meters.
mediaPlayer.start();
startPlayProgressUpdater();
playButton.setEnabled(true);
} catch (IOException e) {
Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e);
return;
}
}
private MediaPlayer createMediaPlayer(File mediaFile)
throws IOException {
MediaPlayer mPlayer = new MediaPlayer();
mPlayer.setOnErrorListener(
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int extra) {
Log.e(getClass().getName(), "Error in MediaPlayer: (" + what +") with extra (" +extra +")" );
return false;
}
});
// It appears that for security/permission reasons, it is better to pass a FileDescriptor rather than a direct path to the File.
// Also I have seen errors such as "PVMFErrNotSupported" and "Prepare failed.: status=0x1" if a file path String is passed to
// setDataSource(). So unless otherwise noted, we use a FileDescriptor here.
FileInputStream fis = new FileInputStream(mediaFile);
mPlayer.setDataSource(fis.getFD());
mPlayer.prepare();
return mPlayer;
}
/**
* Transfer buffered data to the MediaPlayer.
* NOTE: Interacting with a MediaPlayer on a non-main UI thread can cause thread-lock and crashes so
* this method should always be called using a Handler.
*/
private void transferBufferToMediaPlayer() {
try {
// First determine if we need to restart the player after transferring data...e.g. perhaps the user pressed pause
boolean wasPlaying = mediaPlayer.isPlaying();
int curPosition = mediaPlayer.getCurrentPosition();
// Copy the currently downloaded content to a new buffered File. Store the old File for deleting later.
File oldBufferedFile = new File(context.getCacheDir(),"playingMedia" + counter + ".dat");
File bufferedFile = new File(context.getCacheDir(),"playingMedia" + (counter++) + ".dat");
// This may be the last buffered File so ask that it be delete on exit. If it's already deleted, then this won't mean anything. If you want to
// keep and track fully downloaded files for later use, write caching code and please send me a copy.
bufferedFile.deleteOnExit();
moveFile(downloadingMediaFile,bufferedFile);
// Pause the current player now as we are about to create and start a new one. So far (Android v1.5),
// this always happens so quickly that the user never realized we've stopped the player and started a new one
mediaPlayer.pause();
// Create a new MediaPlayer rather than try to re-prepare the prior one.
mediaPlayer = createMediaPlayer(bufferedFile);
mediaPlayer.seekTo(curPosition);
// Restart if at end of prior buffered content or mediaPlayer was previously playing.
// NOTE: We test for < 1second of data because the media player can stop when there is still
// a few milliseconds of data left to play
boolean atEndOfFile = mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition() <= 1000;
if (wasPlaying || atEndOfFile){
mediaPlayer.start();
}
// Lastly delete the previously playing buffered File as it's no longer needed.
oldBufferedFile.delete();
}catch (Exception e) {
Log.e(getClass().getName(), "Error updating to newly loaded content.", e);
}
}
private void fireDataLoadUpdate() {
Runnable updater = new Runnable() {
public void run() {
textStreamed.setText((totalKbRead + " Kb read"));
float loadProgress = ((float)totalKbRead/(float)mediaLengthInKb);
progressBar.setSecondaryProgress((int)(loadProgress*100));
}
};
handler.post(updater);
}
private void fireDataFullyLoaded() {
Runnable updater = new Runnable() {
public void run() {
transferBufferToMediaPlayer();
// Delete the downloaded File as it's now been transferred to the currently playing buffer file.
downloadingMediaFile.delete();
textStreamed.setText(("Audio full loaded: " + totalKbRead + " Kb read"));
}
};
handler.post(updater);
}
public MediaPlayer getMediaPlayer() {
return mediaPlayer;
}
public void startPlayProgressUpdater() {
float progress = (((float)mediaPlayer.getCurrentPosition()/1000)/mediaLengthInSeconds);
progressBar.setProgress((int)(progress*100));
if (mediaPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
startPlayProgressUpdater();
}
};
handler.postDelayed(notification,1000);
}
}
public void interrupt() {
playButton.setEnabled(false);
isInterrupted = true;
validateNotInterrupted();
}
/**
* Move the file in oldLocation to newLocation.
*/
public void moveFile(File oldLocation, File newLocation)
throws IOException {
if ( oldLocation.exists( )) {
BufferedInputStream reader = new BufferedInputStream( new FileInputStream(oldLocation) );
BufferedOutputStream writer = new BufferedOutputStream( new FileOutputStream(newLocation, false));
try {
byte[] buff = new byte[8192];
int numChars;
while ( (numChars = reader.read( buff, 0, buff.length ) ) != -1) {
writer.write( buff, 0, numChars );
}
} catch( IOException ex ) {
throw new IOException("IOException when transferring " + oldLocation.getPath() + " to " + newLocation.getPath());
} finally {
try {
if ( reader != null ){
writer.close();
reader.close();
}
} catch( IOException ex ){
Log.e(getClass().getName(),"Error closing files when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
}
}
} else {
throw new IOException("Old location does not exist when transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
}
}
}