hirbod / react-native-volume-manager

React Native module which adds the ability to change the system volume on iOS and Android, listen to volume changes and supress the native volume UI to build your own volume slider or UX. It can listen to iOS mute switch and ringer mode changes on Android (and let you set the ringer mode)
MIT License
216 stars 14 forks source link

Feature Question: Check if User Has HeadPhones in Using This Library? #27

Open ChristopherGabba opened 4 months ago

ChristopherGabba commented 4 months ago

Is there a way to use this library to see which audio output is being used? By example:

const speakerOutput = await VolumeManager.getSpeakerOutput()
console.log(speakerOutput) // nativeSpeakers, headPhones, airPods, etc.
hirbod commented 4 months ago

That's a valid feature request. I'll look into this in January 2024 :)

ChristopherGabba commented 4 months ago

Thanks @hirbod! I did do some further research on this request and it turns out that the react-native-device-info package does have a headphones check api. Will keep you posted on it.

https://www.npmjs.com/package/react-native-device-info#isHeadphonesConnected

While I've got you here, I did actually have a few questions with your library. I have an app that requires recording video (front camera on phone) and playing videos on the screen (like an expo-av video component). This obviously leads to a fine balance of phone audio to recording audio (you don't want to pick up the videos volume up through the camera mic). I've been using this library and some things work perfectly. For example, setting the volume or setting the "enableInSilenceMode" flag worked flawlessly. See some of my comments below:

Here is an example of my setup code on the screen that records:

     useEffect(() => {
    ;(async function manageVolume() {
      await Promise.all([
        VolumeManager.enableInSilenceMode(true),
        VolumeManager.setActive(true, true),
        VolumeManager.enable(true, true),
        VolumeManager.setCategory("PlayAndRecord", true),
        VolumeManager.setMode("Default"),
      ])
        .then(() => {
          setIsAudioReady(true)
          console.log("audio set up correctly")
        })
        .catch((e) => {
          console.log("Error with audio", e)
        })
    })()

    return () => {
      VolumeManager.setActive(false)
      VolumeManager.enable(false)
    }
  }, [])

I guess what I'm struggling with is do we have to use the "enable" flag or "setActive" flag and what is the lifecycle of this volume manager? Does my code above seem correct? I also believe that the camera package I'm using "react-native-vision-camera" may have it's own AVSessions that it sets (thus overwriting the VolumeManager) when it starts recording. Is this something that could be happening and that's why adjusting the category / mode doesn't make much difference in audio control?

hirbod commented 4 months ago

Hi,

Indeed, most third-party modules start or enable audio sessions on their own. This can be troublesome, especially with expo-av and react-native-video. In my own apps, this leads to issues for me as well. I personally patched expo-av and removed every category and audio session management because I had to enable and disable them on my own. Expo AV, for example, changes the sessions and category when the app is foregrounding or backgrounding, thus interrupting the listeners of the library. I hope that these third-party modules will update in the future with a less opinionated option and leave it to the developers to set those sessions. But all in all, your lifecycle seems fine to me in a best-world scenario where no other library interrupts the settings.

ChristopherGabba commented 4 months ago

@hirbod Brilliant explanation. Thanks so much, that makes so much sense based off what I've been experiencing. Super frustrating because I would set the audio session with Volume Manager and see little to no progress. This explains all of it.

Anyway, thanks again!