Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Unity 3D and iOS Control Center

Discussion in 'iOS and tvOS' started by FedorChunovkin, Mar 11, 2015.

  1. FedorChunovkin

    FedorChunovkin

    Joined:
    Apr 16, 2014
    Posts:
    2
    Hi Everyone!

    We use Unity Engine in our iOS mobile application to present some 3D experience as part of big native application. We've successfully performed integration by modifying our project with Unity auto-generated code, but faced one big problem which is very important for us.

    Our app allows user to listen to some audio channels and control them through iOS Control Center (the UI you get by swiping the screen from the bottom). When we don't embed Unity files in the app everything works fine, but when we do - audio management in iOS Control Center doesn't work. The user is always presented with a 'Play' button, but tapping it does nothing. This is not dependent on whether we are playing our native audio channel or not.

    Looks like Unity's audio engine conflicts with this iOS management UI and doesn't allow us to control our own channels.



    I've managed to reproduce this issue in a small sample application. These are the steps to create this application:

    1. Start Unity (I use version 4.6.2p2) and create a new empty project.
    2. Use File -> Build Settings... to build the project targeting iOS platform. Leave all the settings with their default values. This will produce a folder with Xcode project in it.
    3. Close Unity and open auto-generated Xcode project (I use Xcode 6.2).
    4. Build and run (Cmd + R) the project. You may also need to remove 'UILaunchStoryboardName~iphone' key from Info.plist if you use free version of Unity (otherwise it will crash on runtime when checking for Unity's default launch screens).
    5. Open 'UnityAppController.mm' and make the following changes:

    A. Import following header files:
    Code (CSharp):
    1. #import <AVFoundation/AVFoundation.h>
    2. #import <MediaPlayer/MPMediaItem.h>
    3. #import <MediaPlayer/MPNowPlayingInfoCenter.h>
    (it's Objective C and not C#, but these forums don't have a preset for it).

    B. Add a property for AVPlayer object using class extension.

    Code (CSharp):
    1. @interface UnityAppController ()
    2.  
    3. @property AVPlayer *player;
    4.  
    5. @end
    C. Add the following new methods in class implementation:

    Code (CSharp):
    1. - (BOOL)canBecomeFirstResponder
    2. {
    3.     return YES;
    4. }
    5.  
    6. - (void)remoteControlReceivedWithEvent:(UIEvent *)event
    7. {
    8.     if (event.type == UIEventTypeRemoteControl) {
    9.         switch (event.subtype) {
    10.             case UIEventSubtypeRemoteControlPlay:
    11.                 [self play];
    12.                 break;
    13.             case UIEventSubtypeRemoteControlPause:
    14.             case UIEventSubtypeRemoteControlStop:
    15.                 [self pause];
    16.                 break;
    17.             case UIEventSubtypeRemoteControlTogglePlayPause:
    18.                 [self togglePlayPause];
    19.                 break;
    20.             default:
    21.                 break;
    22.         }
    23.     }
    24. }
    25.  
    26. - (void)setupPlayer
    27. {
    28.     [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
    29.     [[AVAudioSession sharedInstance] setActive:YES error:nil];
    30.    
    31.     [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    32.     [[UIApplication sharedApplication] becomeFirstResponder];
    33.    
    34.     self.player = [AVPlayer playerWithURL:[NSURL URLWithString:@"http://81.9.96.34/eldoradio-64k"]];
    35.     self.player.allowsExternalPlayback = YES;
    36.    
    37.     NSDictionary *nowPlayingInfo = [NSMutableDictionary dictionary];
    38.     [nowPlayingInfo setValue:@"Eldoradio" forKey:MPMediaItemPropertyTitle];
    39.     [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:nowPlayingInfo];
    40.    
    41.     [self play];
    42. }
    43.  
    44. - (void)togglePlayPause
    45. {
    46.     if (self.player.rate == 0.f) {
    47.         [self play];
    48.     }
    49.     else {
    50.         [self pause];
    51.     }
    52. }
    53.  
    54. - (void)play
    55. {
    56.     [self setPlayerRate:1.f];
    57. }
    58.  
    59. - (void)pause
    60. {
    61.     [self setPlayerRate:0.f];
    62. }
    63.  
    64. - (void)setPlayerRate:(float)rate
    65. {
    66.     self.player.rate = rate;
    67.    
    68.     MPNowPlayingInfoCenter *nowPlayingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
    69.     NSDictionary *nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo;
    70.     if (nowPlayingInfo) {
    71.         NSMutableDictionary *mutableNowPlayingInfo = [nowPlayingInfo mutableCopy];
    72.         [mutableNowPlayingInfo setValue:@(rate) forKey:MPNowPlayingInfoPropertyPlaybackRate];
    73.         [nowPlayingInfoCenter setNowPlayingInfo:mutableNowPlayingInfo];
    74.     }
    75. }
    D. Call [self setupPlayer]; in the beginning of application:didFinishLaunchingWithOptions: method:

    Code (CSharp):
    1. - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
    2. {
    3.     [self setupPlayer];
    4.    
    5.     printf_console("-> applicationDidFinishLaunching()\n");
    6. Build and run the application and open iOS Control Center.

    You should see that 'Play' button is displayed but does nothing at all. It is displayed even without any modifications in code - just in the empty Unity project. Moreover, sometimes audio even doesn't start playing but I haven't found any regularity in that.

    I've attached the same code in empty iOS project and it works exactly as expected.

    Does anybody know any way to work around this issue and make iOS Control Center work with native audio player and Unity?
     

    Attached Files:

  2. dreipol

    dreipol

    Joined:
    Jul 20, 2015
    Posts:
    3
    Hey, @FedorChunovkin have you ever managed to fix this problem?
    We kind of have the same behaviour here.
    Thanks!
     
  3. mkurnadi

    mkurnadi

    Joined:
    Jan 29, 2016
    Posts:
    6
    We experienced similar issue, would you mind sharing solutions Mr Fedor ?
     
  4. DVFrance

    DVFrance

    Joined:
    Jul 9, 2012
    Posts:
    19
    +1 on any news about this, I'm kind of stuck.

    I think so but did you try application.runinbackground ?
    Also Enable xcode capabilities "Background Modes" Audio AirPlay and PiP ?
     
  5. prawn-star

    prawn-star

    Joined:
    Nov 21, 2012
    Posts:
    64
    Anyone found a solution to this?
     
  6. pulteraoz

    pulteraoz

    Joined:
    Feb 13, 2017
    Posts:
    3
    bump +1 would be also interested in this
     
  7. inood

    inood

    Joined:
    Aug 9, 2018
    Posts:
    1
    BUmp:) +one
     
  8. prawn-star

    prawn-star

    Joined:
    Nov 21, 2012
    Posts:
    64
    Hi inood

    I eventually found a solution to this which involved bypassing the Unity audio altogether.
    In my plugin I have a MPMoviePlayerController defined which I send the streamed or local audio link to play via Unity.
    This way the MPRemoteCommandCenter doesn't have to interact with Unity at all, it can just call code within the plugin when the app is minimized and teh control center takes over.
    I'm using MPMoviePlayerController (it can play hidden and mp3) because it does both streamed and local files, but there's probably a more updated solution.