android soundpool heapsize overflow - android

I get this error hundreds of times when I run in Debug, it doesn't seem to affect the program, but how do I get rid of it?
I know it can be traced back to the SoundPool based on other posts
09-15 09:03:09.190: ERROR/AudioCache(34): Heap size overflow! req size: 1052672, max size: 1048576

SoundPool is hard code the buffer size as 1M for all loaded file. So you probably will get 'heap size overflow' error when you load too much files into SoundPool. I also have this issue on a game project that will load game sound FX into SoundPool and the solution is as follow:
Play long/large background music in MediaPlayer.
Play short sound files in multi SoundPool instances to prevent the heap error. The sample code for multi SoundPools:
/**
* Multi SoundPool to prevent memory error.
*/
public class SoundPools {
private static final String TAG = "SoundPools";
private static final int MAX_STREAMS_PER_POOL = 15;
private List<SoundPoolContainer> containers;
public SoundPools() {
containers = Collections.synchronizedList(new ArrayList<SoundPoolContainer>());
}
public void loadSound(Context context, String id, String file) {
Log.d(TAG, "SouldPools load sound " + file);
try {
for (SoundPoolContainer container : containers) {
if (container.contains(id)) {
return;
}
}
for (SoundPoolContainer container : containers) {
if (!container.isFull()) {
container.load(context, id, file);
return;
}
}
SoundPoolContainer container = new SoundPoolContainer();
containers.add(container);
container.load(context, id, file);
} catch (Exception e) {
Log.w(TAG, "Load sound error", e);
}
}
public void playSound(Context context, String id, String file) {
Log.d(TAG, "SouldPools play sound " + file);
try {
for (SoundPoolContainer container : containers) {
if (container.contains(id)) {
container.play(context, id, file);
return;
}
}
for (SoundPoolContainer container : containers) {
if (!container.isFull()) {
container.play(context, id, file);
return;
}
}
SoundPoolContainer container = new SoundPoolContainer();
containers.add(container);
container.play(context, id, file);
} catch (Exception e) {
Log.w(TAG, "Play sound error", e);
}
}
public void onPause() {
for (SoundPoolContainer container : containers) {
container.onPause();
}
}
public void onResume() {
for (SoundPoolContainer container : containers) {
container.onResume();
}
}
private static class SoundPoolContainer {
SoundPool soundPool;
Map<String, Integer> soundMap;
AtomicInteger size;
public SoundPoolContainer() {
this.soundPool = new SoundPool(MAX_STREAMS_PER_POOL, android.media.AudioManager.STREAM_MUSIC, 0);
this.soundMap = new ConcurrentHashMap<String, Integer>(MAX_STREAMS_PER_POOL);
this.size = new AtomicInteger(0);
}
public void load(Context context, String id, String file) {
try {
this.size.incrementAndGet();
soundMap.put(id, soundPool.load(context.getAssets().openFd(file), 1));
} catch (Exception e) {
this.size.decrementAndGet();
Log.w(TAG, "Load sound error", e);
}
}
public void play(Context context, String id, String file) {
android.media.AudioManager audioManager = (android.media.AudioManager) context
.getSystemService(Context.AUDIO_SERVICE);
final int streamVolume = audioManager.getStreamVolume(android.media.AudioManager.STREAM_MUSIC);
Integer soundId = soundMap.get(id);
if (soundId == null) {
soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() {
#Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
soundPool.play(sampleId, streamVolume, streamVolume, 1, 0, 1f);
}
});
try {
this.size.incrementAndGet();
soundPool.load(context.getAssets().openFd(file), 1);
} catch (IOException e) {
this.size.decrementAndGet();
Log.w(TAG, "Load/Play sound error", e);
}
} else {
try {
soundPool.play(soundId, streamVolume, streamVolume, 1, 0, 1f);
} catch (Exception e) {
Log.w(TAG, "Play sound error", e);
}
}
}
public boolean contains(String id) {
return soundMap.containsKey(id);
}
public boolean isFull() {
return this.size.get() >= MAX_STREAMS_PER_POOL;
}
public void onPause() {
try {
soundPool.autoPause();
} catch (Exception e) {
Log.w(TAG, "Pause SoundPool error", e);
}
}
public void onResume() {
try {
soundPool.autoResume();
} catch (Exception e) {
Log.w(TAG, "Resume SoundPool error", e);
}
}
}
}

