From 787f41cc8bdc97cd08b04d6f5168a248a6ab2ecf Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:28:05 +0200 Subject: [PATCH 01/15] never overwrite but only upgrade audio session category --- .../camera/camera_avfoundation/CHANGELOG.md | 4 ++ .../ios/RunnerTests/FLTCamSampleBufferTests.m | 23 ++++++++ .../Sources/camera_avfoundation/FLTCam.m | 52 +++++++++++++++++-- .../camera/camera_avfoundation/pubspec.yaml | 2 +- .../video_player_avfoundation/CHANGELOG.md | 4 ++ .../darwin/RunnerTests/VideoPlayerTests.m | 34 ++++++++++++ .../FVPVideoPlayerPlugin.m | 50 ++++++++++++++++-- .../video_player_avfoundation/pubspec.yaml | 2 +- 8 files changed, 159 insertions(+), 12 deletions(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 767f9a75e0a..e7c39ee5818 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.9.17+1 + +* Fixes overwriting flag MixWithOthers set by video_player. + ## 0.9.17 * Adds Swift Package Manager compatibility. diff --git a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSampleBufferTests.m b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSampleBufferTests.m index 65f19cdc7b7..deff626b1b8 100644 --- a/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSampleBufferTests.m +++ b/packages/camera/camera_avfoundation/example/ios/RunnerTests/FLTCamSampleBufferTests.m @@ -200,4 +200,27 @@ - (void)testDidOutputSampleBufferSampleTimesMustBeNumericAfterPauseResume { CFRelease(audioSample); } +- (void)testStartVideoRecordingWithCompletionShouldNotDisableMixWithOthers { + FLTCam *cam = FLTCreateCamWithCaptureSessionQueue(dispatch_queue_create("testing", NULL)); + + id writerMock = OCMClassMock([AVAssetWriter class]); + OCMStub([writerMock alloc]).andReturn(writerMock); + OCMStub([writerMock initWithURL:OCMOCK_ANY fileType:OCMOCK_ANY error:[OCMArg setTo:nil]]) + .andReturn(writerMock); + + [AVAudioSession.sharedInstance setCategory:AVAudioSessionCategoryPlayback + withOptions:AVAudioSessionCategoryOptionMixWithOthers + error:nil]; + + [cam + startVideoRecordingWithCompletion:^(FlutterError *_Nullable error) { + } + messengerForStreaming:nil]; + XCTAssert( + AVAudioSession.sharedInstance.categoryOptions & AVAudioSessionCategoryOptionMixWithOthers, + @"Flag MixWithOthers was removed."); + XCTAssert(AVAudioSession.sharedInstance.category == AVAudioSessionCategoryPlayAndRecord, + @"Category should be PlayAndRecord."); +} + @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 6cfe47b86fb..1c298acec24 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -183,6 +183,8 @@ - (instancetype)initWithMediaSettings:(FCPPlatformMediaSettings *)mediaSettings _videoFormat = kCVPixelFormatType_32BGRA; _inProgressSavePhotoDelegates = [NSMutableDictionary dictionary]; _fileFormat = FCPPlatformImageFileFormatJpeg; + _videoCaptureSession.automaticallyConfiguresApplicationAudioSession = NO; + _audioCaptureSession.automaticallyConfiguresApplicationAudioSession = NO; // To limit memory consumption, limit the number of frames pending processing. // After some testing, 4 was determined to be the best maximum value. @@ -673,7 +675,8 @@ - (void)captureOutput:(AVCaptureOutput *)output [_videoWriter startWriting]; [_videoWriter startSessionAtSourceTime:currentSampleTime]; // fix sample times not being numeric when pause/resume happens before first sample buffer - // arrives https://github.com/flutter/flutter/issues/132014 + // arrives + // https://github.com/flutter/flutter/issues/132014 _lastVideoSampleTime = currentSampleTime; _lastAudioSampleTime = currentSampleTime; } @@ -1216,9 +1219,7 @@ - (BOOL)setupWriterForPath:(NSString *)path { return NO; } - if (_mediaSettings.enableAudio && !_isAudioSetup) { - [self setUpCaptureSessionForAudio]; - } + [self setUpCaptureSessionForAudio]; _videoWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeMPEG4 @@ -1298,9 +1299,47 @@ - (BOOL)setupWriterForPath:(NSString *)path { return YES; } +// configure application wide audio session manually to prevent overwriting +// flag MixWithOthers by capture session, only change category if it is considered +// as upgrade which means it can only enable ability to play in silent mode or +// ability to record audio but never disables it, that could affect other plugins +// which depend on this global state, only change category or options if there is +// change to prevent unnecessary route changes which can cause lags +// https://github.com/flutter/flutter/issues/131553 +static void upgradeAudioSessionCategory(AVAudioSessionCategory category, + AVAudioSessionCategoryOptions options, + AVAudioSessionCategoryOptions clearOptions) { + if (!NSThread.isMainThread) { + dispatch_sync(dispatch_get_main_queue(), ^{ + upgradeAudioSessionCategory(category, options, clearOptions); + }); + return; + } + NSSet *playCategories = [NSSet + setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; + NSSet *recordCategories = + [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; + NSSet *categories = [NSSet setWithObjects:category, AVAudioSession.sharedInstance.category, nil]; + BOOL needPlay = [categories intersectsSet:playCategories]; + BOOL needRecord = [categories intersectsSet:recordCategories]; + if (needPlay && needRecord) { + category = AVAudioSessionCategoryPlayAndRecord; + } else if (needPlay) { + category = AVAudioSessionCategoryPlayback; + } else if (needRecord) { + category = AVAudioSessionCategoryRecord; + } + options = (AVAudioSession.sharedInstance.categoryOptions & ~clearOptions) | options; + if ([category isEqualToString:AVAudioSession.sharedInstance.category] && + options == AVAudioSession.sharedInstance.categoryOptions) { + return; + } + [AVAudioSession.sharedInstance setCategory:category withOptions:options error:nil]; +} + - (void)setUpCaptureSessionForAudio { // Don't setup audio twice or we will lose the audio. - if (_isAudioSetup) { + if (!_mediaSettings.enableAudio || _isAudioSetup) { return; } @@ -1316,6 +1355,9 @@ - (void)setUpCaptureSessionForAudio { // Setup the audio output. _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; + upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, + AVAudioSessionCategoryOptionDefaultToSpeaker, 0); + if ([_audioCaptureSession canAddInput:audioInput]) { [_audioCaptureSession addInput:audioInput]; diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index c00b8d68df0..fbf5e3b3a76 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.17 +version: 0.9.17+1 environment: sdk: ^3.2.3 diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index 4ea05f7f1a9..8ea50fe4311 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.6.2 + +* Fixes audio recorded only with first recording. + ## 2.6.1 * Adds files to make include directory permanent. diff --git a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m index 3ec96e78538..428d9d6bade 100644 --- a/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m +++ b/packages/video_player/video_player_avfoundation/darwin/RunnerTests/VideoPlayerTests.m @@ -791,6 +791,40 @@ - (void)testPublishesInRegistration { } #if TARGET_OS_IOS +- (void)testVideoPlayerShouldNotOverwritePlayAndRecordNorDefaultToSpeaker { + NSObject *registrar = [GetPluginRegistry() + registrarForPlugin:@"testVideoPlayerShouldNotOverwritePlayAndRecordNorDefaultToSpeaker"]; + FVPVideoPlayerPlugin *videoPlayerPlugin = + [[FVPVideoPlayerPlugin alloc] initWithRegistrar:registrar]; + FlutterError *error; + + [AVAudioSession.sharedInstance setCategory:AVAudioSessionCategoryPlayAndRecord + withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker + error:nil]; + + [videoPlayerPlugin initialize:&error]; + [videoPlayerPlugin setMixWithOthers:true error:&error]; + XCTAssert(AVAudioSession.sharedInstance.category == AVAudioSessionCategoryPlayAndRecord, + @"Category should be PlayAndRecord."); + XCTAssert( + AVAudioSession.sharedInstance.categoryOptions & AVAudioSessionCategoryOptionDefaultToSpeaker, + @"Flag DefaultToSpeaker was removed."); + XCTAssert( + AVAudioSession.sharedInstance.categoryOptions & AVAudioSessionCategoryOptionMixWithOthers, + @"Flag MixWithOthers should be set."); + + id sessionMock = OCMClassMock([AVAudioSession class]); + OCMStub([sessionMock sharedInstance]).andReturn(sessionMock); + OCMStub([sessionMock category]).andReturn(AVAudioSessionCategoryPlayAndRecord); + OCMStub([sessionMock categoryOptions]) + .andReturn(AVAudioSessionCategoryOptionMixWithOthers | + AVAudioSessionCategoryOptionDefaultToSpeaker); + OCMReject([sessionMock setCategory:OCMOCK_ANY withOptions:0 error:[OCMArg setTo:nil]]) + .ignoringNonObjectArgs(); + + [videoPlayerPlugin setMixWithOthers:true error:&error]; +} + - (void)validateTransformFixForOrientation:(UIImageOrientation)orientation { AVAssetTrack *track = [[FakeAVAssetTrack alloc] initWithOrientation:orientation]; CGAffineTransform t = FVPGetStandardizedTransformForTrack(track); diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index 14ee7ccefde..a30d7c01d8a 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -708,7 +708,7 @@ - (int64_t)onPlayerSetup:(FVPVideoPlayer *)player frameUpdater:(FVPFrameUpdater - (void)initialize:(FlutterError *__autoreleasing *)error { #if TARGET_OS_IOS // Allow audio playback when the Ring/Silent switch is set to silent - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + upgradeAudioSessionCategory(AVAudioSessionCategoryPlayback, 0, 0); #endif [self.playersByTextureId @@ -813,17 +813,57 @@ - (void)pausePlayer:(NSInteger)textureId error:(FlutterError **)error { [player pause]; } +// do not overwrite PlayAndRecord with Playback which causes inability to record +// audio, do not overwrite all options, only change category if it is considered +// as upgrade which means it can only enable ability to play in silent mode or +// ability to record audio but never disables it, that could affect other plugins +// which depend on this global state, only change category or options if there is +// change to prevent unnecessary route changes which can cause lags +// https://github.com/flutter/flutter/issues/131553 +#if TARGET_OS_IOS +static void upgradeAudioSessionCategory(AVAudioSessionCategory category, + AVAudioSessionCategoryOptions options, + AVAudioSessionCategoryOptions clearOptions) { + if (!NSThread.isMainThread) { + dispatch_sync(dispatch_get_main_queue(), ^{ + upgradeAudioSessionCategory(category, options, clearOptions); + }); + return; + } + NSSet *playCategories = [NSSet + setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; + NSSet *recordCategories = + [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; + NSSet *categories = [NSSet setWithObjects:category, AVAudioSession.sharedInstance.category, nil]; + BOOL needPlay = [categories intersectsSet:playCategories]; + BOOL needRecord = [categories intersectsSet:recordCategories]; + if (needPlay && needRecord) { + category = AVAudioSessionCategoryPlayAndRecord; + } else if (needPlay) { + category = AVAudioSessionCategoryPlayback; + } else if (needRecord) { + category = AVAudioSessionCategoryRecord; + } + options = (AVAudioSession.sharedInstance.categoryOptions & ~clearOptions) | options; + if ([category isEqualToString:AVAudioSession.sharedInstance.category] && + options == AVAudioSession.sharedInstance.categoryOptions) { + return; + } + [AVAudioSession.sharedInstance setCategory:category withOptions:options error:nil]; +} +#endif + - (void)setMixWithOthers:(BOOL)mixWithOthers error:(FlutterError *_Nullable __autoreleasing *)error { #if TARGET_OS_OSX // AVAudioSession doesn't exist on macOS, and audio always mixes, so just no-op. #else if (mixWithOthers) { - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback - withOptions:AVAudioSessionCategoryOptionMixWithOthers - error:nil]; + upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, + AVAudioSessionCategoryOptionMixWithOthers, 0); } else { - [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, 0, + AVAudioSessionCategoryOptionMixWithOthers); } #endif } diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index 674684ee789..5fbf5aa50ef 100644 --- a/packages/video_player/video_player_avfoundation/pubspec.yaml +++ b/packages/video_player/video_player_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_avfoundation description: iOS and macOS implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.6.1 +version: 2.6.2 environment: sdk: ^3.2.3 From 94a80df8b22b6f2cf0aa88aa757b6f7be24e49e1 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Tue, 23 Jul 2024 19:57:51 +0200 Subject: [PATCH 02/15] add more options implicitly present with Playback --- .../camera_avfoundation/Sources/camera_avfoundation/FLTCam.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index d06bcd228c2..cfa0d14be19 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1360,7 +1360,10 @@ - (void)setUpCaptureSessionForAudio { _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, - AVAudioSessionCategoryOptionDefaultToSpeaker, 0); + AVAudioSessionCategoryOptionDefaultToSpeaker | + AVAudioSessionCategoryOptionAllowBluetooth | + AVAudioSessionCategoryOptionAllowBluetoothA2DP | + AVAudioSessionCategoryOptionAllowAirPlay, 0); if ([_audioCaptureSession canAddInput:audioInput]) { [_audioCaptureSession addInput:audioInput]; From f637396175e5c83db2406930468bcb89818e22bb Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Tue, 23 Jul 2024 20:14:32 +0200 Subject: [PATCH 03/15] fix format --- .../Sources/camera_avfoundation/FLTCam.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index cfa0d14be19..c6e74f96f09 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1359,11 +1359,11 @@ - (void)setUpCaptureSessionForAudio { // Setup the audio output. _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; - upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, - AVAudioSessionCategoryOptionDefaultToSpeaker | - AVAudioSessionCategoryOptionAllowBluetooth | - AVAudioSessionCategoryOptionAllowBluetoothA2DP | - AVAudioSessionCategoryOptionAllowAirPlay, 0); + upgradeAudioSessionCategory( + AVAudioSessionCategoryPlayAndRecord, + AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetooth | + AVAudioSessionCategoryOptionAllowBluetoothA2DP | AVAudioSessionCategoryOptionAllowAirPlay, + 0); if ([_audioCaptureSession canAddInput:audioInput]) { [_audioCaptureSession addInput:audioInput]; From 86922ace01338be8135ee6e74e3736e35ba5ea9d Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Wed, 24 Jul 2024 19:50:14 +0200 Subject: [PATCH 04/15] remove HFP and fix using audio session outside of critical section --- .../Sources/camera_avfoundation/FLTCam.m | 7 +++++-- .../video_player_avfoundation/FVPVideoPlayerPlugin.m | 9 +++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index c6e74f96f09..99a2cddf997 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1319,6 +1319,9 @@ static void upgradeAudioSessionCategory(AVAudioSessionCategory category, }); return; } + if (category == nil) { + category = AVAudioSession.sharedInstance.category; + } NSSet *playCategories = [NSSet setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; NSSet *recordCategories = @@ -1361,8 +1364,8 @@ - (void)setUpCaptureSessionForAudio { upgradeAudioSessionCategory( AVAudioSessionCategoryPlayAndRecord, - AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetooth | - AVAudioSessionCategoryOptionAllowBluetoothA2DP | AVAudioSessionCategoryOptionAllowAirPlay, + AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetoothA2DP | + AVAudioSessionCategoryOptionAllowAirPlay, 0); if ([_audioCaptureSession canAddInput:audioInput]) { diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index a30d7c01d8a..efd6613355a 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -830,6 +830,9 @@ static void upgradeAudioSessionCategory(AVAudioSessionCategory category, }); return; } + if (category == nil) { + category = AVAudioSession.sharedInstance.category; + } NSSet *playCategories = [NSSet setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; NSSet *recordCategories = @@ -859,11 +862,9 @@ - (void)setMixWithOthers:(BOOL)mixWithOthers // AVAudioSession doesn't exist on macOS, and audio always mixes, so just no-op. #else if (mixWithOthers) { - upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, - AVAudioSessionCategoryOptionMixWithOthers, 0); + upgradeAudioSessionCategory(nil, AVAudioSessionCategoryOptionMixWithOthers, 0); } else { - upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, 0, - AVAudioSessionCategoryOptionMixWithOthers); + upgradeAudioSessionCategory(nil, 0, AVAudioSessionCategoryOptionMixWithOthers); } #endif } From 6746391fced7cda068b330e77feb4a7a8e41cdf8 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Wed, 24 Jul 2024 19:57:36 +0200 Subject: [PATCH 05/15] fix format --- .../Sources/camera_avfoundation/FLTCam.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 99a2cddf997..48d84567eb3 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1362,11 +1362,11 @@ - (void)setUpCaptureSessionForAudio { // Setup the audio output. _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; - upgradeAudioSessionCategory( - AVAudioSessionCategoryPlayAndRecord, - AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetoothA2DP | - AVAudioSessionCategoryOptionAllowAirPlay, - 0); + upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, + AVAudioSessionCategoryOptionDefaultToSpeaker | + AVAudioSessionCategoryOptionAllowBluetoothA2DP | + AVAudioSessionCategoryOptionAllowAirPlay, + 0); if ([_audioCaptureSession canAddInput:audioInput]) { [_audioCaptureSession addInput:audioInput]; From 42bd00ab269a582d4ffa48f29085a185888d0998 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Thu, 15 Aug 2024 18:39:08 +0200 Subject: [PATCH 06/15] remove dispatch_sync from upgradeAudioSessionCategory --- .../camera_avfoundation/CameraPlugin.m | 2 +- .../Sources/camera_avfoundation/FLTCam.m | 25 ++++++++----------- .../include/camera_avfoundation/FLTCam.h | 2 +- .../FVPVideoPlayerPlugin.m | 9 ++----- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m index 151883c71e9..35962f924da 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m @@ -227,7 +227,7 @@ - (void)prepareForVideoRecordingWithCompletion: (nonnull void (^)(FlutterError *_Nullable))completion { __weak typeof(self) weakSelf = self; dispatch_async(self.captureSessionQueue, ^{ - [weakSelf.camera setUpCaptureSessionForAudio]; + [weakSelf.camera setUpCaptureSessionForAudioIfNeeded]; completion(nil); }); } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 48d84567eb3..e83de03868a 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1223,7 +1223,7 @@ - (BOOL)setupWriterForPath:(NSString *)path { return NO; } - [self setUpCaptureSessionForAudio]; + [self setUpCaptureSessionForAudioIfNeeded]; _videoWriter = [[AVAssetWriter alloc] initWithURL:outputURL fileType:AVFileTypeMPEG4 @@ -1303,22 +1303,17 @@ - (BOOL)setupWriterForPath:(NSString *)path { return YES; } +// this same function is also in video_player_avfoundation // configure application wide audio session manually to prevent overwriting // flag MixWithOthers by capture session, only change category if it is considered // as upgrade which means it can only enable ability to play in silent mode or // ability to record audio but never disables it, that could affect other plugins // which depend on this global state, only change category or options if there is -// change to prevent unnecessary route changes which can cause lags +// change to prevent unnecessary lags and silence // https://github.com/flutter/flutter/issues/131553 static void upgradeAudioSessionCategory(AVAudioSessionCategory category, AVAudioSessionCategoryOptions options, AVAudioSessionCategoryOptions clearOptions) { - if (!NSThread.isMainThread) { - dispatch_sync(dispatch_get_main_queue(), ^{ - upgradeAudioSessionCategory(category, options, clearOptions); - }); - return; - } if (category == nil) { category = AVAudioSession.sharedInstance.category; } @@ -1344,7 +1339,7 @@ static void upgradeAudioSessionCategory(AVAudioSessionCategory category, [AVAudioSession.sharedInstance setCategory:category withOptions:options error:nil]; } -- (void)setUpCaptureSessionForAudio { +- (void)setUpCaptureSessionForAudioIfNeeded { // Don't setup audio twice or we will lose the audio. if (!_mediaSettings.enableAudio || _isAudioSetup) { return; @@ -1362,11 +1357,13 @@ - (void)setUpCaptureSessionForAudio { // Setup the audio output. _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; - upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, - AVAudioSessionCategoryOptionDefaultToSpeaker | - AVAudioSessionCategoryOptionAllowBluetoothA2DP | - AVAudioSessionCategoryOptionAllowAirPlay, - 0); + dispatch_sync(dispatch_get_main_queue(), ^{ + upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, + AVAudioSessionCategoryOptionDefaultToSpeaker | + AVAudioSessionCategoryOptionAllowBluetoothA2DP | + AVAudioSessionCategoryOptionAllowAirPlay, + 0); + }); if ([_audioCaptureSession canAddInput:audioInput]) { [_audioCaptureSession addInput:audioInput]; diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index d8f97926b77..c89ee9f98e5 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -113,7 +113,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)startImageStreamWithMessenger:(NSObject *)messenger; - (void)stopImageStream; - (void)setZoomLevel:(CGFloat)zoom withCompletion:(void (^)(FlutterError *_Nullable))completion; -- (void)setUpCaptureSessionForAudio; +- (void)setUpCaptureSessionForAudioIfNeeded; @end diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index efd6613355a..7390d518078 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -813,23 +813,18 @@ - (void)pausePlayer:(NSInteger)textureId error:(FlutterError **)error { [player pause]; } +// this same function is also in camera_avfoundation // do not overwrite PlayAndRecord with Playback which causes inability to record // audio, do not overwrite all options, only change category if it is considered // as upgrade which means it can only enable ability to play in silent mode or // ability to record audio but never disables it, that could affect other plugins // which depend on this global state, only change category or options if there is -// change to prevent unnecessary route changes which can cause lags +// change to prevent unnecessary lags and silence // https://github.com/flutter/flutter/issues/131553 #if TARGET_OS_IOS static void upgradeAudioSessionCategory(AVAudioSessionCategory category, AVAudioSessionCategoryOptions options, AVAudioSessionCategoryOptions clearOptions) { - if (!NSThread.isMainThread) { - dispatch_sync(dispatch_get_main_queue(), ^{ - upgradeAudioSessionCategory(category, options, clearOptions); - }); - return; - } if (category == nil) { category = AVAudioSession.sharedInstance.category; } From 2f876dd54c20bdbe30f88d57c6f7f0d91c0570c9 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:59:37 +0200 Subject: [PATCH 07/15] test for main thread because tests are running it on that --- .../Sources/camera_avfoundation/FLTCam.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index c98bf0075ad..5f57e410745 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1368,13 +1368,18 @@ - (void)setUpCaptureSessionForAudioIfNeeded { // Setup the audio output. _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; - dispatch_sync(dispatch_get_main_queue(), ^{ + dispatch_block_t block = ^{ upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetoothA2DP | AVAudioSessionCategoryOptionAllowAirPlay, 0); - }); + }; + if (!NSThread.isMainThread) { + dispatch_sync(dispatch_get_main_queue(), block); + } else { + block(); + } if ([_audioCaptureSession canAddInput:audioInput]) { [_audioCaptureSession addInput:audioInput]; From 4ddc2917b3b47d0c83f402a4d8aad199d1bc67b8 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Fri, 6 Sep 2024 21:12:19 +0200 Subject: [PATCH 08/15] remove nil check and rename variables and arguments --- .../Sources/camera_avfoundation/FLTCam.m | 30 ++++++++----------- .../FVPVideoPlayerPlugin.m | 25 +++++++--------- 2 files changed, 24 insertions(+), 31 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 5f57e410745..1f7031aa7ab 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1322,32 +1322,28 @@ - (BOOL)setupWriterForPath:(NSString *)path { // which depend on this global state, only change category or options if there is // change to prevent unnecessary lags and silence // https://github.com/flutter/flutter/issues/131553 -static void upgradeAudioSessionCategory(AVAudioSessionCategory category, - AVAudioSessionCategoryOptions options, - AVAudioSessionCategoryOptions clearOptions) { - if (category == nil) { - category = AVAudioSession.sharedInstance.category; - } +static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory, + AVAudioSessionCategoryOptions options) { NSSet *playCategories = [NSSet setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; NSSet *recordCategories = [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; - NSSet *categories = [NSSet setWithObjects:category, AVAudioSession.sharedInstance.category, nil]; - BOOL needPlay = [categories intersectsSet:playCategories]; - BOOL needRecord = [categories intersectsSet:recordCategories]; + NSSet *requiredCategories = [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; + BOOL needPlay = [requiredCategories intersectsSet:playCategories]; + BOOL needRecord = [requiredCategories intersectsSet:recordCategories]; if (needPlay && needRecord) { - category = AVAudioSessionCategoryPlayAndRecord; + requestedCategory = AVAudioSessionCategoryPlayAndRecord; } else if (needPlay) { - category = AVAudioSessionCategoryPlayback; + requestedCategory = AVAudioSessionCategoryPlayback; } else if (needRecord) { - category = AVAudioSessionCategoryRecord; + requestedCategory = AVAudioSessionCategoryRecord; } - options = (AVAudioSession.sharedInstance.categoryOptions & ~clearOptions) | options; - if ([category isEqualToString:AVAudioSession.sharedInstance.category] && + options = AVAudioSession.sharedInstance.categoryOptions | options; + if ([requestedCategory isEqualToString:AVAudioSession.sharedInstance.category] && options == AVAudioSession.sharedInstance.categoryOptions) { return; } - [AVAudioSession.sharedInstance setCategory:category withOptions:options error:nil]; + [AVAudioSession.sharedInstance setCategory:requestedCategory withOptions:options error:nil]; } - (void)setUpCaptureSessionForAudioIfNeeded { @@ -1369,11 +1365,11 @@ - (void)setUpCaptureSessionForAudioIfNeeded { _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; dispatch_block_t block = ^{ + // Setup options implicit to AVAudioSessionCategoryPlayback to not disturb video_player. upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetoothA2DP | - AVAudioSessionCategoryOptionAllowAirPlay, - 0); + AVAudioSessionCategoryOptionAllowAirPlay); }; if (!NSThread.isMainThread) { dispatch_sync(dispatch_get_main_queue(), block); diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index 7390d518078..d9b42604cc8 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -822,32 +822,29 @@ - (void)pausePlayer:(NSInteger)textureId error:(FlutterError **)error { // change to prevent unnecessary lags and silence // https://github.com/flutter/flutter/issues/131553 #if TARGET_OS_IOS -static void upgradeAudioSessionCategory(AVAudioSessionCategory category, +static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory, AVAudioSessionCategoryOptions options, AVAudioSessionCategoryOptions clearOptions) { - if (category == nil) { - category = AVAudioSession.sharedInstance.category; - } NSSet *playCategories = [NSSet setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; NSSet *recordCategories = [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; - NSSet *categories = [NSSet setWithObjects:category, AVAudioSession.sharedInstance.category, nil]; - BOOL needPlay = [categories intersectsSet:playCategories]; - BOOL needRecord = [categories intersectsSet:recordCategories]; + NSSet *requiredCategories = [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; + BOOL needPlay = [requiredCategories intersectsSet:playCategories]; + BOOL needRecord = [requiredCategories intersectsSet:recordCategories]; if (needPlay && needRecord) { - category = AVAudioSessionCategoryPlayAndRecord; + requestedCategory = AVAudioSessionCategoryPlayAndRecord; } else if (needPlay) { - category = AVAudioSessionCategoryPlayback; + requestedCategory = AVAudioSessionCategoryPlayback; } else if (needRecord) { - category = AVAudioSessionCategoryRecord; + requestedCategory = AVAudioSessionCategoryRecord; } options = (AVAudioSession.sharedInstance.categoryOptions & ~clearOptions) | options; - if ([category isEqualToString:AVAudioSession.sharedInstance.category] && + if ([requestedCategory isEqualToString:AVAudioSession.sharedInstance.category] && options == AVAudioSession.sharedInstance.categoryOptions) { return; } - [AVAudioSession.sharedInstance setCategory:category withOptions:options error:nil]; + [AVAudioSession.sharedInstance setCategory:requestedCategory withOptions:options error:nil]; } #endif @@ -857,9 +854,9 @@ - (void)setMixWithOthers:(BOOL)mixWithOthers // AVAudioSession doesn't exist on macOS, and audio always mixes, so just no-op. #else if (mixWithOthers) { - upgradeAudioSessionCategory(nil, AVAudioSessionCategoryOptionMixWithOthers, 0); + upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, AVAudioSessionCategoryOptionMixWithOthers, 0); } else { - upgradeAudioSessionCategory(nil, 0, AVAudioSessionCategoryOptionMixWithOthers); + upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, 0, AVAudioSessionCategoryOptionMixWithOthers); } #endif } From 81a9449d893dc055c1e0fa4e7eca7fdf272294d6 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Fri, 6 Sep 2024 21:20:43 +0200 Subject: [PATCH 09/15] fix format --- .../Sources/camera_avfoundation/FLTCam.m | 3 ++- .../video_player_avfoundation/FVPVideoPlayerPlugin.m | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 1f7031aa7ab..dccba708a35 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1328,7 +1328,8 @@ static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; NSSet *recordCategories = [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; - NSSet *requiredCategories = [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; + NSSet *requiredCategories = + [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; BOOL needPlay = [requiredCategories intersectsSet:playCategories]; BOOL needRecord = [requiredCategories intersectsSet:recordCategories]; if (needPlay && needRecord) { diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index d9b42604cc8..4c146d8d405 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -829,7 +829,8 @@ static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; NSSet *recordCategories = [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; - NSSet *requiredCategories = [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; + NSSet *requiredCategories = + [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; BOOL needPlay = [requiredCategories intersectsSet:playCategories]; BOOL needRecord = [requiredCategories intersectsSet:recordCategories]; if (needPlay && needRecord) { @@ -854,9 +855,11 @@ - (void)setMixWithOthers:(BOOL)mixWithOthers // AVAudioSession doesn't exist on macOS, and audio always mixes, so just no-op. #else if (mixWithOthers) { - upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, AVAudioSessionCategoryOptionMixWithOthers, 0); + upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, + AVAudioSessionCategoryOptionMixWithOthers, 0); } else { - upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, 0, AVAudioSessionCategoryOptionMixWithOthers); + upgradeAudioSessionCategory(AVAudioSession.sharedInstance.category, 0, + AVAudioSessionCategoryOptionMixWithOthers); } #endif } From 4dd42c1ef54cab66b6f3d5bd499265794038e082 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Thu, 19 Sep 2024 20:07:57 +0200 Subject: [PATCH 10/15] move upgradeAudioSessionCategory above call --- .../FVPVideoPlayerPlugin.m | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index 4c146d8d405..f6875e1a9ce 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -705,6 +705,42 @@ - (int64_t)onPlayerSetup:(FVPVideoPlayer *)player frameUpdater:(FVPFrameUpdater return textureId; } +// this same function is also in camera_avfoundation +// do not overwrite PlayAndRecord with Playback which causes inability to record +// audio, do not overwrite all options, only change category if it is considered +// as upgrade which means it can only enable ability to play in silent mode or +// ability to record audio but never disables it, that could affect other plugins +// which depend on this global state, only change category or options if there is +// change to prevent unnecessary lags and silence +// https://github.com/flutter/flutter/issues/131553 +#if TARGET_OS_IOS +static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory, + AVAudioSessionCategoryOptions options, + AVAudioSessionCategoryOptions clearOptions) { + NSSet *playCategories = [NSSet + setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; + NSSet *recordCategories = + [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; + NSSet *requiredCategories = + [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; + BOOL needPlay = [requiredCategories intersectsSet:playCategories]; + BOOL needRecord = [requiredCategories intersectsSet:recordCategories]; + if (needPlay && needRecord) { + requestedCategory = AVAudioSessionCategoryPlayAndRecord; + } else if (needPlay) { + requestedCategory = AVAudioSessionCategoryPlayback; + } else if (needRecord) { + requestedCategory = AVAudioSessionCategoryRecord; + } + options = (AVAudioSession.sharedInstance.categoryOptions & ~clearOptions) | options; + if ([requestedCategory isEqualToString:AVAudioSession.sharedInstance.category] && + options == AVAudioSession.sharedInstance.categoryOptions) { + return; + } + [AVAudioSession.sharedInstance setCategory:requestedCategory withOptions:options error:nil]; +} +#endif + - (void)initialize:(FlutterError *__autoreleasing *)error { #if TARGET_OS_IOS // Allow audio playback when the Ring/Silent switch is set to silent @@ -813,42 +849,6 @@ - (void)pausePlayer:(NSInteger)textureId error:(FlutterError **)error { [player pause]; } -// this same function is also in camera_avfoundation -// do not overwrite PlayAndRecord with Playback which causes inability to record -// audio, do not overwrite all options, only change category if it is considered -// as upgrade which means it can only enable ability to play in silent mode or -// ability to record audio but never disables it, that could affect other plugins -// which depend on this global state, only change category or options if there is -// change to prevent unnecessary lags and silence -// https://github.com/flutter/flutter/issues/131553 -#if TARGET_OS_IOS -static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory, - AVAudioSessionCategoryOptions options, - AVAudioSessionCategoryOptions clearOptions) { - NSSet *playCategories = [NSSet - setWithObjects:AVAudioSessionCategoryPlayback, AVAudioSessionCategoryPlayAndRecord, nil]; - NSSet *recordCategories = - [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; - NSSet *requiredCategories = - [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; - BOOL needPlay = [requiredCategories intersectsSet:playCategories]; - BOOL needRecord = [requiredCategories intersectsSet:recordCategories]; - if (needPlay && needRecord) { - requestedCategory = AVAudioSessionCategoryPlayAndRecord; - } else if (needPlay) { - requestedCategory = AVAudioSessionCategoryPlayback; - } else if (needRecord) { - requestedCategory = AVAudioSessionCategoryRecord; - } - options = (AVAudioSession.sharedInstance.categoryOptions & ~clearOptions) | options; - if ([requestedCategory isEqualToString:AVAudioSession.sharedInstance.category] && - options == AVAudioSession.sharedInstance.categoryOptions) { - return; - } - [AVAudioSession.sharedInstance setCategory:requestedCategory withOptions:options error:nil]; -} -#endif - - (void)setMixWithOthers:(BOOL)mixWithOthers error:(FlutterError *_Nullable __autoreleasing *)error { #if TARGET_OS_OSX From e02355c076de866ccac569b8b297d8615036356a Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Tue, 15 Oct 2024 18:35:18 +0200 Subject: [PATCH 11/15] update comments --- .../camera/camera_avfoundation/CHANGELOG.md | 4 +-- .../Sources/camera_avfoundation/FLTCam.m | 26 +++++++++---------- .../camera/camera_avfoundation/pubspec.yaml | 2 +- .../video_player_avfoundation/CHANGELOG.md | 4 +-- .../FVPVideoPlayerPlugin.m | 26 +++++++++---------- .../video_player_avfoundation/pubspec.yaml | 2 +- 6 files changed, 32 insertions(+), 32 deletions(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index d85b571ac7c..66f11308993 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,6 +1,6 @@ -## 0.9.17+4 +## 0.9.17+5 -* Fixes overwriting flag MixWithOthers set by video_player. +* Fixes changing global audio session category to be collision free. * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. ## 0.9.17+3 diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index dccba708a35..3a7b46a82ff 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1314,14 +1314,14 @@ - (BOOL)setupWriterForPath:(NSString *)path { return YES; } -// this same function is also in video_player_avfoundation -// configure application wide audio session manually to prevent overwriting -// flag MixWithOthers by capture session, only change category if it is considered -// as upgrade which means it can only enable ability to play in silent mode or -// ability to record audio but never disables it, that could affect other plugins -// which depend on this global state, only change category or options if there is -// change to prevent unnecessary lags and silence -// https://github.com/flutter/flutter/issues/131553 +// This function, although slightly modified, is also in video_player_avfoundation. +// Both need to do the same thing and run on the same thread. +// Configure application wide audio session manually to prevent overwriting flag +// MixWithOthers by capture session. +// Only change category if it is considered an upgrade which means it can only enable +// ability to play in silent mode or ability to record audio but never disables it, +// that could affect other plugins which depend on this global state. Only change +// category or options if there is change to prevent unnecessary lags and silence. static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory, AVAudioSessionCategoryOptions options) { NSSet *playCategories = [NSSet @@ -1330,13 +1330,13 @@ static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; NSSet *requiredCategories = [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; - BOOL needPlay = [requiredCategories intersectsSet:playCategories]; - BOOL needRecord = [requiredCategories intersectsSet:recordCategories]; - if (needPlay && needRecord) { + BOOL requiresPlay = [requiredCategories intersectsSet:playCategories]; + BOOL requiresRecord = [requiredCategories intersectsSet:recordCategories]; + if (requiresPlay && requiresRecord) { requestedCategory = AVAudioSessionCategoryPlayAndRecord; - } else if (needPlay) { + } else if (requiresPlay) { requestedCategory = AVAudioSessionCategoryPlayback; - } else if (needRecord) { + } else if (requiresRecord) { requestedCategory = AVAudioSessionCategoryRecord; } options = AVAudioSession.sharedInstance.categoryOptions | options; diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 713a43cbb25..ba8e22fc9e4 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.17+4 +version: 0.9.17+5 environment: sdk: ^3.3.0 diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index 2f85e51044e..716579217dd 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,6 +1,6 @@ -## 2.6.2 +## 2.6.3 -* Fixes audio recorded only with first recording. +* Fixes changing global audio session category to be collision free. * Updates minimum supported SDK version to Flutter 3.19/Dart 3.3. ## 2.6.1 diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index f6875e1a9ce..eb93664a9c5 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -705,14 +705,14 @@ - (int64_t)onPlayerSetup:(FVPVideoPlayer *)player frameUpdater:(FVPFrameUpdater return textureId; } -// this same function is also in camera_avfoundation -// do not overwrite PlayAndRecord with Playback which causes inability to record -// audio, do not overwrite all options, only change category if it is considered -// as upgrade which means it can only enable ability to play in silent mode or -// ability to record audio but never disables it, that could affect other plugins -// which depend on this global state, only change category or options if there is -// change to prevent unnecessary lags and silence -// https://github.com/flutter/flutter/issues/131553 +// This function, although slightly modified, is also in camera_avfoundation. +// Both need to do the same thing and run on the same thread. +// Do not overwrite PlayAndRecord with Playback which causes inability to record +// audio, do not overwrite all options. +// Only change category if it is considered an upgrade which means it can only enable +// ability to play in silent mode or ability to record audio but never disables it, +// that could affect other plugins which depend on this global state. Only change +// category or options if there is change to prevent unnecessary lags and silence. #if TARGET_OS_IOS static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory, AVAudioSessionCategoryOptions options, @@ -723,13 +723,13 @@ static void upgradeAudioSessionCategory(AVAudioSessionCategory requestedCategory [NSSet setWithObjects:AVAudioSessionCategoryRecord, AVAudioSessionCategoryPlayAndRecord, nil]; NSSet *requiredCategories = [NSSet setWithObjects:requestedCategory, AVAudioSession.sharedInstance.category, nil]; - BOOL needPlay = [requiredCategories intersectsSet:playCategories]; - BOOL needRecord = [requiredCategories intersectsSet:recordCategories]; - if (needPlay && needRecord) { + BOOL requiresPlay = [requiredCategories intersectsSet:playCategories]; + BOOL requiresRecord = [requiredCategories intersectsSet:recordCategories]; + if (requiresPlay && requiresRecord) { requestedCategory = AVAudioSessionCategoryPlayAndRecord; - } else if (needPlay) { + } else if (requiresPlay) { requestedCategory = AVAudioSessionCategoryPlayback; - } else if (needRecord) { + } else if (requiresRecord) { requestedCategory = AVAudioSessionCategoryRecord; } options = (AVAudioSession.sharedInstance.categoryOptions & ~clearOptions) | options; diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index 63952af7c43..0d04e93ed11 100644 --- a/packages/video_player/video_player_avfoundation/pubspec.yaml +++ b/packages/video_player/video_player_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_avfoundation description: iOS and macOS implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.6.2 +version: 2.6.3 environment: sdk: ^3.3.0 From 10864008cbc5e4d131d2493bccbf000066180827 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Thu, 28 Nov 2024 19:41:54 +0100 Subject: [PATCH 12/15] change comments --- packages/camera/camera_avfoundation/CHANGELOG.md | 4 ++-- .../camera_avfoundation/Sources/camera_avfoundation/FLTCam.m | 4 ++-- packages/camera/camera_avfoundation/pubspec.yaml | 2 +- packages/video_player/video_player_avfoundation/CHANGELOG.md | 2 +- .../Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m | 2 +- packages/video_player/video_player_avfoundation/pubspec.yaml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 0a69a44af23..ed09e6e6f0a 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,6 +1,6 @@ -## 0.9.17+5 +## 0.9.17+6 -* Fixes changing global audio session category to be collision free. +* Fixes changing global audio session category to be collision free across plugins. ## 0.9.17+4 diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 3a7b46a82ff..283f67058c2 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1315,7 +1315,7 @@ - (BOOL)setupWriterForPath:(NSString *)path { } // This function, although slightly modified, is also in video_player_avfoundation. -// Both need to do the same thing and run on the same thread. +// Both need to do the same thing and run on the same thread (for example main thread). // Configure application wide audio session manually to prevent overwriting flag // MixWithOthers by capture session. // Only change category if it is considered an upgrade which means it can only enable @@ -1366,7 +1366,7 @@ - (void)setUpCaptureSessionForAudioIfNeeded { _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; dispatch_block_t block = ^{ - // Setup options implicit to AVAudioSessionCategoryPlayback to not disturb video_player. + // Setup options implicit to AVAudioSessionCategoryPlayback to avoid conflicts with other plugins like video_player. upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetoothA2DP | diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 6ceb0b934f6..0bec341b1ce 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.17+5 +version: 0.9.17+6 environment: sdk: ^3.3.0 diff --git a/packages/video_player/video_player_avfoundation/CHANGELOG.md b/packages/video_player/video_player_avfoundation/CHANGELOG.md index 3447b94a155..ac7f97985bb 100644 --- a/packages/video_player/video_player_avfoundation/CHANGELOG.md +++ b/packages/video_player/video_player_avfoundation/CHANGELOG.md @@ -1,4 +1,4 @@ -## 2.6.3 +## 2.6.4 * Fixes changing global audio session category to be collision free. diff --git a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m index eb93664a9c5..5ca388ef2c8 100644 --- a/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m +++ b/packages/video_player/video_player_avfoundation/darwin/video_player_avfoundation/Sources/video_player_avfoundation/FVPVideoPlayerPlugin.m @@ -706,7 +706,7 @@ - (int64_t)onPlayerSetup:(FVPVideoPlayer *)player frameUpdater:(FVPFrameUpdater } // This function, although slightly modified, is also in camera_avfoundation. -// Both need to do the same thing and run on the same thread. +// Both need to do the same thing and run on the same thread (for example main thread). // Do not overwrite PlayAndRecord with Playback which causes inability to record // audio, do not overwrite all options. // Only change category if it is considered an upgrade which means it can only enable diff --git a/packages/video_player/video_player_avfoundation/pubspec.yaml b/packages/video_player/video_player_avfoundation/pubspec.yaml index 31d615dd886..233a9b65e86 100644 --- a/packages/video_player/video_player_avfoundation/pubspec.yaml +++ b/packages/video_player/video_player_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_avfoundation description: iOS and macOS implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.6.3 +version: 2.6.4 environment: sdk: ^3.3.0 From 6216653f80fd15eb9551bbdbb5a4bc47ffc3dcf2 Mon Sep 17 00:00:00 2001 From: misos1 <30872003+misos1@users.noreply.github.com> Date: Thu, 28 Nov 2024 19:51:32 +0100 Subject: [PATCH 13/15] fix format --- .../camera_avfoundation/Sources/camera_avfoundation/FLTCam.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 4c631a0a547..0376a464b28 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1418,7 +1418,8 @@ - (void)setUpCaptureSessionForAudioIfNeeded { _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; dispatch_block_t block = ^{ - // Setup options implicit to AVAudioSessionCategoryPlayback to avoid conflicts with other plugins like video_player. + // Setup options implicit to AVAudioSessionCategoryPlayback to avoid conflicts with other + // plugins like video_player. upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetoothA2DP | From acaad4c418154d601fa2bfb7105630c66e95fdf5 Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 13 Jan 2025 12:43:12 -0500 Subject: [PATCH 14/15] Minor grammar fix --- .../camera_avfoundation/Sources/camera_avfoundation/FLTCam.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index 0376a464b28..699dbf3a806 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1418,7 +1418,7 @@ - (void)setUpCaptureSessionForAudioIfNeeded { _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; dispatch_block_t block = ^{ - // Setup options implicit to AVAudioSessionCategoryPlayback to avoid conflicts with other + // Set up options implicit to AVAudioSessionCategoryPlayback to avoid conflicts with other // plugins like video_player. upgradeAudioSessionCategory(AVAudioSessionCategoryPlayAndRecord, AVAudioSessionCategoryOptionDefaultToSpeaker | From 3d4e63812d068a94633ab8afe80f2e7d83236e6b Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 13 Jan 2025 12:44:31 -0500 Subject: [PATCH 15/15] Re-bump camera version --- packages/camera/camera_avfoundation/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index 0bec341b1ce..fb4945ed709 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.17+6 +version: 0.9.17+7 environment: sdk: ^3.3.0