diff --git a/android/src/main/java/com/ryanheise/just_audio/JustAudioPlugin.java b/android/src/main/java/com/ryanheise/just_audio/JustAudioPlugin.java index 3888d4e..ff6b890 100644 --- a/android/src/main/java/com/ryanheise/just_audio/JustAudioPlugin.java +++ b/android/src/main/java/com/ryanheise/just_audio/JustAudioPlugin.java @@ -30,6 +30,9 @@ public class JustAudioPlugin implements MethodCallHandler { new AudioPlayer(registrar, id); result.success(null); break; + case "setIosCategory": + result.success(null); + break; default: result.notImplemented(); break; diff --git a/darwin/Classes/AudioPlayer.m b/darwin/Classes/AudioPlayer.m index 8a136df..6adc447 100644 --- a/darwin/Classes/AudioPlayer.m +++ b/darwin/Classes/AudioPlayer.m @@ -18,13 +18,15 @@ id _endObserver; id _timeObserver; BOOL _automaticallyWaitsToMinimizeStalling; + BOOL _configuredSession; } -- (instancetype)initWithRegistrar:(NSObject *)registrar playerId:(NSString*)idParam { +- (instancetype)initWithRegistrar:(NSObject *)registrar playerId:(NSString*)idParam configuredSession:(BOOL)configuredSession { 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]]; @@ -285,6 +287,9 @@ // TODO: dynamically adjust the lag. //int lag = 6; //int start = [self getCurrentPosition]; + if (_configuredSession) { + [[AVAudioSession sharedInstance] setActive:YES error:nil]; + } [_player play]; if (!@available(macOS 10.12, iOS 10.0, *)) {[self setPlaybackState:playing];} // TODO: convert this Android code to iOS diff --git a/darwin/Classes/JustAudioPlugin.m b/darwin/Classes/JustAudioPlugin.m index ca4a235..3fedffd 100644 --- a/darwin/Classes/JustAudioPlugin.m +++ b/darwin/Classes/JustAudioPlugin.m @@ -1,9 +1,11 @@ #import "JustAudioPlugin.h" #import "AudioPlayer.h" #import "AudioPlayer.h" +#import @implementation JustAudioPlugin { NSObject* _registrar; + BOOL _configuredSession; } + (void)registerWithRegistrar:(NSObject*)registrar { @@ -25,7 +27,23 @@ if ([@"init" isEqualToString:call.method]) { NSArray* args = (NSArray*)call.arguments; NSString* playerId = args[0]; - AudioPlayer* player = [[AudioPlayer alloc] initWithRegistrar:_registrar playerId:playerId]; + AudioPlayer* player = [[AudioPlayer alloc] initWithRegistrar:_registrar playerId:playerId configuredSession:_configuredSession]; + result(nil); + } else if ([@"setIosCategory" isEqualToString:call.method]) { + NSNumber* categoryIndex = (NSNumber*)call.arguments; + AVAudioSessionCategory category = nil; + switch (categoryIndex.integerValue) { + case 0: category = AVAudioSessionCategoryAmbient; break; + case 1: category = AVAudioSessionCategorySoloAmbient; break; + case 2: category = AVAudioSessionCategoryPlayback; break; + case 3: category = AVAudioSessionCategoryRecord; break; + case 4: category = AVAudioSessionCategoryPlayAndRecord; break; + case 5: category = AVAudioSessionCategoryMultiRoute; break; + } + if (category) { + _configuredSession = YES; + } + [[AVAudioSession sharedInstance] setCategory:category error:nil]; result(nil); } else { result(FlutterMethodNotImplemented); diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 1d85d09..7f7123c 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -25,4 +25,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: f32fb4e7c14f8b3ca19a369d7be425dd9241af27 -COCOAPODS: 1.7.5 +COCOAPODS: 1.9.1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index d2452e5..442406c 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -315,7 +315,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -388,7 +387,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -444,7 +442,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; diff --git a/example/lib/main.dart b/example/lib/main.dart index 1d42a36..7c234d3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -18,6 +18,7 @@ class _MyAppState extends State { @override void initState() { super.initState(); + AudioPlayer.setIosCategory(IosCategory.playback); _player = AudioPlayer(); _player .setUrl( diff --git a/ios/Classes/AudioPlayer.h b/ios/Classes/AudioPlayer.h index a22fae4..1938b2c 100644 --- a/ios/Classes/AudioPlayer.h +++ b/ios/Classes/AudioPlayer.h @@ -2,7 +2,7 @@ @interface AudioPlayer : NSObject -- (instancetype)initWithRegistrar:(NSObject *)registrar playerId:(NSString*)idParam; +- (instancetype)initWithRegistrar:(NSObject *)registrar playerId:(NSString*)idParam configuredSession:(BOOL)configuredSession; @end diff --git a/lib/just_audio.dart b/lib/just_audio.dart index b5a8aa6..5c81b6b 100644 --- a/lib/just_audio.dart +++ b/lib/just_audio.dart @@ -50,6 +50,22 @@ class AudioPlayer { return MethodChannel('com.ryanheise.just_audio.methods.$id'); } + /// Configure the audio session category on iOS. Has no effect on Android. + /// + /// Note that the default category on iOS is [IosCategory.soloAmbient], but + /// for a typical media app, you will probably want to change this to + /// [IosCategory.playback]. If you wish to override the default, call this + /// method before playing any audio. + /// + /// Note: If you use other audio plugins in conjunction with this one, it is + /// possible that the other audio plugin may override the setting you choose + /// here. (You may consider asking the developer of each other plugin you use + /// to provide a similar method so that you can configure the same category + /// universally.) + static Future setIosCategory(IosCategory category) async { + await _mainChannel.invokeMethod('setIosCategory', category.index); + } + final Future _channel; final int _id; @@ -540,3 +556,14 @@ class IcyMetadata { IcyMetadata({@required this.info, @required this.headers}); } + +/// The audio session categories on iOS, to be used with +/// [AudioPlayer.setIosCategory]. +enum IosCategory { + ambient, + soloAmbient, + playback, + record, + playAndRecord, + multiRoute, +}