Giter VIP home page Giter VIP logo

erikas-taroza / simple_audio Goto Github PK

View Code? Open in Web Editor NEW
36.0 3.0 9.0 1.24 GB

A simple cross-platform solution for playing audio in Flutter.

Home Page: https://pub.dev/packages/simple_audio

License: GNU Lesser General Public License v3.0

Kotlin 0.69% Swift 1.42% Objective-C 0.21% Dart 30.30% CMake 7.33% C++ 8.20% C 4.56% Ruby 1.48% Rust 42.95% Python 2.85%
android audio flutter ios linux macos windows audio-player

simple_audio's Introduction

Simple Audio

A cross-platform solution for playing audio in Flutter.

This project's goal is to be as simple as possible, meaning it offers the core functionality only (ex. play/pause). It also aims to be stable and relatively bug free.

I created this plugin for my music app so that I don't have to use different packages for different platforms (audio_service, dart_vlc). This made it hard to deal with bugs from different packages.

Features

  • Simple API
  • Cross platform (Android, Linux, Windows, iOS, macOS)
  • Playback of local and online resources
  • Gapless playback and preloading
  • Volume normalization

Documentation

The documentation is hosted by pub.dev. You can find it here.

Usage

  • Add this plugin as a dependency in pubspec.yaml
  • Follow the setup steps.
  • Call SimpleAudio.init() in main() (see below).
  • Instantiate a SimpleAudio object in your player controller (see below).
  • Use the APIs provided in the instantiated object (see below).

An example player project is located here.

Initialization

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await SimpleAudio.init();

  runApp(const MyApp());
}

Create Player

final SimpleAudio player = SimpleAudio(shouldNormalizeVolume: false);

Open and Play

player.playbackState.listen((state) => print(state));
player.progressState.listen((state) => print(state));
// Autoplays by default
player.open(path);

Setup

Some platform specific things have to be set up in order for this plugin to function properly.

Windows, Linux, macOS, Android

No setup is needed.

iOS

You will have to add a dependency to your Xcode project.

  • Open Runner.xcworkspace in the ios folder.
  • At the top of your project hierarchy view, select the Runner project.
  • Select the Runner target, go to the General tab and scroll down until you see Frameworks, Libraries, Embedded Content
  • Press the + icon and add the AudioToolbox.framework framework. Select Do Not Embed under the Embed column.

Special Thanks

  • sanihaq - Reported multiple bugs in simple_audio's first releases. These bugs would not have been fixed for a long time without their help.

simple_audio's People

Contributors

erikas-taroza avatar yesterday17 avatar dannyglover avatar

Stargazers

Albert Mañosa avatar  avatar Gary Hai avatar Diego Diaz avatar Mike avatar Rio Yudanto avatar Miguel Angel Toscán avatar mtz avatar  avatar  avatar Pownthep Laokhunthot avatar Mouayad Alhamwi avatar Jeff Carpenter avatar Umut BAYĞUT avatar Ashim avatar  avatar Andrew avatar Dhruvin avatar Austin Schey avatar Mingxin avatar Kingkor Roy Tirtho avatar Viet Dinh avatar  avatar  avatar Καπαρελιώτης Ηλίας (Kapareliotis Ilias) avatar Anton Domnikov avatar  avatar Dawei avatar Pramukesh avatar 久绊A avatar fzyzcjy avatar sani haq avatar Alexandru Nechita avatar Kylin avatar danigb avatar Yosef avatar

Watchers

 avatar  avatar  avatar

simple_audio's Issues

Error in linux

Invalid argument(s): Failed to load dynamic library 'libsimple_audio.so': /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by /home/sani/Work/clones/flutter/simple_audio/example/build/linux/x64/debug/bundle/lib/libsimple_audio.so)

I'm on elementry os 6.1 (Ubuntu 20.04)

Retrieve metadata from audio stream/file

Some audio files/stream can contain metadata such as: title, artist.. etc
I wanted to retrieve these informations to display them.

I'm really interested in this project because I have a similar project that i want to realize ( a cross-platform music player ) and i would like to contribute.

