zmxv / react-native-sound

React Native module for playing sound clips

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`mixWithOthers` does not function correctly on iOS.

dsf3449 opened this issue · comments

🪲 Description

mixWithOthers permanently stops audio streams on iOS from other apps such as Spotify, even though mixWithOthers is declared as true.

🪲 What is the observed behavior?

Audio streams are stopped.

🪲 What is the expected behavior?

The sound being played from another app is played along side the sound from your app.

🪲 Please post your code:

In a brand new template app:

  1. npx react-native init TestClean
  2. npm i react-native-sounds
  3. pod install
  4. Add loop.mp3 to the xcode project.
  5. Check off background modes: Audio, AirPlay, and Picture in Picture, External accessory communication
  6. In App.js:
import Sound from "react-native-sound";

Sound.setCategory(`Playback`, true);
Sound.setMode(`Default`);

let sound = new Sound(`loop.mp3`, Sound.MAIN_BUNDLE, error => {
  sound.play();
  if (error) {
    console.error(error);
  } else {
    console.log('success');
  }
});

💡 Possible solution

According to the developer docs for AVAudioSessionCategoryOptionAllowBluetooth:

You can set this option only if the audio session category is AVAudioSessionCategoryPlayAndRecord or AVAudioSessionCategoryRecord.

However, in

if (category) {
if (mixWithOthers) {
[session setCategory:category
withOptions:AVAudioSessionCategoryOptionMixWithOthers |
AVAudioSessionCategoryOptionAllowBluetooth
error:nil];

It is setting this option regardless of the category.

💡 Is there a workaround?

Removing this declaration AVAudioSessionCategoryOptionAllowBluetooth no longer causes the sound to interrupt other apps. I also checked with bluetooth headphones, and there was no difference in behavior with or without this option being present.

Note: I tested this workaround only on playback category, iOS 15.4.

Using patch-package:

diff --git a/node_modules/react-native-sound/RNSound/RNSound.m b/node_modules/react-native-sound/RNSound/RNSound.m
index df3784e..aa97df6 100644
--- a/node_modules/react-native-sound/RNSound/RNSound.m
+++ b/node_modules/react-native-sound/RNSound/RNSound.m
@@ -175,8 +175,7 @@ - (NSDictionary *)constantsToExport {
     if (category) {
         if (mixWithOthers) {
             [session setCategory:category
-                     withOptions:AVAudioSessionCategoryOptionMixWithOthers |
-                                 AVAudioSessionCategoryOptionAllowBluetooth
+                     withOptions:AVAudioSessionCategoryOptionMixWithOthers
                            error:nil];
         } else {
             [session setCategory:category error:nil];

💡 If the bug is confirmed, would you be willing to create a pull request?

Sure

Is your issue with...

  • iOS
  • Android
  • Windows

Are you using...

  • React Native CLI (e.g. react-native run-android)
  • Expo
  • Other: (please specify)

Which versions are you using?

  • React Native Sound: 0.11.2
  • React Native: 0.67.4
  • iOS: iOS 15.4
  • Android: n/a
  • Windows: n/a

Does the problem occur on...

  • Simulator
  • Device

If your problem is happening on a device, which device?

  • Device: iPhone 13 Pro Max

OH MY GOD thank you so much @dsf3449!!! This is exactly the change I needed to make to get my app sounds to work while spotify is running.

To put the steps succintly.

  1. Set your background audio capability in XCode (or info.plist)

  2. In your instantiation of the Sound module, write

// Make sure to use Playback and set Mixwithothers to true
    Sound.setCategory('Playback', true)
// You only need to call the setActive(true) line *once in your code*, and you never set it to false, 
// EVER unless you no longer want audio to be played in background. 
// You do not need to try calling setActive(false) at any point in the onCompletion methods
    Sound.setActive(true)
  1. Then navigate to node_modules/react-native-sound/RNSound/RNSound.m
  2. Edit the line below as such
    Change
if (category) {
        if (mixWithOthers) {
            [session setCategory:category
                     withOptions:AVAudioSessionCategoryOptionMixWithOthers | 
                           AVAudioSessionCategoryOptionAllowBluetooth
                           error:nil];
        } else {
            [session setCategory:category error:nil];
        }
    }

TO

if (category) {
        if (mixWithOthers) {
            [session setCategory:category
                     withOptions:AVAudioSessionCategoryOptionMixWithOthers 
                    //  | AVAudioSessionCategoryOptionAllowBluetooth // I moved the '|' to the next line and commented it out
                           error:nil];
        } else {
            [session setCategory:category error:nil];
        }
    }

Thanks, guys! I had reported the same here as well, but as a feature request as I didn't know the lib supported this behavior.

#781

I have a peculiar case where I want the sound to play/mix together with Spotify with the device looking and the app in the background. Did you @ucheNkadiCode and @dsf3449 manage to make it work? I have tried iOS 15.4 it didn't

We had the same issue. We have sounds playing with Sound.setCategory('Ambient', true); which worked fine in the past and stopped working in the meantime.

I can confirm that the patch of @dsf3449 works and solves the issue. Thank you!

@ucheNkadiCode You should check out https://www.npmjs.com/package/patch-package instead of manually editing the file after each npm/yarn install.