Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,19 @@ VERSION ファイルを上げただけの場合は変更履歴記録は不要。

## タイムライン

- 2025-12-25 [ADD] iOS SDK 向けの AudioDeviceIOS の PauseRecording/ResumeRecording を修正する
- 内部で `VoiceProcessingAudioUnit::SetMicrophoneMute` を呼び出す `AudioDeviceIOS::ReinitAudioUnitForMicrophoneMute(bool)` を追加する
- PauseRecording/ResumeRecording から呼び出す
- @t-miya
- 2025-12-17 [RELEASE] m143.7499.3.1
- @t-miya
- 2025-12-17 [ADD] iOS SDK に RTCAudioDeviceModule を追加する
- iOS 実機のマイクインジケータが消灯状態のミュートをできるようにする
- RTCPeerConnectionFactory に RTCAudioDeviceModule を引数とする initWithEncoderFactory:decoderFactory:audioDeviceModule: を追加する
- RTCAudioDeviceModule は公開 API として pauseRecording/resumeRecording を持つ
- AudioDeviceModuleIOS に pauseRecording/resumeRecording を追加する
- AudioDeviceIOS に pauseRecording/resumeRecording を追加する
- AudioDeviceModuleIOS に PauseRecording/ResumeRecording を追加する
- AudioDeviceIOS に PauseRecording/ResumeRecording を追加する
- PauseRecording による録音停止の状態から ResumeRecording 実行なしに StopRecording を呼ぶことができる
- @t-miya
- 2025-12-16 [RELEASE] m143.7499.3.0
- @torikizi
Expand Down
105 changes: 96 additions & 9 deletions patches/ios_audio_pause_resume.patch
Original file line number Diff line number Diff line change
Expand Up @@ -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..bd3c425
index 0000000..60c4eb6
--- /dev/null
+++ b/sdk/objc/components/audio/RTCAudioDeviceModule.h
@@ -0,0 +1,17 @@
Expand All @@ -146,9 +146,9 @@ index 0000000..bd3c425
+// 内部で AudioDeviceModuleIOS を生成する
+- (instancetype)init;
+
+// 録音を一時停止する。内部で AudioDeviceModuleIOS::pauseRecording を呼ぶ
+// 録音を一時停止する。内部で AudioDeviceModuleIOS::PauseRecording() を呼ぶ
+- (NSInteger)pauseRecording;
+// 録音を再開する。内部で AudioDeviceModuleIOS::resumeRecording を呼ぶ
+// 録音を再開する。内部で AudioDeviceModuleIOS::ResumeRecording() を呼ぶ
+- (NSInteger)resumeRecording;
+
+@end
Expand Down Expand Up @@ -199,7 +199,7 @@ index 0000000..d1e495f
+
+@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..e8b4666 100644
index d1788a3..a3355a0 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,
Expand All @@ -211,8 +211,22 @@ index d1788a3..e8b4666 100644
int32_t StopRecording() override;
bool Recording() const override;

@@ -222,6 +224,13 @@ class AudioDeviceIOS : public AudioDeviceGeneric,
// Resets thread-checkers before a call is restarted.
void PrepareForNewStart();

+ // AudioUnit の SetMicrophoneMute() 実行によりマイクミュートの有効無効を切り替えます。
+ // AudioUnit の state が Uninitialized になっている必要があるため
+ // AudioUnit に対して、Stop -> Uninitialize -> SetMicrophoneMute -> Initialize -> Start
+ // のフローで処理を行います。
+ // この関数は PauseRecording()/ResumeRecording() から呼ばれることを想定しています。
+ int32_t ReinitAudioUnitForMicrophoneMute(bool mute);
+
const Environment env_;

