From 57998be23f692aae549fd60922f957af7fdc06b1 Mon Sep 17 00:00:00 2001 From: t-miya Date: Tue, 9 Dec 2025 14:58:18 +0900 Subject: [PATCH 01/18] =?UTF-8?q?iOS=20SDK=20=E3=81=AE=20RTCAudioSession?= =?UTF-8?q?=20=E3=81=AB=20pauseRecording()/resumeRecording()=20=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 8 + patches/ios_audio_pause_resume.patch | 304 +++++++++++++++++++++++++++ run.py | 1 + 3 files changed, 313 insertions(+) create mode 100644 patches/ios_audio_pause_resume.patch diff --git a/CHANGES.md b/CHANGES.md index 8442639b..b5b35859 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -29,6 +29,14 @@ VERSION ファイルを上げただけの場合は変更履歴記録は不要。 ## タイムライン +- 2025-12-12 [ADD] iOS SDK の RTCAudioSession に公開 API として pauseRecording()/resumeRecording() を追加する + - iOS 実機のマイクインジケータが消灯状態のミュートをできるようにする + - AudioDeviceModuleIOS に pauseRecording()/resumeRecording() を追加する + - 動作中の Audio Device Module 取得用に GetLastInstance() を追加する + - AudioDeviceIOS に pauseRecording()/resumeRecording() を追加する + - 録音一時停止中か管理するための paused_recording_ プロパティを追加する + - VoiceProcessingAudioUnit に二重解放エラーを防ぐための disposed フラグを追加する + - @t-miya - 2025-12-12 [RELEASE] m143.7499.2.1 - @zztkm - 2025-12-10 [ADD] iOS SDK 向けに RTCAudioTrackSink を追加する diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch new file mode 100644 index 00000000..d5775aad --- /dev/null +++ b/patches/ios_audio_pause_resume.patch @@ -0,0 +1,304 @@ +diff --git a/sdk/objc/components/audio/RTCAudioSession.h b/sdk/objc/components/audio/RTCAudioSession.h +index 47a6007..56f22dd 100644 +--- a/sdk/objc/components/audio/RTCAudioSession.h ++++ b/sdk/objc/components/audio/RTCAudioSession.h +@@ -171,6 +171,16 @@ RTC_OBJC_EXPORT + */ + @property(nonatomic, assign) BOOL isAudioEnabled; + ++/** Audio 録音を一時停止する。startRecording() により録音開始している状態を前提とする。 ++ * 一時停止成功時または既に停止状態の場合 YES を返す。 ++ */ ++- (BOOL)pauseRecording; ++ ++/** pauseRecording() により一時停止している Audio 録音を再開する。 ++ * 再開成功または既に録音中の場合 YES を返す。 ++ */ ++- (BOOL)resumeRecording; ++ + // Proxy properties. + @property(readonly) NSString *category; + @property(readonly) AVAudioSessionCategoryOptions categoryOptions; +diff --git a/sdk/objc/components/audio/RTCAudioSession.mm b/sdk/objc/components/audio/RTCAudioSession.mm +index 60cf11e..f81381e 100644 +--- a/sdk/objc/components/audio/RTCAudioSession.mm ++++ b/sdk/objc/components/audio/RTCAudioSession.mm +@@ -18,6 +18,7 @@ + #include "absl/base/attributes.h" + #include "rtc_base/checks.h" + #include "rtc_base/synchronization/mutex.h" ++#include "sdk/objc/native/src/audio/audio_device_module_ios.h" + + #import "RTCAudioSessionConfiguration.h" + #import "base/RTCLogging.h" +@@ -214,6 +215,36 @@ - (BOOL)isAudioEnabled { + } + } + ++- (BOOL)pauseRecording { ++ webrtc::ios_adm::AudioDeviceModuleIOS* adm = ++ webrtc::ios_adm::AudioDeviceModuleIOS::GetLastInstance(); ++ if (!adm) { ++ RTCLogError(@"pauseRecording failed: AudioDeviceModuleIOS not available"); ++ return NO; ++ } ++ int32_t result = adm->PauseRecording(); ++ if (result != 0) { ++ RTCLogError(@"pauseRecording failed with code %d", result); ++ return NO; ++ } ++ return YES; ++} ++ ++- (BOOL)resumeRecording { ++ webrtc::ios_adm::AudioDeviceModuleIOS* adm = ++ webrtc::ios_adm::AudioDeviceModuleIOS::GetLastInstance(); ++ if (!adm) { ++ RTCLogError(@"resumeRecording failed: AudioDeviceModuleIOS not available"); ++ return NO; ++ } ++ int32_t result = adm->ResumeRecording(); ++ if (result != 0) { ++ RTCLogError(@"resumeRecording failed with code %d", result); ++ return NO; ++ } ++ return YES; ++} ++ + - (void)setIgnoresPreferredAttributeConfigurationErrors: + (BOOL)ignoresPreferredAttributeConfigurationErrors { + @synchronized(self) { +diff --git a/sdk/objc/native/src/audio/audio_device_ios.h b/sdk/objc/native/src/audio/audio_device_ios.h +index d1788a3..b3d2b32 100644 +--- a/sdk/objc/native/src/audio/audio_device_ios.h ++++ b/sdk/objc/native/src/audio/audio_device_ios.h +@@ -80,6 +80,8 @@ class AudioDeviceIOS : public AudioDeviceGeneric, + bool Playing() const override; + + int32_t StartRecording() override; ++ int32_t PauseRecording(); ++ int32_t ResumeRecording(); + int32_t StopRecording() override; + bool Recording() const override; + +@@ -292,6 +294,9 @@ class AudioDeviceIOS : public AudioDeviceGeneric, + // Set to 1 when playout is active and 0 otherwise. + std::atomic playing_; + ++ // Set to true when recording has been paused explicitly. ++ bool paused_recording_; ++ + // Set to true after successful call to Init(), false otherwise. + bool initialized_ RTC_GUARDED_BY(thread_); + +diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm +index 021f08a..cda1a76 100644 +--- a/sdk/objc/native/src/audio/audio_device_ios.mm ++++ b/sdk/objc/native/src/audio/audio_device_ios.mm +@@ -110,6 +110,7 @@ static void LogDeviceInfo() { + audio_unit_(nullptr), + recording_(0), + playing_(0), ++ paused_recording_(false), + initialized_(false), + audio_is_initialized_(false), + is_interrupted_(false), +@@ -303,6 +304,11 @@ static void LogDeviceInfo() { + RTC_DCHECK_RUN_ON(thread_); + RTC_DCHECK(audio_is_initialized_); + RTC_DCHECK(!recording_.load()); ++ if (paused_recording_) { ++ RTC_LOG(LS_WARNING) << "StartRecording not allowed while paused; " ++ << "call ResumeRecording instead"; ++ return -1; ++ } + RTC_DCHECK(audio_unit_); + if (!audio_is_initialized_) { + return -1; +@@ -327,6 +333,34 @@ static void LogDeviceInfo() { + return 0; + } + ++int32_t AudioDeviceIOS::PauseRecording() { ++ LOGI() << "PauseRecording"; ++ RTC_DCHECK_RUN_ON(thread_); ++ if (paused_recording_) { ++ return 0; ++ } ++ if (!audio_is_initialized_ || !recording_.load()) { ++ return 0; ++ } ++ recording_.store(0, std::memory_order_release); ++ paused_recording_ = true; ++ return 0; ++} ++ ++int32_t AudioDeviceIOS::ResumeRecording() { ++ LOGI() << "ResumeRecording"; ++ RTC_DCHECK_RUN_ON(thread_); ++ if (!paused_recording_) { ++ return 0; ++ } ++ if (InitRecording() != 0) { ++ RTC_LOG(LS_ERROR) << "InitRecording failed during ResumeRecording"; ++ return -1; ++ } ++ paused_recording_ = false; ++ return StartRecording(); ++} ++ + int32_t AudioDeviceIOS::StopRecording() { + LOGI() << "StopRecording"; + RTC_DCHECK_RUN_ON(thread_); +diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.h b/sdk/objc/native/src/audio/audio_device_module_ios.h +index 5ff5062..58338a6 100644 +--- a/sdk/objc/native/src/audio/audio_device_module_ios.h ++++ b/sdk/objc/native/src/audio/audio_device_module_ios.h +@@ -76,6 +76,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { + int32_t StopPlayout() override; + bool Playing() const override; + int32_t StartRecording() override; ++ int32_t PauseRecording(); ++ int32_t ResumeRecording(); + int32_t StopRecording() override; + bool Recording() const override; + +@@ -131,6 +133,9 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { + + std::optional GetStats() const override; + ++ // RTCAudioSession の pauseRecording/resumeRecording にて動作中の ADM を取得するために利用される ++ static AudioDeviceModuleIOS* GetLastInstance(); ++ + #if defined(WEBRTC_IOS) + int GetPlayoutAudioParameters(AudioParameters* params) const override; + int GetRecordAudioParameters(AudioParameters* params) const override; +diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.mm b/sdk/objc/native/src/audio/audio_device_module_ios.mm +index e2ea360..3608f15 100644 +--- a/sdk/objc/native/src/audio/audio_device_module_ios.mm ++++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm +@@ -42,6 +42,10 @@ + namespace webrtc { + namespace ios_adm { + ++namespace { ++AudioDeviceModuleIOS* g_last_audio_device_module_ios = nullptr; ++} // namespace ++ + AudioDeviceModuleIOS::AudioDeviceModuleIOS( + const Environment& env, + bool bypass_voice_processing, +@@ -53,6 +57,7 @@ + error_handler_(error_handler) { + RTC_LOG(LS_INFO) << "current platform is IOS"; + RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized."; ++ g_last_audio_device_module_ios = this; + } + + int32_t AudioDeviceModuleIOS::AttachAudioBuffer() { +@@ -63,6 +68,9 @@ + + AudioDeviceModuleIOS::~AudioDeviceModuleIOS() { + RTC_DLOG(LS_INFO) << __FUNCTION__; ++ if (g_last_audio_device_module_ios == this) { ++ g_last_audio_device_module_ios = nullptr; ++ } + } + + void AudioDeviceModuleIOS::ReportError(ADMError error) const { +@@ -652,6 +660,28 @@ + return result; + } + ++int32_t AudioDeviceModuleIOS::PauseRecording() { ++ RTC_DLOG(LS_INFO) << __FUNCTION__; ++ CHECKinitialized_(); ++ int32_t result = audio_device_->PauseRecording(); ++ if (result < 0) { ++ ReportError(kRecordingFailed); ++ } ++ RTC_DLOG(LS_INFO) << "output: " << result; ++ return result; ++} ++ ++int32_t AudioDeviceModuleIOS::ResumeRecording() { ++ RTC_DLOG(LS_INFO) << __FUNCTION__; ++ CHECKinitialized_(); ++ int32_t result = audio_device_->ResumeRecording(); ++ if (result < 0) { ++ ReportError(kRecordingFailed); ++ } ++ RTC_DLOG(LS_INFO) << "output: " << result; ++ return result; ++} ++ + int32_t AudioDeviceModuleIOS::StopRecording() { + RTC_DLOG(LS_INFO) << __FUNCTION__; + CHECKinitialized_(); +@@ -783,5 +813,11 @@ + return r; + } + #endif // WEBRTC_IOS ++ ++// RTCAudioSession の pauseRecording/resumeRecording にて動作中の ADM を取得するために利用される ++AudioDeviceModuleIOS* AudioDeviceModuleIOS::GetLastInstance() { ++ return g_last_audio_device_module_ios; ++} ++ + } // namespace ios_adm + } // namespace webrtc +diff --git a/sdk/objc/native/src/audio/voice_processing_audio_unit.h b/sdk/objc/native/src/audio/voice_processing_audio_unit.h +index cad6fe5..694cee1 100644 +--- a/sdk/objc/native/src/audio/voice_processing_audio_unit.h ++++ b/sdk/objc/native/src/audio/voice_processing_audio_unit.h +@@ -144,6 +144,8 @@ class VoiceProcessingAudioUnit { + VoiceProcessingAudioUnitObserver* observer_; + AudioUnit vpio_unit_; + VoiceProcessingAudioUnit::State state_; ++ // 二重解放を防ぐためのフラグ ++ bool disposed_; + }; + } // namespace ios_adm + } // namespace webrtc +diff --git a/sdk/objc/native/src/audio/voice_processing_audio_unit.mm b/sdk/objc/native/src/audio/voice_processing_audio_unit.mm +index 1bd8956..ace3936 100644 +--- a/sdk/objc/native/src/audio/voice_processing_audio_unit.mm ++++ b/sdk/objc/native/src/audio/voice_processing_audio_unit.mm +@@ -82,7 +82,8 @@ static OSStatus GetAGCState(AudioUnit audio_unit, UInt32* enabled) { + detect_mute_speech_(detect_mute_speech), + observer_(observer), + vpio_unit_(nullptr), +- state_(kInitRequired) { ++ state_(kInitRequired), ++ disposed_(false) { + RTC_DCHECK(observer); + } + +@@ -404,6 +405,9 @@ static OSStatus GetAGCState(AudioUnit audio_unit, UInt32* enabled) { + } + + bool VoiceProcessingAudioUnit::Stop() { ++ if (!vpio_unit_ || disposed_) { ++ return true; ++ } + RTC_DCHECK_GE(state_, kUninitialized); + RTCLog(@"Stopping audio unit."); + +@@ -423,6 +427,9 @@ static OSStatus GetAGCState(AudioUnit audio_unit, UInt32* enabled) { + } + + bool VoiceProcessingAudioUnit::Uninitialize() { ++ if (!vpio_unit_ || disposed_) { ++ return true; ++ } + RTC_DCHECK_GE(state_, kUninitialized); + RTCLog(@"Unintializing audio unit."); + +@@ -575,6 +582,7 @@ static OSStatus GetAGCState(AudioUnit audio_unit, UInt32* enabled) { + RTCLogError(@"AudioComponentInstanceDispose failed. Error=%ld.", + (long)result); + } ++ disposed_ = true; + vpio_unit_ = nullptr; + } + } diff --git a/run.py b/run.py index 1ed2bc6d..234c1f1a 100644 --- a/run.py +++ b/run.py @@ -260,6 +260,7 @@ def get_depot_tools(source_dir, fetch=False): "revert_siso.patch", "ios_revive_copy_framework_header.patch", "ios_audio_track_sink.patch", + "ios_audio_pause_resume.patch", ], "android": [ "add_deps.patch", From 41600a32e03df0a343d116a85d9d9f9a277dd856 Mon Sep 17 00:00:00 2001 From: t-miya Date: Tue, 9 Dec 2025 16:28:13 +0900 Subject: [PATCH 02/18] =?UTF-8?q?pause=5Frecording=20=E4=B8=AD=E3=81=AE=20?= =?UTF-8?q?stopRecording()=20=E5=87=A6=E7=90=86=E3=82=92=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E3=80=81dispose=20=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 1 - patches/ios_audio_pause_resume.patch | 85 ++++++++-------------------- 2 files changed, 24 insertions(+), 62 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b5b35859..36c6e8b5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -35,7 +35,6 @@ VERSION ファイルを上げただけの場合は変更履歴記録は不要。 - 動作中の Audio Device Module 取得用に GetLastInstance() を追加する - AudioDeviceIOS に pauseRecording()/resumeRecording() を追加する - 録音一時停止中か管理するための paused_recording_ プロパティを追加する - - VoiceProcessingAudioUnit に二重解放エラーを防ぐための disposed フラグを追加する - @t-miya - 2025-12-12 [RELEASE] m143.7499.2.1 - @zztkm diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index d5775aad..dd750698 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -92,7 +92,7 @@ index d1788a3..b3d2b32 100644 bool initialized_ RTC_GUARDED_BY(thread_); diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..cda1a76 100644 +index 021f08a..3777abe 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -110,6 +110,7 @@ static void LogDeviceInfo() { @@ -103,10 +103,11 @@ index 021f08a..cda1a76 100644 initialized_(false), audio_is_initialized_(false), is_interrupted_(false), -@@ -303,6 +304,11 @@ static void LogDeviceInfo() { +@@ -303,6 +304,12 @@ static void LogDeviceInfo() { RTC_DCHECK_RUN_ON(thread_); RTC_DCHECK(audio_is_initialized_); RTC_DCHECK(!recording_.load()); ++ // 録音ポーズからの復帰時は paused_recording_ フラグ更新のため直接呼ばずに resumeRecording() を経由する + if (paused_recording_) { + RTC_LOG(LS_WARNING) << "StartRecording not allowed while paused; " + << "call ResumeRecording instead"; @@ -115,7 +116,24 @@ index 021f08a..cda1a76 100644 RTC_DCHECK(audio_unit_); if (!audio_is_initialized_) { return -1; -@@ -327,6 +333,34 @@ static void LogDeviceInfo() { +@@ -330,9 +337,15 @@ static void LogDeviceInfo() { + int32_t AudioDeviceIOS::StopRecording() { + LOGI() << "StopRecording"; + RTC_DCHECK_RUN_ON(thread_); +- if (!audio_is_initialized_ || !recording_.load()) { ++ if (!audio_is_initialized_) ++ return 0; ++ // 録音ポーズ中でも解放処理を実行するためのチェック ++ // 録音フラグが立っていない、かつ、録音ポーズ中でない -> 解放済みである、としてリターン ++ if (!recording_.load(std::memory_order_acquire) && !paused_recording_) { + return 0; + } ++ // 一応録音ポーズフラグも解除しておく ++ paused_recording_ = false; + if (!playing_.load()) { + ShutdownPlayOrRecord(); + } +@@ -340,6 +353,34 @@ static void LogDeviceInfo() { return 0; } @@ -147,9 +165,9 @@ index 021f08a..cda1a76 100644 + return StartRecording(); +} + - int32_t AudioDeviceIOS::StopRecording() { - LOGI() << "StopRecording"; - RTC_DCHECK_RUN_ON(thread_); + bool AudioDeviceIOS::Recording() const { + return recording_.load(); + } diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.h b/sdk/objc/native/src/audio/audio_device_module_ios.h index 5ff5062..58338a6 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.h @@ -247,58 +265,3 @@ index e2ea360..3608f15 100644 + } // namespace ios_adm } // namespace webrtc -diff --git a/sdk/objc/native/src/audio/voice_processing_audio_unit.h b/sdk/objc/native/src/audio/voice_processing_audio_unit.h -index cad6fe5..694cee1 100644 ---- a/sdk/objc/native/src/audio/voice_processing_audio_unit.h -+++ b/sdk/objc/native/src/audio/voice_processing_audio_unit.h -@@ -144,6 +144,8 @@ class VoiceProcessingAudioUnit { - VoiceProcessingAudioUnitObserver* observer_; - AudioUnit vpio_unit_; - VoiceProcessingAudioUnit::State state_; -+ // 二重解放を防ぐためのフラグ -+ bool disposed_; - }; - } // namespace ios_adm - } // namespace webrtc -diff --git a/sdk/objc/native/src/audio/voice_processing_audio_unit.mm b/sdk/objc/native/src/audio/voice_processing_audio_unit.mm -index 1bd8956..ace3936 100644 ---- a/sdk/objc/native/src/audio/voice_processing_audio_unit.mm -+++ b/sdk/objc/native/src/audio/voice_processing_audio_unit.mm -@@ -82,7 +82,8 @@ static OSStatus GetAGCState(AudioUnit audio_unit, UInt32* enabled) { - detect_mute_speech_(detect_mute_speech), - observer_(observer), - vpio_unit_(nullptr), -- state_(kInitRequired) { -+ state_(kInitRequired), -+ disposed_(false) { - RTC_DCHECK(observer); - } - -@@ -404,6 +405,9 @@ static OSStatus GetAGCState(AudioUnit audio_unit, UInt32* enabled) { - } - - bool VoiceProcessingAudioUnit::Stop() { -+ if (!vpio_unit_ || disposed_) { -+ return true; -+ } - RTC_DCHECK_GE(state_, kUninitialized); - RTCLog(@"Stopping audio unit."); - -@@ -423,6 +427,9 @@ static OSStatus GetAGCState(AudioUnit audio_unit, UInt32* enabled) { - } - - bool VoiceProcessingAudioUnit::Uninitialize() { -+ if (!vpio_unit_ || disposed_) { -+ return true; -+ } - RTC_DCHECK_GE(state_, kUninitialized); - RTCLog(@"Unintializing audio unit."); - -@@ -575,6 +582,7 @@ static OSStatus GetAGCState(AudioUnit audio_unit, UInt32* enabled) { - RTCLogError(@"AudioComponentInstanceDispose failed. Error=%ld.", - (long)result); - } -+ disposed_ = true; - vpio_unit_ = nullptr; - } - } From 4a155cd0a7aecdcc03dc97d4d804aa49dfe378ac Mon Sep 17 00:00:00 2001 From: t-miya Date: Tue, 9 Dec 2025 16:36:29 +0900 Subject: [PATCH 03/18] =?UTF-8?q?recording=5F.load()=20=E5=BC=95=E6=95=B0?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index dd750698..69a011fd 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -92,7 +92,7 @@ index d1788a3..b3d2b32 100644 bool initialized_ RTC_GUARDED_BY(thread_); diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..3777abe 100644 +index 021f08a..c7610e9 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -110,6 +110,7 @@ static void LogDeviceInfo() { @@ -125,7 +125,7 @@ index 021f08a..3777abe 100644 + return 0; + // 録音ポーズ中でも解放処理を実行するためのチェック + // 録音フラグが立っていない、かつ、録音ポーズ中でない -> 解放済みである、としてリターン -+ if (!recording_.load(std::memory_order_acquire) && !paused_recording_) { ++ if (!recording_.load() && !paused_recording_) { return 0; } + // 一応録音ポーズフラグも解除しておく From 6324529beb5d0d669a79210636d4ca47f72e42a6 Mon Sep 17 00:00:00 2001 From: t-miya Date: Tue, 9 Dec 2025 17:27:33 +0900 Subject: [PATCH 04/18] =?UTF-8?q?startRecording()=20=E3=81=8C=E3=83=9D?= =?UTF-8?q?=E3=83=BC=E3=82=BA=E4=B8=AD=E3=81=AB=E5=91=BC=E3=81=B0=E3=82=8C?= =?UTF-8?q?=E3=81=9F=E5=A0=B4=E5=90=88=E3=81=AF=20resumeRecording()=20?= =?UTF-8?q?=E3=81=AB=E3=83=95=E3=82=A9=E3=83=BC=E3=83=AB=E3=82=B9=E3=83=AB?= =?UTF-8?q?=E3=83=BC=E3=81=99=E3=82=8B=E3=80=81resumeRecording()=20?= =?UTF-8?q?=E3=81=A7=20initRecording()=20=E3=81=AF=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E3=81=AA=E5=A0=B4=E5=90=88=E3=81=AE=E3=81=BF=E8=A1=8C=E3=81=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 42 +++++++++++++++------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 69a011fd..485707f9 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -92,7 +92,7 @@ index d1788a3..b3d2b32 100644 bool initialized_ RTC_GUARDED_BY(thread_); diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..c7610e9 100644 +index 021f08a..690fdcd 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -110,6 +110,7 @@ static void LogDeviceInfo() { @@ -103,20 +103,18 @@ index 021f08a..c7610e9 100644 initialized_(false), audio_is_initialized_(false), is_interrupted_(false), -@@ -303,6 +304,12 @@ static void LogDeviceInfo() { +@@ -302,6 +303,10 @@ static void LogDeviceInfo() { + LOGI() << "StartRecording"; RTC_DCHECK_RUN_ON(thread_); RTC_DCHECK(audio_is_initialized_); - RTC_DCHECK(!recording_.load()); -+ // 録音ポーズからの復帰時は paused_recording_ フラグ更新のため直接呼ばずに resumeRecording() を経由する ++ // 録音ポーズ中であれば ResumeRecording() にフォールスルーする + if (paused_recording_) { -+ RTC_LOG(LS_WARNING) << "StartRecording not allowed while paused; " -+ << "call ResumeRecording instead"; -+ return -1; ++ return ResumeRecording(); + } + RTC_DCHECK(!recording_.load()); RTC_DCHECK(audio_unit_); if (!audio_is_initialized_) { - return -1; -@@ -330,9 +337,15 @@ static void LogDeviceInfo() { +@@ -330,9 +335,15 @@ static void LogDeviceInfo() { int32_t AudioDeviceIOS::StopRecording() { LOGI() << "StopRecording"; RTC_DCHECK_RUN_ON(thread_); @@ -133,7 +131,7 @@ index 021f08a..c7610e9 100644 if (!playing_.load()) { ShutdownPlayOrRecord(); } -@@ -340,6 +353,34 @@ static void LogDeviceInfo() { +@@ -340,6 +351,38 @@ static void LogDeviceInfo() { return 0; } @@ -157,9 +155,13 @@ index 021f08a..c7610e9 100644 + if (!paused_recording_) { + return 0; + } -+ if (InitRecording() != 0) { -+ RTC_LOG(LS_ERROR) << "InitRecording failed during ResumeRecording"; -+ return -1; ++ if (!audio_is_initialized_) { ++ if (InitRecording() != 0) { ++ RTC_LOG(LS_ERROR) << "InitRecording failed during ResumeRecording"; ++ paused_recording_ = false; ++ recording_.store(0, std::memory_order_release); ++ return -1; ++ } + } + paused_recording_ = false; + return StartRecording(); @@ -192,21 +194,23 @@ index 5ff5062..58338a6 100644 int GetPlayoutAudioParameters(AudioParameters* params) const override; int GetRecordAudioParameters(AudioParameters* params) const override; diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.mm b/sdk/objc/native/src/audio/audio_device_module_ios.mm -index e2ea360..3608f15 100644 +index e2ea360..3576ed3 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm -@@ -42,6 +42,10 @@ +@@ -42,6 +42,12 @@ namespace webrtc { namespace ios_adm { +namespace { ++// RTCAudioSession の pauseRecording/resumeRecording にて動作中の ADM を取得するために利用される。 ++// 常に 1 インスタンス前提としている。複数生成した場合の動作は未定義。 +AudioDeviceModuleIOS* g_last_audio_device_module_ios = nullptr; +} // namespace + AudioDeviceModuleIOS::AudioDeviceModuleIOS( const Environment& env, bool bypass_voice_processing, -@@ -53,6 +57,7 @@ +@@ -53,6 +59,7 @@ error_handler_(error_handler) { RTC_LOG(LS_INFO) << "current platform is IOS"; RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized."; @@ -214,7 +218,7 @@ index e2ea360..3608f15 100644 } int32_t AudioDeviceModuleIOS::AttachAudioBuffer() { -@@ -63,6 +68,9 @@ +@@ -63,6 +70,9 @@ AudioDeviceModuleIOS::~AudioDeviceModuleIOS() { RTC_DLOG(LS_INFO) << __FUNCTION__; @@ -224,7 +228,7 @@ index e2ea360..3608f15 100644 } void AudioDeviceModuleIOS::ReportError(ADMError error) const { -@@ -652,6 +660,28 @@ +@@ -652,6 +662,28 @@ return result; } @@ -253,7 +257,7 @@ index e2ea360..3608f15 100644 int32_t AudioDeviceModuleIOS::StopRecording() { RTC_DLOG(LS_INFO) << __FUNCTION__; CHECKinitialized_(); -@@ -783,5 +813,11 @@ +@@ -783,5 +815,11 @@ return r; } #endif // WEBRTC_IOS From 559965f153aad45655eaf7fc4fa0abc6ea927cb9 Mon Sep 17 00:00:00 2001 From: t-miya Date: Tue, 9 Dec 2025 17:58:25 +0900 Subject: [PATCH 05/18] =?UTF-8?q?resumeRecording()=20=E5=86=85=E3=81=A7=20?= =?UTF-8?q?startRecording()=20=E3=81=AB=E5=A4=B1=E6=95=97=E3=81=97?= =?UTF-8?q?=E3=81=9F=E5=A0=B4=E5=90=88=20pause=20=E7=8A=B6=E6=85=8B?= =?UTF-8?q?=E3=81=AB=E6=88=BB=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 485707f9..4a7125fb 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -92,7 +92,7 @@ index d1788a3..b3d2b32 100644 bool initialized_ RTC_GUARDED_BY(thread_); diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..690fdcd 100644 +index 021f08a..f68c494 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -110,6 +110,7 @@ static void LogDeviceInfo() { @@ -126,12 +126,12 @@ index 021f08a..690fdcd 100644 + if (!recording_.load() && !paused_recording_) { return 0; } -+ // 一応録音ポーズフラグも解除しておく ++ // 実際の状態に関わらず録音ポーズフラグも解除しておく + paused_recording_ = false; if (!playing_.load()) { ShutdownPlayOrRecord(); } -@@ -340,6 +351,38 @@ static void LogDeviceInfo() { +@@ -340,6 +351,44 @@ static void LogDeviceInfo() { return 0; } @@ -164,7 +164,13 @@ index 021f08a..690fdcd 100644 + } + } + paused_recording_ = false; -+ return StartRecording(); ++ int32_t result = StartRecording(); ++ if (result != 0) { ++ // Start に失敗したら再度 pause 状態に戻す ++ paused_recording_ = true; ++ recording_.store(0, std::memory_order_release); ++ } ++ return result; +} + bool AudioDeviceIOS::Recording() const { From a184f8c9d8ac7f4615a9cb445cba06134b864632 Mon Sep 17 00:00:00 2001 From: t-miya Date: Wed, 10 Dec 2025 19:16:04 +0900 Subject: [PATCH 06/18] =?UTF-8?q?=E5=85=AC=E9=96=8BAPI=E3=82=92=20RTCAudio?= =?UTF-8?q?Session=20=E3=81=8B=E3=82=89=20RTCAudioDeviceModule=20=E3=81=AB?= =?UTF-8?q?=E7=A7=BB=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 4 +- patches/ios_audio_pause_resume.patch | 231 +++++++++++++++------------ 2 files changed, 134 insertions(+), 101 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 36c6e8b5..698b4baf 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -29,10 +29,10 @@ VERSION ファイルを上げただけの場合は変更履歴記録は不要。 ## タイムライン -- 2025-12-12 [ADD] iOS SDK の RTCAudioSession に公開 API として pauseRecording()/resumeRecording() を追加する +- 2025-12-12 [ADD] iOS SDK に RTCAudioDeviceModule を追加する - iOS 実機のマイクインジケータが消灯状態のミュートをできるようにする + - RTCAudioDeviceModule の 公開 API として pauseRecording()/resumeRecording() を追加する - AudioDeviceModuleIOS に pauseRecording()/resumeRecording() を追加する - - 動作中の Audio Device Module 取得用に GetLastInstance() を追加する - AudioDeviceIOS に pauseRecording()/resumeRecording() を追加する - 録音一時停止中か管理するための paused_recording_ プロパティを追加する - @t-miya diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 4a7125fb..6a2c57cd 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -1,73 +1,125 @@ -diff --git a/sdk/objc/components/audio/RTCAudioSession.h b/sdk/objc/components/audio/RTCAudioSession.h -index 47a6007..56f22dd 100644 ---- a/sdk/objc/components/audio/RTCAudioSession.h -+++ b/sdk/objc/components/audio/RTCAudioSession.h -@@ -171,6 +171,16 @@ RTC_OBJC_EXPORT - */ - @property(nonatomic, assign) BOOL isAudioEnabled; +diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn +index 7b8a024..e2f6c7a 100644 +--- a/sdk/BUILD.gn ++++ b/sdk/BUILD.gn +@@ -172,6 +172,7 @@ if (is_ios || is_mac) { + sources += [ + "objc/helpers/UIDevice+RTCDevice.h", + "objc/helpers/UIDevice+RTCDevice.mm", ++ "objc/components/audio/RTCAudioDeviceModule.mm", + ] -+/** Audio 録音を一時停止する。startRecording() により録音開始している状態を前提とする。 -+ * 一時停止成功時または既に停止状態の場合 YES を返す。 -+ */ -+- (BOOL)pauseRecording; + if (target_platform != "tvos") { +@@ -185,7 +186,7 @@ if (is_ios || is_mac) { + } + } + +- rtc_library("core_audio_helpers_objc") { ++rtc_library("core_audio_helpers_objc") { + sources = [ + "objc/helpers/AudioTimeStamp+Nanoseconds.h", + "objc/helpers/AudioTimeStamp+Nanoseconds.mm", +@@ -1366,6 +1367,7 @@ if (is_ios || is_mac) { + "objc/base/RTCVideoRenderer.h", + "objc/base/RTCYUVPlanarBuffer.h", + "objc/components/audio/RTCAudioDevice.h", ++ "objc/components/audio/RTCAudioDeviceModule.h", + "objc/components/audio/RTCAudioSession.h", + "objc/components/audio/RTCAudioSessionConfiguration.h", + "objc/components/capturer/RTCCameraVideoCapturer.h", +diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.h b/sdk/objc/components/audio/RTCAudioDeviceModule.h +new file mode 100644 +index 0000000..1937cd0 +--- /dev/null ++++ b/sdk/objc/components/audio/RTCAudioDeviceModule.h +@@ -0,0 +1,24 @@ ++// 音声の録音ポーズ・復帰用の公開 API を提供するためのモジュールです ++ ++#import ++ ++#import "sdk/objc/base/RTCMacros.h" ++ ++RTC_OBJC_EXPORT ++@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) : NSObject + -+/** pauseRecording() により一時停止している Audio 録音を再開する。 -+ * 再開成功または既に録音中の場合 YES を返す。 -+ */ ++// 現状は単一の ADM のみを扱う想定として、シングルトンインスタンスを取得する +++ (instancetype)sharedInstance; ++ ++// 登録中の AudioDeviceModuleIOS を弱参照で保持し、録音制御を委譲する ++// ++// 引数の型は AudioDeviceModuleIOS* を想定しているが、C++ 側定義の型であり ++// この ObjC 公開ヘッダでの露出はビルドエラーとなるため void* としている ++// 実装側で AudioDeviceModuleIOS* に static_cast する ++- (void)setAudioDeviceModule:(void *)adm; ++- (void)clearAudioDeviceModule:(void *)adm; ++ ++- (BOOL)pauseRecording; +- (BOOL)resumeRecording; + - // Proxy properties. - @property(readonly) NSString *category; - @property(readonly) AVAudioSessionCategoryOptions categoryOptions; -diff --git a/sdk/objc/components/audio/RTCAudioSession.mm b/sdk/objc/components/audio/RTCAudioSession.mm -index 60cf11e..f81381e 100644 ---- a/sdk/objc/components/audio/RTCAudioSession.mm -+++ b/sdk/objc/components/audio/RTCAudioSession.mm -@@ -18,6 +18,7 @@ - #include "absl/base/attributes.h" - #include "rtc_base/checks.h" - #include "rtc_base/synchronization/mutex.h" ++@end +diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.mm b/sdk/objc/components/audio/RTCAudioDeviceModule.mm +new file mode 100644 +index 0000000..b6b9f29 +--- /dev/null ++++ b/sdk/objc/components/audio/RTCAudioDeviceModule.mm +@@ -0,0 +1,57 @@ ++// 音声の録音ポーズ・復帰用の公開 API を提供するためのモジュールです ++ ++#import "RTCAudioDeviceModule.h" ++ +#include "sdk/objc/native/src/audio/audio_device_module_ios.h" - - #import "RTCAudioSessionConfiguration.h" - #import "base/RTCLogging.h" -@@ -214,6 +215,36 @@ - (BOOL)isAudioEnabled { - } - } - -+- (BOOL)pauseRecording { ++ ++@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) () { ++ webrtc::ios_adm::AudioDeviceModuleIOS* _adm; ++} ++@end ++ ++@implementation RTC_OBJC_TYPE(RTCAudioDeviceModule) ++ +++ (instancetype)sharedInstance { ++ static RTC_OBJC_TYPE(RTCAudioDeviceModule) *instance = nil; ++ static dispatch_once_t onceToken; ++ dispatch_once(&onceToken, ^{ ++ instance = [[self alloc] init]; ++ }); ++ return instance; ++} ++ ++- (void)setAudioDeviceModule:(void *)adm_void { + webrtc::ios_adm::AudioDeviceModuleIOS* adm = -+ webrtc::ios_adm::AudioDeviceModuleIOS::GetLastInstance(); -+ if (!adm) { -+ RTCLogError(@"pauseRecording failed: AudioDeviceModuleIOS not available"); -+ return NO; ++ static_cast(adm_void); ++ if (adm) { ++ _adm = adm; ++ } else { ++ _adm = nullptr; + } -+ int32_t result = adm->PauseRecording(); -+ if (result != 0) { -+ RTCLogError(@"pauseRecording failed with code %d", result); -+ return NO; -+ } -+ return YES; +} + -+- (BOOL)resumeRecording { ++- (void)clearAudioDeviceModule:(void *)adm_void { + webrtc::ios_adm::AudioDeviceModuleIOS* adm = -+ webrtc::ios_adm::AudioDeviceModuleIOS::GetLastInstance(); -+ if (!adm) { -+ RTCLogError(@"resumeRecording failed: AudioDeviceModuleIOS not available"); ++ static_cast(adm_void); ++ if (_adm == adm) { ++ _adm = nullptr; ++ } ++} ++ ++- (BOOL)pauseRecording { ++ webrtc::ios_adm::AudioDeviceModuleIOS* ptr = _adm; ++ if (!ptr) { + return NO; + } -+ int32_t result = adm->ResumeRecording(); -+ if (result != 0) { -+ RTCLogError(@"resumeRecording failed with code %d", result); ++ return ptr->PauseRecording() == 0; ++} ++ ++- (BOOL)resumeRecording { ++ webrtc::ios_adm::AudioDeviceModuleIOS* ptr = _adm; ++ if (!ptr) { + return NO; + } -+ return YES; ++ return ptr->ResumeRecording() == 0; +} + - - (void)setIgnoresPreferredAttributeConfigurationErrors: - (BOOL)ignoresPreferredAttributeConfigurationErrors { - @synchronized(self) { ++@end diff --git a/sdk/objc/native/src/audio/audio_device_ios.h b/sdk/objc/native/src/audio/audio_device_ios.h index d1788a3..b3d2b32 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.h @@ -92,7 +144,7 @@ index d1788a3..b3d2b32 100644 bool initialized_ RTC_GUARDED_BY(thread_); diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..f68c494 100644 +index 021f08a..df215c1 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -110,6 +110,7 @@ static void LogDeviceInfo() { @@ -131,7 +183,7 @@ index 021f08a..f68c494 100644 if (!playing_.load()) { ShutdownPlayOrRecord(); } -@@ -340,6 +351,44 @@ static void LogDeviceInfo() { +@@ -340,6 +351,46 @@ static void LogDeviceInfo() { return 0; } @@ -155,6 +207,8 @@ index 021f08a..f68c494 100644 + if (!paused_recording_) { + return 0; + } ++ // 通常の pauseRecording() から来る場合は不要であるはずだが ++ // 初期化状態をチェックして必要であれば InitRecording() を実行 + if (!audio_is_initialized_) { + if (InitRecording() != 0) { + RTC_LOG(LS_ERROR) << "InitRecording failed during ResumeRecording"; @@ -177,7 +231,7 @@ index 021f08a..f68c494 100644 return recording_.load(); } diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.h b/sdk/objc/native/src/audio/audio_device_module_ios.h -index 5ff5062..58338a6 100644 +index 5ff5062..987deb8 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.h +++ b/sdk/objc/native/src/audio/audio_device_module_ios.h @@ -76,6 +76,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { @@ -189,52 +243,41 @@ index 5ff5062..58338a6 100644 int32_t StopRecording() override; bool Recording() const override; -@@ -131,6 +133,9 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { - - std::optional GetStats() const override; - -+ // RTCAudioSession の pauseRecording/resumeRecording にて動作中の ADM を取得するために利用される -+ static AudioDeviceModuleIOS* GetLastInstance(); -+ - #if defined(WEBRTC_IOS) - int GetPlayoutAudioParameters(AudioParameters* params) const override; - int GetRecordAudioParameters(AudioParameters* params) const override; diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.mm b/sdk/objc/native/src/audio/audio_device_module_ios.mm -index e2ea360..3576ed3 100644 +index e2ea360..137277a 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm -@@ -42,6 +42,12 @@ - namespace webrtc { - namespace ios_adm { +@@ -18,6 +18,7 @@ + #include "rtc_base/logging.h" + #include "rtc_base/ref_count.h" + #include "system_wrappers/include/metrics.h" ++#include "sdk/objc/components/audio/RTCAudioDeviceModule.h" -+namespace { -+// RTCAudioSession の pauseRecording/resumeRecording にて動作中の ADM を取得するために利用される。 -+// 常に 1 インスタンス前提としている。複数生成した場合の動作は未定義。 -+AudioDeviceModuleIOS* g_last_audio_device_module_ios = nullptr; -+} // namespace -+ - AudioDeviceModuleIOS::AudioDeviceModuleIOS( - const Environment& env, - bool bypass_voice_processing, -@@ -53,6 +59,7 @@ + #if defined(WEBRTC_IOS) + #include "audio_device_ios.h" +@@ -53,6 +54,10 @@ error_handler_(error_handler) { RTC_LOG(LS_INFO) << "current platform is IOS"; RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized."; -+ g_last_audio_device_module_ios = this; ++ // RTCAudioDeviceModule のシングルトンインスタンスにポインタ参照をセット ++ RTC_OBJC_TYPE(RTCAudioDeviceModule)* adm_module = ++ [RTC_OBJC_TYPE(RTCAudioDeviceModule) sharedInstance]; ++ [adm_module setAudioDeviceModule:this]; } int32_t AudioDeviceModuleIOS::AttachAudioBuffer() { -@@ -63,6 +70,9 @@ +@@ -63,6 +68,10 @@ AudioDeviceModuleIOS::~AudioDeviceModuleIOS() { RTC_DLOG(LS_INFO) << __FUNCTION__; -+ if (g_last_audio_device_module_ios == this) { -+ g_last_audio_device_module_ios = nullptr; -+ } ++ // RTCAudioDeviceModule のシングルトンインスタンスで保持しているポインタ参照を破棄する ++ RTC_OBJC_TYPE(RTCAudioDeviceModule)* adm_module = ++ [RTC_OBJC_TYPE(RTCAudioDeviceModule) sharedInstance]; ++ [adm_module clearAudioDeviceModule:this]; } void AudioDeviceModuleIOS::ReportError(ADMError error) const { -@@ -652,6 +662,28 @@ +@@ -652,6 +661,30 @@ return result; } @@ -242,6 +285,7 @@ index e2ea360..3576ed3 100644 + RTC_DLOG(LS_INFO) << __FUNCTION__; + CHECKinitialized_(); + int32_t result = audio_device_->PauseRecording(); ++ audio_device_buffer_.get()->StopRecording(); + if (result < 0) { + ReportError(kRecordingFailed); + } @@ -252,6 +296,7 @@ index e2ea360..3576ed3 100644 +int32_t AudioDeviceModuleIOS::ResumeRecording() { + RTC_DLOG(LS_INFO) << __FUNCTION__; + CHECKinitialized_(); ++ audio_device_buffer_.get()->StartRecording(); + int32_t result = audio_device_->ResumeRecording(); + if (result < 0) { + ReportError(kRecordingFailed); @@ -263,15 +308,3 @@ index e2ea360..3576ed3 100644 int32_t AudioDeviceModuleIOS::StopRecording() { RTC_DLOG(LS_INFO) << __FUNCTION__; CHECKinitialized_(); -@@ -783,5 +815,11 @@ - return r; - } - #endif // WEBRTC_IOS -+ -+// RTCAudioSession の pauseRecording/resumeRecording にて動作中の ADM を取得するために利用される -+AudioDeviceModuleIOS* AudioDeviceModuleIOS::GetLastInstance() { -+ return g_last_audio_device_module_ios; -+} -+ - } // namespace ios_adm - } // namespace webrtc From 5ed4205bb7c4a56add75c2647699758d6434e681 Mon Sep 17 00:00:00 2001 From: t-miya Date: Thu, 11 Dec 2025 19:01:46 +0900 Subject: [PATCH 07/18] =?UTF-8?q?RTCAudioModuleDevice=20=E3=82=92=20RTCPee?= =?UTF-8?q?rConnectionFactory=20=E3=81=A7=E7=AE=A1=E7=90=86=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 311 +++++++++++++++++++++------ 1 file changed, 244 insertions(+), 67 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 6a2c57cd..57d23a40 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -27,12 +27,178 @@ index 7b8a024..e2f6c7a 100644 "objc/components/audio/RTCAudioSession.h", "objc/components/audio/RTCAudioSessionConfiguration.h", "objc/components/capturer/RTCCameraVideoCapturer.h", +diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h +index 8287bcf..82a7866 100644 +--- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h ++++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h +@@ -11,6 +11,7 @@ + #import + + #import "sdk/objc/base/RTCMacros.h" ++#import "sdk/objc/components/audio/RTCAudioDeviceModule.h" + + NS_ASSUME_NONNULL_BEGIN + +@@ -34,6 +35,7 @@ NS_ASSUME_NONNULL_BEGIN + (RTCSSLCertificateVerifier); + @protocol RTC_OBJC_TYPE + (RTCAudioDevice); ++@class RTC_OBJC_TYPE(RTCAudioDeviceModule); + + typedef NS_ENUM(NSInteger, RTCProxyType); + +@@ -52,7 +54,7 @@ RTC_OBJC_EXPORT + decoderFactory; + + /* Initialize object with injectable video encoder/decoder factories and +- * injectable ADM */ ++ * injectable ADM (RTCAudioDevice) */ + - (instancetype) + initWithEncoderFactory: + (nullable id)encoderFactory +@@ -61,6 +63,27 @@ RTC_OBJC_EXPORT + audioDevice: + (nullable id)audioDevice; + ++/* Initialize object with injectable video encoder/decoder factories and ++ * RTCAudioDeviceModule (pause/resume 用) */ ++- (instancetype) ++ initWithEncoderFactory: ++ (nullable id)encoderFactory ++ decoderFactory:(nullable id) ++ decoderFactory ++ audioDeviceModule: ++ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule; ++ ++/* Initialize object with injectable video encoder/decoder factories and ++ * both RTCAudioDevice (objC) and RTCAudioDeviceModule (pause/resume 用) */ ++- (instancetype) ++ initWithEncoderFactory: ++ (nullable id)encoderFactory ++ decoderFactory:(nullable id) ++ decoderFactory ++ audioDevice:(nullable id)audioDevice ++ audioDeviceModule: ++ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule; ++ + /** + * Valid kind values are kRTCMediaStreamTrackKindAudio and + * kRTCMediaStreamTrackKindVideo. +diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +index 233cf25..dce583f 100644 +--- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm ++++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +@@ -121,6 +121,11 @@ @implementation RTC_OBJC_TYPE (RTCPeerConnectionFactory) { + std::unique_ptr _workerThread; + std::unique_ptr _signalingThread; + BOOL _hasStartedAecDump; ++ // RTCAudioDeviceModule は内部でネイティブ ADM を生成・保持する(scoped_refptr による所有) ++ // RTCPeerConnectionFactory は初期化時に RTCAudioDeviceModule から生ポインタを受け取り、使用中は弱参照のみ保持する ++ // RTCPeerConnectionFactory は破棄時に clearAudioDeviceModule を呼んで弱参照を解放する ++ // RTCAudioDeviceModule が破棄されると内部 ADM も破棄されるため、factory 側は常に弱参照の生存をチェックしてから操作する ++ __weak RTC_OBJC_TYPE(RTCAudioDeviceModule)* _objcAudioDeviceModule; + } + + @synthesize nativeFactory = _nativeFactory; +@@ -137,9 +142,6 @@ - (instancetype)init { + dependencies.video_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory( + [[RTC_OBJC_TYPE(RTCVideoDecoderFactoryH264) alloc] init]); + dependencies.env = webrtc::CreateEnvironment(); +-#ifdef WEBRTC_IOS +- dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); +-#endif + return [self initWithMediaAndDependencies:dependencies]; + } + +@@ -150,7 +152,8 @@ - (instancetype)init { + decoderFactory { + return [self initWithEncoderFactory:encoderFactory + decoderFactory:decoderFactory +- audioDevice:nil]; ++ audioDevice:nil ++ audioDeviceModule:nil]; + } + + - (instancetype) +@@ -158,8 +161,42 @@ - (instancetype)init { + (nullable id)encoderFactory + decoderFactory:(nullable id) + decoderFactory +- audioDevice: +- (nullable id)audioDevice { ++ audioDevice:(nullable id)audioDevice { ++#ifdef HAVE_NO_MEDIA ++ return [self initWithNoMedia]; ++#else ++ return [self initWithEncoderFactory:encoderFactory ++ decoderFactory:decoderFactory ++ audioDevice:audioDevice ++ audioDeviceModule:nil]; ++#endif ++} ++ ++- (instancetype) ++ initWithEncoderFactory: ++ (nullable id)encoderFactory ++ decoderFactory:(nullable id) ++ decoderFactory ++ audioDeviceModule: ++ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule { ++#ifdef HAVE_NO_MEDIA ++ return [self initWithNoMedia]; ++#else ++ return [self initWithEncoderFactory:encoderFactory ++ decoderFactory:decoderFactory ++ audioDevice:nil ++ audioDeviceModule:audioDeviceModule]; ++#endif ++} ++ ++- (instancetype) ++ initWithEncoderFactory: ++ (nullable id)encoderFactory ++ decoderFactory:(nullable id) ++ decoderFactory ++ audioDevice:(nullable id)audioDevice ++ audioDeviceModule: ++ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule { + #ifdef HAVE_NO_MEDIA + return [self initWithNoMedia]; + #else +@@ -177,14 +214,25 @@ - (instancetype)init { + dependencies.video_decoder_factory = + webrtc::ObjCToNativeVideoDecoderFactory(decoderFactory); + } ++#ifdef WEBRTC_IOS ++ // audioDevice と audioDeviceModule が両方指定されている場合、 ++ // 元々の互換性を優先して audioDevice が指定されているものとする + if (audioDevice) { + dependencies.adm = + webrtc::CreateAudioDeviceModule(*dependencies.env, audioDevice); +-#ifdef WEBRTC_IOS ++ } else if (audioDeviceModule) { ++ void* native_adm = [audioDeviceModule getNativeAudioDeviceModule]; ++ auto adm_ptr = static_cast(native_adm); ++ if (adm_ptr) { ++ dependencies.adm = adm_ptr; ++ _objcAudioDeviceModule = audioDeviceModule; ++ } else { ++ dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); ++ } + } else { + dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); +-#endif + } ++#endif + return [self initWithMediaAndDependencies:dependencies]; + #endif + } diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.h b/sdk/objc/components/audio/RTCAudioDeviceModule.h new file mode 100644 -index 0000000..1937cd0 +index 0000000..fb2cc4e --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.h -@@ -0,0 +1,24 @@ +@@ -0,0 +1,22 @@ +// 音声の録音ポーズ・復帰用の公開 API を提供するためのモジュールです + +#import @@ -42,15 +208,13 @@ index 0000000..1937cd0 +RTC_OBJC_EXPORT +@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) : NSObject + -+// 現状は単一の ADM のみを扱う想定として、シングルトンインスタンスを取得する -++ (instancetype)sharedInstance; ++// 内部で AudioDeviceModuleIOS を生成し、弱参照で保持します ++// 所有権はネイティブ側となります ++- (instancetype)init; + -+// 登録中の AudioDeviceModuleIOS を弱参照で保持し、録音制御を委譲する -+// -+// 引数の型は AudioDeviceModuleIOS* を想定しているが、C++ 側定義の型であり -+// この ObjC 公開ヘッダでの露出はビルドエラーとなるため void* としている -+// 実装側で AudioDeviceModuleIOS* に static_cast する -+- (void)setAudioDeviceModule:(void *)adm; ++// ネイティブ ADM を取得します(所有権移動なし、未初期化なら nullptr) ++- (void *)getNativeAudioDeviceModule; ++// 保持中の ADM 参照をクリアします(弱参照を破棄するだけで所有権は移動しません) +- (void)clearAudioDeviceModule:(void *)adm; + +- (BOOL)pauseRecording; @@ -59,52 +223,59 @@ index 0000000..1937cd0 +@end diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.mm b/sdk/objc/components/audio/RTCAudioDeviceModule.mm new file mode 100644 -index 0000000..b6b9f29 +index 0000000..8cc38c5 --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.mm -@@ -0,0 +1,57 @@ -+// 音声の録音ポーズ・復帰用の公開 API を提供するためのモジュールです -+ +@@ -0,0 +1,64 @@ +#import "RTCAudioDeviceModule.h" + ++#include ++ ++#include "api/environment/environment_factory.h" ++#include "api/scoped_refptr.h" ++#include "sdk/objc/native/api/audio_device_module.h" +#include "sdk/objc/native/src/audio/audio_device_module_ios.h" ++#include "rtc_base/weak_ptr.h" + +@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) () { -+ webrtc::ios_adm::AudioDeviceModuleIOS* _adm; ++ // 所有権とライフサイクル管理対象のネイティブADM ++ webrtc::scoped_refptr _adm_owner; ++ // 実装クラス AudioDeviceModuleIOS の弱参照 ++ webrtc::WeakPtr _adm; +} +@end + +@implementation RTC_OBJC_TYPE(RTCAudioDeviceModule) + -++ (instancetype)sharedInstance { -+ static RTC_OBJC_TYPE(RTCAudioDeviceModule) *instance = nil; -+ static dispatch_once_t onceToken; -+ dispatch_once(&onceToken, ^{ -+ instance = [[self alloc] init]; -+ }); -+ return instance; ++- (instancetype)init { ++ self = [super init]; ++ if (self) { ++ auto env = webrtc::CreateEnvironment(); ++ _adm_owner = webrtc::CreateAudioDeviceModule(env); ++ if (_adm_owner) { ++ auto ios_adm = ++ static_cast(_adm_owner.get()); ++ _adm = ios_adm->GetWeakPtr(); ++ } ++ } ++ return self; +} + -+- (void)setAudioDeviceModule:(void *)adm_void { -+ webrtc::ios_adm::AudioDeviceModuleIOS* adm = -+ static_cast(adm_void); -+ if (adm) { -+ _adm = adm; -+ } else { -+ _adm = nullptr; -+ } ++- (void *)getNativeAudioDeviceModule { ++ return _adm_owner.get(); +} + -+- (void)clearAudioDeviceModule:(void *)adm_void { -+ webrtc::ios_adm::AudioDeviceModuleIOS* adm = -+ static_cast(adm_void); -+ if (_adm == adm) { -+ _adm = nullptr; ++- (void)clearAudioDeviceModule:(void *)adm { ++ webrtc::AudioDeviceModule* adm_ptr = ++ static_cast(adm); ++ if (_adm_owner.get() == adm_ptr) { ++ _adm.reset(); ++ _adm_owner = nullptr; + } +} + +- (BOOL)pauseRecording { -+ webrtc::ios_adm::AudioDeviceModuleIOS* ptr = _adm; ++ auto ptr = _adm.get(); + if (!ptr) { + return NO; + } @@ -112,7 +283,7 @@ index 0000000..b6b9f29 +} + +- (BOOL)resumeRecording { -+ webrtc::ios_adm::AudioDeviceModuleIOS* ptr = _adm; ++ auto ptr = _adm.get(); + if (!ptr) { + return NO; + } @@ -231,10 +402,18 @@ index 021f08a..df215c1 100644 return recording_.load(); } diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.h b/sdk/objc/native/src/audio/audio_device_module_ios.h -index 5ff5062..987deb8 100644 +index 5ff5062..d31e979 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.h +++ b/sdk/objc/native/src/audio/audio_device_module_ios.h -@@ -76,6 +76,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { +@@ -17,6 +17,7 @@ + #include "audio_device_ios.h" + #include "modules/audio_device/audio_device_buffer.h" + #include "rtc_base/checks.h" ++#include "rtc_base/weak_ptr.h" + #include "sdk/objc/native/api/audio_device_module_error_handler.h" + + namespace webrtc { +@@ -76,6 +77,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { int32_t StopPlayout() override; bool Playing() const override; int32_t StartRecording() override; @@ -243,41 +422,39 @@ index 5ff5062..987deb8 100644 int32_t StopRecording() override; bool Recording() const override; +@@ -135,6 +138,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { + int GetPlayoutAudioParameters(AudioParameters* params) const override; + int GetRecordAudioParameters(AudioParameters* params) const override; + #endif // WEBRTC_IOS ++ ++ webrtc::WeakPtr GetWeakPtr(); + private: + void ReportError(ADMError error) const; + +@@ -145,6 +150,7 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { + bool initialized_ = false; + std::unique_ptr audio_device_; + std::unique_ptr audio_device_buffer_; ++ webrtc::WeakPtrFactory weak_factory_{this}; + }; + } // namespace ios_adm + } // namespace webrtc diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.mm b/sdk/objc/native/src/audio/audio_device_module_ios.mm -index e2ea360..137277a 100644 +index e2ea360..72eaaa9 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm -@@ -18,6 +18,7 @@ - #include "rtc_base/logging.h" - #include "rtc_base/ref_count.h" - #include "system_wrappers/include/metrics.h" -+#include "sdk/objc/components/audio/RTCAudioDeviceModule.h" - - #if defined(WEBRTC_IOS) - #include "audio_device_ios.h" -@@ -53,6 +54,10 @@ - error_handler_(error_handler) { - RTC_LOG(LS_INFO) << "current platform is IOS"; - RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized."; -+ // RTCAudioDeviceModule のシングルトンインスタンスにポインタ参照をセット -+ RTC_OBJC_TYPE(RTCAudioDeviceModule)* adm_module = -+ [RTC_OBJC_TYPE(RTCAudioDeviceModule) sharedInstance]; -+ [adm_module setAudioDeviceModule:this]; - } - - int32_t AudioDeviceModuleIOS::AttachAudioBuffer() { -@@ -63,6 +68,10 @@ - - AudioDeviceModuleIOS::~AudioDeviceModuleIOS() { +@@ -65,6 +65,10 @@ RTC_DLOG(LS_INFO) << __FUNCTION__; -+ // RTCAudioDeviceModule のシングルトンインスタンスで保持しているポインタ参照を破棄する -+ RTC_OBJC_TYPE(RTCAudioDeviceModule)* adm_module = -+ [RTC_OBJC_TYPE(RTCAudioDeviceModule) sharedInstance]; -+ [adm_module clearAudioDeviceModule:this]; } ++webrtc::WeakPtr AudioDeviceModuleIOS::GetWeakPtr() { ++ return weak_factory_.GetWeakPtr(); ++} ++ void AudioDeviceModuleIOS::ReportError(ADMError error) const { -@@ -652,6 +661,30 @@ + if (error_handler_) { + error_handler_(error); +@@ -652,6 +656,30 @@ return result; } From 93596048b0fc137c07342767bb19e85d000f6565 Mon Sep 17 00:00:00 2001 From: t-miya Date: Thu, 11 Dec 2025 20:20:35 +0900 Subject: [PATCH 08/18] =?UTF-8?q?RTCAudioDeviceModule=20=E3=81=AE=20weak?= =?UTF-8?q?=5Fptr=20=E3=82=92=E5=A4=96=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 153 ++++++++++++++------------- 1 file changed, 78 insertions(+), 75 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 57d23a40..fefe589d 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -85,22 +85,21 @@ index 8287bcf..82a7866 100644 * Valid kind values are kRTCMediaStreamTrackKindAudio and * kRTCMediaStreamTrackKindVideo. diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -index 233cf25..dce583f 100644 +index 233cf25..1e2c0fa 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -@@ -121,6 +121,11 @@ @implementation RTC_OBJC_TYPE (RTCPeerConnectionFactory) { +@@ -121,6 +121,10 @@ @implementation RTC_OBJC_TYPE (RTCPeerConnectionFactory) { std::unique_ptr _workerThread; std::unique_ptr _signalingThread; BOOL _hasStartedAecDump; + // RTCAudioDeviceModule は内部でネイティブ ADM を生成・保持する(scoped_refptr による所有) -+ // RTCPeerConnectionFactory は初期化時に RTCAudioDeviceModule から生ポインタを受け取り、使用中は弱参照のみ保持する -+ // RTCPeerConnectionFactory は破棄時に clearAudioDeviceModule を呼んで弱参照を解放する -+ // RTCAudioDeviceModule が破棄されると内部 ADM も破棄されるため、factory 側は常に弱参照の生存をチェックしてから操作する ++ // RTCPeerConnectionFactory は初期化時に RTCAudioDeviceModule から生ポインタを受け取る ++ // RTCAudioDeviceModule が破棄されると内部 ADM も破棄される + __weak RTC_OBJC_TYPE(RTCAudioDeviceModule)* _objcAudioDeviceModule; } @synthesize nativeFactory = _nativeFactory; -@@ -137,9 +142,6 @@ - (instancetype)init { +@@ -137,9 +141,6 @@ - (instancetype)init { dependencies.video_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory( [[RTC_OBJC_TYPE(RTCVideoDecoderFactoryH264) alloc] init]); dependencies.env = webrtc::CreateEnvironment(); @@ -110,7 +109,7 @@ index 233cf25..dce583f 100644 return [self initWithMediaAndDependencies:dependencies]; } -@@ -150,7 +152,8 @@ - (instancetype)init { +@@ -150,7 +151,8 @@ - (instancetype)init { decoderFactory { return [self initWithEncoderFactory:encoderFactory decoderFactory:decoderFactory @@ -120,7 +119,7 @@ index 233cf25..dce583f 100644 } - (instancetype) -@@ -158,8 +161,42 @@ - (instancetype)init { +@@ -158,8 +160,42 @@ - (instancetype)init { (nullable id)encoderFactory decoderFactory:(nullable id) decoderFactory @@ -165,7 +164,7 @@ index 233cf25..dce583f 100644 #ifdef HAVE_NO_MEDIA return [self initWithNoMedia]; #else -@@ -177,14 +214,25 @@ - (instancetype)init { +@@ -177,14 +213,25 @@ - (instancetype)init { dependencies.video_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory(decoderFactory); } @@ -195,12 +194,11 @@ index 233cf25..dce583f 100644 } diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.h b/sdk/objc/components/audio/RTCAudioDeviceModule.h new file mode 100644 -index 0000000..fb2cc4e +index 0000000..0823504 --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.h -@@ -0,0 +1,22 @@ -+// 音声の録音ポーズ・復帰用の公開 API を提供するためのモジュールです -+ +@@ -0,0 +1,21 @@ ++// iOS 用の AudioDeviceModule を生成し、pauseRecording()/resumeRecording() を公開するためのラッパー +#import + +#import "sdk/objc/base/RTCMacros.h" @@ -208,25 +206,25 @@ index 0000000..fb2cc4e +RTC_OBJC_EXPORT +@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) : NSObject + -+// 内部で AudioDeviceModuleIOS を生成し、弱参照で保持します -+// 所有権はネイティブ側となります ++// 内部で AudioDeviceModuleIOS を生成する +- (instancetype)init; + -+// ネイティブ ADM を取得します(所有権移動なし、未初期化なら nullptr) ++// ネイティブ ADM を取得する(所有権移動なし、未初期化なら nullptr) +- (void *)getNativeAudioDeviceModule; -+// 保持中の ADM 参照をクリアします(弱参照を破棄するだけで所有権は移動しません) -+- (void)clearAudioDeviceModule:(void *)adm; + ++// 録音を一時停止/再開する。成功時または状態が変わらない場合に YES を返す ++// ++// 一時停止状態で AudioDeviceIOS::StartRecording() が呼ばれた場合は ResumeRecording() にフォールバックされる +- (BOOL)pauseRecording; +- (BOOL)resumeRecording; + +@end diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.mm b/sdk/objc/components/audio/RTCAudioDeviceModule.mm new file mode 100644 -index 0000000..8cc38c5 +index 0000000..b20c4a6 --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.mm -@@ -0,0 +1,64 @@ +@@ -0,0 +1,49 @@ +#import "RTCAudioDeviceModule.h" + +#include @@ -235,13 +233,10 @@ index 0000000..8cc38c5 +#include "api/scoped_refptr.h" +#include "sdk/objc/native/api/audio_device_module.h" +#include "sdk/objc/native/src/audio/audio_device_module_ios.h" -+#include "rtc_base/weak_ptr.h" + +@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) () { + // 所有権とライフサイクル管理対象のネイティブADM + webrtc::scoped_refptr _adm_owner; -+ // 実装クラス AudioDeviceModuleIOS の弱参照 -+ webrtc::WeakPtr _adm; +} +@end + @@ -252,11 +247,6 @@ index 0000000..8cc38c5 + if (self) { + auto env = webrtc::CreateEnvironment(); + _adm_owner = webrtc::CreateAudioDeviceModule(env); -+ if (_adm_owner) { -+ auto ios_adm = -+ static_cast(_adm_owner.get()); -+ _adm = ios_adm->GetWeakPtr(); -+ } + } + return self; +} @@ -265,17 +255,9 @@ index 0000000..8cc38c5 + return _adm_owner.get(); +} + -+- (void)clearAudioDeviceModule:(void *)adm { -+ webrtc::AudioDeviceModule* adm_ptr = -+ static_cast(adm); -+ if (_adm_owner.get() == adm_ptr) { -+ _adm.reset(); -+ _adm_owner = nullptr; -+ } -+} -+ +- (BOOL)pauseRecording { -+ auto ptr = _adm.get(); ++ auto ptr = ++ static_cast(_adm_owner.get()); + if (!ptr) { + return NO; + } @@ -283,7 +265,8 @@ index 0000000..8cc38c5 +} + +- (BOOL)resumeRecording { -+ auto ptr = _adm.get(); ++ auto ptr = ++ static_cast(_adm_owner.get()); + if (!ptr) { + return NO; + } @@ -315,7 +298,7 @@ index d1788a3..b3d2b32 100644 bool initialized_ RTC_GUARDED_BY(thread_); diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..df215c1 100644 +index 021f08a..b60ca3c 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -110,6 +110,7 @@ static void LogDeviceInfo() { @@ -354,7 +337,7 @@ index 021f08a..df215c1 100644 if (!playing_.load()) { ShutdownPlayOrRecord(); } -@@ -340,6 +351,46 @@ static void LogDeviceInfo() { +@@ -340,6 +351,52 @@ static void LogDeviceInfo() { return 0; } @@ -362,9 +345,15 @@ index 021f08a..df215c1 100644 + LOGI() << "PauseRecording"; + RTC_DCHECK_RUN_ON(thread_); + if (paused_recording_) { ++ RTC_LOG(LS_VERBOSE) << "PauseRecording called while already paused"; ++ return 0; ++ } ++ if (!audio_is_initialized_) { ++ RTC_LOG(LS_WARNING) << "PauseRecording called before audio is initialized"; + return 0; + } -+ if (!audio_is_initialized_ || !recording_.load()) { ++ if (!recording_.load()) { ++ RTC_LOG(LS_WARNING) << "PauseRecording called while not recording"; + return 0; + } + recording_.store(0, std::memory_order_release); @@ -378,8 +367,8 @@ index 021f08a..df215c1 100644 + if (!paused_recording_) { + return 0; + } -+ // 通常の pauseRecording() から来る場合は不要であるはずだが -+ // 初期化状態をチェックして必要であれば InitRecording() を実行 ++ // InitRecording に失敗した場合は pause 状態の解除も recording_ の再立て直しも行えないため ++ // 上位にエラーを返す + if (!audio_is_initialized_) { + if (InitRecording() != 0) { + RTC_LOG(LS_ERROR) << "InitRecording failed during ResumeRecording"; @@ -402,18 +391,10 @@ index 021f08a..df215c1 100644 return recording_.load(); } diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.h b/sdk/objc/native/src/audio/audio_device_module_ios.h -index 5ff5062..d31e979 100644 +index 5ff5062..40626ae 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.h +++ b/sdk/objc/native/src/audio/audio_device_module_ios.h -@@ -17,6 +17,7 @@ - #include "audio_device_ios.h" - #include "modules/audio_device/audio_device_buffer.h" - #include "rtc_base/checks.h" -+#include "rtc_base/weak_ptr.h" - #include "sdk/objc/native/api/audio_device_module_error_handler.h" - - namespace webrtc { -@@ -76,6 +77,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { +@@ -76,6 +76,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { int32_t StopPlayout() override; bool Playing() const override; int32_t StartRecording() override; @@ -422,39 +403,49 @@ index 5ff5062..d31e979 100644 int32_t StopRecording() override; bool Recording() const override; -@@ -135,6 +138,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { +@@ -135,6 +137,7 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { int GetPlayoutAudioParameters(AudioParameters* params) const override; int GetRecordAudioParameters(AudioParameters* params) const override; #endif // WEBRTC_IOS + -+ webrtc::WeakPtr GetWeakPtr(); private: void ReportError(ADMError error) const; -@@ -145,6 +150,7 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { - bool initialized_ = false; - std::unique_ptr audio_device_; - std::unique_ptr audio_device_buffer_; -+ webrtc::WeakPtrFactory weak_factory_{this}; - }; - } // namespace ios_adm - } // namespace webrtc diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.mm b/sdk/objc/native/src/audio/audio_device_module_ios.mm -index e2ea360..72eaaa9 100644 +index e2ea360..cb75318 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm -@@ -65,6 +65,10 @@ +@@ -55,14 +55,14 @@ + RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized."; + } + +-int32_t AudioDeviceModuleIOS::AttachAudioBuffer() { ++AudioDeviceModuleIOS::~AudioDeviceModuleIOS() { RTC_DLOG(LS_INFO) << __FUNCTION__; +- audio_device_->AttachAudioBuffer(audio_device_buffer_.get()); +- return 0; + } + +-AudioDeviceModuleIOS::~AudioDeviceModuleIOS() { ++int32_t AudioDeviceModuleIOS::AttachAudioBuffer() { + RTC_DLOG(LS_INFO) << __FUNCTION__; ++ audio_device_->AttachAudioBuffer(audio_device_buffer_.get()); ++ return 0; } -+webrtc::WeakPtr AudioDeviceModuleIOS::GetWeakPtr() { -+ return weak_factory_.GetWeakPtr(); -+} -+ void AudioDeviceModuleIOS::ReportError(ADMError error) const { - if (error_handler_) { - error_handler_(error); -@@ -652,6 +656,30 @@ +@@ -641,7 +641,9 @@ + if (Recording()) { + return 0; + } +- audio_device_buffer_.get()->StartRecording(); ++ if (audio_device_buffer_) { ++ audio_device_buffer_->StartRecording(); ++ } + int32_t result = audio_device_->StartRecording(); + if (result < 0) { + ReportError(kRecordingStartFailed); +@@ -652,11 +654,41 @@ return result; } @@ -462,7 +453,9 @@ index e2ea360..72eaaa9 100644 + RTC_DLOG(LS_INFO) << __FUNCTION__; + CHECKinitialized_(); + int32_t result = audio_device_->PauseRecording(); -+ audio_device_buffer_.get()->StopRecording(); ++ if (audio_device_buffer_) { ++ audio_device_buffer_->StopRecording(); ++ } + if (result < 0) { + ReportError(kRecordingFailed); + } @@ -473,7 +466,9 @@ index e2ea360..72eaaa9 100644 +int32_t AudioDeviceModuleIOS::ResumeRecording() { + RTC_DLOG(LS_INFO) << __FUNCTION__; + CHECKinitialized_(); -+ audio_device_buffer_.get()->StartRecording(); ++ if (audio_device_buffer_) { ++ audio_device_buffer_->StartRecording(); ++ } + int32_t result = audio_device_->ResumeRecording(); + if (result < 0) { + ReportError(kRecordingFailed); @@ -485,3 +480,11 @@ index e2ea360..72eaaa9 100644 int32_t AudioDeviceModuleIOS::StopRecording() { RTC_DLOG(LS_INFO) << __FUNCTION__; CHECKinitialized_(); + int32_t result = audio_device_->StopRecording(); +- audio_device_buffer_.get()->StopRecording(); ++ if (audio_device_buffer_) { ++ audio_device_buffer_->StopRecording(); ++ } + if (result < 0) { + ReportError(kRecordingFailed); + } From 01df8d1ce13c6b14bd0922f63266c2c3d049e47f Mon Sep 17 00:00:00 2001 From: t-miya Date: Fri, 12 Dec 2025 18:27:26 +0900 Subject: [PATCH 09/18] =?UTF-8?q?AudioDeviceIOS=20=E5=86=85=E3=81=AE=20pau?= =?UTF-8?q?seRecording()/resumeRecording()=20=E3=81=AF=20recording=5F=20?= =?UTF-8?q?=E3=83=95=E3=83=A9=E3=82=B0=E3=81=AE=E6=93=8D=E4=BD=9C=E3=81=AE?= =?UTF-8?q?=E3=81=BF=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 97 +++++++--------------------- 1 file changed, 25 insertions(+), 72 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index fefe589d..b6e661ee 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -1,5 +1,5 @@ diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn -index 7b8a024..e2f6c7a 100644 +index f61cf30..3849c09 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -172,6 +172,7 @@ if (is_ios || is_mac) { @@ -19,7 +19,7 @@ index 7b8a024..e2f6c7a 100644 sources = [ "objc/helpers/AudioTimeStamp+Nanoseconds.h", "objc/helpers/AudioTimeStamp+Nanoseconds.mm", -@@ -1366,6 +1367,7 @@ if (is_ios || is_mac) { +@@ -1369,6 +1370,7 @@ if (is_ios || is_mac) { "objc/base/RTCVideoRenderer.h", "objc/base/RTCYUVPlanarBuffer.h", "objc/components/audio/RTCAudioDevice.h", @@ -275,7 +275,7 @@ index 0000000..b20c4a6 + +@end diff --git a/sdk/objc/native/src/audio/audio_device_ios.h b/sdk/objc/native/src/audio/audio_device_ios.h -index d1788a3..b3d2b32 100644 +index d1788a3..e8b4666 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.h +++ b/sdk/objc/native/src/audio/audio_device_ios.h @@ -80,6 +80,8 @@ class AudioDeviceIOS : public AudioDeviceGeneric, @@ -287,67 +287,32 @@ index d1788a3..b3d2b32 100644 int32_t StopRecording() override; bool Recording() const override; -@@ -292,6 +294,9 @@ class AudioDeviceIOS : public AudioDeviceGeneric, - // Set to 1 when playout is active and 0 otherwise. - std::atomic playing_; - -+ // Set to true when recording has been paused explicitly. -+ bool paused_recording_; -+ - // Set to true after successful call to Init(), false otherwise. - bool initialized_ RTC_GUARDED_BY(thread_); - diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..b60ca3c 100644 +index 021f08a..44404da 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm -@@ -110,6 +110,7 @@ static void LogDeviceInfo() { - audio_unit_(nullptr), - recording_(0), - playing_(0), -+ paused_recording_(false), - initialized_(false), - audio_is_initialized_(false), - is_interrupted_(false), -@@ -302,6 +303,10 @@ static void LogDeviceInfo() { - LOGI() << "StartRecording"; - RTC_DCHECK_RUN_ON(thread_); - RTC_DCHECK(audio_is_initialized_); -+ // 録音ポーズ中であれば ResumeRecording() にフォールスルーする -+ if (paused_recording_) { -+ return ResumeRecording(); -+ } - RTC_DCHECK(!recording_.load()); - RTC_DCHECK(audio_unit_); - if (!audio_is_initialized_) { -@@ -330,9 +335,15 @@ static void LogDeviceInfo() { +@@ -330,16 +330,50 @@ static void LogDeviceInfo() { int32_t AudioDeviceIOS::StopRecording() { LOGI() << "StopRecording"; RTC_DCHECK_RUN_ON(thread_); - if (!audio_is_initialized_ || !recording_.load()) { -+ if (!audio_is_initialized_) -+ return 0; -+ // 録音ポーズ中でも解放処理を実行するためのチェック -+ // 録音フラグが立っていない、かつ、録音ポーズ中でない -> 解放済みである、としてリターン -+ if (!recording_.load() && !paused_recording_) { ++ // 元々は !recording_.load() との OR 判定だったが、PauseRecording() 追加により ++ // StopRecording() 前に recording_ が 0 となることがあるため分岐を修正している ++ if (!audio_is_initialized_) { return 0; } -+ // 実際の状態に関わらず録音ポーズフラグも解除しておく -+ paused_recording_ = false; if (!playing_.load()) { ShutdownPlayOrRecord(); } -@@ -340,6 +351,52 @@ static void LogDeviceInfo() { - return 0; - } - ++ if (recording_.load()) { ++ recording_.store(0, std::memory_order_release); ++ } ++ return 0; ++} ++ +int32_t AudioDeviceIOS::PauseRecording() { + LOGI() << "PauseRecording"; + RTC_DCHECK_RUN_ON(thread_); -+ if (paused_recording_) { -+ RTC_LOG(LS_VERBOSE) << "PauseRecording called while already paused"; -+ return 0; -+ } + if (!audio_is_initialized_) { + RTC_LOG(LS_WARNING) << "PauseRecording called before audio is initialized"; + return 0; @@ -356,35 +321,23 @@ index 021f08a..b60ca3c 100644 + RTC_LOG(LS_WARNING) << "PauseRecording called while not recording"; + return 0; + } -+ recording_.store(0, std::memory_order_release); -+ paused_recording_ = true; -+ return 0; -+} -+ + recording_.store(0, std::memory_order_release); + return 0; + } + +int32_t AudioDeviceIOS::ResumeRecording() { + LOGI() << "ResumeRecording"; + RTC_DCHECK_RUN_ON(thread_); -+ if (!paused_recording_) { -+ return 0; -+ } -+ // InitRecording に失敗した場合は pause 状態の解除も recording_ の再立て直しも行えないため -+ // 上位にエラーを返す + if (!audio_is_initialized_) { -+ if (InitRecording() != 0) { -+ RTC_LOG(LS_ERROR) << "InitRecording failed during ResumeRecording"; -+ paused_recording_ = false; -+ recording_.store(0, std::memory_order_release); -+ return -1; -+ } ++ RTC_LOG(LS_WARNING) << "PauseRecording called before audio is initialized"; ++ return 0; + } -+ paused_recording_ = false; -+ int32_t result = StartRecording(); -+ if (result != 0) { -+ // Start に失敗したら再度 pause 状態に戻す -+ paused_recording_ = true; -+ recording_.store(0, std::memory_order_release); ++ if (recording_.load()) { ++ RTC_LOG(LS_WARNING) << "ResumeRecording called while recording"; ++ return 0; + } -+ return result; ++ recording_.store(1, std::memory_order_release); ++ return 0; +} + bool AudioDeviceIOS::Recording() const { From 4bd7c152f16e7245f58a8044e38ff53105c5abd4 Mon Sep 17 00:00:00 2001 From: t-miya Date: Fri, 12 Dec 2025 19:45:42 +0900 Subject: [PATCH 10/18] =?UTF-8?q?RTCPeerConnectionFactory=20=E3=81=AE=20in?= =?UTF-8?q?itWithEncoderFactory=20=E3=82=92=20audioDevice=E7=89=88?= =?UTF-8?q?=E3=80=81audioDeviceModule=E7=89=88=E3=81=9D=E3=82=8C=E3=81=9E?= =?UTF-8?q?=E3=82=8C=E3=81=AB=E5=88=86=E9=9B=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 131 +++++++-------------------- 1 file changed, 34 insertions(+), 97 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index b6e661ee..25a55595 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -28,7 +28,7 @@ index f61cf30..3849c09 100644 "objc/components/audio/RTCAudioSessionConfiguration.h", "objc/components/capturer/RTCCameraVideoCapturer.h", diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h -index 8287bcf..82a7866 100644 +index 8287bcf..28420d7 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h @@ -11,6 +11,7 @@ @@ -47,16 +47,7 @@ index 8287bcf..82a7866 100644 typedef NS_ENUM(NSInteger, RTCProxyType); -@@ -52,7 +54,7 @@ RTC_OBJC_EXPORT - decoderFactory; - - /* Initialize object with injectable video encoder/decoder factories and -- * injectable ADM */ -+ * injectable ADM (RTCAudioDevice) */ - - (instancetype) - initWithEncoderFactory: - (nullable id)encoderFactory -@@ -61,6 +63,27 @@ RTC_OBJC_EXPORT +@@ -61,6 +63,16 @@ RTC_OBJC_EXPORT audioDevice: (nullable id)audioDevice; @@ -69,37 +60,15 @@ index 8287bcf..82a7866 100644 + decoderFactory + audioDeviceModule: + (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule; -+ -+/* Initialize object with injectable video encoder/decoder factories and -+ * both RTCAudioDevice (objC) and RTCAudioDeviceModule (pause/resume 用) */ -+- (instancetype) -+ initWithEncoderFactory: -+ (nullable id)encoderFactory -+ decoderFactory:(nullable id) -+ decoderFactory -+ audioDevice:(nullable id)audioDevice -+ audioDeviceModule: -+ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule; + /** * Valid kind values are kRTCMediaStreamTrackKindAudio and * kRTCMediaStreamTrackKindVideo. diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -index 233cf25..1e2c0fa 100644 +index 233cf25..5801167 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -@@ -121,6 +121,10 @@ @implementation RTC_OBJC_TYPE (RTCPeerConnectionFactory) { - std::unique_ptr _workerThread; - std::unique_ptr _signalingThread; - BOOL _hasStartedAecDump; -+ // RTCAudioDeviceModule は内部でネイティブ ADM を生成・保持する(scoped_refptr による所有) -+ // RTCPeerConnectionFactory は初期化時に RTCAudioDeviceModule から生ポインタを受け取る -+ // RTCAudioDeviceModule が破棄されると内部 ADM も破棄される -+ __weak RTC_OBJC_TYPE(RTCAudioDeviceModule)* _objcAudioDeviceModule; - } - - @synthesize nativeFactory = _nativeFactory; -@@ -137,9 +141,6 @@ - (instancetype)init { +@@ -137,9 +137,6 @@ - (instancetype)init { dependencies.video_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory( [[RTC_OBJC_TYPE(RTCVideoDecoderFactoryH264) alloc] init]); dependencies.env = webrtc::CreateEnvironment(); @@ -109,33 +78,13 @@ index 233cf25..1e2c0fa 100644 return [self initWithMediaAndDependencies:dependencies]; } -@@ -150,7 +151,8 @@ - (instancetype)init { - decoderFactory { - return [self initWithEncoderFactory:encoderFactory - decoderFactory:decoderFactory -- audioDevice:nil]; -+ audioDevice:nil -+ audioDeviceModule:nil]; +@@ -189,6 +186,50 @@ - (instancetype)init { + #endif } - - (instancetype) -@@ -158,8 +160,42 @@ - (instancetype)init { - (nullable id)encoderFactory - decoderFactory:(nullable id) - decoderFactory -- audioDevice: -- (nullable id)audioDevice { -+ audioDevice:(nullable id)audioDevice { -+#ifdef HAVE_NO_MEDIA -+ return [self initWithNoMedia]; -+#else -+ return [self initWithEncoderFactory:encoderFactory -+ decoderFactory:decoderFactory -+ audioDevice:audioDevice -+ audioDeviceModule:nil]; -+#endif -+} -+ ++// audioDeviceModule を引数に取る initWithEncoderFactory ++// audioDeviceModule から Native ADM を取得して dependencies.adm にセットする処理以外は ++// audioDevice 版と同様の実装 +- (instancetype) + initWithEncoderFactory: + (nullable id)encoderFactory @@ -146,52 +95,40 @@ index 233cf25..1e2c0fa 100644 +#ifdef HAVE_NO_MEDIA + return [self initWithNoMedia]; +#else -+ return [self initWithEncoderFactory:encoderFactory -+ decoderFactory:decoderFactory -+ audioDevice:nil -+ audioDeviceModule:audioDeviceModule]; -+#endif -+} -+ -+- (instancetype) -+ initWithEncoderFactory: -+ (nullable id)encoderFactory -+ decoderFactory:(nullable id) -+ decoderFactory -+ audioDevice:(nullable id)audioDevice -+ audioDeviceModule: -+ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule { - #ifdef HAVE_NO_MEDIA - return [self initWithNoMedia]; - #else -@@ -177,14 +213,25 @@ - (instancetype)init { - dependencies.video_decoder_factory = - webrtc::ObjCToNativeVideoDecoderFactory(decoderFactory); - } ++ webrtc::PeerConnectionFactoryDependencies dependencies; ++ dependencies.env = webrtc::CreateEnvironment(); ++ dependencies.audio_encoder_factory = ++ webrtc::CreateBuiltinAudioEncoderFactory(); ++ dependencies.audio_decoder_factory = ++ webrtc::CreateBuiltinAudioDecoderFactory(); ++ if (encoderFactory) { ++ dependencies.video_encoder_factory = ++ webrtc::ObjCToNativeVideoEncoderFactory(encoderFactory); ++ } ++ if (decoderFactory) { ++ dependencies.video_decoder_factory = ++ webrtc::ObjCToNativeVideoDecoderFactory(decoderFactory); ++ } +#ifdef WEBRTC_IOS -+ // audioDevice と audioDeviceModule が両方指定されている場合、 -+ // 元々の互換性を優先して audioDevice が指定されているものとする - if (audioDevice) { - dependencies.adm = - webrtc::CreateAudioDeviceModule(*dependencies.env, audioDevice); --#ifdef WEBRTC_IOS -+ } else if (audioDeviceModule) { ++ if (audioDeviceModule) { + void* native_adm = [audioDeviceModule getNativeAudioDeviceModule]; + auto adm_ptr = static_cast(native_adm); + if (adm_ptr) { + dependencies.adm = adm_ptr; -+ _objcAudioDeviceModule = audioDeviceModule; + } else { + dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); + } - } else { - dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); --#endif - } ++ } else { ++ dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); ++ } +#endif - return [self initWithMediaAndDependencies:dependencies]; - #endif - } ++ return [self initWithMediaAndDependencies:dependencies]; ++#endif ++} ++ + - (instancetype)initWithNativeDependencies: + (webrtc::PeerConnectionFactoryDependencies &)dependencies { + self = [super init]; diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.h b/sdk/objc/components/audio/RTCAudioDeviceModule.h new file mode 100644 index 0000000..0823504 From d5d0db9a914e59b2b29e5ed5c28203d3ee45d6a4 Mon Sep 17 00:00:00 2001 From: t-miya Date: Mon, 15 Dec 2025 12:29:10 +0900 Subject: [PATCH 11/18] =?UTF-8?q?RTCAudioDeviceModule+Private.h=20?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0=E3=80=81=E3=81=9D=E3=81=AE=E4=BB=96?= =?UTF-8?q?=E9=96=A2=E6=95=B0=E3=81=AE=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 109 ++++++++++++++------------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 25a55595..bab835c0 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -65,10 +65,18 @@ index 8287bcf..28420d7 100644 * Valid kind values are kRTCMediaStreamTrackKindAudio and * kRTCMediaStreamTrackKindVideo. diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -index 233cf25..5801167 100644 +index 233cf25..0195f2d 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -@@ -137,9 +137,6 @@ - (instancetype)init { +@@ -14,6 +14,7 @@ + #import "RTCPeerConnectionFactory+Private.h" + #import "RTCPeerConnectionFactoryOptions+Private.h" + #import "RTCRtpCapabilities+Private.h" ++#import "sdk/objc/components/audio/RTCAudioDeviceModule+Private.h" + + #import "RTCAudioSource+Private.h" + #import "RTCAudioTrack+Private.h" +@@ -137,9 +138,6 @@ - (instancetype)init { dependencies.video_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory( [[RTC_OBJC_TYPE(RTCVideoDecoderFactoryH264) alloc] init]); dependencies.env = webrtc::CreateEnvironment(); @@ -78,7 +86,7 @@ index 233cf25..5801167 100644 return [self initWithMediaAndDependencies:dependencies]; } -@@ -189,6 +186,50 @@ - (instancetype)init { +@@ -189,6 +187,49 @@ - (instancetype)init { #endif } @@ -111,8 +119,7 @@ index 233cf25..5801167 100644 + } +#ifdef WEBRTC_IOS + if (audioDeviceModule) { -+ void* native_adm = [audioDeviceModule getNativeAudioDeviceModule]; -+ auto adm_ptr = static_cast(native_adm); ++ auto adm_ptr = [audioDeviceModule nativeAudioDeviceModule]; + if (adm_ptr) { + dependencies.adm = adm_ptr; + } else { @@ -129,12 +136,34 @@ index 233cf25..5801167 100644 - (instancetype)initWithNativeDependencies: (webrtc::PeerConnectionFactoryDependencies &)dependencies { self = [super init]; +diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h b/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h +new file mode 100644 +index 0000000..4e2bb60 +--- /dev/null ++++ b/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h +@@ -0,0 +1,16 @@ ++// 公開APIで隠している C++ 型のネイティブ ADM ポインタ webrtc::AudioDeviceModule* を安全に取得するためのヘッダ ++// C++ 用の型 webrtc::AudioDeviceModule を扱うため ObjC++ からのみインクルードされる想定 ++#import "RTCAudioDeviceModule.h" ++ ++#ifdef __cplusplus ++#include "api/audio/audio_device.h" ++#endif ++ ++@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) (Private) ++ ++#ifdef __cplusplus ++// ネイティブ ADM を取得する。所有権移動なし ++- (webrtc::AudioDeviceModule*)nativeAudioDeviceModule; ++#endif ++ ++@end diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.h b/sdk/objc/components/audio/RTCAudioDeviceModule.h new file mode 100644 -index 0000000..0823504 +index 0000000..d6f7983 --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.h -@@ -0,0 +1,21 @@ +@@ -0,0 +1,17 @@ +// iOS 用の AudioDeviceModule を生成し、pauseRecording()/resumeRecording() を公開するためのラッパー +#import + @@ -146,23 +175,20 @@ index 0000000..0823504 +// 内部で AudioDeviceModuleIOS を生成する +- (instancetype)init; + -+// ネイティブ ADM を取得する(所有権移動なし、未初期化なら nullptr) -+- (void *)getNativeAudioDeviceModule; -+ -+// 録音を一時停止/再開する。成功時または状態が変わらない場合に YES を返す -+// -+// 一時停止状態で AudioDeviceIOS::StartRecording() が呼ばれた場合は ResumeRecording() にフォールバックされる -+- (BOOL)pauseRecording; -+- (BOOL)resumeRecording; ++// 録音を一時停止/再開する ++// 内部で AudioDeviceModuleIOS -> AudioDeviceIOS の pauseRecording()/resumeRecording() を呼び出す ++- (NSInteger)pauseRecording; ++- (NSInteger)resumeRecording; + +@end diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.mm b/sdk/objc/components/audio/RTCAudioDeviceModule.mm new file mode 100644 -index 0000000..b20c4a6 +index 0000000..0f82b91 --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.mm -@@ -0,0 +1,49 @@ +@@ -0,0 +1,46 @@ +#import "RTCAudioDeviceModule.h" ++#include + +#include + @@ -173,7 +199,7 @@ index 0000000..b20c4a6 + +@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) () { + // 所有権とライフサイクル管理対象のネイティブADM -+ webrtc::scoped_refptr _adm_owner; ++ webrtc::scoped_refptr _adm; +} +@end + @@ -183,31 +209,27 @@ index 0000000..b20c4a6 + self = [super init]; + if (self) { + auto env = webrtc::CreateEnvironment(); -+ _adm_owner = webrtc::CreateAudioDeviceModule(env); ++ _adm = webrtc::CreateAudioDeviceModule(env); + } + return self; +} + -+- (void *)getNativeAudioDeviceModule { -+ return _adm_owner.get(); ++#ifdef __cplusplus ++- (webrtc::AudioDeviceModule*)nativeAudioDeviceModule { ++ return _adm.get(); +} ++#endif + -+- (BOOL)pauseRecording { ++- (NSInteger)pauseRecording { + auto ptr = -+ static_cast(_adm_owner.get()); -+ if (!ptr) { -+ return NO; -+ } -+ return ptr->PauseRecording() == 0; ++ static_cast(_adm.get()); ++ return ptr->PauseRecording(); +} + -+- (BOOL)resumeRecording { ++- (NSInteger)resumeRecording { + auto ptr = -+ static_cast(_adm_owner.get()); -+ if (!ptr) { -+ return NO; -+ } -+ return ptr->ResumeRecording() == 0; ++ static_cast(_adm.get()); ++ return ptr->ResumeRecording(); +} + +@end @@ -302,28 +324,9 @@ index 5ff5062..40626ae 100644 void ReportError(ADMError error) const; diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.mm b/sdk/objc/native/src/audio/audio_device_module_ios.mm -index e2ea360..cb75318 100644 +index e2ea360..6a8164e 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm -@@ -55,14 +55,14 @@ - RTC_LOG(LS_INFO) << "iPhone Audio APIs will be utilized."; - } - --int32_t AudioDeviceModuleIOS::AttachAudioBuffer() { -+AudioDeviceModuleIOS::~AudioDeviceModuleIOS() { - RTC_DLOG(LS_INFO) << __FUNCTION__; -- audio_device_->AttachAudioBuffer(audio_device_buffer_.get()); -- return 0; - } - --AudioDeviceModuleIOS::~AudioDeviceModuleIOS() { -+int32_t AudioDeviceModuleIOS::AttachAudioBuffer() { - RTC_DLOG(LS_INFO) << __FUNCTION__; -+ audio_device_->AttachAudioBuffer(audio_device_buffer_.get()); -+ return 0; - } - - void AudioDeviceModuleIOS::ReportError(ADMError error) const { @@ -641,7 +641,9 @@ if (Recording()) { return 0; From 8cc18298444029b350dcd33e736616fcf8582117 Mon Sep 17 00:00:00 2001 From: t-miya Date: Mon, 15 Dec 2025 12:37:06 +0900 Subject: [PATCH 12/18] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E3=82=B3?= =?UTF-8?q?=E3=83=A1=E3=83=B3=E3=83=88=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index bab835c0..20e8e18b 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -138,10 +138,10 @@ index 233cf25..0195f2d 100644 self = [super init]; diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h b/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h new file mode 100644 -index 0000000..4e2bb60 +index 0000000..cf2f92d --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h -@@ -0,0 +1,16 @@ +@@ -0,0 +1,15 @@ +// 公開APIで隠している C++ 型のネイティブ ADM ポインタ webrtc::AudioDeviceModule* を安全に取得するためのヘッダ +// C++ 用の型 webrtc::AudioDeviceModule を扱うため ObjC++ からのみインクルードされる想定 +#import "RTCAudioDeviceModule.h" @@ -153,7 +153,6 @@ index 0000000..4e2bb60 +@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) (Private) + +#ifdef __cplusplus -+// ネイティブ ADM を取得する。所有権移動なし +- (webrtc::AudioDeviceModule*)nativeAudioDeviceModule; +#endif + From 4506f1709464bbd76a3a5143843714a282ccc08e Mon Sep 17 00:00:00 2001 From: t-miya Date: Tue, 16 Dec 2025 13:34:18 +0900 Subject: [PATCH 13/18] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E5=88=86?= =?UTF-8?q?=E5=B2=90=E3=80=81ifdef=20=E3=81=AE=E6=95=B4=E7=90=86=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 151 ++++++++------------------- 1 file changed, 45 insertions(+), 106 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 20e8e18b..6b7b1aa6 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -1,5 +1,5 @@ diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn -index f61cf30..3849c09 100644 +index f61cf30..aab3684 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -172,6 +172,7 @@ if (is_ios || is_mac) { @@ -10,15 +10,6 @@ index f61cf30..3849c09 100644 ] if (target_platform != "tvos") { -@@ -185,7 +186,7 @@ if (is_ios || is_mac) { - } - } - -- rtc_library("core_audio_helpers_objc") { -+rtc_library("core_audio_helpers_objc") { - sources = [ - "objc/helpers/AudioTimeStamp+Nanoseconds.h", - "objc/helpers/AudioTimeStamp+Nanoseconds.mm", @@ -1369,6 +1370,7 @@ if (is_ios || is_mac) { "objc/base/RTCVideoRenderer.h", "objc/base/RTCYUVPlanarBuffer.h", @@ -28,7 +19,7 @@ index f61cf30..3849c09 100644 "objc/components/audio/RTCAudioSessionConfiguration.h", "objc/components/capturer/RTCCameraVideoCapturer.h", diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h -index 8287bcf..28420d7 100644 +index 8287bcf..7090921 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h @@ -11,6 +11,7 @@ @@ -39,33 +30,34 @@ index 8287bcf..28420d7 100644 NS_ASSUME_NONNULL_BEGIN -@@ -34,6 +35,7 @@ NS_ASSUME_NONNULL_BEGIN - (RTCSSLCertificateVerifier); - @protocol RTC_OBJC_TYPE - (RTCAudioDevice); +@@ -24,6 +25,7 @@ NS_ASSUME_NONNULL_BEGIN + @class RTC_OBJC_TYPE(RTCVideoSource); + @class RTC_OBJC_TYPE(RTCVideoTrack); + @class RTC_OBJC_TYPE(RTCPeerConnectionFactoryOptions); +@class RTC_OBJC_TYPE(RTCAudioDeviceModule); - - typedef NS_ENUM(NSInteger, RTCProxyType); - -@@ -61,6 +63,16 @@ RTC_OBJC_EXPORT + @protocol RTC_OBJC_TYPE + (RTCPeerConnectionDelegate); + @protocol RTC_OBJC_TYPE +@@ -61,6 +63,17 @@ RTC_OBJC_EXPORT audioDevice: (nullable id)audioDevice; -+/* Initialize object with injectable video encoder/decoder factories and -+ * RTCAudioDeviceModule (pause/resume 用) */ ++/** ++ * Video encoder/decorder ファクトリと RTCAudioDeviceModule 差し込みによる初期化 ++ */ +- (instancetype) + initWithEncoderFactory: + (nullable id)encoderFactory + decoderFactory:(nullable id) + decoderFactory -+ audioDeviceModule: -+ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule; ++ audioDeviceModule: ++ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule; + /** * Valid kind values are kRTCMediaStreamTrackKindAudio and * kRTCMediaStreamTrackKindVideo. diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -index 233cf25..0195f2d 100644 +index 233cf25..b2b063e 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm @@ -14,6 +14,7 @@ @@ -76,17 +68,7 @@ index 233cf25..0195f2d 100644 #import "RTCAudioSource+Private.h" #import "RTCAudioTrack+Private.h" -@@ -137,9 +138,6 @@ - (instancetype)init { - dependencies.video_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory( - [[RTC_OBJC_TYPE(RTCVideoDecoderFactoryH264) alloc] init]); - dependencies.env = webrtc::CreateEnvironment(); --#ifdef WEBRTC_IOS -- dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); --#endif - return [self initWithMediaAndDependencies:dependencies]; - } - -@@ -189,6 +187,49 @@ - (instancetype)init { +@@ -189,6 +190,43 @@ - (instancetype)init { #endif } @@ -98,8 +80,8 @@ index 233cf25..0195f2d 100644 + (nullable id)encoderFactory + decoderFactory:(nullable id) + decoderFactory -+ audioDeviceModule: -+ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule { ++ audioDeviceModule: ++ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule { +#ifdef HAVE_NO_MEDIA + return [self initWithNoMedia]; +#else @@ -117,18 +99,12 @@ index 233cf25..0195f2d 100644 + dependencies.video_decoder_factory = + webrtc::ObjCToNativeVideoDecoderFactory(decoderFactory); + } -+#ifdef WEBRTC_IOS + if (audioDeviceModule) { + auto adm_ptr = [audioDeviceModule nativeAudioDeviceModule]; -+ if (adm_ptr) { -+ dependencies.adm = adm_ptr; -+ } else { -+ dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); -+ } ++ dependencies.adm = adm_ptr; + } else { + dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env); + } -+#endif + return [self initWithMediaAndDependencies:dependencies]; +#endif +} @@ -138,28 +114,24 @@ index 233cf25..0195f2d 100644 self = [super init]; diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h b/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h new file mode 100644 -index 0000000..cf2f92d +index 0000000..3e67c85 --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h -@@ -0,0 +1,15 @@ +@@ -0,0 +1,11 @@ +// 公開APIで隠している C++ 型のネイティブ ADM ポインタ webrtc::AudioDeviceModule* を安全に取得するためのヘッダ +// C++ 用の型 webrtc::AudioDeviceModule を扱うため ObjC++ からのみインクルードされる想定 +#import "RTCAudioDeviceModule.h" + -+#ifdef __cplusplus +#include "api/audio/audio_device.h" -+#endif + -+@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) (Private) ++@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) () + -+#ifdef __cplusplus -+- (webrtc::AudioDeviceModule*)nativeAudioDeviceModule; -+#endif ++- (webrtc::scoped_refptr)nativeAudioDeviceModule; + +@end diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.h b/sdk/objc/components/audio/RTCAudioDeviceModule.h new file mode 100644 -index 0000000..d6f7983 +index 0000000..84034ef --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.h @@ -0,0 +1,17 @@ @@ -174,22 +146,19 @@ index 0000000..d6f7983 +// 内部で AudioDeviceModuleIOS を生成する +- (instancetype)init; + -+// 録音を一時停止/再開する -+// 内部で AudioDeviceModuleIOS -> AudioDeviceIOS の pauseRecording()/resumeRecording() を呼び出す ++// 録音を一時停止する。内部で AudioDeviceModuleIOS::pauseRecording() を呼ぶ +- (NSInteger)pauseRecording; ++// 録音を再開する。内部で AudioDeviceModuleIOS::resumeRecording() を呼ぶ +- (NSInteger)resumeRecording; + +@end diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.mm b/sdk/objc/components/audio/RTCAudioDeviceModule.mm new file mode 100644 -index 0000000..0f82b91 +index 0000000..d1e495f --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.mm -@@ -0,0 +1,46 @@ +@@ -0,0 +1,40 @@ +#import "RTCAudioDeviceModule.h" -+#include -+ -+#include + +#include "api/environment/environment_factory.h" +#include "api/scoped_refptr.h" @@ -197,7 +166,6 @@ index 0000000..0f82b91 +#include "sdk/objc/native/src/audio/audio_device_module_ios.h" + +@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) () { -+ // 所有権とライフサイクル管理対象のネイティブADM + webrtc::scoped_refptr _adm; +} +@end @@ -213,11 +181,9 @@ index 0000000..0f82b91 + return self; +} + -+#ifdef __cplusplus -+- (webrtc::AudioDeviceModule*)nativeAudioDeviceModule { -+ return _adm.get(); ++- (webrtc::scoped_refptr)nativeAudioDeviceModule { ++ return _adm; +} -+#endif + +- (NSInteger)pauseRecording { + auto ptr = @@ -246,10 +212,10 @@ index d1788a3..e8b4666 100644 bool Recording() const override; diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..44404da 100644 +index 021f08a..17a759a 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm -@@ -330,16 +330,50 @@ static void LogDeviceInfo() { +@@ -330,7 +330,9 @@ static void LogDeviceInfo() { int32_t AudioDeviceIOS::StopRecording() { LOGI() << "StopRecording"; RTC_DCHECK_RUN_ON(thread_); @@ -260,14 +226,10 @@ index 021f08a..44404da 100644 return 0; } if (!playing_.load()) { - ShutdownPlayOrRecord(); - } -+ if (recording_.load()) { -+ recording_.store(0, std::memory_order_release); -+ } -+ return 0; -+} -+ +@@ -340,6 +342,36 @@ static void LogDeviceInfo() { + return 0; + } + +int32_t AudioDeviceIOS::PauseRecording() { + LOGI() << "PauseRecording"; + RTC_DCHECK_RUN_ON(thread_); @@ -279,10 +241,10 @@ index 021f08a..44404da 100644 + RTC_LOG(LS_WARNING) << "PauseRecording called while not recording"; + return 0; + } - recording_.store(0, std::memory_order_release); - return 0; - } - ++ recording_.store(0, std::memory_order_release); ++ return 0; ++} ++ +int32_t AudioDeviceIOS::ResumeRecording() { + LOGI() << "ResumeRecording"; + RTC_DCHECK_RUN_ON(thread_); @@ -323,21 +285,10 @@ index 5ff5062..40626ae 100644 void ReportError(ADMError error) const; diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.mm b/sdk/objc/native/src/audio/audio_device_module_ios.mm -index e2ea360..6a8164e 100644 +index e2ea360..9ac6904 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm -@@ -641,7 +641,9 @@ - if (Recording()) { - return 0; - } -- audio_device_buffer_.get()->StartRecording(); -+ if (audio_device_buffer_) { -+ audio_device_buffer_->StartRecording(); -+ } - int32_t result = audio_device_->StartRecording(); - if (result < 0) { - ReportError(kRecordingStartFailed); -@@ -652,11 +654,41 @@ +@@ -652,6 +652,30 @@ return result; } @@ -345,9 +296,7 @@ index e2ea360..6a8164e 100644 + RTC_DLOG(LS_INFO) << __FUNCTION__; + CHECKinitialized_(); + int32_t result = audio_device_->PauseRecording(); -+ if (audio_device_buffer_) { -+ audio_device_buffer_->StopRecording(); -+ } ++ audio_device_buffer_.get()->StopRecording(); + if (result < 0) { + ReportError(kRecordingFailed); + } @@ -358,10 +307,8 @@ index e2ea360..6a8164e 100644 +int32_t AudioDeviceModuleIOS::ResumeRecording() { + RTC_DLOG(LS_INFO) << __FUNCTION__; + CHECKinitialized_(); -+ if (audio_device_buffer_) { -+ audio_device_buffer_->StartRecording(); -+ } + int32_t result = audio_device_->ResumeRecording(); ++ audio_device_buffer_.get()->StartRecording(); + if (result < 0) { + ReportError(kRecordingFailed); + } @@ -372,11 +319,3 @@ index e2ea360..6a8164e 100644 int32_t AudioDeviceModuleIOS::StopRecording() { RTC_DLOG(LS_INFO) << __FUNCTION__; CHECKinitialized_(); - int32_t result = audio_device_->StopRecording(); -- audio_device_buffer_.get()->StopRecording(); -+ if (audio_device_buffer_) { -+ audio_device_buffer_->StopRecording(); -+ } - if (result < 0) { - ReportError(kRecordingFailed); - } From 61f6963b9e8850854d6d42b626f52757d4bbf3bc Mon Sep 17 00:00:00 2001 From: t-miya Date: Tue, 16 Dec 2025 13:39:59 +0900 Subject: [PATCH 14/18] =?UTF-8?q?=E6=94=B9=E8=A1=8C=E5=B7=AE=E5=88=86?= =?UTF-8?q?=E3=82=92=E9=99=A4=E5=8E=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 6b7b1aa6..b0a429ad 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -264,7 +264,7 @@ index 021f08a..17a759a 100644 return recording_.load(); } diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.h b/sdk/objc/native/src/audio/audio_device_module_ios.h -index 5ff5062..40626ae 100644 +index 5ff5062..987deb8 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.h +++ b/sdk/objc/native/src/audio/audio_device_module_ios.h @@ -76,6 +76,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { @@ -276,14 +276,6 @@ index 5ff5062..40626ae 100644 int32_t StopRecording() override; bool Recording() const override; -@@ -135,6 +137,7 @@ class AudioDeviceModuleIOS : public AudioDeviceModule { - int GetPlayoutAudioParameters(AudioParameters* params) const override; - int GetRecordAudioParameters(AudioParameters* params) const override; - #endif // WEBRTC_IOS -+ - private: - void ReportError(ADMError error) const; - diff --git a/sdk/objc/native/src/audio/audio_device_module_ios.mm b/sdk/objc/native/src/audio/audio_device_module_ios.mm index e2ea360..9ac6904 100644 --- a/sdk/objc/native/src/audio/audio_device_module_ios.mm From bbddaa4bfdd7b4a7e23834ef8e1b78fc1a7ec61d Mon Sep 17 00:00:00 2001 From: t-miya Date: Wed, 17 Dec 2025 11:04:29 +0900 Subject: [PATCH 15/18] =?UTF-8?q?CHANGES=20=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 698b4baf..31567b1c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -31,10 +31,10 @@ VERSION ファイルを上げただけの場合は変更履歴記録は不要。 - 2025-12-12 [ADD] iOS SDK に RTCAudioDeviceModule を追加する - iOS 実機のマイクインジケータが消灯状態のミュートをできるようにする - - RTCAudioDeviceModule の 公開 API として pauseRecording()/resumeRecording() を追加する + - RTCPeerConnectionFactory に RTCAudioDeviceModule を引数とする initWithEncoderFactory() を追加する + - RTCAudioDeviceModule は公開 API として pauseRecording()/resumeRecording() を持つ - AudioDeviceModuleIOS に pauseRecording()/resumeRecording() を追加する - AudioDeviceIOS に pauseRecording()/resumeRecording() を追加する - - 録音一時停止中か管理するための paused_recording_ プロパティを追加する - @t-miya - 2025-12-12 [RELEASE] m143.7499.2.1 - @zztkm From 18b7e386fdef1dde293d17a629713dc3332a50c3 Mon Sep 17 00:00:00 2001 From: t-miya Date: Wed, 17 Dec 2025 11:40:40 +0900 Subject: [PATCH 16/18] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- patches/ios_audio_pause_resume.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index b0a429ad..9a64164b 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -212,7 +212,7 @@ index d1788a3..e8b4666 100644 bool Recording() const override; diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..17a759a 100644 +index 021f08a..05a7f2a 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -330,7 +330,9 @@ static void LogDeviceInfo() { @@ -249,7 +249,7 @@ index 021f08a..17a759a 100644 + LOGI() << "ResumeRecording"; + RTC_DCHECK_RUN_ON(thread_); + if (!audio_is_initialized_) { -+ RTC_LOG(LS_WARNING) << "PauseRecording called before audio is initialized"; ++ RTC_LOG(LS_WARNING) << "ResumeRecording called before audio is initialized"; + return 0; + } + if (recording_.load()) { From 05cb368f050b928fa5381f2ae04f70972684f440 Mon Sep 17 00:00:00 2001 From: t-miya Date: Wed, 17 Dec 2025 13:20:12 +0900 Subject: [PATCH 17/18] =?UTF-8?q?initWithEncoderFactory=20=E3=81=AB?= =?UTF-8?q?=E9=96=A2=E3=81=99=E3=82=8B=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E3=82=92=20ObjC=20=E3=81=AE=E5=BD=A2=E5=BC=8F=E3=81=AB?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 2 +- patches/ios_audio_pause_resume.patch | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 31567b1c..19d63ded 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -31,7 +31,7 @@ VERSION ファイルを上げただけの場合は変更履歴記録は不要。 - 2025-12-12 [ADD] iOS SDK に RTCAudioDeviceModule を追加する - iOS 実機のマイクインジケータが消灯状態のミュートをできるようにする - - RTCPeerConnectionFactory に RTCAudioDeviceModule を引数とする initWithEncoderFactory() を追加する + - RTCPeerConnectionFactory に RTCAudioDeviceModule を引数とする initWithEncoderFactory:decoderFactory:audioDeviceModule を追加する - RTCAudioDeviceModule は公開 API として pauseRecording()/resumeRecording() を持つ - AudioDeviceModuleIOS に pauseRecording()/resumeRecording() を追加する - AudioDeviceIOS に pauseRecording()/resumeRecording() を追加する diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index 9a64164b..c54a9fee 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -57,7 +57,7 @@ index 8287bcf..7090921 100644 * Valid kind values are kRTCMediaStreamTrackKindAudio and * kRTCMediaStreamTrackKindVideo. diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -index 233cf25..b2b063e 100644 +index 233cf25..e94ab00 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm @@ -14,6 +14,7 @@ @@ -72,9 +72,9 @@ index 233cf25..b2b063e 100644 #endif } -+// audioDeviceModule を引数に取る initWithEncoderFactory ++// RTCAudioDeviceModule* により ADM を初期化する +// audioDeviceModule から Native ADM を取得して dependencies.adm にセットする処理以外は -+// audioDevice 版と同様の実装 ++// initWithEncoderFactory:decoderFactory:audioDevice と同様の実装 +- (instancetype) + initWithEncoderFactory: + (nullable id)encoderFactory From c80883e099fc7df12ea5a3e636c45a788830a063 Mon Sep 17 00:00:00 2001 From: t-miya Date: Wed, 17 Dec 2025 13:29:12 +0900 Subject: [PATCH 18/18] =?UTF-8?q?=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E4=B8=AD=E3=81=AE=E9=96=A2=E6=95=B0=E3=81=AB=E9=96=A2=E3=81=99?= =?UTF-8?q?=E3=82=8B=E6=A8=99=E8=A8=98=E3=82=92=20ObjC=20=E5=BD=A2?= =?UTF-8?q?=E5=BC=8F=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGES.md | 8 ++++---- patches/ios_audio_pause_resume.patch | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 19d63ded..49c1d240 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -31,10 +31,10 @@ VERSION ファイルを上げただけの場合は変更履歴記録は不要。 - 2025-12-12 [ADD] iOS SDK に RTCAudioDeviceModule を追加する - iOS 実機のマイクインジケータが消灯状態のミュートをできるようにする - - RTCPeerConnectionFactory に RTCAudioDeviceModule を引数とする initWithEncoderFactory:decoderFactory:audioDeviceModule を追加する - - RTCAudioDeviceModule は公開 API として pauseRecording()/resumeRecording() を持つ - - AudioDeviceModuleIOS に pauseRecording()/resumeRecording() を追加する - - AudioDeviceIOS に pauseRecording()/resumeRecording() を追加する + - RTCPeerConnectionFactory に RTCAudioDeviceModule を引数とする initWithEncoderFactory:decoderFactory:audioDeviceModule: を追加する + - RTCAudioDeviceModule は公開 API として pauseRecording/resumeRecording を持つ + - AudioDeviceModuleIOS に pauseRecording/resumeRecording を追加する + - AudioDeviceIOS に pauseRecording/resumeRecording を追加する - @t-miya - 2025-12-12 [RELEASE] m143.7499.2.1 - @zztkm diff --git a/patches/ios_audio_pause_resume.patch b/patches/ios_audio_pause_resume.patch index c54a9fee..e13f8beb 100644 --- a/patches/ios_audio_pause_resume.patch +++ b/patches/ios_audio_pause_resume.patch @@ -57,7 +57,7 @@ index 8287bcf..7090921 100644 * Valid kind values are kRTCMediaStreamTrackKindAudio and * kRTCMediaStreamTrackKindVideo. diff --git a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm -index 233cf25..e94ab00 100644 +index 233cf25..0c20512 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm @@ -14,6 +14,7 @@ @@ -74,7 +74,7 @@ index 233cf25..e94ab00 100644 +// RTCAudioDeviceModule* により ADM を初期化する +// audioDeviceModule から Native ADM を取得して dependencies.adm にセットする処理以外は -+// initWithEncoderFactory:decoderFactory:audioDevice と同様の実装 ++// initWithEncoderFactory:decoderFactory:audioDevice: と同様の実装 +- (instancetype) + initWithEncoderFactory: + (nullable id)encoderFactory @@ -131,7 +131,7 @@ index 0000000..3e67c85 +@end diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.h b/sdk/objc/components/audio/RTCAudioDeviceModule.h new file mode 100644 -index 0000000..84034ef +index 0000000..bd3c425 --- /dev/null +++ b/sdk/objc/components/audio/RTCAudioDeviceModule.h @@ -0,0 +1,17 @@ @@ -146,9 +146,9 @@ index 0000000..84034ef +// 内部で AudioDeviceModuleIOS を生成する +- (instancetype)init; + -+// 録音を一時停止する。内部で AudioDeviceModuleIOS::pauseRecording() を呼ぶ ++// 録音を一時停止する。内部で AudioDeviceModuleIOS::pauseRecording を呼ぶ +- (NSInteger)pauseRecording; -+// 録音を再開する。内部で AudioDeviceModuleIOS::resumeRecording() を呼ぶ ++// 録音を再開する。内部で AudioDeviceModuleIOS::resumeRecording を呼ぶ +- (NSInteger)resumeRecording; + +@end @@ -212,7 +212,7 @@ index d1788a3..e8b4666 100644 bool Recording() const override; diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm -index 021f08a..05a7f2a 100644 +index 021f08a..5d2b8b2 100644 --- a/sdk/objc/native/src/audio/audio_device_ios.mm +++ b/sdk/objc/native/src/audio/audio_device_ios.mm @@ -330,7 +330,9 @@ static void LogDeviceInfo() { @@ -220,8 +220,8 @@ index 021f08a..05a7f2a 100644 LOGI() << "StopRecording"; RTC_DCHECK_RUN_ON(thread_); - if (!audio_is_initialized_ || !recording_.load()) { -+ // 元々は !recording_.load() との OR 判定だったが、PauseRecording() 追加により -+ // StopRecording() 前に recording_ が 0 となることがあるため分岐を修正している ++ // 元々は !recording_.load() との OR 判定だったが、PauseRecording 追加により ++ // StopRecording 実行前に recording_ が 0 となることがあるため分岐を修正している + if (!audio_is_initialized_) { return 0; }