Maybe your media resource is too big for playing with soundpool. Soundpool only plays short sound effects. On the Soundpool API there is no specification about the maximum of a resource for playing with soundpool, but if You use it, play just short sound effects like, for example, a short explosion in a shooter game.
If this is Your problem, You should use MediaPlayer for playing your sounds.

It is not possible for this error to be about heap size, because there aren't any device with such a small heap 1052672 ~ 1Mb., but about SoundPool buffer size.
SoundPool has hardcoded limit of 1Mb of raw PCM_16 data in memory. This limit applies for every sound you are loading into memory, and not for sounds in sum per one SoundPool. So the most voted answer about SoundPools is very wrong!
Let me introduce SoundPoolCompat which uses AudioTrack under the hood and have custom bufferSize. All data within specified buffer will be loaded into memory and played with small latency like SoundPool does. All data that exceed that bufferSize will be loaded on demand (which adds latency, similar to MediaPlayer). Api is very similart to SoundPool, also it is added a feature to load sounds from Uri (for example gdrive). And there is playOnce method, all resources will be unloaded after file is played.
implementation 'com.olekdia:sound-pool:3.0.2'
https://gitlab.com/olekdia/common/libraries/sound-pool

Related

Android MediaPlayer Streaming YouTube audio stream unexpected LOUD static

