I’m engaged on an audio streaming app utilizing the audio_service bundle in Flutter, and I’m going through a problem the place the music switching works tremendous within the foreground, however when the app is within the background, the music does not swap, and the audio participant will get caught on buffering. This challenge is particular to iOS, because the app works tremendous on Android.
Here’s what I’ve performed thus far:
I’ve arrange background modes within the Data.plist to permit audio and Xcode additionally.
I’ve carried out the mandatory background activity for audio playback, however music switching within the background will not be functioning as anticipated.
That is my songHandler file
import 'dart:developer';
import 'bundle:audio_service/audio_service.dart';
import 'bundle:just_audio/just_audio.dart';
import 'bundle:rxdart/rxdart.dart' as rx;
class SongHandler extends BaseAudioHandler with SeekHandler {
remaining AudioPlayer audioPlayer = AudioPlayer();
MediaItem? currentMediaItem;
bool hasPrevious = false;
bool hasNext = false;
void _broadcastState() {
mediaItem.add(currentMediaItem);
playbackState.add(playbackState.worth.copyWith(
controls: [
if (hasPrevious) MediaControl.skipToPrevious,
if (audioPlayer.playing) MediaControl.pause else MediaControl.play,
if (hasNext) MediaControl.skipToNext,
],
systemActions: {
MediaAction.search,
MediaAction.seekForward,
MediaAction.seekBackward,
},
processingState: {
ProcessingState.idle: AudioProcessingState.idle,
ProcessingState.loading: AudioProcessingState.loading,
ProcessingState.buffering: AudioProcessingState.buffering,
ProcessingState.prepared: AudioProcessingState.prepared,
ProcessingState.accomplished: AudioProcessingState.accomplished,
}[audioPlayer.processingState]!,
enjoying: audioPlayer.enjoying,
updatePosition: audioPlayer.place,
bufferedPosition: audioPlayer.bufferedPosition,
velocity: audioPlayer.velocity,
queueIndex: 0,
));
}
Future initSong(
AudioSource audioSource,
MediaItem music,
) async {
currentMediaItem = music; // Set present media merchandise
audioPlayer.playbackEventStream.hear((_) => _broadcastState());
await audioPlayer.setAudioSource(audioSource);
play();
}
Future updateAudioSource(AudioSource audioSource, MediaItem music,
{bool? isShowButton = false}) async {
await audioPlayer.setAudioSource(audioSource);
currentMediaItem = music;
hasPrevious = isShowButton ?? false;
hasNext = isShowButton ?? false;
}
@override
Future play() async {
if (currentMediaItem != null) {
await audioPlayer.play();
}
}
@override
Future pause() => audioPlayer.pause();
@override
Future search(Period place) => audioPlayer.search(place);
@override
Future skipToNext() async {
remaining musicPlayerViewModel = Get.discover();
musicPlayerViewModel.moveNextSong();
// Logic to skip to the following music
log('message');
}
@override
Future skipToPrevious() async {
remaining musicPlayerViewModel = Get.discover();
musicPlayerViewModel.movePreviousSong();
// Logic to skip to the earlier music
log('message');
}
Stream get positionDataStream =>
rx.CombineLatestStream.combine3(
audioPlayer.positionStream,
audioPlayer.bufferedPositionStream,
audioPlayer.durationStream,
(place, bufferedPosition, length) => PositionData(
place: place,
bufferedPosition: bufferedPosition,
length: length ?? Period.zero,
),
);
}
that is my listner and music switching perform
void musicSetupListeners() {
playerStateSubscription?.cancel();
playerStateSubscription =
songHandler.audioPlayer.playerStateStream.hear((state) async {
log('Participant state: ${state.processingState}');
swap (state.processingState) {
case ProcessingState.idle:
// Deal with idle state if wanted
break;
case ProcessingState.loading:
// Deal with loading state if wanted
break;
case ProcessingState.buffering:
// Deal with buffering state if wanted
break;
case ProcessingState.prepared:
// Deal with prepared state if wanted
break;
case ProcessingState.accomplished:
await handleCompletion();
break;
}
}, onError: (error) {
log('Stream error: $error');
});
}
Future handleCompletion() async {
await songHandler.pause();
await songHandler.search(Period.zero);
await Future.delayed(const Period(milliseconds: 500), () async {
strive {
if (!isProcessingCompletion.worth) {
isNewSongLoading.worth = true;
isNewSongLoading.refresh();
isProcessingCompletion.worth = true;
isProcessingCompletion.refresh();
await songHandler.cease();
await Future.delayed(const Period(milliseconds: 500), () async {
await _playNextSong(this);
isProcessingCompletion.worth = false;
});
}
} catch (e) {
log('Error throughout completion dealing with: $e');
}
});
}
Future _playNextSong(MusicPlayerViewModel musicPlayerViewModel) async {
if (isChangeList.worth == false) {
if (britanyPlyController.isShuffle.worth) {
await britanyPlyController.selectRandomSongs(musicPlayerViewModel);
} else {
await britanyPlyController.selectSequenceSongs(musicPlayerViewModel);
}
} else {
await selectSequenceSongs();
}
Future.delayed(
const Period(milliseconds: 300),
() {
isNewSongLoading.worth = false;
isNewSongLoading.refresh();
},
);
await songHandler.play();
}
i would like anyone might help me to resolve out this challenge.