Error msg when using "loopPlayback"

Error showing when repeating a file

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method setPlaybackState on channel simple_audio)
#0      MethodChannel._invokeMethod
platform_channel.dart:313
<asynchronous suspension>

Notification does not show metadata on Android

Behavior

  1. On my app the notification does not appear at all.
  2. Sometimes the notification appears. But no metadata would be displayed. The control buttons are present and work well.

Info

  • Android version: 12
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel master, 3.9.0-12.0.pre.1, on Manjaro Linux 6.1.19-1-MANJARO, locale zh_CN.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[✓] Android Studio (version 2022.1)
[✓] Connected device (2 available)
[✓] Network resources

• No issues found!

Error

The only error I found was:

W/MediaSessionCompat(15456): Couldn't find a unique registered media button receiver in the given context.
D/CompatibilityChangeReporter(15456): Compat change id reported: 160794467; UID 10414; state: ENABLED
E/MethodChannel#simple_audio(15456): Failed to handle method call
E/MethodChannel#simple_audio(15456): java.lang.NullPointerException
E/MethodChannel#simple_audio(15456): 	at com.erikas.simple_audio.SimpleAudioPlugin.onMethodCall(SimpleAudioPlugin.kt:89)
E/MethodChannel#simple_audio(15456): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258)
E/MethodChannel#simple_audio(15456): 	at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
E/MethodChannel#simple_audio(15456): 	at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322)
E/MethodChannel#simple_audio(15456): 	at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/MethodChannel#simple_audio(15456): 	at android.os.Handler.handleCallback(Handler.java:980)
E/MethodChannel#simple_audio(15456): 	at android.os.Handler.dispatchMessage(Handler.java:104)
E/MethodChannel#simple_audio(15456): 	at android.os.Looper.loopOnce(Looper.java:238)
E/MethodChannel#simple_audio(15456): 	at android.os.Looper.loop(Looper.java:357)
E/MethodChannel#simple_audio(15456): 	at android.app.ActivityThread.main(ActivityThread.java:8098)
E/MethodChannel#simple_audio(15456): 	at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#simple_audio(15456): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
E/MethodChannel#simple_audio(15456): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1026)
E/flutter (15456): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(error, null, null, java.lang.NullPointerException
E/flutter (15456): 	at com.erikas.simple_audio.SimpleAudioPlugin.onMethodCall(SimpleAudioPlugin.kt:89)
E/flutter (15456): 	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:258)
E/flutter (15456): 	at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
E/flutter (15456): 	at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$io-flutter-embedding-engine-dart-DartMessenger(DartMessenger.java:322)
E/flutter (15456): 	at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
E/flutter (15456): 	at android.os.Handler.handleCallback(Handler.java:980)
E/flutter (15456): 	at android.os.Handler.dispatchMessage(Handler.java:104)
E/flutter (15456): 	at android.os.Looper.loopOnce(Looper.java:238)
E/flutter (15456): 	at android.os.Looper.loop(Looper.java:357)
E/flutter (15456): 	at android.app.ActivityThread.main(ActivityThread.java:8098)
E/flutter (15456): 	at java.lang.reflect.Method.invoke(Native Method)
E/flutter (15456): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
E/flutter (15456): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1026)
E/flutter (15456): )
E/flutter (15456): #0      StandardMethodCodec.decodeEnvelope
E/flutter (15456): #1      MethodChannel._invokeMethod
E/flutter (15456): <asynchronous suspension>

Not sure whether flutter version is a problem. I would try with flutter stable this weekend.

using `stop()` function leads to weird behavior

I'm not sure if i'm doing something wrong or something wrong in the library. but trying to play using open after using stop, sometimes works sometime it doesn't.

// _player is a `SimpleAudio` instance

// calling only this funtion works
 Future<void> play(String path) async {
    await _player.stop(); // i've tried commenting this line, doesn't work.
    await _player.open(path);
  }

