21

I am using MPVolumeView for showing Airplay icon and it works fine.

But I need to show an animation when Airplay network comes, and hide that animation when airplay network hides.

Is there a notification that will let me know when Airplay starts and ends?

Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165
sankar siva
  • 255
  • 1
  • 2
  • 5
  • And check out this answer for a nice approach - http://stackoverflow.com/questions/12318377/how-to-customize-the-airplay-button-when-airplay-is-active – amergin Oct 18 '12 at 20:22
  • Is there really no apple notification for this, a year from this question's date? – Morkrom Feb 05 '14 at 21:06

6 Answers6

18

This is exactly what you're looking for - https://github.com/StevePotter/AirPlayDetector

It is a single class that provides a property to determine whether airplay devices are active. And a notification when availability changes.

Using it is simple. Like, to determine availability you write:

[AirPlayDetector defaultDetector].isAirPlayAvailable

Enjoy!

Steve Potter
  • 1,899
  • 2
  • 22
  • 25
  • Nice hack. Obviously it will need testing with every iOS release. Is this acceptable in the App Store, I realise it isn't using private APIs but still wondering? – mttrb May 14 '12 at 15:29
  • That's for Apple to say, not us. We can't speak for them or their policies. But my gut says it'll be acceptable. – Jonathan Grynspan May 14 '12 at 15:43
  • We had no problem with it being accepted. MPVolumeView is a public class. The only questionable thing going on is looping through its subviews. But it doesn't use any private APIs. – Steve Potter May 14 '12 at 16:10
  • By the way, here is an ARC compatible version. https://github.com/MobileVet/AirPlayDetector – Morkrom Feb 07 '14 at 17:16
  • This does not guarantee that airplayIsAvailable. That alpha value of volumeView's routeSelection button will be set if there are any wirelessRoutes available. It just does same as MPVolumeView's volumeView.areWirelessRoutesAvailable – ambientlight Jul 30 '14 at 18:17
  • It works for me on both iOS 7 and 8. And observing the alpha value is a good idea! – RayChen Aug 05 '15 at 03:22
  • Hey all, I updated the readme in the repo. I'm not longer doing ios development so I can't manage the project. Forks are welcome – Steve Potter Aug 06 '15 at 13:49
  • @RayChen It doesn't guarantee, it will be true in the case when wireless routes are available, that means bluetooth device is available, but airplay device is not. It will do exactly the same as volumeView.areWirelessRoutesAvailable; – ambientlight Feb 18 '16 at 08:07
8

To be precise: To check exactly for airplay with public API: NO

All you can do with public API is to check for available wireless routes, which includes airplay in it: (In simple case when you have a MPVolumeView instance hooked up somewhere to your view, you can just call volumeView.areWirelessRoutesAvailable;)

If you are curious how to check if exactly airplay is available with private API:

- (BOOL)isAirplayAvailable
{
    Class MPAVRoutingController = NSClassFromString(@"MPAVRoutingController");
    id routingController = [[MPAVRoutingController alloc] init];

    NSArray* availableRoutes = [routingController performSelector:@selector(availableRoutes)];
    for (id route in availableRoutes) {
        NSDictionary* routeDescription = [route performSelector:@selector(avRouteDescription)];
        if ([routeDescription[@"AVAudioRouteName"] isEqualToString:@"AirTunes"])
            return true;
    }

    return false;
}

(And in fact MPVolumeView has an MPAVRoutingController instance as its ivar, so the -areWirelessRoutesAvailable is just an accessor exactly for [volumeView->_routingController wirelessDisplayRoutesAvailable])

Also AVAudioSession exposes currentRoute to you, so you do can check if airplay is active easily with:

- (BOOL)isAudioSessionUsingAirplayOutputRoute
{
    AVAudioSession* audioSession = [AVAudioSession sharedInstance];
    AVAudioSessionRouteDescription* currentRoute = audioSession.currentRoute;
    for (AVAudioSessionPortDescription* outputPort in currentRoute.outputs){
        if ([outputPort.portType isEqualToString:AVAudioSessionPortAirPlay])
            return true;
    }

    return false;
}

(the answer about AirPlayDetector doesn't guarantee that Airplay is available - all it does it checks the alpha value of MPVolumeView's routeSelection button, which will be shown in any case when wireless routes are available, bluetooth for example. It will do exactly the same as volumeView.areWirelessRoutesAvailable;)

ambientlight
  • 7,212
  • 3
  • 49
  • 61
  • In conjonction with an AVPlayer's method `isExternalPlaybackActive` when an AVPlayerItem is loaded it's perfect for me. Thanks! – iGranDav Feb 09 '15 at 22:08
  • So that means, that MPVolumeView instance will not show if bluetooth is turned off? – KarenAnne Apr 13 '16 at 08:35
  • you mean volumeView.areWirelessRoutesAvailable? AVAudioSession treats bluetooth and airplay audio devices similarly. As long as any of the available wireless devices are available (bluetooth or airplay) -> it will return true. – ambientlight Apr 13 '16 at 08:40
7

There's a MPVolumeViewWirelessRoutesAvailableDidChangeNotification since iOS 7 you can register for.

Micky
  • 5,578
  • 7
  • 31
  • 55
3

It can be done much easier with ReactiveCocoa. Check it out:

MPVolumeView *myVolumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(0, 0, 180, 22)];
for (UIView *view in myVolumeView.subviews) {
    if ([view isKindOfClass:[UIButton class]]) {
        [[RACAbleWithStart(view, alpha) distinctUntilChanged] subscribeNext:^(id x) {
            NSLog(@"airplay button visibility changed %@", x);
        }];
        [[RACAbleWithStart(view, frame) distinctUntilChanged] subscribeNext:^(id x) {
            NSLog(@"airplay button connection changed %@", x);
        }];
    }
}
Roman B.
  • 3,598
  • 1
  • 25
  • 21
  • I wouldn't do this. This solution could break at any time if Apple ever decides that the AirPlay button isn't a top-level subview of MPVolumeView. Or if they ever decide that the AirPlay view is no longer a UIButton. – Alexander Mar 09 '15 at 19:36
  • @Alexander true, but the change will not cause a crash, so assuming there are no public apis available its ok – Roman B. Mar 09 '15 at 20:52
0

6 years later. I think Sankar Siva did not ask for detecting, but for activating an airplay route.

I've upped @Alf because he placed me on the right direction, but he is not answering to the question.

MPVolumeViewWirelessRoutesAvailableDidChangeNotification fires when MPVolumeView detects a new route.

On the other hand, MPVolumeViewWirelessRouteActiveDidChangeNotification fires when a new route is taken, eg: when you select your Apple TV for example.

No need of private API.

Martin
  • 11,881
  • 6
  • 64
  • 110
0

If you want a notification here is the way to do it

[[NSNotificationCenter defaultCenter]
    addObserver:self
    selector: @selector(deviceChanged:)
    name:AVAudioSessionRouteChangeNotification
    object:[AVAudioSession sharedInstance]];

- (void)deviceChanged:(NSNotification *)sender {
      NSLog(@"Enters here when connect or disconnect from Airplay");
}