Skip to content
This repository has been archived by the owner on Oct 6, 2022. It is now read-only.

Do lockscreen controls of this library (1.3.0) work on iOs with react-native 6.3.0 and expo-av 8.6.0 #378

Open
rubenkaiser opened this issue Mar 7, 2021 · 14 comments

Comments

@rubenkaiser
Copy link

After creating a basic player with this library I noticed the lockscreen controls are not showing. On Android everything is working fine, on the simulator in iOs however I can't get it to work.

In an useEffect I set the audio mode

      await Audio.setIsEnabledAsync(true);
      await Audio.setAudioModeAsync({
        allowsRecordingIOS: true,
        playsInSilentLockedModeIOS: true,
        playsInSilentModeIOS: true,
        interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
        shouldDuckAndroid: true,
        interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
        playThroughEarpieceAndroid: false,
        staysActiveInBackground: true,
      });

Also I initialize the controls:

    MusicControl.enableBackgroundMode(true);
    MusicControl.handleAudioInterruptions(true);

    MusicControl.enableControl('closeNotification', true, {when: 'always'});

    // Basic Controls
    MusicControl.enableControl('play', true);
    MusicControl.enableControl('pause', true);
    MusicControl.enableControl('stop', true);

    MusicControl.on('play', togglePlay);
    MusicControl.on('pause', togglePlay);
    MusicControl.on('stop', stopPlay);
    MusicControl.on('closeNotification', stopPlay);

After that I only call the play on the soundObject and update the controls:

await soundObject.playAsync();
MusicControl.setNowPlaying({ ... });

Any help is appreciated

@rubenkaiser rubenkaiser changed the title Do lockscreen controls of this library (1.3.0) work on iOs with the react-native 6.3.0 and expo-av 8.6.0 Do lockscreen controls of this library (1.3.0) work on iOs with react-native 6.3.0 and expo-av 8.6.0 Mar 8, 2021
@PupoSDC
Copy link

PupoSDC commented Mar 8, 2021

Im also struggling a lot with this: #377

Im still investigating, but so far I've realized the library does not work until you stop the controls once (lol). And since you can only stop the controls after starting. You need something like this:

        // fake start, necessary so we can stop the plugin safely
        MusicControl.enableBackgroundMode(true);
        MusicControl.handleAudioInterruptions(true);
        MusicControl.enableControl(Command.play, true);
        MusicControl.setNowPlaying({});
        MusicControl.updatePlayback(data); // you also need this or it wont work...

        setTimeout(() => {
            // The plugin doesn't work until we stop it at least once...
            // so we do it here.
            MusicControl.stopControl();
        }, 50);

        setTimeout(() => {
            // Real start.
            MusicControl.handleAudioInterruptions(true);
            MusicControl.enableBackgroundMode(true);
            MusicControl.enableControl(Command.play, true);
            MusicControl.enableControl(Command.pause, true);
            MusicControl.on(Command.play, onPlay);
            MusicControl.on(Command.pause, onPause);
            MusicControl.setNowPlaying(data);   
        }, 100);

@PupoSDC
Copy link

PupoSDC commented Mar 11, 2021