// Determines whether voice processing should be enabled or disabled.
diff --git a/sdk/objc/native/src/audio/audio_device_ios.mm b/sdk/objc/native/src/audio/audio_device_ios.mm
index 021f08a..5d2b8b2 100644
index 021f08a..11c9286 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() {
Expand All @@ -226,7 +240,7 @@ index 021f08a..5d2b8b2 100644
return 0;
}
if (!playing_.load()) {
@@ -340,6 +342,36 @@ static void LogDeviceInfo() {
@@ -340,6 +342,107 @@ static void LogDeviceInfo() {
return 0;
}

Expand All @@ -241,6 +255,12 @@ index 021f08a..5d2b8b2 100644
+ RTC_LOG(LS_WARNING) << "PauseRecording called while not recording";
+ return 0;
+ }
+ // マイクミュートします
+ int32_t result = ReinitAudioUnitForMicrophoneMute(true);
+ if (result != 0) {
+ return result;
+ }
+ // 録音フラグをOFFにします
+ recording_.store(0, std::memory_order_release);
+ return 0;
+}
Expand All @@ -256,9 +276,74 @@ index 021f08a..5d2b8b2 100644
+ RTC_LOG(LS_WARNING) << "ResumeRecording called while recording";
+ return 0;
+ }
+ // マイクミュートを解除します
+ int32_t result = ReinitAudioUnitForMicrophoneMute(false);
+ if (result != 0) {
+ return result;
+ }
+ // 録音フラグをONにします
+ recording_.store(1, std::memory_order_release);
+ return 0;
+}
+
+int32_t AudioDeviceIOS::ReinitAudioUnitForMicrophoneMute(bool mute) {
+ LOGI() << "ReinitAudioUnitForMicrophoneMute mute=" << mute;
+ RTC_DCHECK_RUN_ON(thread_);
+ if (!audio_unit_) {
+ RTC_LOG(LS_ERROR) << "ReinitAudioUnitForMicrophoneMute called with null audio unit";
+ return -1;
+ }
+ if (audio_unit_->GetState() < VoiceProcessingAudioUnit::kUninitialized) {
+ RTC_LOG(LS_ERROR) << "ReinitAudioUnitForMicrophoneMute called in invalid audio unit state="
+ << audio_unit_->GetState();
+ return -1;
+ }
+
+ // AudioUnit を停止します
+ if (audio_unit_->GetState() == VoiceProcessingAudioUnit::kStarted) {
+ if (!audio_unit_->Stop()) {
+ RTC_LOG(LS_ERROR) << "ReinitAudioUnitForMicrophoneMute failed to stop audio unit";
+ return -1;
+ }
+ PrepareForNewStart();
+ }
+
+ // AudioUnit の初期化を解除します。SetMicrophoneMute 実行に必要です
+ if (!audio_unit_->Uninitialize()) {
+ RTC_LOG(LS_ERROR)
+ << "ReinitAudioUnitForMicrophoneMute failed to uninitialize audio unit";
+ return -1;
+ }
+
+ // AudioUnit の入力を無効化/有効化します。マイクインジケータ消灯/点灯のために必要です
+ if (!audio_unit_->SetMicrophoneMute(mute)) {
+ RTC_LOG(LS_ERROR) << "ReinitAudioUnitForMicrophoneMute failed to set microphone mute=" << mute;
+ return -1;
+ }
+
+ // 音声パラメータとバッファを作り直します。AudioUnit 再初期化後の想定フレームずれを防ぎます
+ SetupAudioBuffersForActiveAudioSession();
+
+ // AudioUnit を再度初期化します
+ if (!audio_unit_->Initialize(playout_parameters_.sample_rate())) {
+ RTC_LOG(LS_ERROR) << "ReinitAudioUnitForMicrophoneMute failed to reinitialize audio unit";
+ return -1;
+ }
+
+ // AudioUnit を再開して出力を戻します
+ OSStatus result = audio_unit_->Start();
+ if (result != noErr) {
+ RTC_OBJC_TYPE(RTCAudioSession)* session =
+ [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
+ [session notifyAudioUnitStartFailedWithError:result];
+ RTC_LOG(LS_ERROR)
+ << "ReinitAudioUnitForMicrophoneMute failed to restart audio unit, OSStatus="
+ << result;
+ return -1;
+ }
+
+ return 0;
+}
+
bool AudioDeviceIOS::Recording() const {
return recording_.load();
Expand All @@ -277,17 +362,18 @@ index 5ff5062..987deb8 100644
bool Recording() 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..9ac6904 100644
index e2ea360..a1cd5ca 100644
--- a/sdk/objc/native/src/audio/audio_device_module_ios.mm
+++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm
@@ -652,6 +652,30 @@
@@ -652,6 +652,32 @@
return result;
}

+int32_t AudioDeviceModuleIOS::PauseRecording() {
+ RTC_DLOG(LS_INFO) << __FUNCTION__;
+ CHECKinitialized_();
+ int32_t result = audio_device_->PauseRecording();
+ // StopRecording() での停止順序と同様にします
+ audio_device_buffer_.get()->StopRecording();
+ if (result < 0) {
+ ReportError(kRecordingFailed);
Expand All @@ -299,8 +385,9 @@ index e2ea360..9ac6904 100644
+int32_t AudioDeviceModuleIOS::ResumeRecording() {
+ RTC_DLOG(LS_INFO) << __FUNCTION__;
+ CHECKinitialized_();
+ int32_t result = audio_device_->ResumeRecording();
+ // StartRecording() での開始順序と同様にします
+ audio_device_buffer_.get()->StartRecording();
+ int32_t result = audio_device_->ResumeRecording();
+ if (result < 0) {
+ ReportError(kRecordingFailed);
+ }
Expand Down