What I'm attempting:
I'm using youtube-dl in a Python Daemon on a remote server to get a URL.
That URL is fed into an Android App into a MediaPlayer instance.
What is happening:
Occasionally and unexpectedly the Media player will BLAST static and play at normal speed, sometimes it will blast static and play at 1.5 times speed.
Here's a video of what happens. HEADPHONE WARNING
YouTube Video
Observations:
If there is static it is for the whole song (it isn't intermittent).
I've taken the URLs it provides and they play fine in a PC browser with no static.
It happens on different phones, and it is not just my particular phone.
It takes longer to start tracks that end up being staticy.
Tracks that are staticy make my progress bar (seconds minutes display) just behave strangely. I've seen it count up and down in the first couple seconds, and there is the 1.5x speed I was talking about.
MediaHTTPConnection throws alot of exceptions that I don't know how to handle.
E/MediaHTTPConnectionEx: disconnecting
E/MediaHTTPConnectionEx: RuntimeException: Unbalanced enter/exit
mConnection.disconnect();
Below is the portion of my Python daemon that returns the URL
ydl_opts = {
'skip_download':True, # We just want to extract the info
'format':'bestaudio',
'forceurl':True,
'ignoreerrors':True,
'youtube_include_dash_manifest':False,
'restrict_filenames':True,
'source_address':'10.1.0.38',#we have to set this to force ipv4
'logger': MyLogger()
}
def ytdl(self, url):
url2 = "https://www.youtube.com/watch?v="+url
ydl.download([url2])
Here's the (basically boilerplate) MediaPlayer
public static Stack<Track> tracks = new Stack<>();
private static MediaPlayer mediaPlayer;
private String mediaFile;
private static int duration = 0;
private AudioManager audioManager;
private Boolean userPause = false;
// Binder given to clients
private final IBinder iBinder = new LocalBinder();
public static final String TAG = "Player";
#Override
public IBinder onBind(Intent intent) {
return iBinder;
}
class LocalBinder extends Binder {
Player getService() {
return Player.this;
}
}
public static void seekTo(int msec){
if(mediaPlayer != null){
mediaPlayer.seekTo(msec);
}
}
//The system calls this method when an activity, requests the service be started
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
boolean success = true;
//An audio file is passed to the service through putExtra();
if(intent.hasExtra("uri")){
mediaFile = intent.getStringExtra("uri");
} else {
stopSelf();
success = false;
}
//Request audio focus
if (!requestAudioFocus()) {
//Could not gain focus
Log.d(TAG, "error requesting audio focus");
stopSelf();
success = false;
}
if (mediaFile != null && !mediaFile.equals("") && success) {
Log.d(TAG, "Media File:" + mediaFile);
success = initMediaPlayer();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
//we cant destroy the player here because the back button fires this
//maybe i can not fire super?
super.onDestroy();
/*if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop();
}
mediaPlayer.release();
}
removeAudioFocus();*/
}
private boolean initMediaPlayer() {
boolean error = false;
//one time setup
if(mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
//setup listeners
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setOnErrorListener(this);
mediaPlayer.setOnPreparedListener(this);
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnSeekCompleteListener(this);
mediaPlayer.setOnInfoListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
//Reset so that the MediaPlayer is not pointing to another data source
mediaPlayer.reset();
try {
Log.d(TAG, "setDataSource");
mediaPlayer.setDataSource(mediaFile);
} catch (IOException e) {
Log.e(TAG,"setDataSource error:"+e);
error = true;
}
try {
Log.d(TAG, "prepare");
mediaPlayer.prepare();
} catch (IOException e) {
Log.d(TAG, "prepare error");
e.printStackTrace();
error = true;
}
return error;
}
#Override
public void onPrepared(MediaPlayer mp) {
//Invoked when the media source is ready for playback.
Log.d(TAG, "onPrepared");
mp.start();
duration = mp.getDuration();
}
#Override
public void onCompletion(MediaPlayer mp) {
//Invoked when playback of a media source has completed.
removeAudioFocus();
mp.stop();
mp.reset();
}
#Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
//Invoked to communicate some info.
return false;
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
//Invoked indicating buffering status of
//a media resource being streamed over the network.
if(percent%25==0)
Log.d(TAG, "buffering:"+percent);
}
#Override
public void onSeekComplete(MediaPlayer mp) {
//Invoked indicating the completion of a seek operation.
Log.d(TAG, "onSeekComplete() current pos : " + mp.getCurrentPosition());
SystemClock.sleep(200);
start();
}
//Handle errors
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
//Invoked when there has been an error during an asynchronous operation
switch (what) {
case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
Log.e(TAG, "MEDIA ERROR NOT VALID FOR PROGRESSIVE PLAYBACK " + extra);
break;
case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
Log.e(TAG, "MEDIA ERROR SERVER DIED " + extra);
break;
case MediaPlayer.MEDIA_ERROR_UNKNOWN:
Log.e(TAG, "MEDIA ERROR UNKNOWN " + extra);
//NowPlaying.error = true;
break;
default:
Log.e(TAG, what + "," + extra);
break;
}
PlayerActivity.error = true;
return false;
}
#Override
public void onAudioFocusChange(int focusState) {
//Invoked when the audio focus of the system is updated.
switch (focusState) {
case AudioManager.AUDIOFOCUS_GAIN:
// resume playback
mediaPlayer.setVolume(1.0f, 1.0f);
if(!mediaPlayer.isPlaying()
&& !userPause) {
pause(false);
}
break;
case AudioManager.AUDIOFOCUS_LOSS:
// Lost focus for an unbounded amount of time: stop playback and release media player
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
removeAudioFocus();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
// Lost focus for a short time, but we have to stop
// playback. We don't release the media player because playback
// is likely to resume
if (mediaPlayer.isPlaying()) mediaPlayer.pause();
break;
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
// Lost focus for a short time, but it's ok to keep playing
// at an attenuated level
if (mediaPlayer.isPlaying()) mediaPlayer.setVolume(0.1f, 0.1f);
break;
}
}
private boolean requestAudioFocus() {
int result = 0;
if(audioManager == null) audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager != null) {
result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
}
Log.d(TAG, "requestAudioFocus:"+result);
return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
//Could not gain focus
}
private void removeAudioFocus() {
audioManager.abandonAudioFocus(this);
}
boolean isPlaying() {
if(mediaPlayer != null)
return mediaPlayer.isPlaying();
return false;
}
//pause(true) == pause
//pause(false) == play
//this is used by the system
void pause(Boolean state){
//pause
if (state) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
} else {
if (!mediaPlayer.isPlaying()) {
start();
}
}
}
//this is a pause toggle that is only triggered by the pause/play button
boolean pause() {
if (mediaPlayer.isPlaying()){
userPause = true;
mediaPlayer.pause();
} else {
userPause = false;
start();
}
return !mediaPlayer.isPlaying();
}
void start(){
mediaPlayer.start();
}
int getCurrentPosition(){
if(mediaPlayer != null)
return mediaPlayer.getCurrentPosition();
return 0;
}
int getDuration(){
return duration;
}
}
I feel like someone else is going to have this problem so I'm going to post my solution.
So I noticed a mime type error popped up for every track. The error still shows up now that I've fixed this problem but the loud static has stopped.
Here is the error that started the wheels turning:
E/MediaHTTPConnectionEx: getMIMEType
[seekToEx] offset:0/mCurrentOffset:-1
I noticed some of the URLs youtube-dl was giving me for the webm didn't have a mime type specified in the URL.
Here is an example:
...O8c2&mime=&pl=...
But all of the m4a streams had a mime type in the URL
...70F61&mime=audio%2Fmp4&itag=140&key...
So I think that while my solution isn't the best solution, it's the easiest. Since ALL the m4a streams had a mime specified I just limited myself to those streams.
The rub is this:
I'm pretty sure that if I just checked the URL for a specified mime field I could still play most webm files. The only ones that were failing (staticy) were URLs that did not have that field.
My solution:
Python only pulls m4a files:
...
'format':'bestaudio[ext=m4a]',
...
Android now passes hard coded headers:
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "audio/mp4"); // change content type if necessary
Uri uri = Uri.parse(mediaFile);
Log.d(TAG, "getMimeType="+getMimeType(uri));//this is ALWAYS null
mediaPlayer.setDataSource(getApplicationContext(), uri, headers);