// calling this function before calling `play` doesn't work
Future<void> stop() async {
  if (playbackState.value != PlaybackState.done) {
     await _player.stop();
}

Allow editing media controller actions at runtime.

The only way to edit what actions are allowed is to configure actions in SimpleAudio.init(). This functionality can be expanded to allow configuration at runtime. An example use case of this feature would be with the skipNext action being disabled if the user has no more files to skip to.

Can it support `opus` format?

It is happy to see an open-sourced library using my open-sourced library (https://github.com/fzyzcjy/flutter_rust_bridge) that seems useful to my app ;)

So, I wonder whether this package supports opus format? The doc is not yet very elaborate so I have not found information about this.

In addition, I wonder whether it is possible to support audio recording as well? (For example, opus format)

Audio output issues on Windows

There is an issue where changing audio outputs on windows results in no audio being played.

For instance, if you have a TV hooked up to your pc and start playback on the TV speakers and switch to your pc speakers, no audio is played.

I did a test on Linux and plugging in/out headphones resulted in audio continuing playback on the active device (which is expected). I will conduct more experiments shortly on Linux to test the same conditions as above to ensure that the situation works on Linux too.

I'm going to look into this asap too.
Thanks bud.

Content-Length error

When I try to open audio files through HTTP it gives me this error,
Could not get "Content-Length" header for HTTP stream,
I know this is more of an issue on my side but packages like audioplayers and just_audio didn't give me this exception. Maybe if that parameter in header is null you can get length from the file instead?

Media control configuration

  • need a way to set media information in media control notification
  • ways to disable keys (preferably only show the key needed)

p.s - see this repository for a work in progress project using this plugin package.

`dummy_method_to_enforce_bundling` may have different definitions in different modules

Error

'dummy_method_to_enforce_bundling' has different definitions in different modules; definition in module 'simple_audio.bridge_generated' first difference is function body

https://github.com/ProjectAnni/annix/actions/runs/4517442554/jobs/7956646587

Cause

dummy_method_to_enforce_bundling is generated by flutter_rust_bridge. All projects using flutter_rust_bridge would create such dummy function with the same name. If there are multiple rust libraries, then the signature might collide on macOS and iOS because libraries are statically linked on those platforms.

--class-name can be used to fix it. If class-name is specified, then the function generated would be named to dummy_method_to_enforce_bundling_{className}.

Example:
https://github.com/ProjectAnni/annix/blob/04f0dd423fcb8c68b7ffb8bac16449ff9e6fd340/macos/Runner/generated_network.h#L60-L69

reloading app in development mode, still plays audio

It's not a big issue but...
after reloading, some function still works like volume control but some doesn't like play,pause.
is there way to hook into a already playing audio instance?
what is the process looks like if i want to close the application but keep the audio playing and upon reopening hook into the previous instance of SimpleAudio. is that possible?

need a way to dispose a player (i.e. dispose() method).

Ubuntu 20.04 Build Error

I got the following error:

Building Linux application...
CMake Error at flutter/ephemeral/.plugin_symlinks/simple_audio/linux/CMakeLists.txt:51 (file):
file does not recognize sub-command ARCHIVE_EXTRACT

Exception: Unable to generate build files

Windows media notification control issues

I've done extensive testing comparing the Linux behaviour to windows, and have noted the following issues:

The Linux implementation works perfectly, whilst the windows implementation has the following issues:

  • sometimes never shows any metadata at all
  • sometimes doesn't show the media controls
  • when it does work, it randomly stops working and the currently playing info it's showing is incorrect and relates to a file that was played several songs back. When that happens, the media controls in the notification stop working also.

I'm going to start investigations soon. I'm just trying to wrap up some tasks in my own project first. I wouldn't object to collaboration also :)

Thanks buddy.

Notification onClick is not working

i have added the receiver in manifest file
but when i click on the icons and the seekbar its not working from notification but when i try from the app its working

Old samples are played before new ones

Because there is only 1 output stream, if the stream is paused and a new file is played, the old samples that were written to the stream do not get played. When the stream is unpaused, the old samples are played before the new ones.

Setting volume right after creating player instance, giving error.

After creating a player, changing default volume.

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: LateInitializationError: Field '_player@384384061' has not been initialized.
#0      _player (package:simple_audio/src/simple_audio.dart)
#1      SimpleAudio.setVolume (package:simple_audio/src/simple_audio.dart:314:22)
#2      PlaybackController.setVolume (package:simple_music_player/states/player_controller.dart:72:19)
#3      _VolumeControlState.initState.<anonymous closure> (package:simple_music_player/components/volume_control.dart:27:26)
<asynchronous suspension>

Normalizer improvements

Currently, the audio is normalized live as playback progresses. This can result in uneven volumes during playback, especially when the audio file is quiet in the beginning. The goal is to remove as much of the volume change as possible while still normalizing the audio.

To fix this, I have thought of these changes:

Solution 1

  • Implement new function to pass in a custom gain to use instead of the one calculated at runtime.
  • Return the calculated global gain for the audio file when playback finishes.

The returned gain can be stored and then passed in when playing the same audio file.

This solution requires more work by the developer because they need to store the results somewhere (for the best UX). The audio file will also have to be played at least once where the volume is uneven. The benefits of this solution (compared to the one below) is performance. The calculated gain can be reused to save time. It also allows for the developer to use their own gain values if they already know the amount needed beforehand.

Solution 2
Seek to a specific part of an audio file (ex. 20% in) and calculate the gain there. Use that gain as a starting point.

This solution would be more automated than the first one, but it may take longer to start playing the file (especially network streams). If the audio at the position is quiet, more will have to be decoded and processed, increasing the time it takes to begin playing a file. This shouldn't be a big issue on local files and it can be mitigated with preloading for remote files. But without preloading, the performance hit may be high.

Solution 2 would be preferable to keep it simple for users of this plugin. I may have to do more research on this topic before committing to a solution.

Can not build on iOS

https://pipelines.actions.githubusercontent.com/serviceHosts/1990a263-8757-4bdb-9dd4-b3aaea312869/_apis/pipelines/1/runs/794/signedlogcontent/4?urlExpires=2023-06-09T13%3A48%3A08.6604963Z&urlSigningMethod=HMACV1&urlSignature=fGkYGY3ZFMpMBQciH9j6D%2Fm9jbaNTo97HkQyOHla%2Bm0%3D

This script exist in simple_audio.podspec:

mkdir Frameworks
cd Frameworks
if [ ! -d simple_audio.xcframework ]
then
  mkdir simple_audio.xcframework
  cd simple_audio.xcframework
  mkdir ios-arm64
  mkdir ios-arm64_x86_64-simulator
  curl -L "#{lib_url}/Info.plist?raw=true" -o Info.plist
  curl -L "#{lib_url}/ios-arm64/libsimple_audio.a?raw=true" -o ios-arm64/libsimple_audio.a
  curl -L "#{lib_url}/ios-arm64_x86_64-simulator/libsimple_audio.a?raw=true" -o ios-arm64_x86_64-simulator/libsimple_audio.a
fi
cd ../..

But directory simple_audio.xcframework already exists(in published package). So the following download script is never executed, making the compilation fail.

Another strange behavior is that even though I've removed the xcframework directory, it still can not build. It seems that the script is not executed?

Android 13 stuck on `setMetadata` if calling with `await`

Hello!

I found that when calling setMetadata with await keyword, app stuck here on Android 13.

The example app can reproduce this:

diff --git a/example/lib/main.dart b/example/lib/main.dart
index 1f683c2..e519327 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -128,7 +129,7 @@ class _MyAppState extends State<MyApp> {
                 onPressed: () async {
                   String path = await pickFile();

-                  player.setMetadata(
+                  await player.setMetadata(
                     const Metadata(
                       title: "Title",
                       artist: "Artist",

Everything goes well without await keyword.

Is setMetadata should only used without await?

Besides it's a async function so the linter will give warning "Missing an 'await' for the 'Future' computed by this expression", is there any way to make it sync if designed without await?

Feature Request: Support playlist

Though playlist support can be implemented outside this package, implementing it on rust side has many benefits. For example, preload and gapless playback support could be done further for better user experience.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.