react-native-music-control
react-native-music-control copied to clipboard
Do lockscreen controls of this library (1.3.0) work on iOs with react-native 6.3.0 and expo-av 8.6.0
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
Im also struggling a lot with this: https://github.com/tanguyantoine/react-native-music-control/issues/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);
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 :(
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
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.
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.
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 π
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
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 :)
Hi everyone π Any news on that issue ? Iβm stuck for many days now :/
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...
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
});
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.
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,
});
};
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