Media Player with multiple mp3 files issue

I have a piano app working with this method:
public void play(String note) {
score++;
score();
try {
mp = MediaPlayer.create(this, getResources().getIdentifier(note, "raw", getPackageName()));
mp.start();
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer media) {
media.release();
}
});
} catch (Exception e) {
Log.e("Error", "error playing file : " + note + "\n" + e);
}
}
The issue is that if I press the keys too fast and several times i get errors like this:
E/MediaPlayer: error (1, -19)
These errors occur as I go on playing. But when I uninstall the app, something seems to reset, and I get less errors...Why is this happening and is there a solution for it?
As your code implies you are playing notes and not long MP3s, I suggest you use SoundPool instead of MediaPlayer. It is better suited for this kind of application as it pre-loads all the resources in advance.
An example of this kind of implementation:
private SoundPool soundPool;
private HashMap<String, Integer> soundNameToSoundIdMap;
private void initSoundMap() {
soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);
soundNameToSoundIdMap = new HashMap<String, Integer>();
soundNameToSoundIdMap.put("note_a", loadSound(getContext(), R.raw.note_a));
soundNameToSoundIdMap.put("note_b", loadSound(getContext(), R.raw.note_b));
}
private int loadSound(Context context, int resId) {
return soundPool.load(context, resId, 1);
}
public void play(String note) {
score++;
score();
Integer soundId = soundNameToSoundIdMap.get(note);
if (soundId != null){
soundPool.play(soundId.intValue(), 100, 100, 1, 0, 0);
}
}

Media Player using AudioTrack class does not resume after pause()

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.

Recognize Stop AudioTrack

How to detect if an AudioTrack has finished playing? it's not simple!!!
I need to touch immediately after the other (enqueue) This code is not working ...
When press 2 times, the 1st not end, and two sound plays same time...
private void getNextAudio() {
try{
byte[] buffer = playlist.poll();
if (buffer != null) {
AudioTrack myatrack = getAudioTrack(buffer);
myatrack.setPlaybackPositionUpdateListener( new OnPlaybackPositionUpdateListener() {
public void onPeriodicNotification(AudioTrack track) {
}
public void onMarkerReached(AudioTrack track) {
Log.d(TAG, "onMarker - estado: " + track.getPlayState());
if(track.getPlayState() == AudioTrack.PLAYSTATE_STOPPED){
track.flush();
track.stop();
track.release();
getNextAudio();
}
}
});
if (myatrack != null) {
// toco o audio.
myatrack.play();
}
}else{
Log.d(TAG,"Finish");
}
}catch(NoSuchElementException ex){
Log.d(TAG,"No such element");
}
}
Thanks again!
Mateus

