[TIMOB-13150] Android: AudioPlayer.start() freezes UI thread
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Medium |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2013-08-22T20:39:34.000+0000 |
Affected Version/s | n/a |
Fix Version/s | 2013 Sprint 17, 2013 Sprint 17 API, Release 3.2.0 |
Components | Android |
Labels | exalture, module_media, qe-testadded, triage |
Reporter | Remo |
Assignee | Sunila |
Created | 2012-10-03T15:36:48.000+0000 |
Updated | 2014-02-14T09:55:24.000+0000 |
Description
*Problem description*
AudioPlayer.start() freezes the user interface on Android for several seconds (9 seconds and more) until playback starts. I would expect it to be asynchronous (there are events that all one to know what happens...). Or at least it should also have a startAsync(). The url of the AudioPlayer is set to a remote MP3/SHOUTcast stream.
*Test case*
var win = Ti.UI.createWindow({
backgroundColor : "#FFF"
});
var audioPlayer = Titanium.Media.createAudioPlayer({
allowBackground : true
});
audioPlayer.setUrl('http://broadcast.infomaniak.net:80/energyzuerich-high.mp3');
var s = new Date().getTime();
audioPlayer.start();
audioPlayer.stop();
alert("time required: " + (new Date().getTime() - s));
win.open();
Attachments
File | Date | Size |
---|---|---|
app.js | 2013-08-05T23:20:07.000+0000 | 1066 |
Apologies for taking so long to reply, but could you possibly provide a test case for us to try out? Thanks!
A simple example is: var audioPlayer = Titanium.Media.createAudioPlayer({allowBackground:true}); audioPlayer.setUrl('http://broadcast.infomaniak.net:80/energyzuerich-high.mp3'); var s = new Date().getTime(); audioPlayer.start(); audioPlayer.stop(); throw "time required: " + (new Date().getTime() - s); With Android 4.0, a Samsung Galaxy S2 and a 3G connection the given code blocks for up to nine seconds. If a have a faster WIFI connection, it usually blocks for one to three seconds. Since the AudioPlayer provides a listener to get notified once it has started/stopped, I would expect the methods to return immediately. Maybe a dedicated thread in Android is needed to circumvent the blocking. Have not tested it on iOS. Nine seconds of blocking is quite bad since the entire UI blocks as well.
In case no data is received from the given url (e.g. the station is temporarly offline), it seems Titanium freezes indefinitely. Android shows a App termination dialog to stop the freezed app. There is no way to stop this. The problem remains with Titanium SDK 3.0.
I had a look at the Titanium source code. In initialize(), one finds on line 124: mp.prepare(); // Probably need to allow for Async Here you should at least allow to call mp.prepareAsync(). That will prevent the blocking. You may add a method setAsyncMode(...) to the AudioMediaPlayer. That should be a very small fix. Otherwise, building any kind of streaming app using Titanium is next to impossible.
What the f**k... No possiblity to do any kind of live media streaming application (audio/video) due to unacceptable blocking of the UI by the network stack. A fix would take all of a few lines of codes. Support in Android is available. Still nothing after months of wainting.
I'm having this exact issue at the moment while building a live radio app for a client. How can I add this fix? It's been a long long time since I built my own SDK version from git. The app takes far too many seconds to initialize a stream. And also to release it. To change the url property requires a release() of the stream before a start(). This process can take up to 60 seconds which is unacceptable. (I notice in my app, I have a clock in the UI, running on a 1 second interval which freezes while this is going on)
@Remo Could you point out which files contain the fix you suggest? I would like to try this fix, as the Android radio app I have built is far, far too slow when starting and stopping streams - for the reasons I think you suggest. Thanks.
I have studied the issue further. The stream starting slow is a separate issue which is related to a bug in the Android media player itself. Using a stream above 32kbps solves the above 60 sec wait time and makes it leaner towards 6 - 10 seconds on a wifi network. And yes, a higher bitrate stream loads faster.... The async issue is a complete bummer though, as its a simple command in the core appcelerator code. The current code says mp.prepare() which simply needs to be switched to mp.prepareAsync() If only I knew how to compile the appcelerator source, this takes a minute to run. For now waiting... See line 124 on: https://github.com/appcelerator/titanium_mobile/blob/master/android/modules/media/src/java/ti/modules/titanium/media/TiSound.java
Hi, Thanks for looking into this. This old Q&A post instructions for building the Ti SDK is still valid (as far as I can tell) http://developer.appcelerator.com/question/3931/building-titanium-from-source Clone the source. Cd to the directory. run: scons (for platform specific builds only, use scons android=1 or scons iphone=1) To speed up builds, you can disable documentation generation with build_jsca=0
I've tried to implement this fix using the master source from github, but the Android SDK build is failing. (Not to do with the fix I think. Something to do with my setup). Infuriating.
OK. I managed to get an SDK built with the fix in place, however, while things appear to be working faster, I can't hear any audio at all now. I think it is possibly missing the logic to initialize and then start in this way. Due to the lack of an OnPreparedListener?
hmmm ... i will look at a module option here .. let me try and implement the fix in a kroll module and then hand over to you for building into the original source? To keep Jira clean, I suggest we take this thread over email / skype at rahul.dhingra@aurusit.com / AurusIT
Addes async support https://github.com/appcelerator/titanium_mobile/pull/4220
Sunila : Thanks for this. It appears to be working a lot better now with prepareAsyc. One thing though, your stop() method seems to still use the non-async prepare() method. Thanks again. Kosso
Sunila, Will pull the version and provide feedback.. Regards, Rahul Dhingra
Hi Sunila, Request you to let me know if the fix is available in a continuous build which I can download and rebuild my application accordingly. If not then please let me know how to use the above fix in the app or an article on how to use the same would also be of great help. Regards, Rahul Dhingra
I managed to get Sunilla's code working for now in a local fork [thanks! :) ] , but I'm looking forward to it working by default. Another bug I should add is that the events don't match between iOS and Android. Also, it would be nice to have an error event on the AudioPlayer for both iOS and Android instead of the native error message which can't be edited (AFAIK).
New pull request with changes based on review comments
Testing Notes
* Use the attached app.js and run the app. * Click the button to start -- The stream should play *and* the label at the bottom should indicate that start() returned in less than 1 second. * Click the button to stop -- The stream should stop playing *and* the label at the bottom should indicate that stop() returned in less than 1 second.Pull request updated with the fix for 'stop'
Added new pull request merging all changes and fixed the issue with async prepare after stop https://github.com/appcelerator/titanium_mobile/pull/4593
Verified the fix. The start() returns in around 6ms & stop returns around 4ms, which is less than 1sec. Thus closing. Environment: Appcel Studio : 3.2.0.201310221639 Ti SDK : 3.2.0.v20131022050844 Mac OSX : 10.8.5 CLI - 3.2.0 with hash 72f7426b4ee6c2d2883c666d5b7e03906a16012f Device: Samsung Galaxy S4 running android 4.2.2