Titanium Community Questions & Answer Archive

We felt that 6+ years of knowledge should not die so this is the Titanium Community Questions & Answer Archive

Background audio in 1.4?

The specs say that background audio is supported in version 1.4, but I can't seem to find how to implement it.

There is a new example window in the new 1.4 kitchen sink, but it doesn't actually play in the background, as it stops when you close the application.

So, does anyone know how to implement this new feature? If there is a new version of Kitchen Sink that has that feature working, or other example code of it working, that would be mighty helpful.

Thanks,

Peter Janett

UPDATE - I have been able to make this work, see the second answer below!

— asked July 28th 2010 by Peter janett
  • 1.4
  • audio
  • background
  • ios4
1 Comment
  • A very nice app showed up the other day that appears to be using background audio, despite the fact that pro support is saying it is not yet supported.

    I've asked the developer for details on how he got it to work, on his thread here:
    http://developer.appcelerator.com/question/58471/app-approved—thank-you-to-appcelerator#111081

    Hopefully he can help us all figure out how to make it work!

    Thanks,

    Peter Janett

    — commented September 9th 2010 by Peter janett

13 Answers

  • Accepted Answer

    I posted this question 2 months ago, and today, after much trial and error, and help from this forum (which for this issue was more helpful than paid support), I have found the answers.

    So, here's how to do streaming background audio:

    1) Include the following (I put it in both app.js and my music window code):

    Ti.Media.defaultAudioSessionMode = Ti.Media.AUDIO_SESSION_MODE_PLAYBACK;
    

    2) Use Ti.Media.createAudioPlayer(); as this is the function that actually streams your audio.

    3) Edit your info.plist file:

    a) Open "YOUR APP FOLDER"/Build/Iphone (You should see BOTH
    Info.plist AND Info.plist.template files in this folder.)

    b) Copy Info.plist into "YOUR APP FOLDER". I did this by right clicking
    on Info.plist, choosing "Duplicate", which created "Info copy.plist".
    Then drag "Info copy.plist" up 3 directory levels into "YOUR APP
    FOLDER". Finally, rename "Info copy.plist" to "Info.plist".

    c) Open "YOUR APP FOLDER"/Info.plist with a text editor. (I've read
    that the plist editor that may be the default program to open the file
    will not edit the file correct.)

    d) Add these lines into "YOUR APP FOLDER"/Info.plist:

        <key>UIBackgroundModes</key>
        <array>
                <string>audio</string>
        </array>
    

    4) Test on an iPhone 3GS or an iPhone 4. (The simulator simply won't work, you must test on a real device.)


    A few notes, to try to make this as clear as possible. "YOUR APP FOLDER" represents the folder that is the same name as your Titanium Project. (It's the folder that contains the Resources folder where you edit all your JavaScript files.)

    Also note that the "Audio Controls", which you see when you double click the home button, and to the left of the running apps on iOS 4, DO NOT WORK with this setup. We'll hope that is fixed in the next version, or that someone here can figure out how to enable those with streaming audio…

    I also included:

    Ti.App.idleTimerDisabled = true;
    

    In both my app.js and my JS file for the streaming window, which should prevent the device from going to sleep. I haven't yet experimented to see if I want or need to keep this code in the files.

    I know this is wordy, but I wanted to try to spell it all out in detail, to save others from all the trial and error.

    Special thanks to Eric Telford, who's app showed me that background audio was possible, after I had been told it was not. Eric also shared how easy it really is, and provided the above info showing it was possible.
    http://developer.appcelerator.com/question/58471/app-approved—thank-you-to-appcelerator

    I hope this helps!

    Peter Janett

    — answered September 13th 2010 by Peter janett
    permalink
    4 Comments
    • Yay! This helped me solve my problem of audio stopping when the phone locks. Setting audioSessionMode to AUDIO_SESSION_MODE_PLAYBACK enabled this. I know this is different than actual backgrounding but this may help someone else who had my problem.

      — commented October 6th 2010 by Nick Robillard
    • Thank you very Good !!! It Works

      — commented November 4th 2010 by Flavo Mario
    • Wow, worked! Frustrated that this doesnt just work out of the box though. Having to hack around files is less than ideal, and having the audio controls in iOS4 not sork really sucks. Hopefully it is fixed in 1.5.

      — commented November 30th 2010 by Anthony Webb
    • Was this ever fixed or must we still do this?

      — commented April 8th 2012 by Stephen Page
  • Here are the changes that need made to accommodate Background Audio Streaming controls:

    MediaModule.h - add the following properties:

    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_PLAY;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_PAUSE;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_STOP;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_PLAY_PAUSE;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_NEXT;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_PREV;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_START_SEEK_BACK;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_END_SEEK_BACK;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_START_SEEK_FORWARD;
    @property (nonatomic,readonly) NSNumber *REMOTE_CONTROL_END_SEEK_FORWARD;
    

    MediaModule.m - create system properties using the following:

    MAKE_SYSTEM_PROP(REMOTE_CONTROL_PLAY,UIEventSubtypeRemoteControlPlay);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_PAUSE,UIEventSubtypeRemoteControlPause);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_STOP,UIEventSubtypeRemoteControlStop);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_PLAY_PAUSE,UIEventSubtypeRemoteControlTogglePlayPause);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_NEXT,UIEventSubtypeRemoteControlNextTrack);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_PREV,UIEventSubtypeRemoteControlPreviousTrack);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_START_SEEK_BACK,UIEventSubtypeRemoteControlBeginSeekingBackward);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_END_SEEK_BACK,UIEventSubtypeRemoteControlEndSeekingBackward);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_START_SEEK_FORWARD,UIEventSubtypeRemoteControlBeginSeekingForward);
    MAKE_SYSTEM_PROP(REMOTE_CONTROL_END_SEEK_FORWARD,UIEventSubtypeRemoteControlEndSeekingForward);
    

    TiMediaAudioPlayerProxy.h - add a private fireRemoteControlEvent variable:

    BOOL fireRemoteControlEvents;
    

    TiMediaAudioPlayerProxy.m - make changes/create to the following functions:

    -(void)_initWithProperties:(NSDictionary *)properties
    {
        volume = [TiUtils doubleValue:@"volume" properties:properties def:1.0];
        url = [[TiUtils toURL:[properties objectForKey:@"url"] proxy:self] retain];
        int initialMode = [TiUtils intValue:@"audioSessionMode" 
                                 properties:properties
                                        def:0];
        if (initialMode) {
            [self setAudioSessionMode:[NSNumber numberWithInt:initialMode]];
        }
    
        // default handlePlayRemoteControls to true
        bool handlePlayRemoteControls = [TiUtils boolValue:@"handlePlayRemoteControls" properties:properties def:YES];
        [self setValue:NUMBOOL(handlePlayRemoteControls) forKey:@"handlePlayRemoteControls"];
    
        WARN_IF_BACKGROUND_THREAD_OBJ;    //NSNotificationCenter is not threadsafe!
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(remoteControlEvent:) name:kTiRemoteControlNotification object:nil];
    }
    
    -(void)_listenerAdded:(NSString *)type count:(int)count
    {
        if (count == 1 && [type isEqualToString:@"progress"])
        {
            progress = YES;
        }
    
        if (count == 1 && [type isEqualToString:@"remoteControl"])
        {
            fireRemoteControlEvents = YES;
        }
    }
    
    -(void)_listenerRemoved:(NSString *)type count:(int)count
    {
        if (count == 0 && [type isEqualToString:@"progress"])
        {
            progress = NO;
        }
    
        if (count == 0 && [type isEqualToString:@"remoteControl"])
        {
            fireRemoteControlEvents = NO;
        }
    }
    
    - (void)remoteControlEvent:(NSNotification*)note
    {
        UIEvent *uiEvent = [[note userInfo] objectForKey:@"event"];
    
        if (fireRemoteControlEvents)
        {
            NSDictionary *event = [NSDictionary dictionaryWithObject:NUMINT(uiEvent.subtype) forKey:@"controlType"];
            [self fireEvent:@"remoteControl" withObject:event];
        }
    
        if (![TiUtils boolValue:[self valueForKey:@"handlePlayRemoteControls"]])
        {
            return;
        }
    
        switch(uiEvent.subtype)
        {
            case UIEventSubtypeRemoteControlTogglePlayPause:
            {
                if ([player isPaused])
                {
                    [self start:nil];
                }
                else
                {
                    [self pause:nil];
                }
                break;
            }
            case UIEventSubtypeRemoteControlPause:
            {
                [self pause:nil];
                break;
            }
            case UIEventSubtypeRemoteControlStop:
            {
                [self stop:nil];
                break;
            }
            case UIEventSubtypeRemoteControlPlay:
            {
                [self start:nil];
                break;
            }
            default:
                break;
        }
    }
    

    Then in your Titanium Mobile application you can do the following:

    audioPlayer.addEventListener('remoteControl',function(e) {
        var handledString = '';
    
        // if we set the 'handlePlayRemoteControls' property of our Ti.Media.AudioPlayer to false,
        // then we will need to handle all remote control events
        // otherwise: play, pause, stop, and play / pause toggle will be handled for us
        if (audioPlayer.handlePlayRemoteControls) {
            handledString = ' - will be handled by our Ti.Media.AudioPlayer';
        }
    
        switch(e.controlType) {
            case Ti.Media.REMOTE_CONTROL_PLAY:
                Ti.API.info('remote control - play' + handledString);
                break;
            case Ti.Media.REMOTE_CONTROL_PAUSE:
                Ti.API.info('remote control - pause' + handledString);
                break;
            case Ti.Media.REMOTE_CONTROL_STOP:
                Ti.API.info('remote control - stop' + handledString);
                break;
            case Ti.Media.REMOTE_CONTROL_PLAY_PAUSE:
                Ti.API.info('remote control - play / pause toggle' + handledString);
                break;
            case Ti.Media.REMOTE_CONTROL_NEXT: Ti.API.info('remote control - next track');
                break;
            case Ti.Media.REMOTE_CONTROL_PREV:
                Ti.API.info('remote control - prev track');
                break;
            case Ti.Media.REMOTE_CONTROL_START_SEEK_BACK:
                Ti.API.info('remote control - seek back - start');
                break;
            case Ti.Media.REMOTE_CONTROL_END_SEEK_BACK:
                Ti.API.info('remote control - seek back - end');
                break;
            case Ti.Media.REMOTE_CONTROL_START_SEEK_FORWARD:
                Ti.API.info('remote control - seek forward - start');
                break;
            case Ti.Media.REMOTE_CONTROL_END_SEEK_FORWARD:
                Ti.API.info('remote control - seek forward - end');
                break;
        }
    
    });
    

    NOTE: This code came from Instant Automatic's titanium_mobile branch https://github.com/instantautomatic/titanium_mobile

    — answered September 26th 2012 by Dustin Hume
    permalink
    2 Comments
    • Great one, Dustin! This also works with Ti.Media.VideoPlayer!

      — commented October 24th 2012 by Anders Oestergaard Nielsen
    • Thanks !! It works very well !

      — commented May 29th 2013 by Mohammed JAOUAD
  • I was talking about how background audio works if, for example, one wants to play a mp3 file. I had to struggle with guys at Apple and understood that it is not an easy task as one may think.

    I hope Titanium will support this, but I suggest to give a chance to xCode by now to get these results. As I pointed out, the background audio implies some modifications in plist and AppDelegate. The biggest problem was however to handle the new lifecycle methods implied with background. For example, audio can quite easily play in background but forget that iPhone handles it if you receive a phone call. You have to invoke a delegate method of AVAudioPlayer framework to do this. So, it's not so easy as one may think.

    The biggest obstacle was to have to do test renting an iPhone 3GS, because iPhone 3G is not supporting anything in background and simulators don't support audio while multitasking (Apple confirmed it).

    Another problem is that customers of applications seem to be very unhappy, claiming to have not a multitasking audio solution, when developers had months to update apps (when SDK 4 was in beta). But they are not completely right. being everything under NDA, you could even not talk about it in forums, so that only information could come from a very uncompleted documentation from Apple pr from support, which one pays.

    So, I suggest to use xCode by now for this. This stated, Titanium rocks :)

    — answered July 29th 2010 by Fabio Ricci
    permalink
    1 Comment
    • The only problem: how? I don't know any Objective C, etc. Or do you just need to say: enable bg-audio with a couple of lines of code?

      — commented July 29th 2010 by Doney den Ouden
  • I want to know this, too. Please don't tell me you can only play iPod songs in the background, I want to be able to stream audio in the background. Thanks.

    — answered July 29th 2010 by Doney den Ouden
    permalink
    0 Comments
  • I don't know the solution, but I suggest to consider that:

    • background audio is not possible on iOS4 if the iPhone is a 3G one;
    • the simulator can NOT play background audio.

    To test this you need to:

    • build against SDK 4;
    • test with a real iPhone 3GS or 4

    p.s. do NOT test with iPad, because SDK 4 does not exist, it will be available in September…

    I suggest to read my next post as well about confusion with SDK.

    Hope it helps…
    Fabio

    — answered July 29th 2010 by Fabio Ricci
    permalink
    0 Comments
  • Hi,
    the answer , is "YES YOU CANT" :(
    The background logic functionality and the background engine will be available in the next release, titanium sdk 1.5

    Background audio has to be intended from ipod playlist integration and not streaming.

    https://developer.appcelerator.com/apidoc/mobile/1.4/changelog.html

    Hope some guys at appcell tell me that im wrong too.
    Andrea

    — answered July 29th 2010 by Andrea S
    permalink
    0 Comments
  • Aww, come on Appcelerator. Why don't you guys completely support background radio streaming.. My users are eagerly waiting for it!

    — answered July 29th 2010 by Doney den Ouden
    permalink
    0 Comments
  • BUMP

    — answered August 13th 2010 by Peter janett
    permalink
    0 Comments
  • I signed up for pro support and asked that this featured be made a priority to be added into Titanium mobile.

    https://appcelerator.lighthouseapp.com/projects/32238/tickets/1671-add-streaming-audio-support-for-background-audio-ios-4

    Peter Janett

    http://www.NewMediaOne.net

    — answered August 30th 2010 by Peter janett
    permalink
    0 Comments
  • My app has links to MP3 that are on my server. I was about to implement these tips and had just added the UIBackgroundModes node in Info.plist and got sidetracked. Turns out just adding that line made background audio work for me with the default QuickTime player. The controller (pause play, etc) in the multitasking dock and on the lock screen also work. Boy. That was easy ;)

    Not sure if you all were trying to do more than that but just wanted to share my experience.

    — answered October 13th 2010 by Dave F
    permalink
    0 Comments
  • thank you Peter. Any update on your app? is it already working with the "audio controls" outside app? and earphone remote maybe?

    — answered December 10th 2010 by soemarko ridwan
    permalink
    0 Comments
  • worked great for me, thanks for the info!

    — answered May 23rd 2011 by Jim Carter III
    permalink
    0 Comments
  • 25

    — answered June 19th 2012 by Bill Freedman
    permalink
    0 Comments
The ownership of individual contributions to this community generated content is retained by the authors of their contributions.
All trademarks remain the property of the respective owner.