diff --git a/packages/audioplayers/lib/src/audioplayer.dart b/packages/audioplayers/lib/src/audioplayer.dart index 34895de0b..7c4dbf25e 100644 --- a/packages/audioplayers/lib/src/audioplayer.dart +++ b/packages/audioplayers/lib/src/audioplayer.dart @@ -47,6 +47,15 @@ class AudioPlayer { double get playbackRate => _playbackRate; + bool _allowsExternalPlayback = false; + + /// A Boolean value that indicates whether the player allows switching + /// to external playback mode. + /// + /// Default is [_allowsExternalPlayback] and + /// switch by calling [setAllowsExternalPlayback] + bool get allowsExternalPlayback => _allowsExternalPlayback; + /// Current mode of the audio player. Can be updated at any time, but is going /// to take effect only at the next time you play the audio. PlayerMode _mode = PlayerMode.mediaPlayer; @@ -168,6 +177,7 @@ class AudioPlayer { positionUpdater = FramePositionUpdater( getPosition: getCurrentPosition, ); + setAllowsExternalPlayback(allows: _allowsExternalPlayback); } Future _create() async { @@ -230,6 +240,18 @@ class AudioPlayer { return _platform.setPlayerMode(playerId, mode); } + /// Switching the external playback mode + /// + /// Available in OS 6.0+ | iPadOS 6.0+ | Mac Catalyst 13.1+ | + /// + /// macOS 10.11+ | tvOS 9.0+ + /// + /// Not Available in Android, Linux and Windows + Future setAllowsExternalPlayback({required bool allows}) async { + _allowsExternalPlayback = allows; + return _platform.setAllowsExternalPlayback(playerId, allows: allows); + } + /// Pauses the audio that is currently playing. /// /// If you call [resume] later, the audio will resume from the point that it diff --git a/packages/audioplayers/test/audioplayers_test.dart b/packages/audioplayers/test/audioplayers_test.dart index 1d12ebd1f..821d1d367 100644 --- a/packages/audioplayers/test/audioplayers_test.dart +++ b/packages/audioplayers/test/audioplayers_test.dart @@ -22,6 +22,7 @@ void main() { expect(player.source, null); await player.creatingCompleter.future; expect(platform.popCall().method, 'create'); + expect(platform.popCall().method, 'setAllowsExternalPlayback'); expect(platform.popLastCall().method, 'getEventStream'); return player; } diff --git a/packages/audioplayers/test/fake_audioplayers_platform.dart b/packages/audioplayers/test/fake_audioplayers_platform.dart index 40c49a44f..28360c313 100644 --- a/packages/audioplayers/test/fake_audioplayers_platform.dart +++ b/packages/audioplayers/test/fake_audioplayers_platform.dart @@ -163,4 +163,18 @@ class FakeAudioplayersPlatform extends AudioplayersPlatformInterface { calls.add(FakeCall(id: playerId, method: 'getEventStream')); return eventStreamControllers[playerId]!.stream; } + + @override + Future setAllowsExternalPlayback( + String playerId, { + required bool allows, + }) async { + calls.add( + FakeCall( + id: playerId, + method: 'setAllowsExternalPlayback', + value: allows, + ), + ); + } } diff --git a/packages/audioplayers_android/android/src/main/kotlin/xyz/luan/audioplayers/AudioplayersPlugin.kt b/packages/audioplayers_android/android/src/main/kotlin/xyz/luan/audioplayers/AudioplayersPlugin.kt index 77bf87409..38cfad14a 100644 --- a/packages/audioplayers_android/android/src/main/kotlin/xyz/luan/audioplayers/AudioplayersPlugin.kt +++ b/packages/audioplayers_android/android/src/main/kotlin/xyz/luan/audioplayers/AudioplayersPlugin.kt @@ -148,6 +148,9 @@ class AudioplayersPlugin : FlutterPlugin { player.rate = rate.toFloat() } + "setAllowsExternalPlayback" -> { + } + "getDuration" -> { response.success(player.getDuration()) return diff --git a/packages/audioplayers_darwin/darwin/Classes/SwiftAudioplayersDarwinPlugin.swift b/packages/audioplayers_darwin/darwin/Classes/SwiftAudioplayersDarwinPlugin.swift index d545e4264..f303c8b68 100644 --- a/packages/audioplayers_darwin/darwin/Classes/SwiftAudioplayersDarwinPlugin.swift +++ b/packages/audioplayers_darwin/darwin/Classes/SwiftAudioplayersDarwinPlugin.swift @@ -265,6 +265,17 @@ public class SwiftAudioplayersDarwinPlugin: NSObject, FlutterPlugin { let currentPosition = player.getCurrentPosition() result(currentPosition) return + } else if method == "setAllowsExternalPlayback" { + guard let allows = args["allows"] as? Bool else { + result( + FlutterError( + code: "DarwinAudioError", + message: "Error calling setAllowsExternalPlayback, allows cannot be null", + details: nil)) + return + } + + player.setAllowsExternalPlayback(allows: allows) } else if method == "setPlaybackRate" { guard let playbackRate = args["playbackRate"] as? Double else { result( diff --git a/packages/audioplayers_darwin/darwin/Classes/WrappedMediaPlayer.swift b/packages/audioplayers_darwin/darwin/Classes/WrappedMediaPlayer.swift index 08fc7f12c..61a10dea5 100644 --- a/packages/audioplayers_darwin/darwin/Classes/WrappedMediaPlayer.swift +++ b/packages/audioplayers_darwin/darwin/Classes/WrappedMediaPlayer.swift @@ -6,6 +6,8 @@ private let defaultVolume: Double = 1.0 private let defaultLooping: Bool = false +private let defaultAllowsExternalPlayback: Bool = false + typealias Completer = () -> Void typealias CompleterError = (Error?) -> Void @@ -121,6 +123,14 @@ class WrappedMediaPlayer { } } + func setAllowsExternalPlayback(allows: Bool) { + if #available(iOS 10.0, macOS 10.12, *) { + player.allowsExternalPlayback = allows + } else { + player.allowsExternalPlayback = defaultAllowsExternalPlayback + } + } + func seek(time: CMTime, completer: Completer? = nil) { guard let currentItem = player.currentItem else { completer?() diff --git a/packages/audioplayers_linux/linux/audioplayers_linux_plugin.cc b/packages/audioplayers_linux/linux/audioplayers_linux_plugin.cc index 4b6bef5dc..a1c519449 100644 --- a/packages/audioplayers_linux/linux/audioplayers_linux_plugin.cc +++ b/packages/audioplayers_linux/linux/audioplayers_linux_plugin.cc @@ -180,6 +180,7 @@ static void audioplayers_linux_plugin_handle_method_call( double playbackRate = flPlaybackRate == nullptr ? 1.0 : fl_value_get_float(flPlaybackRate); player->SetPlaybackRate(playbackRate); + } else if (strcmp(method, "setAllowsExternalPlayback") == 0) { } else if (strcmp(method, "setReleaseMode") == 0) { auto flReleaseMode = fl_value_lookup_string(args, "releaseMode"); std::string releaseMode = diff --git a/packages/audioplayers_platform_interface/lib/src/audioplayers_platform.dart b/packages/audioplayers_platform_interface/lib/src/audioplayers_platform.dart index 4fab6ca48..a319e8d37 100644 --- a/packages/audioplayers_platform_interface/lib/src/audioplayers_platform.dart +++ b/packages/audioplayers_platform_interface/lib/src/audioplayers_platform.dart @@ -124,6 +124,18 @@ mixin MethodChannelAudioplayersPlatform ); } + @override + Future setAllowsExternalPlayback( + String playerId, { + required bool allows, + }) { + return _call( + 'setAllowsExternalPlayback', + playerId, + {'allows': allows}, + ); + } + @override Future setReleaseMode(String playerId, ReleaseMode releaseMode) { return _call( diff --git a/packages/audioplayers_platform_interface/lib/src/audioplayers_platform_interface.dart b/packages/audioplayers_platform_interface/lib/src/audioplayers_platform_interface.dart index 9e3ee4d5f..3cc87f8c3 100644 --- a/packages/audioplayers_platform_interface/lib/src/audioplayers_platform_interface.dart +++ b/packages/audioplayers_platform_interface/lib/src/audioplayers_platform_interface.dart @@ -88,6 +88,12 @@ abstract class MethodChannelAudioplayersPlatformInterface { /// Android SDK version should be 23 or higher Future setPlaybackRate(String playerId, double playbackRate); + /// Switching the external playback mode + Future setAllowsExternalPlayback( + String playerId, { + required bool allows, + }); + /// Configures the player to read the audio from a URL. /// /// The resources will start being fetched or buffered as soon as you call diff --git a/packages/audioplayers_web/lib/audioplayers_web.dart b/packages/audioplayers_web/lib/audioplayers_web.dart index b26d5d2a5..22ff4f34a 100644 --- a/packages/audioplayers_web/lib/audioplayers_web.dart +++ b/packages/audioplayers_web/lib/audioplayers_web.dart @@ -99,6 +99,14 @@ class WebAudioplayersPlatform extends AudioplayersPlatformInterface { getPlayer(playerId).playbackRate = playbackRate; } + @override + Future setAllowsExternalPlayback( + String playerId, { + required bool allows, + }) async { + // no-op: web doesn't have external playback, it supports only iOS, macOS + } + @override Future setReleaseMode(String playerId, ReleaseMode releaseMode) async { getPlayer(playerId).releaseMode = releaseMode; diff --git a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp index 24e6b9b4c..200fcc425 100644 --- a/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp +++ b/packages/audioplayers_windows/windows/audioplayers_windows_plugin.cpp @@ -207,6 +207,8 @@ void AudioplayersWindowsPlugin::HandleMethodCall( } else if (method_call.method_name().compare("setPlaybackRate") == 0) { auto playbackRate = GetArgument("playbackRate", args, 1.0); player->SetPlaybackSpeed(playbackRate); + } else if (method_call.method_name().compare("setAllowsExternalPlayback") == + 0) { } else if (method_call.method_name().compare("setReleaseMode") == 0) { auto releaseMode = GetArgument("releaseMode", args, std::string());