bluefireteam / audioplayers

A Flutter package to play multiple audio files simultaneously (Android/iOS/web/Linux/Windows/macOS)
https://pub.dartlang.org/packages/audioplayers
MIT License
2.01k stars 845 forks source link

PlatformException(DarwinAudioError, AVPlayerItem.Status.failed on setSourceUrl, #1546

Closed lurongshuang closed 1 year ago

lurongshuang commented 1 year ago

Checklist

Current bug behaviour

\^[[31mAudioPlayers Exception: AudioPlayerException( DeviceFileSource(path: /var/mobile/Containers/Data/Application/05BFE1FD-0371-4C27-A279-38645C04E5C3/Library/Caches/recording.aac), PlatformException(DarwinAudioError, AVPlayerItem.Status.failed on setSourceUrl, null, null)<…> [VERBOSE-2:dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(DarwinAudioError, AVPlayerItem.Status.failed on setSourceUrl, null, null)

Expected behaviour

await _player.setSourceDeviceFile(fileUrl); _player.play(source);

Steps to reproduce

  1. Execute flutter run on the code sample
  2. ...
  3. ...

Code sample

  void playAudioWithFile(String fileUrl,
      {Function? onPlaying, Function? onPlayCompleted}) async{
    this.onPlaying = onPlaying;
    this.onPlayCompleted = onPlayCompleted;
    DeviceFileSource source = DeviceFileSource(fileUrl);

    await _player.setSourceDeviceFile(fileUrl);
    _player.play(source);
  }

Affected platforms

iOS

Platform details

Android 正常 ios 报错

AudioPlayers Version

audioplayers: ^4.1.0

Build mode

debug

Audio Files/URLs/Sources

No response

Screenshots

No response

Logs

my relevant logs
Full Logs ``` my full logs or a link to a gist ``` Flutter doctor: ``` Output of: flutter doctor -v ```

Related issues / more information

No response

Working on PR

no way

isaanyoha commented 1 year ago

Same here. Did you resolve this? This happened to me in iOS 16.0 (physical device) & iOS 16.2 (Simulator)

lurongshuang commented 1 year ago

Codec _codec = Codec.defaultCodec; String _mPath = 'tau_file';

isaanyoha commented 1 year ago

Codec _codec = Codec.defaultCodec; String _mPath = 'tau_file';

Thanks for reply. Meanwhile, kindly give me details. Where do I write this?

-BELOW IS MY CODE-

final audioPlayer = AudioPlayer(); try { await audioPlayer.play(AssetSource("sounds/file1.aac")); }catch(e){ print("could not play sound from local"); }

-ERROR BELOW-

flutter: \^[[31mAudioPlayers Exception: AudioPlayerException( AssetSource(path: sounds/file1.aac), PlatformException(DarwinAudioError, AVPlayerItem.Status.failed on setSourceUrl, null, null)<…> flutter: soundNotification error -> PlatformException(DarwinAudioError, AVPlayerItem.Status.failed on setSourceUrl, null, null)

simpleease commented 1 year ago

same here. Both on simulator or device, iOS 16.1 & iOS 16.4. For remote Url, the same error: PlatformException(DarwinAudioError, AVPlayerItem.Status.failed on setSourceUrl, null, null)<…> flutter: soundNotification error -> PlatformException(DarwinAudioError, AVPlayerItem.Status.failed on setSourceUrl, null, null)

======= test url below(token may expired) : http://rongcloud-audio.ronghub.com/audio_amr__RC-2023-06-23_105_1687459422837.aac?e=1703011423&token=livk5rb3__JZjCtEiMxXpQ8QscLxbNLehwhHySnX:uaD5J8RHAALUPty1NloOyk0HhIk=

======= but when the above url downloaded to local and saved as ".m4a" extension, it works, without error.

Mamong commented 1 year ago

I think it's apple's bug. audioplayers can do nothing. as a workaround, you can download it before playing.

SwiftSpotter commented 1 year ago

I am facing the same issue

fullflash commented 1 year ago

yes looks like this plugin has issues playing asset files happens with asset and remote files. was working properly.

karlssonlui commented 1 year ago

I faced this problem too with the following situation, and I think this is because ios (or macos as well) has its own codec for audio, which android aacLc may not be equal to apple aacLc (Please correct me if I make a wrong statement). Somehow I changed the encoder method from aacLc to pcm16bit for ios platform (record package mentioned that pcm8bit has been removed in 5.0.0-beta.2, thats why i use pcm16bit). Hope this idea helps.

References platform: ios audio source: record: ^4.4.4 audio player: audioplayers: ^4.0.1

Original code

final Record _recorder = Record();
AudioEncoder encoder = AudioEncoder.aacLc;
await _recorder.start(path: path, encoder: encoder);

New code

final Record _recorder = Record();
AudioEncoder encoder = Platform.isIOS ? AudioEncoder.pcm16bit : AudioEncoder.aacLc;
await _recorder.start(path: path, encoder: encoder);
SwiftSpotter commented 1 year ago

I am not trying to record any audio I want to play audio from the asset folder

On Tue, Aug 1, 2023 at 8:39 AM Karlsson Lui @.***> wrote:

I faced this problem too with the following situation, and I think this is because ios (or macos as well) has its own codec for audio, which android aacLc may not be equal to apple aacLc (Please correct me if I make a wrong statement). Somehow I changed the encoder method from aacLc to pcm16bit for ios platform (record package mentioned that pcm8bit has been removed in 5.0.0-beta.2, thats why i use pcm16bit). Hope this idea helps.

References platform: ios audio source: record: ^4.4.4 audio player: audioplayers: ^4.0.1

Original code

final Record _recorder = Record(); AudioEncoder encoder = AudioEncoder.aacLc; await _recorder.start(path: path, encoder: encoder);

New code

final Record _recorder = Record(); AudioEncoder encoder = Platform.isIOS ? AudioEncoder.pcm16bit : AudioEncoder.aacLc; await _recorder.start(path: path, encoder: encoder);

— Reply to this email directly, view it on GitHub https://github.com/bluefireteam/audioplayers/issues/1546#issuecomment-1659741804, or unsubscribe https://github.com/notifications/unsubscribe-auth/AYVJH7QQUYMAOC3ANY4EXB3XTCXCDANCNFSM6AAAAAAZHW5XME . You are receiving this because you commented.Message ID: @.***>

karlssonlui commented 1 year ago

For my case, it seems that audioplayers cannot decode the audio bytes in the audio files, may be you can find another audio file from different source and test your code first, if the different source audio file works, you have to convert your audio files to a usable one

008v commented 1 year ago

edit your Info.plist , add these lines:

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

it works for me

nomagicisreal commented 1 year ago

i solved by renaming path without any space

maojiu-bb commented 1 year ago

https://github.com/bluefireteam/audioplayers/issues/1546#issuecomment-1689413410 its work for me too

petiibhuzah commented 1 year ago

In iOS instead of using UrlSource() use DeviceFileSource(), in case you downloaded the audio file and saved it to the device, before playing to the audio player.

if (Platform.isIOS) {
  await audioPlayer.play(DeviceFileSource(File(_url.value).path));
} else {
 await audioPlayer.play(UrlSource(File(_url.value).path));
}

For android UrlSource() works perfectly fine.

Gustl22 commented 1 year ago

if (Platform.isIOS) {

@petiibhuzah For local files (here: downloaded files), always use the DeviceFileSource. No need to make an exception for Android (or any other platform) to use UrlSource there...it's not meant to use for local files.

haihv433 commented 1 year ago

any work around? I'm facing this in fresh new project (Simulate IP14 but was okay on Web version)

Gustl22 commented 1 year ago

@lurongshuang it's most likely #1494. And further your code doesn't really make sense:

Plz call either:

DeviceFileSource source = DeviceFileSource(fileUrl);
await _player.setSourceDeviceFile(fileUrl);
await _player.resume();

or

DeviceFileSource source = DeviceFileSource(fileUrl);
await _player.play(source);
Mamong commented 1 year ago

you can test this url:https://dict.youdao.com/dictvoice?audio=hobby&type=1

Gustl22 commented 1 year ago

@Mamong, see https://github.com/bluefireteam/audioplayers/blob/main/troubleshooting.md#ios-macos-urls-or-paths-without-a-file-extension

Mamong commented 1 year ago

@Gustl22 Thanks,after some research,I think avplayer can play a remote audio file through a url without a file extension correctly. In my case, it fails only because it has wrong "content-type", while this link can play successfully: https://dict.youdao.com/dictvoice?audio=hobby&type=2 . it's an mp3 file.

Mamong commented 1 year ago

@Gustl22 this repo based on AVPlayer and AVAssetResourceLoaderDelegate may optimise the way playing a remote audio: SZAVPlayer

Gustl22 commented 12 months ago

@Mamong We trying to avoid third party implementations, and rather fix the missing contentType ourselfes. It is definitely not that hard, it just needs to be done. I have no Apple environment to properly develop and test, and I also don't have the time at the moment. Feel free to help us out. Let's continue discussion in #803.

5Gears0Chill commented 11 months ago

So i stumbled across this error. I know this issue is closed, but this seemed to help.

First i had the issue in just_audio, where flutter ios would fail.

I thought to myself, weird It works perfectly on android but iOS just dies.

Migrated to audioplayers and got hit with this Darwin error.

I said this must be an issue with iOS and the URL im trying to get the file from.

For context we are using Strapi as our CMS.

So i built this simple method.

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';

  Future<File?> downloadMp3(String url) async {
    Dio dio = Dio();
    Directory tempDir = await getTemporaryDirectory();
    String fileName = url.split('/').last; // Extract the file name from the URL
    String savePath = '${tempDir.path}/$fileName';

    // Check if the file already exists
    File file = File(savePath);
    if (await file.exists()) {
      // File already exists, no need to download again
      return file;
    }

    try {
      EasyLoading.show(
        status: 'Downloading...',
      );
      await dio.download(
        url,
        savePath,
        onReceiveProgress: (received, total) {
          if (total != -1) {
            if (kDebugMode) {
              print('${(received / total * 100).toStringAsFixed(0)}%');
            }
          }
        },
      );
    } catch (e) {
      if (kDebugMode) {
        print('Error downloading file: $e');
      }
      EasyLoading.showError('Failed to download file');
      return null; // Return null to indicate failure
    } finally {
      EasyLoading.dismiss();
    }

    return File(savePath);
  }

Then for my playAudio functionality

playAudio() async {
    try {
      if (isPlaying) {
        await player.pause();
      } else {
        await player.stop();
        if (Platform.isAndroid) {
          await player.play(UrlSource(widget.url));
        } else {
          var file = await downloadMp3(widget.url);
          if (file != null) {
            await player.play(DeviceFileSource(file.path));
          }
        }
      }
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

And it works perfectly now.

narakai commented 10 months ago

So i stumbled across this error. I know this issue is closed, but this seemed to help.

First i had the issue in just_audio, where flutter ios would fail.

I thought to myself, weird It works perfectly on android but iOS just dies.

Migrated to audioplayers and got hit with this Darwin error.

I said this must be an issue with iOS and the URL im trying to get the file from.

For context we are using Strapi as our CMS.

So i built this simple method.

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';

  Future<File?> downloadMp3(String url) async {
    Dio dio = Dio();
    Directory tempDir = await getTemporaryDirectory();
    String fileName = url.split('/').last; // Extract the file name from the URL
    String savePath = '${tempDir.path}/$fileName';

    // Check if the file already exists
    File file = File(savePath);
    if (await file.exists()) {
      // File already exists, no need to download again
      return file;
    }

    try {
      EasyLoading.show(
        status: 'Downloading...',
      );
      await dio.download(
        url,
        savePath,
        onReceiveProgress: (received, total) {
          if (total != -1) {
            if (kDebugMode) {
              print('${(received / total * 100).toStringAsFixed(0)}%');
            }
          }
        },
      );
    } catch (e) {
      if (kDebugMode) {
        print('Error downloading file: $e');
      }
      EasyLoading.showError('Failed to download file');
      return null; // Return null to indicate failure
    } finally {
      EasyLoading.dismiss();
    }

    return File(savePath);
  }

Then for my playAudio functionality

playAudio() async {
    try {
      if (isPlaying) {
        await player.pause();
      } else {
        await player.stop();
        if (Platform.isAndroid) {
          await player.play(UrlSource(widget.url));
        } else {
          var file = await downloadMp3(widget.url);
          if (file != null) {
            await player.play(DeviceFileSource(file.path));
          }
        }
      }
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

And it works perfectly now.

Hi, I met same issue, first I used just_audio, but flutter ios keep failing. Now I use audioplayers to try to get ios work. I tried to download first and then play mp3, but still it says: 'PlatformException(DarwinAudioError, Failed to set source'.

My code is like:

// Method to dynamically set a new MediaItem. Future setMediaItem(MediaItem item) async { _item = item; mediaItem.add(_item); // Load the player with the new media item. DeviceFileSource source = DeviceFileSource(_item.id); await _player.setSourceDeviceFile(_item.id); await _player.play(source); }

Can you give me some advice, thanks.

vaimikpatel2908 commented 10 months ago

My code is as follows:

Future<void> startPlayer(String filepath) async {
    try {
 // For ex, filepath is getApplicationDocumentDirectory().path+"/file.aac"
      final DeviceFileSource source = DeviceFileSource(filepath); 

        await _player?.play(source);
        } catch (e) {
      throw SoundPlayerException(e.toString());
    }
  }

But it still throws the PlatformException(DarwinAudioError, AVPlayerItem.Status.failed on setSourceUrl, Failed to set source. For troubleshooting, see "

I have also copied the code from the demo/examples and tried to play the same file as well but no luck with both plugins.

If anyone has idea, please guide me. I am totally clueless.

Gustl22 commented 8 months ago

Some of the problems are probably fixed via https://github.com/bluefireteam/audioplayers/pull/1763

Plz open new issues on problems after this fix, to better separate different causes for the issue.

5Gears0Chill commented 6 months ago

So i stumbled across this error. I know this issue is closed, but this seemed to help. First i had the issue in just_audio, where flutter ios would fail. I thought to myself, weird It works perfectly on android but iOS just dies. Migrated to audioplayers and got hit with this Darwin error. I said this must be an issue with iOS and the URL im trying to get the file from. For context we are using Strapi as our CMS. So i built this simple method.

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';

  Future<File?> downloadMp3(String url) async {
    Dio dio = Dio();
    Directory tempDir = await getTemporaryDirectory();
    String fileName = url.split('/').last; // Extract the file name from the URL
    String savePath = '${tempDir.path}/$fileName';

    // Check if the file already exists
    File file = File(savePath);
    if (await file.exists()) {
      // File already exists, no need to download again
      return file;
    }

    try {
      EasyLoading.show(
        status: 'Downloading...',
      );
      await dio.download(
        url,
        savePath,
        onReceiveProgress: (received, total) {
          if (total != -1) {
            if (kDebugMode) {
              print('${(received / total * 100).toStringAsFixed(0)}%');
            }
          }
        },
      );
    } catch (e) {
      if (kDebugMode) {
        print('Error downloading file: $e');
      }
      EasyLoading.showError('Failed to download file');
      return null; // Return null to indicate failure
    } finally {
      EasyLoading.dismiss();
    }

    return File(savePath);
  }

Then for my playAudio functionality

playAudio() async {
    try {
      if (isPlaying) {
        await player.pause();
      } else {
        await player.stop();
        if (Platform.isAndroid) {
          await player.play(UrlSource(widget.url));
        } else {
          var file = await downloadMp3(widget.url);
          if (file != null) {
            await player.play(DeviceFileSource(file.path));
          }
        }
      }
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

And it works perfectly now.

Hi, I met same issue, first I used just_audio, but flutter ios keep failing. Now I use audioplayers to try to get ios work. I tried to download first and then play mp3, but still it says: 'PlatformException(DarwinAudioError, Failed to set source'.

My code is like:

// Method to dynamically set a new MediaItem. Future setMediaItem(MediaItem item) async { _item = item; mediaItem.add(_item); // Load the player with the new media item. DeviceFileSource source = DeviceFileSource(_item.id); await _player.setSourceDeviceFile(_item.id); await _player.play(source); }

Can you give me some advice, thanks.

It seems you are using item.id ? Maybe that is your issue?

minnatranscriber commented 6 months ago

do we have any solution for this?

wishwelloklu commented 6 months ago

@lurongshuang it's most likely #1494. And further your code doesn't really make sense:

Plz call either:

DeviceFileSource source = DeviceFileSource(fileUrl);
await _player.setSourceDeviceFile(fileUrl);
await _player.resume();

or

DeviceFileSource source = DeviceFileSource(fileUrl);
await _player.play(source);

This worked for me. Thank you