Such Problem: I have video file recorded with two sound channels. I tried to switch off left sound channel by this code:
MediaPlayer mp;
....
mp.setVolume(0.f, 1f);
... and on Tablet this work good (right volume channel sounds well). But then I tried it on googleTv which I connect to Samsung UE46ES6307U and this code did not work, sound swichs off.
Maybe it is bounds to Dolby Digital Plus / Dolby Pulse audio? Can I somehow programmatically discover how sound channels device has, and what volume in each chanels setuped?
Update:
On this forum http://www.googletvforum.org/forum/logitech-revue/375-audio-problems-logitech-revue.html in one of replies such message: "Logitech has not yet figured out how to pipe multichannel audio thru hdmi.you have to use the optical output. Which is ok."
"How are you constructing the MediaPlayer?"
Videoview vv;
...............
vv.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.setVolume(0.f, 1f);
}
});
Update:
public class MainActivity extends Activity {
MediaPlayer mp = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (mp != null) {
mp.reset();
mp.release();
}
mp = MediaPlayer.create(this, R.raw.test);
mp.start();
}
public void onTurnOffLeft(View v){
mp.setVolume(0.f, 1.f);
}
public void onTurnOffRight(View v){
mp.setVolume(1.f, 0.f);
}
}
Method onTurnOffLeft switchs off all sound, and onTurnOffRight method has no effect.
Update2
I tried to play .ogg audio file codded with Vorbis codec - channels turns off well. But I tried to play video files codded with mp3, ac3, pcm, aac - and problem with turning off channels is still there... I need to turn off audio channels in video, but how to solve that problem, I do not know yet.
The MediaPlayer object is backed by different libraries across the devices (not the same between a tablet and a Google TV). How are you constructing the MediaPlayer?
One thing you may want to try is calling #reset() on the MediaPlayer right after it is constructed. By default when you use a "new" operator to construct a MediaPlayer instance it is in an IDLE state (at least on Google TV). By calling reset you allow your own OnErrorListener.onError() handler to be invoked. This will let you see if there is some underlying error that is not visible otherwise.
You may also want to look at AudioManager#setStreamVolume(int, int, int) which sets the volume of ALL streams of a particular type.
Edit 1:
Since you are just grabbing the VideoView from layout (I'm guessing since that code was omitted) after you setup the listener you should call reset on the video view.
Related
This should be a very straightfoward awnser, but I still can't find a reliable solution. Say I have a .mp3 on the raw resource folder, and I want to start playing it from the middle... So I use the MediaPlayer API and make a method that looks something like this:
MediaPlayer player = MediaPlayer.create(context, R.raw.blablabla);
player.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
mp.seekTo(mp.getDuration() / 2);
}
});
This in theory should work, but it always starts the music from start. Even putting the line mp.seekTo(mp.getDuration() / 2); before the start or out of the Listener doesn't solve my problem. What exactly I am doing wrong?
In onPrepared the stream size is probably not known, so getDuration returns 0, most likely. You need to check the duration when the size is known - onVideoSizeChanged() is probably the right place.
I am learning to code for Android and I have a problem with... maybe performance?
I want to play very short sound every second. I have created a CountDownTimer (with tick interval 20ms so very accurate) and putted there in onTick to play it. But the sound is played not precisely after one second and I can hear this - this is the problem...
fragment of my code:
private class ExerciseCountDownTimer extends CountDownTimer
{
...
public void onTick(long millisUntilFinished)
{
...
if(/*this is a next second not just a tick*/)
playSound(R.raw.quick_rest, true);
}
}
private void playSound(int resId, boolean releaseAfter)
{
if (currentMediaPlayerRes != resId || mediaPlayer == null)
{
if (mediaPlayer != null)
{
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
}
currentMediaPlayerRes = resId;
mediaPlayer = MediaPlayer.create(this, resId);
if (releaseAfter)
{
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
{
#Override
public void onCompletion(MediaPlayer mp)
{
mediaPlayer.release();
mediaPlayer = null;
}
});
}
}
mediaPlayer.start();
}
Is it possible to have counter like this?
use this code to play a music one time
MediaPlayer AlarmMusic;
AlarmMusic = MediaPlayer.create(G.context, R.raw.music1);
AlarmMusic.setLooping(false);
AlarmMusic.start();
this worked for me !
Because of the lack of real time guarantees in Java/Android, using one thread to cue another probably will always have some inaccuracy.
I can think of two approaches that might work for you:
(1) make the sound file exactly 1 second long, e.g., 44100 frames at 44100 fps, if you are using the standard "CD-quality" format that Java supports. The sound file can probably be edited with Audacity to an exact frame length. Then, use a looping playback.
(2) Open a line for streaming audio. I can't recall exactly what the Android-supported command is for this, but I know it exists. With it, count elapsing frames while sending silence (bytes with 0 value). When you get to the 44100th frame, start feeding the PCM data that you wish to hear. When it is done, go back to feeding 0's until the next 44100 frame arrives. Never stop the line--keep it running in its own thread, probably with a high priority. It is generally okay to give audio a high priority (as long as you are doing nothing else on the line) as audio spends a vast majority of its time in a "blocked" state during which it is yielding to other lines.
A fellow on java-gaming.org made a metronome and got it working on Android. I bet if you search for "metronome" on that site, his thread will pop up and have some useful info. He basically used the second approach that I described above.
I have an array of audio files and I want to play 3 audio files one after the other, so as the gap in between them is not noticeable.
I am trying it using onCompletion listener but unable to do.
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
// TODO Auto-generated method stub
if ((image100==1)&&(image10==0)&&(image1==1))
{
mediaplayer = MediaPlayer.create(getApplicationContext(), sounds[0]);
mediaplayer.start();
mediaplayer = MediaPlayer.create(getApplicationContext(), sounds[12]);
mediaplayer.start();
mediaplayer = MediaPlayer.create(getApplicationContext(), sounds[3]);
mediaplayer.start();
}
}
You may want to try using the AudioTrack class to play your sounds. With it, you can get very close and even overlapping sounds. To use it, you create separate threads for each sound.
Here's the AudioTrack reference page and here's an easy to follow blog entry where the author implements a piano with arbitrary length and simultaneous sounds. In it, he loops very short duration sounds, but you could easily adapt that to longer, single-play sounds.
If these 3 audio files are short sounds, like game sound effects or piano tones, you can use SoundPool for playing them.
Here is a link to the sample code:
Game Sound effects in Android
In iPhone, we can use AVQueuePlayer, AVAsset, and AVPlayerItem if we want to play a list of movies sequentially. It is very convenient over MPMediaPlayer and MPMediaPlayerController in iPhone. From, apple documentation:
AVQueuePlayer is a subclass of AVPlayer you use to play a number
of items in sequence.
So, my question is, is there anything like that in android which we can use instead of MediaPlayer and VideoView.
In Android, there is no automatic way of playing sounds in sequence (at least not a "built-in" one). If you need to start playback of the second sound when the first one finishes, you can use method
public void setOnCompletionListener (MediaPlayer.OnCompletionListener listener)
of the MediaPlayer to start the second playback when the first one is finished. Something like this:
MediaPlayer player = MediaPlayer.create(context, uriOfFirstSound);
player.setOnCompletionListener(new OnCompletionListener(
public void onCompletion(MediaPlayer mp) {
mp.setDataSource(context, uriOfNextSound);
mp.prepare();
mp.start();
}
));
player.prepare();
player.start();
Naturally, if you have more than two sounds, you can do this in a loop.
I can play the videos fine back to back by implementing the OnCompletionListener to set the data source to a different file. No problems there. I call reset() and prepare() just fine.
What I haven't been able to figure out, is how to get rid of the 1-2 second gap screen flicker between the data source change and the new video starting. The gap shows a black screen, and I haven't found any way to get around it.
I've tried setting the background of the parent view to an image, but it manages to bypass that. Even if the SurfaceView is transparent (which it is by default.) I've also tried to have the multiple video files played at the same time, and switching mediaplayer's display when one ends and the other is supposed to start.
The last thing I tried, was to have a second view in the background that I show temporarily while the video is "preparing" and removing it when the video is ready to start. That also wasn't very seamless.
Is there any way to get rid of that gap. Running a video in a loop works wonderfully and does exactly what I want with the exception that it's looking through the same video instead of playing a different one that I pick.
main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:background="#drawable/background"
android:layout_height="fill_parent">
<SurfaceView
android:id="#+id/surface"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center">
</SurfaceView>
</FrameLayout>
Player.java
public class Player extends Activity implements
OnCompletionListener, MediaPlayer.OnPreparedListener, SurfaceHolder.Callback {
private MediaPlayer player;
private SurfaceView surface;
private SurfaceHolder holder;
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.main);
surface = (SurfaceView)findViewById(R.id.surface);
holder = surface.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void onCompletion(MediaPlayer arg0) {
File clip = new File(Environment.getExternalStorageDirectory(),"file2.mp4");
playVideo(clip.getAbsolutePath());
}
public void onPrepared(MediaPlayer mediaplayer) {
holder.setFixedSize(player.getVideoWidth(), player.getVideoHeight());
player.start();
}
private void playVideo(String url) {
try {
File clip = new File(Environment.getExternalStorageDirectory(),"file1.mp4");
if (player == null) {
player = new MediaPlayer();
player.setScreenOnWhilePlaying(true);
}
else {
player.stop();
player.reset();
}
player.setDataSource(url);
player.setDisplay(holder);
player.setOnPreparedListener(this);
player.prepare();
player.setOnCompletionListener(this);
}
catch (Throwable t) {
Log.e("ERROR", "Exception Error", t);
}
}
I too have the same problem as outlined by below link
VideoView Disappears for a second when video is changed
But this issue wont occur if you try using Android 4.0+ (ICS). I started to port VideoView.java and MediaPlayer.java from 4.0 to my app , but thats seems complex and no luck till now. Basically it seems a bug in the native code of the older versions.
after too much wasted time trying to figure out how to play consecutive videos without the "gap", i'm leaning towards impossible. unless of course you're able to dig down to the native level and implement your own player, Android's media player simply doesn't support seamless playback as of the moment.
I've not done this with video playback on a MediaPlayer but I've done something similar with audio files when a stream gets interrupted because a user has switched from 3G to Wifi.
I think the delay that you're seeing is whilst the media player is buffering the input file.
So maybe you can define both players at the start? You should do define the datasource and prepare both players but only start one of them.
Then in your onCompletionListener you can flip them over instead of resetting the existing one and setting a new datasource.
player.release();
player = flipPlayer;
flipPlayer = null;
player.start();
Obviously you'd need to either use a different onPreparedListener for flipPlayer or take the player.start() out of the onPrepare. (Since you're calling it synchronously I wouldn't have thought this was an issue).
I don't think it's possible.
Reason: Mortplayer was also available for windows mobile and one of its strengths was that it supported gapless play. However it doesn't in the android version of the app, and the developer itself writes that the SDK does not allow it on xda:
http://forum.xda-developers.com/showpost.php?p=5364530&postcount=5
HTH, Daniele
Did you try to have ready (opened/prepared) 2 VideoView's, with one being visible, other invisible and stopped, and ass soon you get OnCompletionListener callback, make 2nd one visible, start it, and hide 1st one.
In meantime, as 2nd one plays, you can call open/prepare on 1st VideoView to open/prepare another file.
#user1263019 - were you able to port Android 4.0 MediaPlayer to your app? I'm facing the same issue and I'm looking for a nice solution. My case is having an image over the SurfaceView which should be hidden in order to show the video playing, but there is a gap between calling start() and the actual start of the video. The only solution so far is to start a Thread that checks if getCurrentPosition() is > 0.
On the topic - I think it is not possible to have gapless playback, though Winamp claim to have such abilities. A dirty hack is to prepare the second player several seconds before the end of the playback of the first player and then call start() of the second player 100-200ms before end of playback.
In your exoplayer implementation (or mediaplayer) use a handler to repeatedly post a runnable, while playing, that gets the current tracking time and passes it to a callback:
public interface MediaAction {
public void onTrackingChanged(long currentPosition);
}
public class ExoPlayerImplementation implements Exoplayer {
..
private MediaAction mediaActionCallback;
public void setMediaActionCallback(MediaAction ma) {
mediaActionCallback = ma;
}
public void releaseMediaAction() { mediaActionCallback = null; }
private Handler trackingCallback = new Handler(Looper.getMainLooper());
Runnable trackingTask;
private Runnable getTrackingTask() {
Runnable r = new Runnable {
#Override public void run() {
long currentPosition = getCurrentPosition();
if (mediaActionCallback != null) {
mediaActionCallback.onTrackingChanged(currentPosition);
}
// 60hz is 16 ms frame delay...
trackingCallback.postDelayed(getTrackingTask(), 15);
}
};
trackingTask = r;
return r;
}
public void play() {
// exoplayer start code
trackingCallback.post(getTrackingTask());
}
public void pause/stop() {
trackingCallback.removeCallbacks(trackingTask);
}
..
}
And now you can track when the current position actually has changed--if it has changed, then you can show your video output view / swap views / remove preview (ie, use MediaExtractor to grab initial frames, overlay as preview in an ImageView then hide once current position is increasing). You can make this code more complete by combining it with the state listener: then you know if you are buffering (check buffering position versus current position), actually playing, paused or stopped with proper callbacks (in MediaAction). You can apply this method to both MediaPlayer and ExoPlayer classes (since it is just an interface and handler).
Hope that helps!