The setVideoURI method of VideoView in Android seems to be blocking the UI thread. As soon as I call this method, the UI get's laggy, even on fast devices. Is there a way to improve performance here?
The only other thread with that topic I could find here:
https://groups.google.com/forum/#!topic/android-developers/eAAEAEDcksM
but it's quite old and doesn't have a satisfying answer.
VideoView.setVideoURI() starts a new thread for media playback, but it is the media decoding part which causes extra delay.The only solution that might be ok for you is using some NDK hacks, but doesn't worths for me
What i did was place the setVideoUri() method into a handler with a looper i.e.
new Handler(Looper.myLooper()).post(new Runnable(){
#Override
public void run(){
videoview.setVideoUri("uri");
}
});
this runs the code outside the main UI thread, but keeps it in a looper so the code can be executed without throwing an exception
I have found that VideoView not blocking UI thread. Actually in the receiver of "android.media.VOLUME_CHANGED_ACTION" blocking UI thread.
My problem code:
public void setVolume(int volume) {
try {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
ivVoice.setTag(volume != 0);
updateVoiceImage();
} catch (Exception e) {
e.printStackTrace();
}
}
setVolume called from volume receiver , it has called 1000+ times when playing a 5s mp4.
audioManager.setStreamVolume takes too long in main thread.
solution codeļ¼
public void setVolume(int volume) {
try {
//if volume not changed , do nothing.
if(volume != lastVolume){
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,volume,0);
ivVoice.setTag(volume != 0);
updateVoiceImage();
lastVolume = volume;
}
} catch (Exception e) {
e.printStackTrace();
}
}
So, please check your volume receiver. Maybe it can helps you.
VideoView myVideoView = (VideoView)findViewById(R.id.myvideoview);
myVideoView.setVideoURI(Uri.parse(url));
myVideoView.setMediaController(new MediaController(this));
myVideoView.requestFocus();
myVideoView.start();
i used this code may it will help you
Related
What i have:
I have implemented three MediaPlayer.Objects in my App.
All Three are created using a thread:
protected void onResume() {
// Threads
mTT1 = new TrackThread(this, R.raw.audiofile1, 1, mHandler);
mTT2 = new TrackThread(this, R.raw.audiofile2, 2, mHandler);
mTT3 = new TrackThread(this, R.raw.audiofile3, 3, mHandler);
// start thread
mTT1.start();
mTT2.start();
mTT3.start();
super.onResume();
}
"simplified" Code in the Thread for creating:
public class TrackThread extends Thread implements OnPreparedListener {
...
...
...
public void run() {
super.run();
try {
mMp.setDataSource(afd.getFileDescriptor(),
afd.getStartOffset(), afd.getDeclaredLength());
mMp.prepare();
} catch (IllegalArgumentException | IllegalStateException
| IOException e) {
Log.e(TAG, "Unable to play audio queue do to exception: "
+ e.getMessage(), e);
}
}
As I read in several Tutorials the "prepare()" methode takes a little bit of time to finish. Therefore i implemented a "Waiting loop" which waits until all MPs are prepared and created.
When "prepare and create" are done i enable the Start button and i want to start all 3 Mediaplayers SIMULTANEOUSLY.
I again use a Thread for dooing so:
public void onClick(View v) {
// Button 1
if (mBtn.getId() == v.getId()) {
mTT1.startMusic();
mTT2.startMusic();
mTT3.startMusic();
}
Code in the thread:
public class TrackThread extends Thread implements OnPreparedListener {
...
...
...
// start
public void startMusic() {
if (mMp == null)
return;
mMp.start();
}
Please note that the code above is not the full code, but it should be enough to define my problem.
What i want, My problem:
All MPs should play their Music in Sync, unfortunately sometimes when i start the music, there is a time delay between them.
The MPs must start at the exact same time as the 3Audio-files must be played simultaneously (and exactly in sync)
What i have already tried:
+) using SoundPool: My Audio-files are to big(5Megabyte and larger) for SoundPool
+) seekTo(msec): i wanted to seek every MP to a Specific time: eg.: 0, but this did not solve the problem.
+) to reach more Programmers i also asked this question on: coderanch.com
I hope somebody can help me!
Thanks in advance
The bottleneck here will certainly be preparing the mediaplayers to play. The Android framework provides an asynchronous method to perform this loading, and so with a bit of synchronization code you should be able to get these audio sources to play at roughly the same time. To keep from sound artifacting, you'll want less than 10ms of latency.
Initialize an atomic counter, C, to the number of things to load.
Use the prepareAsync() functions within MediaPlayer to prepare all three. Immediately after calling prepareAsync, supply a listener using setOnPreparedListener(listener).
Inside this listener, decrement C and check the value. If the value is greater than 0, wait on an object using the java object .wait() function. If the value is equal to 0, call notifyAll() on the object to wake up all of the other mediaplayer prepared-listener callback threads.
public void startMediaPlayers(List<MediaPlayer> mediaPlayers) {
private AtomicInteger counter = new AtomicInteger(mediaPlayers.size());
Object barrier = new Object();
/* start off all media players */
for (MediaPlayer player : mediaPlayers) {
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(final MediaPlayer mediaPlayer) {
int value = counter.decrementAndGet();
if (value == 0) {
// all media players are done loading.
// wake up all the ones that are asleep
barrier.notifyAll();
} else {
while (value > 0) {
try {
// wait for everyone else to load
barrier.wait();
} catch (InterruptedException e) {
// ignore
}
}
}
mediaPlayer.start();
callback.success(true);
}
player.prepareAsync();
}
}
As nobody could help me I found a solution on my own. MediaPlayer did not fulfill my requirements but Android JETPlayer in combination with JETCreator did.
CAUTION: Installing Python for using JETCreator is very tricky, therfore
follow this tutorial. And be careful with the versions of python and wxpython, not all versions support the JETCreator.
I used:
Python Version 2.5.4 (python-2.5.4.msi)
wxPython 2.8 (wxPython2.8-win32-unicode-2.8.7.1-py25.exe)
For those who do not know how to implement the Jetplayer watch this video
(at min.5 he starts with programming the Jetplayer).
Unfortunately I do not speak French so I just followed the code which worked for me.
Using Android JETCreator you can create your own JET Files and use them as your resource.
Useful links:
Demo data
Manual
Code/class
for last three weeks I have worked on a Media Player in Android.I am trying to find a solution of how can I make my Media Player to change the song when it's already playing one.
Here is my Listener on the RecyclerView
musicList.addOnItemTouchListener(
new RecyclerItemClickListener(getApplicationContext(), new RecyclerItemClickListener.OnItemClickListener() {
#Override
public void onItemClick(View view, final int position) {
currentPosition = position;
if(!mediaPlayer.isPlaying()){
musicThread.start();
} else {
mediaPlayer.reset();
}
}
})
);
}
and my Thread is this:
final Thread musicThread = new Thread(new Runnable(){
#Override
public void run() {
try {
URL = getMusicURL(myDataset[currentPosition]);
try {
mediaPlayer.setDataSource(URL);
//mediaPlayer.prepare(); // might take long! (for buffering, etc)
mediaPlayer.prepareAsync(); // prepare async to not block main thread
} catch (IOException e) {
e.printStackTrace();
Log.i("TEST","Eroare: "+e.getMessage());
}
} catch (StorageApiException e) {
e.printStackTrace();
Log.i("TEST","Eroare: "+e.getMessage());
}
}
});
I think you have a mess. First of all, you dont need a thread to play music, the own mediaplayer API does it for you when you call mediaPlayer.start(). However, you have to care about the time it takes to prepare the data source if you are for example streaming online music. For this, just use mediaPlayer.prepareAsync() and register a callback. When it has finished preparing, you can automatically start playing or do whatever you want.
If you want to change the data source, just follow the automaton map that you can find in MediaPlayer docs. Essentially, when the user selects another track, you register the call in your button listener, then reset the mediaPlayer, and recall all prepare, start... cycle again. By the way, it is advised to deploy all your mediaplayer code into a service so that it can keep playing even though the user has closed your activity.
I have tried all methods mentioned in the following links
How to shut off the sound MediaRecorder plays when the state changes
Need to shut off the sound MediaRecorder plays when the state changes
but none of them work.
Anyone knows how to achieve that ?
Though I am too late to answer it. It may still help peoples who all are googling the same problem.
Before starting media recorder add following two lines of code ..
Its gonna mute phones sound..
//mute phone
AudioManager audioManager = (AudioManager) context.getSystemService(AUDIO_SERVICE);
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
mediaRecorder.start();
After starting media recorder wait one or two seconds and un-mute the phone, u may use following runnable...
new Thread(new UnmuterThread()).start();
//timer thread to un-mute phone after 1 sec
//This is runnable inner class inside your activity/service
class UnmuterThread implements Runnable{
#Override
public void run() {
synchronized (this){
try {
wait(1000);
} catch (InterruptedException e) {
} finally {
//unmute the phone
AudioManager audioManager1 = (AudioManager) context.getSystemService(AUDIO_SERVICE);
audioManager1.setRingerMode(AudioManager.RINGER_MODE_NORMAL); }
}
}
}
I am using the Android MediaPlayer class and trying to write a testcase which verifies that the onCompletion method is called.
I use it to play the next track after the previous one is finished.
When I run the app using the emulator (2.1 or 4.0) the onCompletion method is called and the next track starts playing, but in the testcase it is not.
Here is the simplified code:
public class MediaPlayerControllerTest extends AndroidTestCase implements OnCompletionListener {
public void testContinuePlayNextTrack() {
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setOnCompletionListener(this);
try {
mediaPlayer.setDataSource("/mnt/sdcard/5749/01.mp3");
mediaPlayer.prepare();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mediaPlayer.start();
}
#Override
public void onCompletion(MediaPlayer mp) {
System.out.println("ON COMPLETION!!!!!");
}
}
The code above is normally part of a class MediPlayerController which is used in the app and the test, so it's the same class. I broke the problem down to the few lines of code above.
This cost me a lot of hours. I hope someone has a solution!
Thanks a lot!!!
I have encountered this problem, and nothing was working for me. From the official Site (click me) for the MediaPlayer one can find the following sentence:
In order to receive the respective callback associated with these listeners, applications are required to create MediaPlayer objects on a thread with its own Looper running (main UI thread by default has a Looper running).
I was a bit lost, as there was no hint for this need on in the API for onCompletionListener himself.
I think the problem is that your test case is no longer running when the MediaPlayer finishes playing the mp3. So your solution is to keep the test case alive until the onCompletion() is fired.
I had a similar issue when playing a file from an IntentService. The Service was being destroyed before the callback was initiated.
Actually, the reason is that the MediaPlayer is a local variable. After the testContinuePlayNextTrack() is finished, the MediaPlayer is collected by GC. So the fix is easy, make your MediaPlayer a member of the class.
public class MediaPlayerControllerTest extends AndroidTestCase implements OnCompletionListener {
MediaPlayer mediaPlayer = new MediaPlayer();
public void testContinuePlayNextTrack() {
mediaPlayer.setOnCompletionListener(this);
try {
mediaPlayer.setDataSource("/mnt/sdcard/5749/01.mp3");
mediaPlayer.prepare();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mediaPlayer.start();
}
#Override
public void onCompletion(MediaPlayer mp) {
System.out.println("ON COMPLETION!!!!!");
}
}
I'm trying to start a media player that streams from a website. Right now, when "start" is pressed the entire activity just freezes for anywhere from 5 to 20 seconds while the stream connects. I'm trying to get the "player.start();" call to run in a thread to free up the activity while the stream connects but it's not working. Anyone have any ideas?
private void startplayer() {
try {
stream_player = new MediaPlayer();
stream_player.setAudioStreamType(AudioManager.STREAM_MUSIC);
stream_player = MediaPlayer.create(this, Uri.parse("http://stream-address"));
Thread thread = new Thread(new Runnable() {
public void run() {
stream_player.start();
}
});
thread.start();
SetNotification(1, "live");
liveON = true;
} catch (Exception e) {
Log.e(getClass().getName(), "Error starting to stream audio.", e);
Toast.makeText(this, "Stream seems to be offline", Toast.LENGTH_LONG).show();
}
}
Move the whole method to a separate thread. The part that takes the most time is the MediaPlayer.create() part, since this a synchronous call, which returns when the media player is ready to play.
An alternative is not to use create, but use the other format used in here which sets a listener before the prepare method, and when the listener is called, the start method is called.