How to mute/unmute audio when playing video using MPMoviePlayerController?

Camsoft picture Camsoft · Apr 11, 2013 · Viewed 15.3k times · Source

I've created my own custom controls for use with the MPMoviePlayerController. So far everything works except the mute button control.

I've configured the AVAudioSession using the following code before I create my instance of the MPMoviePlayerController.

    NSError *modeError = nil;
    [self.audioSession setMode:AVAudioSessionModeMoviePlayback error:&modeError];
    if (modeError != nil) {
        NSLog(@"Error setting mode for AVAudioSession: %@", modeError);
    }

    NSError *categoryError = nil;
    [self.audioSession setCategory:AVAudioSessionCategoryPlayback error:&categoryError];
    if (categoryError != nil) {
        NSLog(@"Error setting category for AVAudioSession: %@", categoryError);
    }

Then in my mute button callback method I have the following code:

    NSError *activeError = nil;
    [self.audioSession setActive:NO error:&activeError];
    if (activeError != nil) {
        NSLog(@"Error setting inactive state for AVAudioSession: %@", activeError);
    }

When clicking the Mute button I get the following unuseful error:

Error Domain=NSOSStatusErrorDomain Code=560030580 "The operation couldn’t be completed. (OSStatus error 560030580.)"

I am linking to the AVFoundation framework.

This is really starting to bug me as I can't for the life of me work out a way to reduce or mute the playback audio of my application.

I don't want to change the system global volume just the application level volume as defined by the AVAudioSession AVAudioSessionCategoryPlayback category.

It seems that you can set the volume of the AVAudioPlayer but not the MPMoviePlayerController. I've seen other posts here on SO that say just create an instance of AVAudioPlayer and set the volume but this just causes my app to crash and I expect it has something to do with the fact I'm not using the initWithContentsOfURL:error: or initWithData:error: and instead using `init'.

Any help would be appreciated.

Answer

Camsoft picture Camsoft · Apr 19, 2013

After speaking to an Apple technician it turns out that it's not possible to control or mute the audio using MPMoviePlayerController.

Instead you have to create your own controller using AVFoundations AVPlayer class.

Once you're using that it's a matter of creating a custom audio mix and setting the volume level. It actually works very well.

Sample code:

    AVURLAsset * asset = [AVURLAsset URLAssetWithURL:[self localMovieURL] options:nil];
    NSArray *audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];

    // Mute all the audio tracks
    NSMutableArray * allAudioParams = [NSMutableArray array];
    for (AVAssetTrack *track in audioTracks) {
            AVMutableAudioMixInputParameters *audioInputParams =[AVMutableAudioMixInputParameters audioMixInputParameters];
            [audioInputParams setVolume:0.0 atTime:kCMTimeZero ];
            [audioInputParams setTrackID:[track trackID]];
            [allAudioParams addObject:audioInputParams];
    }
    AVMutableAudioMix * audioZeroMix = [AVMutableAudioMix audioMix];
    [audioZeroMix setInputParameters:allAudioParams];

    // Create a player item
    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
    [playerItem setAudioMix:audioZeroMix]; // Mute the player item

    // Create a new Player, and set the player to use the player item
    // with the muted audio mix
    AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];

    self.mPlayer = player;

    [mPlayer play];

I've written an MPMoviePlayerController replacement class that adds support for volume level. I will upload the to github shortly and add the link in this post.