Add disposePlayer to platform interface. Retain player.position after dispose.
This commit is contained in:
parent
35a6e4810b
commit
ad9e4518cf
|
@ -37,17 +37,15 @@
|
|||
FlutterResult _playResult;
|
||||
id _timeObserver;
|
||||
BOOL _automaticallyWaitsToMinimizeStalling;
|
||||
BOOL _configuredSession;
|
||||
BOOL _playing;
|
||||
float _speed;
|
||||
}
|
||||
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar playerId:(NSString*)idParam configuredSession:(BOOL)configuredSession {
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar playerId:(NSString*)idParam {
|
||||
self = [super init];
|
||||
NSAssert(self, @"super init cannot be nil");
|
||||
_registrar = registrar;
|
||||
_playerId = idParam;
|
||||
_configuredSession = configuredSession;
|
||||
_methodChannel =
|
||||
[FlutterMethodChannel methodChannelWithName:[NSMutableString stringWithFormat:@"com.ryanheise.just_audio.methods.%@", _playerId]
|
||||
binaryMessenger:[registrar messenger]];
|
||||
|
@ -113,9 +111,6 @@
|
|||
[self seek:position index:request[@"index"] completionHandler:^(BOOL finished) {
|
||||
result(@{});
|
||||
}];
|
||||
} else if ([@"dispose" isEqualToString:call.method]) {
|
||||
[self dispose];
|
||||
result(@{});
|
||||
} else if ([@"concatenatingInsertAll" isEqualToString:call.method]) {
|
||||
[self concatenatingInsertAll:(NSString *)request[@"id"] index:[request[@"index"] intValue] sources:(NSArray *)request[@"children"]];
|
||||
result(@{});
|
||||
|
@ -908,11 +903,6 @@
|
|||
_playResult = result;
|
||||
}
|
||||
_playing = YES;
|
||||
#if TARGET_OS_IPHONE
|
||||
if (_configuredSession) {
|
||||
[[AVAudioSession sharedInstance] setActive:YES error:nil];
|
||||
}
|
||||
#endif
|
||||
_player.rate = _speed;
|
||||
[self updatePosition];
|
||||
if (@available(macOS 10.12, iOS 10.0, *)) {}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
@implementation JustAudioPlugin {
|
||||
NSObject<FlutterPluginRegistrar>* _registrar;
|
||||
BOOL _configuredSession;
|
||||
NSMutableDictionary<NSString *, AudioPlayer *> *_players;
|
||||
}
|
||||
|
||||
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
|
@ -20,6 +20,7 @@
|
|||
self = [super init];
|
||||
NSAssert(self, @"super init cannot be nil");
|
||||
_registrar = registrar;
|
||||
_players = [[NSMutableDictionary alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -27,11 +28,25 @@
|
|||
if ([@"init" isEqualToString:call.method]) {
|
||||
NSDictionary *request = (NSDictionary *)call.arguments;
|
||||
NSString *playerId = request[@"id"];
|
||||
/*AudioPlayer* player =*/ [[AudioPlayer alloc] initWithRegistrar:_registrar playerId:playerId configuredSession:_configuredSession];
|
||||
AudioPlayer* player = [[AudioPlayer alloc] initWithRegistrar:_registrar playerId:playerId];
|
||||
[_players setValue:player forKey:playerId];
|
||||
result(nil);
|
||||
} else if ([@"disposePlayer" isEqualToString:call.method]) {
|
||||
NSDictionary *request = (NSDictionary *)call.arguments;
|
||||
NSString *playerId = request[@"id"];
|
||||
[_players[playerId] dispose];
|
||||
[_players setValue:nil forKey:playerId];
|
||||
result(@{});
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
for (NSString *playerId in _players) {
|
||||
[_players[playerId] dispose];
|
||||
}
|
||||
[_players removeAllObjects];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -10,75 +10,29 @@ project 'Runner', {
|
|||
'Release' => :release,
|
||||
}
|
||||
|
||||
def parse_KV_file(file, separator='=')
|
||||
file_abs_path = File.expand_path(file)
|
||||
if !File.exists? file_abs_path
|
||||
return [];
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
generated_key_values = {}
|
||||
skip_line_start_symbols = ["#", "/"]
|
||||
File.foreach(file_abs_path) do |line|
|
||||
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
|
||||
plugin = line.split(pattern=separator)
|
||||
if plugin.length == 2
|
||||
podname = plugin[0].strip()
|
||||
path = plugin[1].strip()
|
||||
podpath = File.expand_path("#{path}", file_abs_path)
|
||||
generated_key_values[podname] = podpath
|
||||
else
|
||||
puts "Invalid plugin specification: #{line}"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
generated_key_values
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
# Flutter Pod
|
||||
|
||||
copied_flutter_dir = File.join(__dir__, 'Flutter')
|
||||
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
|
||||
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
|
||||
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
|
||||
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
|
||||
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
|
||||
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
|
||||
|
||||
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
|
||||
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
|
||||
|
||||
unless File.exist?(copied_framework_path)
|
||||
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
|
||||
end
|
||||
unless File.exist?(copied_podspec_path)
|
||||
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
|
||||
end
|
||||
end
|
||||
|
||||
# Keep pod path relative so it can be checked into Podfile.lock.
|
||||
pod 'Flutter', :path => 'Flutter'
|
||||
|
||||
# Plugin Pods
|
||||
|
||||
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
|
||||
# referring to absolute paths on developers' machines.
|
||||
system('rm -rf .symlinks')
|
||||
system('mkdir -p .symlinks/plugins')
|
||||
plugin_pods = parse_KV_file('../.flutter-plugins')
|
||||
plugin_pods.each do |name, path|
|
||||
symlink = File.join('.symlinks', 'plugins', name)
|
||||
File.symlink(path, symlink)
|
||||
pod name, :path => File.join(symlink, 'ios')
|
||||
end
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['ENABLE_BITCODE'] = 'NO'
|
||||
end
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,18 +6,12 @@ PODS:
|
|||
- Flutter
|
||||
- path_provider (0.0.1):
|
||||
- Flutter
|
||||
- path_provider_linux (0.0.1):
|
||||
- Flutter
|
||||
- path_provider_macos (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- just_audio (from `.symlinks/plugins/just_audio/ios`)
|
||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||
- path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
|
||||
- path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
audio_session:
|
||||
|
@ -28,19 +22,13 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/just_audio/ios"
|
||||
path_provider:
|
||||
:path: ".symlinks/plugins/path_provider/ios"
|
||||
path_provider_linux:
|
||||
:path: ".symlinks/plugins/path_provider_linux/ios"
|
||||
path_provider_macos:
|
||||
:path: ".symlinks/plugins/path_provider_macos/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
audio_session: 4f3e461722055d21515cf3261b64c973c062f345
|
||||
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
||||
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4
|
||||
path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0
|
||||
|
||||
PODFILE CHECKSUM: f32fb4e7c14f8b3ca19a369d7be425dd9241af27
|
||||
PODFILE CHECKSUM: 8e679eca47255a8ca8067c4c67aab20e64cb974d
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import path_provider_macos
|
||||
import audio_session
|
||||
import just_audio
|
||||
import path_provider_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
||||
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
}
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
@interface AudioPlayer : NSObject<FlutterStreamHandler>
|
||||
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar playerId:(NSString*)idParam configuredSession:(BOOL)configuredSession;
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar playerId:(NSString*)idParam;
|
||||
- (void)dispose;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -324,7 +324,6 @@ class AudioPlayer {
|
|||
|
||||
/// The current position of the player.
|
||||
Duration get position {
|
||||
if (_disposed) return null;
|
||||
if (playing && processingState == ProcessingState.ready) {
|
||||
final result = _playbackEvent.updatePosition +
|
||||
(DateTime.now().difference(_playbackEvent.updateTime)) * speed;
|
||||
|
@ -682,7 +681,13 @@ class AudioPlayer {
|
|||
Future<void> dispose() async {
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
await (await _platform).dispose(DisposeRequest());
|
||||
try {
|
||||
await JustAudioPlatform.instance
|
||||
.disposePlayer(DisposePlayerRequest(id: _id));
|
||||
} catch (e) {
|
||||
print("disposePlayer() not implemented. Falling back to dispose()");
|
||||
await (await _platform).dispose(DisposeRequest());
|
||||
}
|
||||
_audioSource = null;
|
||||
_audioSources.values.forEach((s) => s._dispose());
|
||||
_audioSources.clear();
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
@interface AudioPlayer : NSObject<FlutterStreamHandler>
|
||||
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar playerId:(NSString*)idParam configuredSession:(BOOL)configuredSession;
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar playerId:(NSString*)idParam;
|
||||
- (void)dispose;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ environment:
|
|||
flutter: ">=1.12.13+hotfix.5"
|
||||
|
||||
dependencies:
|
||||
just_audio_platform_interface: ^1.0.0
|
||||
# just_audio_platform_interface: ^1.0.0
|
||||
just_audio_platform_interface:
|
||||
path: ../just_audio_platform_interface
|
||||
audio_session: ^0.0.7
|
||||
rxdart: ^0.24.1
|
||||
path: ^1.6.4
|
||||
|
|
|
@ -41,6 +41,11 @@ abstract class JustAudioPlatform extends PlatformInterface {
|
|||
Future<AudioPlayerPlatform> init(InitRequest request) {
|
||||
throw UnimplementedError('init() has not been implemented.');
|
||||
}
|
||||
|
||||
/// Disposes of a platform player.
|
||||
Future<DisposePlayerResponse> disposePlayer(DisposePlayerRequest request) {
|
||||
throw UnimplementedError('disposePlayer() has not been implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
/// A nested platform interface for communicating with a particular player
|
||||
|
@ -53,6 +58,10 @@ abstract class JustAudioPlatform extends PlatformInterface {
|
|||
/// `implements` this interface will be broken by newly added
|
||||
/// [AudioPlayerPlatform] methods.
|
||||
abstract class AudioPlayerPlatform {
|
||||
final String id;
|
||||
|
||||
AudioPlayerPlatform(this.id);
|
||||
|
||||
Stream<PlaybackEventMessage> get playbackEventMessageStream {
|
||||
throw UnimplementedError(
|
||||
'playbackEventMessageStream has not been implemented.');
|
||||
|
@ -103,6 +112,9 @@ abstract class AudioPlayerPlatform {
|
|||
"setAndroidAudioAttributes() has not been implemented.");
|
||||
}
|
||||
|
||||
/// This method has been superceded by [JustAudioPlatform.disposePlayer].
|
||||
/// For backward compatibility, this method will still be called as a
|
||||
/// fallback if [JustAudioPlatform.disposePlayer] is not implemented.
|
||||
Future<DisposeResponse> dispose(DisposeRequest request) {
|
||||
throw UnimplementedError("dispose() has not been implemented.");
|
||||
}
|
||||
|
@ -244,6 +256,21 @@ class InitRequest {
|
|||
};
|
||||
}
|
||||
|
||||
class DisposePlayerRequest {
|
||||
final String id;
|
||||
|
||||
DisposePlayerRequest({@required this.id});
|
||||
|
||||
Map<dynamic, dynamic> toMap() => {
|
||||
'id': id,
|
||||
};
|
||||
}
|
||||
|
||||
class DisposePlayerResponse {
|
||||
static DisposePlayerResponse fromMap(Map<dynamic, dynamic> map) =>
|
||||
DisposePlayerResponse();
|
||||
}
|
||||
|
||||
class LoadRequest {
|
||||
final AudioSourceMessage audioSourceMessage;
|
||||
|
||||
|
|
|
@ -13,15 +13,22 @@ class MethodChannelJustAudio extends JustAudioPlatform {
|
|||
await _mainChannel.invokeMethod('init', request.toMap());
|
||||
return MethodChannelAudioPlayer(request.id);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<DisposePlayerResponse> disposePlayer(
|
||||
DisposePlayerRequest request) async {
|
||||
return DisposePlayerResponse.fromMap(
|
||||
await _mainChannel.invokeMethod('disposePlayer', request.toMap()));
|
||||
}
|
||||
}
|
||||
|
||||
/// An implementation of [AudioPlayerPlatform] that uses method channels.
|
||||
class MethodChannelAudioPlayer extends AudioPlayerPlatform {
|
||||
final String id;
|
||||
final MethodChannel _channel;
|
||||
|
||||
MethodChannelAudioPlayer(this.id)
|
||||
: _channel = MethodChannel('com.ryanheise.just_audio.methods.$id');
|
||||
MethodChannelAudioPlayer(String id)
|
||||
: _channel = MethodChannel('com.ryanheise.just_audio.methods.$id'),
|
||||
super(id);
|
||||
|
||||
@override
|
||||
Stream<PlaybackEventMessage> get playbackEventMessageStream =>
|
||||
|
|
Loading…
Reference in New Issue