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.
Related
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've got an application where I will be playing 2 audio files simultaneously and the user will be attempting to hear the one (spoken words) over the other (background noise). With successful feedback input that they heard the file correctly, I want to decrease the volume of 1 (words) of the 2 files and play it again and they will attempt to hear it over the noise. I only want to decrease the volume of one file... the other one needs to remain constant (otherwise it defeats the purpose of trying to hear the one over the other). All I've found so far with the MediaManager is the ability to change the global volume of the application and not the specific audio clips within the application.
Any help is greatly appreciated.
My impression that the media player was global was incorrect. You can set the volume for this file and it will keep that volume even when you play a louder or quieter file (even when using the same mp). The oncompletion listener is important to releasing the file when over other wise you'll get exceptions and lose all sound. The logarithmic math function is important to getting the volume to scale appropriately between 0 & 100.
Assuming MAX_VOLUME is 100:
mp = MediaPlayer.create(getApplicationContext(), R.raw.noise);
final float noisevolume = (float) (1 - (Math.log(MAX_VOLUME - 50) / Math.log(MAX_VOLUME)));
mp.setVolume(noisevolume, noisevolume);
mp.start();
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
App I'm developing contains many short (1-2 sec) videos.
The videos are displayed in one activity. User can either replay video (possibly while video is beeing played) or change actual video.
Part of code changing video:
String videoPath = getVideoPath();
videoView.setVideoPath(videoPath);
videoView.start();
Those 3 lines already causes app to load new video and play it.
Problem starts after video is completed. From this point loading new video causes many problems (Like sometimes for half a movie only sound is played while screen is black blank). There are similar problems with replaying video (which I end up with calling 3 lanes from above).
It seems like android after completing movie releases resources or something like this (and that's why I am settings same path, when I want to replay video).
Ideally I would want video to simply pause and seekTo to beggining of movie after finished playing (but I cannot do this in OnCompletedListener, since it already changed state to stopped...).
Can I somehow achieve this? (By this I mean -> after completed video pauses and seekTo to beginning)
I already tried all combinations of pausing vidoes, suspending them, setting OnPreparedListener, setting OnCompletedListener.
Thx!
Try something like
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer arg0) {
mVideoView.start();
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.reset();
mVideoView.setVideoPath(file.getAbsolutePath());
mVideoView.start();
}
});
stop the playback, change video path, start video
videoView.stopPlayback();
videoView.setVideoPath(newVideoPath);
videoView.start();
I refactored my code in a following way: Everytime I need new video I reload whole activity. It works most of times, but now instead of video blackness at the beginning of playing I sometimes get "Cannot open media file" error.
Has it something to do with android resource managment? I release mediaPlayer in onCompletionListener.
Has anyone had such problem with playing many videos from external storage?
You can do something like this:
videoView.setOnCompletionListener(MediaPlayer.OnCompletionListener { mp ->
mp.seekTo(0);//go to second 0
mp.start()// start again
})
I discover in this link:
https://developer.android.com/reference/android/media/MediaPlayer
Do this.
videoView.setOnPreparedListener { mp ->
mp.isLooping = true
)
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.
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.