1

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.

amergin
  • 3,106
  • 32
  • 44
  • My app fades songs in and out over airplay successfully. Can you post some code you're using to do the volume adjustments? – sam_899 Oct 19 '12 at 20:00
  • Thanks for the response Sam, I have posted some code into my question. – amergin Oct 19 '12 at 23:37
  • I had a further play with my app and confirm it actually doesn't do the fade properly. When I tested it, I was testing with Airplay mirroring turned on which worked fine. When using airplay for just audio, it doesn't play nicely. I'm sure that it worked in iOS 5 alright when I last tested it with just audio, but I was using a different device then. I'm currently testing with [AirServerApp for mac](http://www.airserverapp.com/en/Download/Referrer/231237) What device are you testing with? – sam_899 Oct 20 '12 at 10:03
  • Testing with an ipad3 and AirServer app but I've tested with Reflection app as well on the mac. I still have ios 5 on my 4s and that exhibits the same problems. Very interesting observation about it working with mirroring on, I hadn't tried that and it works as you say. I need to have a think about this and see if this will do as a workaround. Many thanks Sam. – amergin Oct 21 '12 at 17:15
  • Sam, I've decided the only way to handle this is with Airplay Mirroring and to remove the MPVolumeView. If you put your suggestion up as an answer I'll acknowledge it. Thanks. – amergin Oct 29 '12 at 18:36

1 Answers1

2

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.

amergin
  • 3,106
  • 32
  • 44