24

I have a AVPlayer with AVPlayerItem. What i want is to turn off the audio playback off AVPlayer. I want play just video.

Can someone help me? Thank you!

    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];
Gaby Fitcal
  • 1,814
  • 1
  • 17
  • 28

5 Answers5

45

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

player.isMuted = true

Handling all the 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" the AVAudioSession from the Operating system, which means if the user was, lets say, listening to music (spotify or apple music), their music would get interrupted. That is because your App will have a default setup of AVAudioSession to AVAudioSessionCategorySoloAmbient , which means that your app will ALWAYS interrupt all audio sessions that is running 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 taking over the AVAudioSession. And then once you are done playing your video let the "interrupted" background music (example: Spotify, Apple Music etc.) to resume. The steps below achieves exactly how Twitter's app handles videos and background music-

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

      do{
       try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, 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(AVAudioSessionCategoryPlayback)
          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.

  1. 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(AVAudioSessionCategoryPlayback, options: [.mixWithOthers])
           try AVAudioSession.sharedInstance().setActive(false, options: AVAudioSessionSetActiveOptions.notifyOthersOnDeactivation)
        }catch{//some meaningful exception handling}
    

There's a lot more options available on how to handle AVAudioSession and here's the documentation. And here are Apple's guidelines on using AVAudioSession for different type 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 here and there. Bottom line is - if your app deals with Audio/Videos 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.

Lucas Derraugh
  • 6,929
  • 3
  • 27
  • 43
Anjan Biswas
  • 7,746
  • 5
  • 47
  • 77
  • This answer is great, Thank you :) – Rahul Singha Roy Jan 28 '19 at 10:10
  • 3
    The API for this is now `AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [AVAudioSession.CategoryOptions.mixWithOthers])` – Reza Shirazian Jun 07 '19 at 05:05
  • Is it necessary to call setActive(true) after making category/option changes? – tmm1 Jan 29 '21 at 01:10
  • There is only one problem with mixWithOthers - it disables Control Center functionality if you use it :(. If you enable mixWithOthers, you won't be able to display your information in Media Player in Control Center... – Wojciech Kulik Oct 20 '21 at 13:56
  • Well, Is this that of what Facebook does? Thx xD – KoreanXcodeWorker Feb 18 '22 at 06:08
  • @KoreanXcodeWorker I am not entirely sure about Facebook. But Twitter definitely does this. – Anjan Biswas Jul 24 '22 at 04:41
  • @WojciechKulik +1, As I mentioned in my answer, there are a whole host of things that needs to be looked into when dealing with `AVAudioSession`; control center is one of them. Unfortunately, I am far from iOS development at the moment, so I can't shed too much light on this. – Anjan Biswas Jul 24 '22 at 04:48
25

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

} 
Joe Hallenbeck
  • 1,452
  • 12
  • 24
6

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.

Tung Fam
  • 7,899
  • 4
  • 56
  • 63
  • 2
    One small problem- if the user is playing a song (Spotify or Apple Music etc) in the background then the AVPlayer will take over the soundtrack and pause the music that is playing in the background – Anjan Biswas Apr 28 '18 at 19:54
  • @Annjawn hm interesting. but I'm wondering. if you play sound on your app do you want the other sound to be on the back, or should it be paused? – Tung Fam Apr 28 '18 at 22:01
  • It should be paused and it should resume again when your apps video stops. Checkout Twitter’s implementation. – Anjan Biswas Apr 28 '18 at 22:03
  • @Annjawn checked, yeah they did a good job. do you know the way how to make the same? or do you mean that we shouldn't use `isMuted` property in this case? – Tung Fam Apr 28 '18 at 22:06
  • 1
    i have a fair idea of how to achieve it... (got the idea from a Twitter Engineer himself :-) ). I am going to post an answer with the code shortly. – Anjan Biswas Apr 29 '18 at 02:22
  • Also, using `isMuted` is correct, to achieve the way twitter handles we will have to put just a little bit more code. – Anjan Biswas Apr 29 '18 at 02:30
  • @Annjawn gotcha:) looking forward to seeing your solution! – Tung Fam Apr 29 '18 at 07:35
  • posted the answer. – Anjan Biswas Apr 29 '18 at 09:25
  • How could we "delete" or deactivate the music so that when tunred on it does not overlap with other music? –  Nov 23 '18 at 21:30
2

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")
    }
}
glemoulant
  • 517
  • 7
  • 18
-1

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://goo.gl/WYJNUF
  2. https://goo.gl/epHNGs
AddWeb Solution Pvt Ltd
  • 21,025
  • 5
  • 26
  • 57