13

I have an app that needs to have:

  • Background music playing while using the app (eg. spotify)
  • Background music playing while watching movie from AVPlayer
  • Stop the music when recording a video

Like Snapchat, the camera-viewcontroller is part of a "swipeview" and therefore always on.

However, when opening and closing the app, the music makes a short "crack" noise/sound that ruins the music.

I recorded it here: https://soundcloud.com/morten-stulen/hacky-sound-ios (3 occurrences)

I use these settings for changing the AVAudiosession in the appdelegate didFinishLaunchingWithOptions:

     do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord,withOptions: 
                [AVAudioSessionCategoryOptions.MixWithOthers,
                 AVAudioSessionCategoryOptions.DefaultToSpeaker])
            try AVAudioSession.sharedInstance().setActive(true)

        } catch {
            print("error")
        }

I use the LLSimpleCamera control for video recording and I've set the session there to:

_session.automaticallyConfiguresApplicationAudioSession = NO;

It seems others have the same problem with other camera libraries as well: https://github.com/rFlex/SCRecorder/issues/127

https://github.com/rFlex/SCRecorder/issues/224

This guy removed the audioDeviceInput, but I kinda need that for recording video. https://github.com/omergul123/LLSimpleCamera/issues/48

I also tried with Apple's code "AvCam", and I still have the same issue. How does Snapchat do this?!

Any help would be greatly appreciated, and I'll gladly provide more info or code!

Morten Stulen
  • 1,243
  • 1
  • 14
  • 26
  • Did you find a solution? I need the same thing and can't achieve it. – Marie Dm Jun 10 '16 at 08:45
  • 1
    I found a solution, but it's not optimal. I add the audiodeviceInput when I start recording ( [self.session addInput:_audioDeviceInput]; ) and remove it when I'm done. At the same time I set the AVAudioSession Category to AVAudioSessionCategoryPlayAndRecord, which I also switch back afterwards. To compensate for the weird camera UI behavior, I fade in and out a blur-view on top. – Morten Stulen Jun 10 '16 at 22:09
  • Yes, that's what I tried. Not optimal as you said. I also tried to keep PlayAndRecord category with MixWithOthers, DuckOthers, DefaultToSpeaker but the background music stops for a second when I init the session. Also the music is too loud (even with Duckothers) and I can't hear well my own sound when it's playing. – Marie Dm Jun 11 '16 at 11:18
  • It shouldn't stop if you init the session without audioInput and with AVAudioSessionCategoryAmbient. I have AVAudioSessionCategoryAmbient without an audioInput which will let you listen to background music while taking a picture and everything else in the app, but won't record sound when recording video. So I add the audioInput when I start recording and at the same time switch to AVAudioSessionCategoryPlayAndRecord which will fade out the music. (BTW, even Snapchat has crack-sound when switching audiosession if you listen to music when filming. I don't believe there is an optimal solution) – Morten Stulen Jun 11 '16 at 19:36

1 Answers1

5

I do something similar to what you're wanting, but without the camera aspect, but I think this will do what you want. My app allows background audio that will mix with non-fullscreen video/audio. When the user plays an audio file or a full screen video file, I stop the background audio completely.

The reason I do SoloAmbient then Playback is because I allow my audio to be played in the background when the device is locked. Going SoloAmbient will stop all background music playing and then switching to Playback lets my audio play in the app as well as in the background.

This is why you see a call to a method that sets the lock screen information in the Unload method. In this case, it is nulling it out so that there is no lock screen info.

In AppDelegate.swift

//MARK: Audio Session Mixing
func allowBackgroundAudio()
{
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, withOptions: .MixWithOthers)
    } catch {
        NSLog("AVAudioSession SetCategory - Playback:MixWithOthers failed")
    }
}

func preventBackgroundAudio()
{
    do {
        //Ask for Solo Ambient to prevent any background audio playing, then change to normal Playback so we can play while locked
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient)
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
    } catch {
        NSLog("AVAudioSession SetCategory - SoloAmbient failed")
    }
}

When I want to stop background audio, for example when playing an audio track that should be alone, I do the following:

In MyAudioPlayer.swift

func playUrl(url: NSURL?, backgroundImageUrl: NSURL?, title: String, subtitle: String) 
{
    ForgeHelper.appDelegate().preventBackgroundAudio()

    if _mediaPlayer == nil {
        self._mediaPlayer = MediaPlayer()
        _mediaPlayer!.delegate = self
    }

    //... Code removed for brevity
}

And when I'm done with my media playing, I do this:

private func unloadMediaPlayer()
{
    if _mediaPlayer != nil {
        _mediaPlayer!.unload()
        self._mediaPlayer = nil
    }

    _controlView.updateForProgress(0, duration: 0, animate: false)

    ForgeHelper.appDelegate().allowBackgroundAudio()
    setLockScreenInfo()
}

Hope this helps you out!

  • Thanks for your answer! However, it's different when dealing with a camera because the camera requires audio-input. According to the [Apple Documentation](https://developer.apple.com/library/ios/documentation/Audio/Conceptual/AudioSessionProgrammingGuide/AudioSessionCategoriesandModes/AudioSessionCategoriesandModes.html#//apple_ref/doc/uid/TP40007875-CH10-SW1) the AVAudioSessionCategoryPlayback only allows output. Using your example code, the background music plays fine, but the camera won't start. – Morten Stulen Nov 25 '15 at 16:00