I'm trying to set up a seekbar to control the level of an instance of exoplayer streaming dash.
The setup I am using is a modified version of the demo project and am having trouble figuring out which element I should be trying to affect with the seekbars output ie how to use MSG_SET_VOLUME properly etc etc
Any input would be massively appreciated.
The end result I am looking for is an application with two instances of exoplayer both streaming dash content with a fader(seekbar) controlling the mix of the two players (which once this is figured out i presume should be easy enough if the maths is correct)
Again any help would be massively appreciated I have had a bit of a time with Exoplayer so far being such a novice! thanks guys!
If I read the ExoPlayer source code correctly you have to keep references to the audioRenderers you use when preparing the ExoPlayer instance.
exoPlayer.prepare(audioRenderer);
To change volume you have to send the following message:
exoPlayer.sendMessage(audioRenderer, MediaCodecAudioTrackRenderer.MSG_SET_VOLUME, 0.1f);
First you pass the audioRenderer for which you want to change the volume. Secondly you define the message which you want to send to the renderer which is MSG_SET_VOLUME, since you want to affect audio.
Finally you pass the value you want to set the volume to. In this example I chose 0.1f but of course you can use any value which fits your needs.
You can effect two different playback volumes if you send messages to both MediaCodecAudioTrackRenderers which you used to prepare playback. So you could send two messages with for example value 0.4f for audioRenderer1 and 0.6f for audioRenderer2 to blend the playbacks into one another.
I did not try this myself, but I think it should work.
This is the snippet of the original ExoPlayer code which is responsible for handling the MSG_SET_VOLUME message:
public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
if (messageType == MSG_SET_VOLUME) {
audioTrack.setVolume((Float) message);
} else {
super.handleMessage(messageType, message);
}
}
I'm working on an app in which the video is paused at 3 different intervals. After the second pause, if a button is clicked, it should start back from the previous location.
Eg. if it is currently paused at 1:30, then on click of a button, it goes to the previous bookmark, i.e. 00:45.
I thought using MediaPlayer.seekTo() will help me achieve this. But, seekTo() doesn't seek the position at all. The currentPosition stays the same even after a call to seekTo();
Here's my code.
mediaPlayer.setOnSeekCompleteListener(new OnSeekCompleteListener() {
#Override
public void onSeekComplete(MediaPlayer mp) {
Log.d("VID_PLAYER","Seek Complete. Current Position: " + mp.getCurrentPosition());
mp.start();
}
});
and somewhere below, I have this...
mediaPlayer.seekTo(45000);
What is the problem? Why isn't seekTo(); working?
Any help would be appreciated.
I am currently testing it on Android v4.0.3 (ICS)
Try the code snippet given below to achieve more accuracy in seeking to specific positions of the media.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
mediaPlayer.seekTo(seekPosition,MediaPlayer.SEEK_CLOSEST);
else
mediaPlayer.seekTo((int)seekPosition);
Keep in mind that - as the accuracy increases, speed of seeking decreases. So while playing high resolution videos its advised not to use MediaPlayer.SEEK_CLOSESTmore often.
One of the reasons why Android is not able to do seekTo is because of strange encoding of the videos. For example in MP4 format so called "seek points" (i.e. search index) can be specified at the begining and at the end of the file. If they are specified at the begining of the file then seekTo will behave correctly. But if they are specified at the end of the file then seekTo will do nothing and video will start from the begining after seekTo.
This is confirmed bug-or-feature in Android 4.4.2.
P.S. On Youtube all videos are encoded with "seek points" at the begining of the file. So if you have this problem with seekTo in your app first of all check your app with some video files from Youtube. Perhaps you'll need to reencode your videos...
Does your problem have something to do with this bug:
https://code.google.com/p/android/issues/detail?id=4124
I recall encountering this about a year ago. I don't think I found a workaround at the time.
Since API 26, Android added a
seekTo(long msec, int mode);
By specifying a mode, we are able to tell to our MediaPlayer how to seek:
SEEK_PREVIOUS_SYNC: Has the same behavior as seekTo(int msec). It looks for the nearest 'seek point' (i.e. sync frame) backwards.
SEEK_NEXT_SYNC: Same as PREVIOUS, but looks forwards.
SEEK_CLOSEST_SYNC: This looks for the nearest sync frame given a msec time.
SEEK_CLOSEST: This seeks for the nearest frame given a msec time.
I faced a similar problem a couple days ago and by using SEEK_CLOSEST mode, this problem was solved.
For reference, check out these links: https://developer.android.com/reference/android/media/MediaPlayer.html#seekTo(long,%20int)
https://en.wikipedia.org/wiki/Video_compression_picture_types
I've got a SoundPool[] that I use to play mixed audio files.
Soundpools play together without any problem, and it's very efficient!
Very briefly:
private SoundPool[] sound = new SoundPool[C.ROWS];
// every sound is initizialized with a load()
// and when asked...
public void play(int row, int variation) {
if (mute[row]) return;
if (variation != 0)
sound[row].play(variation_scheme[row][variation-1], volume[row], volume[row], PRI, 0, 1f);
}
This is just to show! :)
I don't put other pieces of code because everything works very fine and it is not really a problem.
My question, instead, is:
how can I redirect the whole output of the application to a file, instead of (or in addition to) the audio speaker?
In other words, there are two main solutions:
1. how can I instruct AudioPool to play() the sounds to a file instead of to an audio device?
2. or how can I redirect all the audio output of my app (or even of all the phone) to a file?
Thank you.
The only way I found how to record audio is by recording each information of the sound being press such as, duration (using mediaplayer), soundID, millisecond time stamp to do play back to the millisecond, volume, rate (if needed). Then write these to a text file (internally or externally) for later use. Create a play back system that decodes that saved information from text file and organize it in some arrays or hashmaps and play back throught some sort of play back method with maybe using a handler and postDelay to play sound and desired time and then plug in necessary data to play sound from array or hashmap.
In this way you can have your own data files for playing sound sequences.
In my app I set a mediaplayer with with this instructions:
mpBackGround = MediaPlayer.create(context, R.raw.bg_music);
mpBackGround.setVolume(0.7f, 0.7f);
mpBackGround.setLooping(true);
mpBackGround.start();
but at the end of first loop I have a little pause between first cycle and second cycle; I also have cut silence spaces in the file (bg_music). With files of type .mid I have not problem but with mp3, wav and other I have this problem...and I have all mp3 files (not midi).
Is there another solution to solve this problem? thanks
just out of curiosity, is this little pause between the cycles roughly equivalent to the time it takes to seek from one end of the file to the other? It sounds like a performance issue related issue to me.
If thats the case, I would create two instances of media players, and handle the repeating my self. As in, .start() one when the other one finishes. Then you can "rewind" one while the other is playing.
I am programming for android 2.2 and am trying to using the
SoundPool class to play several sounds simultaneously but at what feel like random times sound will stop coming out of the speakers.
for each sound that would have been played this is printed in the logcat:
AudioFlinger could not create track. status: -12
Error creating AudioTrack
Audio track delete
No exception is thrown and the program continues to execute without any changes except for the lack of volume. I've had a really hard time tracking down what conditions cause the error or recreating it after it happens. I can't find the error in the documentation anywhere and am pretty much at a loss.
Any help would be greatly appreciated!
Edit: I forgot to mention that I am loading mp3 files, not ogg.
i had almost this exact same problem with some sounds i was attempting to load and play recently.
i even broke it down to loading a single mp3 that was causing this error.
one thing i noted: when i loaded with a loop of -1, it would fail with the "status 12" error, but when i loaded it to loop 0 times, it would succeed. even attempting to load 1 time failed.
the final solution was to open the mp3 in an audio editor and re-edit it with slightly lesser quality so that the file is now smaller, and doesn't seem to take up quite as many resources in the system.
finally, there is this discussion that encourages performing a release on the objects you are using, because there is indeed a hard limit on the resources that can be used, and it is system-wide, so if you use several of the resources, other apps will not be able to use them.
https://groups.google.com/forum/#!topic/android-platform/tyITQ09vV3s/discussion%5B1-25%5D
For audio, there's a hard limit of 32 active AudioTrack objects per
device (not per app: you need to share those 32 with rest of the system), and AudioTrack is used internally beneath SoundPool,
ToneGenerator, MediaPlayer, native audio based on OpenSL ES, etc. But
the actual AudioTrack limit is < 32; it depends more on soft factors
such as memory, CPU load, etc. Also note that the limiter in the
Android audio mixer does not currently have dynamic range compression,
so it is possible to clip if you have a large number of active sounds
and they're all loud.
For video players the limit is much much lower due to the intense load
that video puts on the device.
I'll use this as an opportunity to remind media developers: please
remember to call release() for media objects when your app is paused.
This frees up the underlying resources that other apps will need.
Don't rely on the media objects being cleaned up in finalize by the
garbage collector, as that has unpredictable timing.
I had a similar issue where the music tracker within my Android game would drop notes and I got the Audioflinger error (although my status was -22). I got it working however so this might help some people.
The problem occurred when a single sample was being output multiple times simultaneously. So in my case it was a single sample being played on two or more tracks. This seemed to occasionally deadlock or something and one of the two notes would be dropped. The solution was to have two copies of the sample (two actual ogg files - identical but both in the assets). Then on each track even although I was playing the same sample, it was coming from a different file. This totally fixed the issue for me.
Not sure why it works as I cache the samples into memory, but even loading the same file into two different sounds didn't fix it. Only when the samples came out of two different files did the errors go away.
I'm sure this won't help everyone and it's not the prettiest fix but it might help someone.
john.k.doe is right. You must reduce the size of your mp3 file. You should keep the size under 100kb per file. I had to reduce my 200kb file to 72kb using a constante bit rate(CBR) of 32kbps instead of the usual 128kbps. That worked for me!
Try
final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 50);
tg.startTone(ToneGenerator.TONE_PROP_BEEP, 200);
tg.release();
Releasing should keep your resources.
I was with this problem. In order to solve it i run the method .release() of SoundPool object after finish playing the sound.
Here's my code:
SoundPool pool = new SoundPool(10, AudioManager.STREAM_MUSIC, 50);
final int teste = pool.load(this.ctx,this.soundS,1);
pool.setOnLoadCompleteListener(new OnLoadCompleteListener(){
#Override
public void onLoadComplete(SoundPool sound,int sampleId,int status){
pool.play(teste, 20,20, 1, 0, 1);
new Thread(new Runnable(){
#Override
public void run(){
try {
Thread.sleep(2000);
pool.release();
} catch (InterruptedException e) { e.printStackTrace(); }
}
}).start();
}
});
Note that in my case my sounds had length 1-2 seconds max, so i put the value of 2000 miliseconds in Thread.sleep(), in order to only release the resources after the player have had finished.
Like said above, there is a problem with looping: when I set repeat to -1 I get this error, but with 0 everything is working properly.
I've noticed that some sounds give this error when I'm trying to play them one by one. For example:
mSoundPool.stop(mStreamID);
mStreamID = mSoundPool.play(mRandID, mVolume, mVolume, 1, -1, 1f);
In such case, first track is played ok, but when I switch sounds, next track gives this error. It seems that using looping, a buffer is somehow overloaded, and mSoundPool.stop cannot release resources immediately.
Solution:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mStreamID = mSoundPool.play(mRandID, mVolume, mVolume, 1, -1, 1f);
}, 350);
And it's working, but delay is different for different devices.
In my case, reducing the quality and thereby the file sizes of the MP3's to under 100kb wasn't sufficient, as some 51kb files worked while some longer duration 41kb files still did not.
What helped us was reducing the sample rate from 44100 to 22050 or shortening the duration to less than 5 seconds.
I see too many overcomplicated answer. Error -12 means that you did not release the variables.
I had the same problem after I played an OGG audio file 8 times.
This worked for me:
SoundPoolPlayer onBeep; //Global variable
if(onBeep!=null){
onBeep.release();
}
onBeep = SoundPoolPlayer.create(getContext(), R.raw.micon);
onBeep.setOnCompletionListener(
new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) { //mp will be null here
loge("ON Beep! END");
startGoogleASR_API_inner();
}
}
);
onBeep.play();
Releasing the variable right after .play() would mess things up, and it is not possible to release the variable inside onCompletion, so notice how I release the variable before using it(and checking for null to avoid nullpointer exceptions).
It works like charm!
A single soundPool has an internal memory limitation of 1 (one) Mb. You might be hitting this if your sound is very high quality. If you have many sounds and are hitting this limit, just create more soundpools, and distribute your sounds across them.
You may not even be able to reach the hard track limit if you are running out of memory before you get there.
That error not only appears when the stream or track limit has been reached, but also the memory limit. Soundpool will stop playing old and/or de-prioritized sounds in order to play a new sound.