Search code examples
iosswiftavaudioplayer

How can i change current system volume without making the current music stopping


So i am looking for a way to change current system volume (volume played from other apps like YouTube Music or Spotify) but gradually, so that the user is not surprised with a sudden volume change.

I tried this :

import MediaPlayer
func changeVolume(volume: Float) async{
    do{
        try! AVAudioSession.sharedInstance().setActive(true)
    }
    var currentvol = AVAudioSession.sharedInstance().outputVolume
    let delta = volume - currentvol
    var incrementer = currentvol/10*delta
    
    print("--------------")
    print("Volume : \(volume)")
    print("currentvol : \(currentvol)")
    print("incrementer : \(incrementer)")
    print("delta : \(delta)")
    while(currentvol < volume){
        if(incrementer <= 0){
            incrementer = 0.01
        }
        currentvol += incrementer
        print("updated : \(currentvol)")
        await MPVolumeView.setVolume(currentvol)
        try! await Task.sleep(nanoseconds: UInt64(0.05 * Double(NSEC_PER_SEC)))
    }
    await MPVolumeView.setVolume(volume)
}

But the problem is that it pause the current music instead of just changing the volume (maybe because my app is taking over the mediaplayer i think)

My app do not play music so i'm just looking for a way to change volume from other apps while the user is using my app

Any idea how i could do ?

Thanks


Solution

  • Note that while what you're describing is likely possible (I've shipped a product that does this in order to interoperate with custom hardware), it's completely unsupported, is likely to break in the future (it broke a couple of times for me when the OS upgraded), and can potentially get your app removed from AppStore. Given the changes we've seen in recent releases, I expect the tricks used to pull this off won't work at all in future OS versions. The feature you're describing is not permitted by Apple. As the docs for AVAudioSession.outputVolume note: "Only the user can directly set the system volume. Provide a volume control in your app, using MPVolumeView, to provide the interface to adjust the system volume."

    There is no MPVolumeView.setVolume method in the public API, so it's unclear what you're actually doing here. You should likely include the code for the extension I assume you've written.

    That said, the reason it's pausing is because you told it to pause here:

        try! AVAudioSession.sharedInstance().setActive(true)
    

    The default behavior of this line is to take control of the audio session in .playback mode, which will interrupt all background sessions. Ideally you should not activate the audio session at all if you don't plan to play audio. If you do, then you should set the category to .ambient (to indicate that audio is not important for your app) or you should pass the option .mixWithOthers (to indicate it is important, but you still want other sessions to continue playing).

    Depending on your actual goals, a better solution to this is likely to pass the option .duckOthers, which will reduce the volume of other apps in a supported way.