I am having a problem with the sleep lock in my application.
I am using a native thread which is using sockets to retrieve RTP packets who contains audio data. This audio data is then sent to the android audio player class in Java (MediaPlayer, I think - didn't write that piece myself) and is being played out.
What happens if, if I manually(not because its "idle") engage the sleep-lock, it seems the native threads keeps buffering audio data but the media player is not requesting it, which means once you deactivate the sleep lock you get like a 5-seconds delay.
I am using native library for buffering the RTP packtets (speex jitterbuffer) and cannot do much about it im afraid. My question is then: how do I tell my app to continue playing sound after having manually activated the sleep lock?
Thanks
Related
I have an app that plays an song displaying its lyrics on the screen.
Two situations:
When the song is loaded from a local mp3 file.
When the song is loaded from remote location via internet
My understanding is that Android Service comes to rescue when the song is streamed from remote location via internet. Android Service helps here because of the i/o overheads involved. In the first case, where the song is played form local location, services is perhaps an overkill. I can simply play the music loading it in the activity and use MediaPlayer API to play it.
Is this understanding correct? Am I missing anything?
Update: The song size is over 10MB. So when you stream it via a slow internet over phone there might be some buffering and stuff to be accommodated for better user experience.
Thanks in advance.
There are different Services for different use cases. For a Media Player it depends if you want to have the playback continuously playing in the back- or foreground.
So both cases are applicable for a Media Player Service. But the Android Developer Guide Media Player Service outshines my answer
Using a Service with MediaPlayer
If you want your media to play in the background even when your application is not onscreen—that is, you want it to continue playing while the user is interacting with other applications—then you must start a Service and control the MediaPlayer instance from there. You should be careful about this setup, because the user and the system have expectations about how an application running a background service should interact with the rest of the system. If your application does not fulfil those expectations, the user may have a bad experience. This section describes the main issues that you should be aware of and offers suggestions about how to approach them
Your second case is more a question about networking and in this case you could use a IntentService to download the .mp3 and pass it to the MediaPlayer.
Using MediaPlayer.OnInfoListener I am able to see when MediaPlayer is temporarily pausing playback internally in order to buffer more data.
But as MediaPlayer obeys progressive HTTP download, Ideally it pauses buffering since enough buffering is already done, If user continues to
watch video it will buffer next chunk of data.
I want to know exactly when buffering has stopped because enough buffering is done. (not because network issues, congestion, low bandwidth etc.)
Am I thinking it in wrong way?
If not, Is there any way to find this?
I am using a MediaPlayer to stream audio from a URL.
According to the documentation, calling the MediaPlayer pause followed by a play will resume from the point where it was paused.
I am wondering how this works with a live audio stream. When I call pause is the MediaPlayer creating some sort of buffer of all the incoming data, and storing it until I call play again?
If this is indeed the case, is there a max size on this buffer? I am mainly concerned about a user pausing the MediaPlayer and it using a lot of memory while it stores incoming audio data.
As, I understand you are using Mediaplayer for streaming audio from a URL.. something like radio channels. In this process, you are using buffers. So, the behaviour you are getting is quite obvious. When you pause, your data will continue to store and on resuming the stream, it will start from the point it was paused.
But streaming should not behave in this manner unlike stored audio which start from the point it was paused. Streaming audio should always start from the live streaming at that point. So, onPause, you should free the buffers. When the user resumes again, you can restart the stream the way you did it first time. This is how the behavior should be.
If you check out, normal radio streaming is implemented in most of the radio streaming apps.
I am streaming audio using MediaPlayer on Android.
When the device moves from Wi-Fi to the cell network or vice-versa, the MediaPlayer stops playback.
Typically there are a few seconds-worth of audio in the buffer, so playback does not cease immediately.
Ideally I would like to pick up the stream for uninterrupted playback, but I cannot see how to do it.
I am working with both mp3 files hosted on the server and a live broadcast stream.
From a servers point of view, changing network mode from WiFi to 3G (visa versa), will look like a brand new connection from a separate IP's (client).
If the server that you are downloading from does not support tracking the stream (e.g number of seconds, sequence, byte) (unlike media-servers),It will have to start serving your mp3 from 0 byte again.
If your URL is pointing to a MP3 file located at a standard HTTP server, your situation will be what to expect. You should look into using a Media streaming server, so you could resume downloading/streaming at your choice. When you receive the intent that the connection is lost/resume, you could point your mediaplayer to the new URL with file-position in the URL (e.g seconds=19, bytes=57365).
Not sure if this helps you, but it explains a bit whats going on "behind the scenes".
Try setting your setOnCompletionListener and setOnErrorListener. In on complete with a live stream you can just call prepareAsync() again and this will kick off the stream again. There is no graceful way of doing this really unless you write your own media framework.
You can also listen in you onError() for the MEDIA_ERROR_SERVER_DIED you can then fire off the prepareAsync() again.
You'll find that the MediaPlayer will either Error or Complete. If you handle both these callbacks the very least you can do is restart the stream on change of network, as for smooth playback.. that would require custom mediaframework as the android one is pretty shoddy.
I don't know why your media player is stopping, but maybe you could add an onReceive method and put "mp.start()" in the method to make it restart playback.
Android, How to handle change in network (from GPRS to Wi-fi and vice-versa) while polling for data
You might need to make a separate class, but that should explain how to create a method that is called when you switch networks, at which point you could call "mp.start()" to resume playback (assuming mp is your MediaPlayer).
This assumes, of course, that your MediaPlayer is only being paused when you are switching networks, not stopped.
As Vidar says, reestablishing the connection will be treated by the server as a new connection.
It appears that I have to double-buffer the audio playback, which means building a custom media player. This can provide continuous audio, but it will still skip when listening to a live stream.
The MP3 file is a bit easier because I can know the playback position. Not so with the live stream.
As gmaster says, I'll need a broadcast receiver to establish a new connection when the network changes.
The audio buffer from the previous network connection should continue to playback while a new audio buffer is filled via the new connection.
When the new buffer is full enough to start playback I can switch playback to it.
If I am streaming a file, with server support and a little bit of work I can ensure that the current playback position data is in both buffers and switch seamlessly.
As the live stream buffers cannot be synchronized, there will inevitably be a glitch when they switch.
A larger buffer will avoid audio drop-out if the connection takes a while to establish, but will delay the first start of playback. An MP3 file can be downloaded and fill the buffer faster than real time, but the live stream will buffer in real time.
Chris.Jenkins mentions some MediaPlayer methods that can help but points out that this does seem to need a custom framework. It will need to handle the conditions he mentions and others.
If I can make it look pretty I'll post it here. I'm going to keep the question open.
I have a simple app, which plays a short sound repeatedly, by invoking the play() method on the audio element in JavaScript. It works well on desktop browsers, ipads, iphones, etc. On a mobile device running Android 2.3.3, the first time I play the sound, I hear it immediately after invoking the play() method, but on subsequent invocations, there is a noticeable and variable delay.
I have done some sleuthing and found that the device is fetching the audio file from the server each time the play() method is invoked. I can invoke the load() method on the audio element to re-load it after each play, thus queueing it up for the next play, but there are a number of problems with that band-aid. I'd really like to make the browser just keep the audio element loaded permanently, instead of unloading it as soon as it finishes playing. Does anyone know if that's possible?
EDIT: I've done a little more investigating, and I've found that after playing the sound, the audio element's readystate remains at HAVE_ENOUGH_DATA, even though the browser won't play that sound again without re-fetching it from the server. I believe this is a bug. I'd hoped to use the readystate to detect browsers that unload after playing, and only explicitly load if necessary, but that's not going to work.
The more experiments I do, the more rough edges I find in Android 2.3.3's implementation of the HTML5 audio tag. There's a lot broken there, at least on the Droid X phone I'm using for testing.
The best I have come up with so far is the band-aid alluded to in my original question: as soon as an invocation of play() completes, invoke the load() method, to prepare for the next play():
if (navigator.userAgent.toLowerCase().indexOf("android") > -1)
audElt.addEventListener('ended', function () {
var t = setTimeout(function () { audElt.load(); }, 1000);
}, false);
I had to restrict the work-around to Android user agents, because simply invoking the load() method creates problems on Chrome and generates unnecessary trips to the server on non-Android systems.
I had to add a 1-sec delay, because if I simply invoked load() from the "ended" handler, it interrupted the playback, which, apparently, hadn't really "ended" yet....
Of course, it's still fetching the sound from the server repeatedly, so if you try to play the sound multiple times in rapid succession, things go south quickly.
best solution i've found. Another options is to just use the video tag but there are some problems with that as well. Nothing seems to work good enough to implement.
luckily im using phone gap so I'll give their audio methods a shot.
You can bind on updatetime to pause() the playback a second before reaching the end of the audio and rewind before playing it again. Android will not flush the audio then.