Gaby Fitcal
Gaby Fitcal

Reputation: 1944

Turn off audio playback of AVPlayer?

I have a AVPlayer with AVPlayerItem. What I want is to turn off the audio playback in the AVPlayer. I want to play only video, no audio.

Here's what I have so far:

self.avPlayerItem = [AVPlayerItem playerItemWithURL:self.videoUrl];
self.avPlayer = [AVPlayer playerWithPlayerItem:self.avPlayerItem];
[self.avPlayer play];
self.avPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;

self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
self.avPlayerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(playerItemDidPlayToEndTime:)                                           
                                             name:AVPlayerItemDidPlayToEndTimeNotification
                                           object:self.avPlayerItem];

CGRect screenRect = [[UIScreen mainScreen] bounds];

self.avPlayerLayer.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
[self.view.layer insertSublayer:self.avPlayerLayer atIndex:0];

Upvotes: 27

Views: 24498

Answers (5)

AddWeb Solution Pvt Ltd
AddWeb Solution Pvt Ltd

Reputation: 21681

You can mute the audio by implementing following code into viewDidLoad().

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

// Mute all the audio 
tracksNSMutableArray *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];

Following links may help you.

  1. https://developer.apple.com/hints/reference/avfoundation/av_foundation_audio_settings_constants#//apple_ref/c/tdef/AVAudioQuality
  2. https://developer.apple.com/library/archive/qa/qa1716/_index.html

Upvotes: -1

Anjan Biswas
Anjan Biswas

Reputation: 7912

As @Tung Fam's answer suggests, you can easily do this in your app to mute a video:

player.isMuted = true

Handling All Use Cases

You may run a video on mute using the code above, the problem is, if you simply use isMuted = true (for let's say the video preview) it will work, but your app will "hijack" any existing system AVAudioSession. This means if the user was, let's say, listening to music (Spotify or Apple Music), their music would get interrupted. This is because app's have AVAudioSession set to AVAudioSessionCategorySoloAmbient by default, therefore your app will ALWAYS interrupt all running audio sessions in the background as soon as it starts playing a video, muted or un-muted. This may not be a very pleasing user experience and lead to confusion.

What you may want to do is show your video muted as a preview while the user continues to play their song in the background. When user goes to full screen with your app's video, any background audio must "pause" or be "interrupted"; essentially your app will take over the AVAudioSession. Then, once you are done playing your video let the "interrupted" background audio (e.g. Spotify, Apple Music, etc.) resume. The steps below achieve a behavior similar to how Twitter handles videos and background music:

  1. In your AppDelegate's didFinishLaunchingWithOptions method make sure your app is not interrupting any background music. Because your videos would be running in "mute" you can simply mixWithOthers.

    do {
        try AVAudioSession.sharedInstance().setCategory(
            AVAudioSession.Category.playback, 
            options: [.mixWithOthers]
        )
        try AVAudioSession.sharedInstance().setActive(true)
    } catch { /* some meaningful exception handling */ }
    
  2. When your App starts to play your video Full screen (un-muted/with sound), you must now interrupt any background music. For that, before your player.play() you can set the AVAudioSession again, like so-

    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
        try AVAudioSession.sharedInstance().setActive(true)
    } catch { /* some meaningful exception handling */ }
    

    This will basically pause/interrupt any background audio in progress and let your video play with sound.

  3. Once your video is done playing with sound, you must now let the AVAudioSession know that it can resume any audio session that was interrupted by you (i.e. Spotify, Apple Music, map navigation instructions etc.). To do that, once your video stops playing you can do this:

    do {
        try AVAudioSession.sharedInstance().setCategory(
            AVAudioSession.Category.playback, 
            options: [.mixWithOthers]
        )
        try AVAudioSession.sharedInstance().setActive(false, options: AVAudioSession.SetActiveOptions.notifyOthersOnDeactivation)
    } catch { /* Some meaningful exception handling */ }
    

There are a lot more options available on how to handle AVAudioSession. Here's the documentation, and here are Apple's guidelines on using AVAudioSession for different types of apps.


This is just a very basic explanation on how AVAudioSession can be used, but depending on your app's functionality there may be a need to use KVOs, AppDelegate methods (for app going to background and or coming to foreground and so on) to set the AVAudioSession appropriately. Further caveat is that you really need to play around with all the options on AVAudioSession since it may not work the way you think it should so it could become a little grueling. Even more caveat is that surprisingly I've found very little online that goes into detail with AVAudioSession except for Apple's documentation and a few questions here on SO.

Bottom line is: if your app deals with audio/video then it is HIGHLY recommended to handle AVAudioSession appropriately based on Apple's playbook of "Audio Guidelines By App Type"... maybe not when you launch your app but definitely as your app matures and becomes more stable.

Upvotes: 50

glemoulant
glemoulant

Reputation: 527

You can add this in the AppDelegate didFinishLaunchingWithOptions. If you don't want your video to stop the sound that is currently played on other apps (even if your video player is set to mute)

func setAudioMix(){
    do{
        try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: [.mixWithOthers])
        try AVAudioSession.sharedInstance().setActive(true)
    }catch{
        print("something went wrong")
    }
}

Upvotes: 2

Tung Fam
Tung Fam

Reputation: 8147

In case someone is looking for Swift 4:

player.isMuted = true // To mute the sound
player.isMuted = false // To un-mute the sound

Side note: muting the video does not reset the video sound to start. It works as just a common sense mute feature.

Upvotes: 7

Joe Hallenbeck
Joe Hallenbeck

Reputation: 1450

AVPlayer have option

@property (nonatomic, getter=isMuted) BOOL muted NS_AVAILABLE(10_7, 7_0);

You can write

- (void) muteSound:(BOOL)mute
{
    self.avPlayer.muted = mute;
}

And use it, how you want

- (void) startPlayingVideo
{

    [self muteSound:YES];

    //other code

} 

Upvotes: 25

Related Questions