admin管理员组文章数量:1335444
I am working on an audio streaming app using the audio_service package in Flutter, and I am facing an issue where the song switching works fine in the foreground, but when the app is in the background, the song doesn't switch, and the audio player gets stuck on buffering. This issue is specific to iOS, as the app works fine on Android.
Here is what I have done so far:
I have set up background modes in the Info.plist to allow audio and Xcode also. I have implemented the necessary background task for audio playback, but song switching in the background is not functioning as expected.
This is my songHandler file
import 'dart:developer';
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
import 'package:rxdart/rxdart.dart' as rx;
class SongHandler extends BaseAudioHandler with SeekHandler {
final AudioPlayer audioPlayer = AudioPlayer();
MediaItem? currentMediaItem;
bool hasPrevious = false;
bool hasNext = false;
void _broadcastState() {
mediaItem.add(currentMediaItem);
playbackState.add(playbackState.value.copyWith(
controls: [
if (hasPrevious) MediaControl.skipToPrevious,
if (audioPlayer.playing) MediaControl.pause else MediaControl.play,
if (hasNext) MediaControl.skipToNext,
],
systemActions: {
MediaAction.seek,
MediaAction.seekForward,
MediaAction.seekBackward,
},
processingState: {
ProcessingState.idle: AudioProcessingState.idle,
ProcessingState.loading: AudioProcessingState.loading,
ProcessingState.buffering: AudioProcessingState.buffering,
ProcessingState.ready: AudioProcessingState.ready,
ProcessingStatepleted: AudioProcessingStatepleted,
}[audioPlayer.processingState]!,
playing: audioPlayer.playing,
updatePosition: audioPlayer.position,
bufferedPosition: audioPlayer.bufferedPosition,
speed: audioPlayer.speed,
queueIndex: 0,
));
}
Future<void> initSong(
AudioSource audioSource,
MediaItem song,
) async {
currentMediaItem = song; // Set current media item
audioPlayer.playbackEventStream.listen((_) => _broadcastState());
await audioPlayer.setAudioSource(audioSource);
play();
}
Future<void> updateAudioSource(AudioSource audioSource, MediaItem song,
{bool? isShowButton = false}) async {
await audioPlayer.setAudioSource(audioSource);
currentMediaItem = song;
hasPrevious = isShowButton ?? false;
hasNext = isShowButton ?? false;
}
@override
Future<void> play() async {
if (currentMediaItem != null) {
await audioPlayer.play();
}
}
@override
Future<void> pause() => audioPlayer.pause();
@override
Future<void> seek(Duration position) => audioPlayer.seek(position);
@override
Future<void> skipToNext() async {
final musicPlayerViewModel = Get.find<MusicPlayerViewModel>();
musicPlayerViewModel.moveNextSong();
// Logic to skip to the next song
log('message');
}
@override
Future<void> skipToPrevious() async {
final musicPlayerViewModel = Get.find<MusicPlayerViewModel>();
musicPlayerViewModel.movePreviousSong();
// Logic to skip to the previous song
log('message');
}
Stream<PositionData> get positionDataStream =>
rx.CombineLatestStreambine3(
audioPlayer.positionStream,
audioPlayer.bufferedPositionStream,
audioPlayer.durationStream,
(position, bufferedPosition, duration) => PositionData(
position: position,
bufferedPosition: bufferedPosition,
duration: duration ?? Duration.zero,
),
);
}
this is my listner and song switching function
void musicSetupListeners() {
playerStateSubscription?.cancel();
playerStateSubscription =
songHandler.audioPlayer.playerStateStream.listen((state) async {
log('Player state: ${state.processingState}');
switch (state.processingState) {
case ProcessingState.idle:
// Handle idle state if needed
break;
case ProcessingState.loading:
// Handle loading state if needed
break;
case ProcessingState.buffering:
// Handle buffering state if needed
break;
case ProcessingState.ready:
// Handle ready state if needed
break;
case ProcessingStatepleted:
await handleCompletion();
break;
}
}, onError: (error) {
log('Stream error: $error');
});
}
Future<void> handleCompletion() async {
await songHandler.pause();
await songHandler.seek(Duration.zero);
await Future.delayed(const Duration(milliseconds: 500), () async {
try {
if (!isProcessingCompletion.value) {
isNewSongLoading.value = true;
isNewSongLoading.refresh();
isProcessingCompletion.value = true;
isProcessingCompletion.refresh();
await songHandler.stop();
await Future.delayed(const Duration(milliseconds: 500), () async {
await _playNextSong(this);
isProcessingCompletion.value = false;
});
}
} catch (e) {
log('Error during completion handling: $e');
}
});
}
Future _playNextSong(MusicPlayerViewModel musicPlayerViewModel) async {
if (isChangeList.value == false) {
if (britanyPlyController.isShuffle.value) {
await britanyPlyController.selectRandomSongs(musicPlayerViewModel);
} else {
await britanyPlyController.selectSequenceSongs(musicPlayerViewModel);
}
} else {
await selectSequenceSongs();
}
Future.delayed(
const Duration(milliseconds: 300),
() {
isNewSongLoading.value = false;
isNewSongLoading.refresh();
},
);
await songHandler.play();
}
i want any one can help me to solve out this issue.
I am working on an audio streaming app using the audio_service package in Flutter, and I am facing an issue where the song switching works fine in the foreground, but when the app is in the background, the song doesn't switch, and the audio player gets stuck on buffering. This issue is specific to iOS, as the app works fine on Android.
Here is what I have done so far:
I have set up background modes in the Info.plist to allow audio and Xcode also. I have implemented the necessary background task for audio playback, but song switching in the background is not functioning as expected.
This is my songHandler file
import 'dart:developer';
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
import 'package:rxdart/rxdart.dart' as rx;
class SongHandler extends BaseAudioHandler with SeekHandler {
final AudioPlayer audioPlayer = AudioPlayer();
MediaItem? currentMediaItem;
bool hasPrevious = false;
bool hasNext = false;
void _broadcastState() {
mediaItem.add(currentMediaItem);
playbackState.add(playbackState.value.copyWith(
controls: [
if (hasPrevious) MediaControl.skipToPrevious,
if (audioPlayer.playing) MediaControl.pause else MediaControl.play,
if (hasNext) MediaControl.skipToNext,
],
systemActions: {
MediaAction.seek,
MediaAction.seekForward,
MediaAction.seekBackward,
},
processingState: {
ProcessingState.idle: AudioProcessingState.idle,
ProcessingState.loading: AudioProcessingState.loading,
ProcessingState.buffering: AudioProcessingState.buffering,
ProcessingState.ready: AudioProcessingState.ready,
ProcessingStatepleted: AudioProcessingStatepleted,
}[audioPlayer.processingState]!,
playing: audioPlayer.playing,
updatePosition: audioPlayer.position,
bufferedPosition: audioPlayer.bufferedPosition,
speed: audioPlayer.speed,
queueIndex: 0,
));
}
Future<void> initSong(
AudioSource audioSource,
MediaItem song,
) async {
currentMediaItem = song; // Set current media item
audioPlayer.playbackEventStream.listen((_) => _broadcastState());
await audioPlayer.setAudioSource(audioSource);
play();
}
Future<void> updateAudioSource(AudioSource audioSource, MediaItem song,
{bool? isShowButton = false}) async {
await audioPlayer.setAudioSource(audioSource);
currentMediaItem = song;
hasPrevious = isShowButton ?? false;
hasNext = isShowButton ?? false;
}
@override
Future<void> play() async {
if (currentMediaItem != null) {
await audioPlayer.play();
}
}
@override
Future<void> pause() => audioPlayer.pause();
@override
Future<void> seek(Duration position) => audioPlayer.seek(position);
@override
Future<void> skipToNext() async {
final musicPlayerViewModel = Get.find<MusicPlayerViewModel>();
musicPlayerViewModel.moveNextSong();
// Logic to skip to the next song
log('message');
}
@override
Future<void> skipToPrevious() async {
final musicPlayerViewModel = Get.find<MusicPlayerViewModel>();
musicPlayerViewModel.movePreviousSong();
// Logic to skip to the previous song
log('message');
}
Stream<PositionData> get positionDataStream =>
rx.CombineLatestStreambine3(
audioPlayer.positionStream,
audioPlayer.bufferedPositionStream,
audioPlayer.durationStream,
(position, bufferedPosition, duration) => PositionData(
position: position,
bufferedPosition: bufferedPosition,
duration: duration ?? Duration.zero,
),
);
}
this is my listner and song switching function
void musicSetupListeners() {
playerStateSubscription?.cancel();
playerStateSubscription =
songHandler.audioPlayer.playerStateStream.listen((state) async {
log('Player state: ${state.processingState}');
switch (state.processingState) {
case ProcessingState.idle:
// Handle idle state if needed
break;
case ProcessingState.loading:
// Handle loading state if needed
break;
case ProcessingState.buffering:
// Handle buffering state if needed
break;
case ProcessingState.ready:
// Handle ready state if needed
break;
case ProcessingStatepleted:
await handleCompletion();
break;
}
}, onError: (error) {
log('Stream error: $error');
});
}
Future<void> handleCompletion() async {
await songHandler.pause();
await songHandler.seek(Duration.zero);
await Future.delayed(const Duration(milliseconds: 500), () async {
try {
if (!isProcessingCompletion.value) {
isNewSongLoading.value = true;
isNewSongLoading.refresh();
isProcessingCompletion.value = true;
isProcessingCompletion.refresh();
await songHandler.stop();
await Future.delayed(const Duration(milliseconds: 500), () async {
await _playNextSong(this);
isProcessingCompletion.value = false;
});
}
} catch (e) {
log('Error during completion handling: $e');
}
});
}
Future _playNextSong(MusicPlayerViewModel musicPlayerViewModel) async {
if (isChangeList.value == false) {
if (britanyPlyController.isShuffle.value) {
await britanyPlyController.selectRandomSongs(musicPlayerViewModel);
} else {
await britanyPlyController.selectSequenceSongs(musicPlayerViewModel);
}
} else {
await selectSequenceSongs();
}
Future.delayed(
const Duration(milliseconds: 300),
() {
isNewSongLoading.value = false;
isNewSongLoading.refresh();
},
);
await songHandler.play();
}
i want any one can help me to solve out this issue.
Share Improve this question asked Nov 20, 2024 at 6:42 Hassaan AhmedHassaan Ahmed 11 Answer
Reset to default 0I also had this problem in my code
本文标签:
版权声明:本文标题:Issue with song switching and buffering in iOS background using audio_service package in Flutter - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742376383a2463247.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论