is it possible to display video information from an rtsp stream in an android app UI

I have managed to get a working video player that can stream rtsp links, however im not sure how to display the videos current time position in the UI, i have used the getDuration and getCurrentPosition calls, stored this information in a string and tried to display it in the UI but it doesnt seem to work
**in main.xml:**
TextView android:id="#+id/player"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="1px"
android:text="#string/cpos"
/>
**in strings.xml:**
string name="cpos">"" /string>
**in Player.java**
private void playVideo(String url) {
try {
media.setEnabled(false);
if (player == null) {
player = new MediaPlayer();
player.setScreenOnWhilePlaying(true);
} else {
player.stop();
player.reset();
}
player.setDataSource(url);
player.getCurrentPosition();
player.setDisplay(holder);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.prepareAsync();
player.setOnBufferingUpdateListener(this);
player.setOnCompletionListener(this);
} catch (Throwable t) {
Log.e(TAG, "Exception in media prep", t);
goBlooey(t);
try {
try {
player.prepare();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.v(TAG, "Duration: ===> " + player.getDuration());
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private Runnable onEverySecond = new Runnable() {
public void run() {
if (lastActionTime > 0
&& SystemClock.elapsedRealtime() - lastActionTime > 3000) {
clearPanels(false);
}
if (player != null) {
timeline.setProgress(player.getCurrentPosition());
//stores getCurrentPosition as a string
cpos = String.valueOf(player.getCurrentPosition());
System.out.print(cpos);
}
if (player != null) {
timeline.setProgress(player.getDuration());
//stores getDuration as a string
cdur = String.valueOf(player.getDuration());
System.out.print(cdur);
}
if (!isPaused) {
surface.postDelayed(onEverySecond, 1000);
}
}
};
Your code snippet looks significantly like my vidtry sample. getCurrentPosition() and getDuration() works for HTTP streaming, such as for use in updating the progress bar.
I have not tried vidtry with an RTSP video stream, mostly because I don't know of any.
Check the SDP response from the server to ensure that it is sending the duration in the response (live streams don't have a recognizable time and that may cause the client to not provide this information.)
E.g. a live feed will look like:
a=range:npt=0-
Whereas a VoD clip should look like:
a=range:npt=0-399.1680
If getCurrentPosition() doesn't work, but you know the Duration (either getDuration() works or you have an alternate way of getting this information; you could calculate it by watching the buffering events and tracking this your self. Your approach is the more desirable approach than this one.
If I got you right, you want to show in a TextView elapsed time e.g. hh:mm:ss?
If so, I'll give you a little walkthrough on how to do that.
private TextView mElapsedTimeText;
private VideoView mVideoView;
private Thread mThread;
#Override
public void onCreate(Bundle savedInstanceState) {
/* here goes your code */
// let's assume that your IDs are elapsedId and videoId
mElapsedTimeText = (TextView) findViewById(R.id.elapsedId);
mVideoView = (VideoView) findViewById(R.id.videoId);
mThread = new Thread() {
#Override
public void run() {
mElapsedTime.setText(getNiceString());
mVideoView.postDelayed(mThread, 1000);
}
}
/* here goes your code */
}
public String getNiceString() {
String result = "";
int position = mVideoView.getCurrentPosition();
/* here goes your code */
//result is hh:mm:ss formatted string
return result;
}
#Override
public void onPrepared(MediaPlayer mp) {
/* here goes your code */
// you have to trigger the process somewhere
mVideoView.postDelayed(mThread, 1000);
/* here goes your code */
}
And one more thing I forgot to mention. In order to make this work your activity class has to implement the OnPreparedListener interface.
I hope you or someone else will find this post useful.
Best regards,
Igor

Categories

Resources