Difficulty with music switching and buffering in iOS background utilizing audio_service bundle in Flutter


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.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles