Flutter-AssetsAudioPlayer icon indicating copy to clipboard operation
Flutter-AssetsAudioPlayer copied to clipboard

[iOS 15.1+] AVAudioSessionErrorCodeMediaServicesFailed

Open Tregan opened this issue 3 years ago • 0 comments

Flutter Version

My version : 2.10.2

Lib Version

My version : 3.0.4+1

Platform (Android / iOS / web) + version

Platform : iOS 15.1+ image

Describe the bug

Recently, we've been getting reports from iOS 15.1+ devices, for example PlatformException(PLAY_ERROR, Cannot play assets/audio/correct_answer.wav, The operation couldn’t be completed. (OSStatus error 1836282486.), null). We're getting the error for multiple audio files. Somehow I can't reproduce it myself (test device is on iOS 15.1+ as well ofcourse)

Apparently the OSStatus is https://developer.apple.com/documentation/coreaudiotypes/avaudiosessionerrorcode/avaudiosessionerrorcodemediaservicesfailed

How we play audio

Our app plays a lot of sound effects,. To make sure that we don't create too many audio players on web, we reuse players whenever we can. Our pages can access this SoundRepository and can just call soundRepository.correctAnswer().

import 'package:assets_audio_player/assets_audio_player.dart';

enum _SoundType {
  soundEffect,
  music,
}

typedef CreateAudioPlayer = AssetsAudioPlayer Function();

class SoundRepository {
  final CreateAudioPlayer createAudioPlayer;

  final Map<String, List<AssetsAudioPlayer>> _audioPlayers = {};

  static const String _correctAnswer = 'correct_answer.wav';
  // more static files here

  Future<AssetsAudioPlayer?> correctAnswer() => _play(_correctAnswer);
  // more audio functions here

  SoundRepository({
    required this.createAudioPlayer,
  });

  factory SoundRepository.create({
    required CreateAudioPlayer createAudioPlayer,
  }) {
    return SoundRepository(
      createAudioPlayer: createAudioPlayer,
    );
  }

  Future<AssetsAudioPlayer?> _play(String fileName) {
    return _getAudioPlayer(fileName).then((audioPlayer) {
      audioPlayer.setVolume(0.5);
      audioPlayer.setLoopMode(LoopMode.none);
      audioPlayer.play();
      return audioPlayer;
    });
  }

  Future<AssetsAudioPlayer> _getAudioPlayer(String fileName) {
    if (_audioPlayers.containsKey(fileName)) {
      final AssetsAudioPlayer? availablePlayer = _audioPlayers[fileName]!.firstWhereOrNull(
        (audioPlayer) => !audioPlayer.isPlaying.value,
      );

      if (availablePlayer != null) {
        return Future.value(availablePlayer);
      }
    } else {
      _audioPlayers[fileName] = [];
    }

    final AssetsAudioPlayer audioPlayer = createAudioPlayer();
    _audioPlayers[fileName]!.add(audioPlayer);
    return audioPlayer
        .open(
          Audio('assets/audio/$fileName'),
          autoStart: false,
          volume: 0.5,
          headPhoneStrategy: HeadPhoneStrategy.none,
          audioFocusStrategy: AudioFocusStrategy.none(),
        )
        .then((value) => audioPlayer);
  }
}

Tregan avatar Feb 25 '22 10:02 Tregan