I finally got my hands on a real ios device, and unfortunately my rather hackish solution above only works on an emulator, not on a real device :(

@rubenkaiser
Copy link
Author

I tried your "hack" on both the simulator and a real device and it did not work in my project. Maybe you can share your simplest version of the app that worked on the simulator for me to check. I tried to run it on ios 14.4

@PupoSDC
Copy link

PupoSDC commented Mar 11, 2021

This is my current PoC with the basic needs of my project:

https://github.com/PupoSDC/react-native-multimedia-demo

it includes a video and audio player in which both are controlled via the native music controls.

Meanwhile i fixed the problem with ios devices by not setting mixWithOthers on react-native-video. Most of the problems with this library relate to how other libraries interact with the same base APIs, so if you are using different audio/video libraries your mileage may vary.

Im not using expo.

@rubenkaiser
Copy link
Author

Replacing Expo-av with react-native-sound-player fixed the issue in my app. I do still need the time out fix you proposed. My guess is that it indeed was an issue with expo-av and it's ios settings.

@PupoSDC
Copy link

PupoSDC commented Mar 14, 2021

yeay!
I think the root cause of all this silliness, is that most of these audio libraries also fiddle with the native controls in way or the other, and they all use the same base level API.

Thanks for confirming the timeout fix is needed for you as well, and that insanity is not my own only 😅

@PupoSDC
Copy link

PupoSDC commented Mar 26, 2021

After some back and forwarding we discovered the above solution / hack only works in development mode. as soon as the app is built, it stops working :(

If anyone has any ideas, it would be awesome to hear from you

@sshah98
Copy link

sshah98 commented Jun 17, 2021

Yeah we've tried using expo-av and react-native-music-control to no avail. Thanks for this thread, going to switch to react-native-sound-player as well :)

@devpolo
Copy link

devpolo commented Sep 7, 2021

Hi everyone 👋
Any news on that issue ? I’m stuck for many days now :/

@PupoSDC
Copy link

PupoSDC commented Sep 8, 2021

The IOS specific formula that worked for me ended up looking something like:

  MusicControl.handleAudioInterruptions(true);
  MusicControl.setNowPlaying(data);
  MusicControl.enableBackgroundMode(true);
  MusicControl.enableControl(Command.play, true);
  MusicControl.enableControl(Command.pause, true);
  MusicControl.enableControl(Command.closeNotification, true, {
    when: 'always',
  });

  MusicControl.enableControl(Command.skipBackward, !!onSkipBackward, {
    interval: skipInterval,
  });

  MusicControl.enableControl(Command.skipForward, !!onSkipForward, {
    interval: skipInterval,
  });

  MusicControl.on(Command.play, onPlay);
  MusicControl.on(Command.pause, onPause);
  MusicControl.on(Command.skipBackward, () => onSkipBackward?.(skipInterval));
  MusicControl.on(Command.skipForward, () => onSkipForward?.(skipInterval));

In any case it was still very unstable, requiring all stars to align, and some bugs still existed that I was unable to track down last i worked on this...

@temahot
Copy link

temahot commented Sep 20, 2021

The IOS specific formula that worked for me ended up looking something like:

  MusicControl.handleAudioInterruptions(true);
  MusicControl.setNowPlaying(data);
  MusicControl.enableBackgroundMode(true);
  MusicControl.enableControl(Command.play, true);
  MusicControl.enableControl(Command.pause, true);
  MusicControl.enableControl(Command.closeNotification, true, {
    when: 'always',
  });

  MusicControl.enableControl(Command.skipBackward, !!onSkipBackward, {
    interval: skipInterval,
  });

  MusicControl.enableControl(Command.skipForward, !!onSkipForward, {
    interval: skipInterval,
  });

  MusicControl.on(Command.play, onPlay);
  MusicControl.on(Command.pause, onPause);
  MusicControl.on(Command.skipBackward, () => onSkipBackward?.(skipInterval));
  MusicControl.on(Command.skipForward, () => onSkipForward?.(skipInterval));

In any case it was still very unstable, requiring all stars to align, and some bugs still existed that I was unable to track down last i worked on this...

Im tried run your music control ios case on my device and this solution doesnt work in background mode 😔

Could you explain for me one thing?☺️
how you turn on background mode in code ? (i am turned on this in xcode)
When I running next code in file like Main.js, music controls doesnt work. But if i delete it, controls will show and my playing audio have paused when I open controls panel

Audio.setAudioModeAsync({
            staysActiveInBackground: true
      });

@PupoSDC
Copy link

PupoSDC commented Sep 21, 2021

Hi @vedamet,

Unfortunately I can't be super useful, Im no longer working on this project, so I am working a bit out of memory + my own notes.

I'm not sure what the Audio API you posted is, so I cant give any specific advice. Generically, what I had to do to get the hang of things was study the actual IOS API under the hood, and using the xcode debugger see what calls were being made when. What i realized was that a lot of these libraries, that from the react native perspective handle different things (video, audio, controls...) interact with the same base IOS APIs, which causes conflicts. So my tip is, go deep into the ios code and try to understand what is happening in your code.

I know its super frustrating, at the end of the day, the point of react-native is to abstract away these native APIs, but in this particular case, it must be done.

@cjhines
Copy link

cjhines commented Sep 29, 2021

I have it working on react-native: 0.65.1 and expo-av: 9.2.3.

Audio.setAudioModeAsync({
      allowsRecordingIOS: false,
      playsInSilentModeIOS: true,
      staysActiveInBackground: true,
      interruptionModeIOS: INTERRUPTION_MODE_IOS_DO_NOT_MIX,
    });
  };

@calflegal
Copy link

The above

 interruptionModeIOS: INTERRUPTION_MODE_IOS_DO_NOT_MIX,

is critical.

I'm getting it via

import {INTERRUPTION_MODE_IOS_DO_NOT_MIX} from 'expo-av/build/Audio';

According to expo-av, the default is INTERRUPTION_MODE_IOS_MIX_WITH_OTHERS https://docs.expo.dev/versions/v45.0.0/sdk/audio/#arguments-1

I think this prevents the lock screen controls from showing up

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants