Search code examples
iosaudioavplayerairplay

AVPlayer audio volume over Airplay?


Does anyone know of a way to adjust an AVPlayer track's volume when it is playing over Airplay? I have tried AVAudioMix and MPVolumeView but neither of them work. I have tried on iOS 5 and iOS 6 and am using the latest xcode 4.5.1. A simple example of this not working is Apple's AVPlayerTestApp which does a simple fade out using setVolumeRampFromStartVolume. This works fine on the device but doesn't if connected through Airplay.

In ViewDidLoad I load a track and start it playing (this is all taken from AVPlayerTestApp)

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:TRUE error:nil];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];

self.mediaItems = [[[MPMediaQuery songsQuery] items] mutableCopy];

NSURL *anUrl = [[mediaItems objectAtIndex: 0] valueForProperty:MPMediaItemPropertyAssetURL];
AVAsset *asset = [AVURLAsset URLAssetWithURL:anUrl options:nil];
AVPlayerItem *myPlayerItem = [AVPlayerItem playerItemWithAsset:asset];


self.myPlayer1 = [[[AVPlayer alloc] initWithPlayerItem:myPlayerItem] retain];

[myPlayer1 play];

then I have a button which opens an alertview allowing user to set volume and switch on airplay

MPVolumeView *volumeView = [[[MPVolumeView alloc] initWithFrame: CGRectMake(10, 37, 260, 20)] autorelease];
UIAlertView *volumeAlert = [[UIAlertView alloc] initWithTitle:@"Volume" message:@"" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[volumeView sizeToFit];
[volumeAlert addSubview:volumeView];
[volumeAlert show];
[volumeAlert release];

then another button which fades out the currently playing track

AVAsset *asset = [myPlayer1.currentItem asset];
NSArray *keys = [NSArray arrayWithObject:@"tracks"];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^(void) {
    NSError *error = nil;
    AVKeyValueStatus trackStatus = [asset statusOfValueForKey:@"tracks" error:&error];
    CMTime currentTime;
    switch (trackStatus) {
        case AVKeyValueStatusLoaded:
            if(myPlayer1)
            {
                NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeAudio];
                NSMutableArray * allAudioParams = [NSMutableArray array];
                for (AVAssetTrack *t in tracks) {
                    AVMutableAudioMixInputParameters *params =[AVMutableAudioMixInputParameters audioMixInputParameters];

                    float fadeOutSeconds = 5;

                    currentTime = [myPlayer1 currentTime];

                    [params setVolumeRampFromStartVolume: 1.0 toEndVolume: 0.0 timeRange: CMTimeRangeMake(currentTime, CMTimeMakeWithSeconds(fadeOutSeconds, 1))];

                    [params setTrackID:[t trackID]];
                    [allAudioParams addObject:params];
                }
                AVMutableAudioMix * zeromix = [AVMutableAudioMix audioMix];
                [zeromix setInputParameters:allAudioParams];

                [myPlayer1.currentItem setAudioMix:zeromix];
            }

            break;
        case AVKeyValueStatusFailed:
            // error occured loading AVAsset
            NSLog(@"error occured loading AVAsset");
            break;
        case AVKeyValueStatusCancelled:
            // loading of the AVAsset was cancelled
            NSLog(@"loading of the AVAsset was cancelled");
            break;
        default:
            break;
    }
}];

This works as expected on the device and fades the volume when the button is tapped. However, if Airplay is turned on the volume change doesn't get through. Using MPMoviePlayController I can do fades myself which work over Airplay but AVPlayer has less latency over Airplay so I would rather use that.

Any help much appreciated.


Solution

  • As Sam_899 didn't post an answer I'll have to do it. As far as I can work out, it is impossible to control the volume of avplayer over airplay unless the connection is made with mirroring turned on. As the only way to turn mirroring on is from outside your app the only option is to inform users how to turn it on themselves and hope they are happy with it! For those who don't know how to turn on mirroring over airplay; double click the home button, swipe left to the volume control, tap the airplay icon, choose the airplay device to connect to then switch mirroring on.