Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
57998be
iOS SDK の RTCAudioSession に pauseRecording()/resumeRecording() 追加
t-miya Dec 9, 2025
41600a3
pause_recording 中の stopRecording() 処理を修正、dispose を修正
t-miya Dec 9, 2025
4a155cd
recording_.load() 引数を修正
t-miya Dec 9, 2025
6324529
startRecording() がポーズ中に呼ばれた場合は resumeRecording() にフォールスルーする、resumeRec…
t-miya Dec 9, 2025
559965f
resumeRecording() 内で startRecording() に失敗した場合 pause 状態に戻す
t-miya Dec 9, 2025
a184f8c
公開APIを RTCAudioSession から RTCAudioDeviceModule に移行
t-miya Dec 10, 2025
5ed4205
RTCAudioModuleDevice を RTCPeerConnectionFactory で管理するよう修正
t-miya Dec 11, 2025
9359604
RTCAudioDeviceModule の weak_ptr を外す
t-miya Dec 11, 2025
01df8d1
AudioDeviceIOS 内の pauseRecording()/resumeRecording() は recording_ フラグ…
t-miya Dec 12, 2025
4bd7c15
RTCPeerConnectionFactory の initWithEncoderFactory を audioDevice版、audi…
t-miya Dec 12, 2025
d5d0db9
RTCAudioDeviceModule+Private.h を追加、その他関数の整理
t-miya Dec 15, 2025
8cc1829
不要なコメント削除
t-miya Dec 15, 2025
4506f17
不要な分岐、ifdef の整理等
t-miya Dec 16, 2025
61f6963
改行差分を除去
t-miya Dec 16, 2025
bbddaa4
CHANGES 修正
t-miya Dec 17, 2025
18b7e38
コメント修正
t-miya Dec 17, 2025
05cb368
initWithEncoderFactory に関するコメントを ObjC の形式に修正
t-miya Dec 17, 2025
c80883e
コメント中の関数に関する標記を ObjC 形式に修正
t-miya Dec 17, 2025
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
7 changes: 7 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ VERSION ファイルを上げただけの場合は変更履歴記録は不要。

## タイムライン

- 2025-12-12 [ADD] iOS SDK に RTCAudioDeviceModule を追加する
- iOS 実機のマイクインジケータが消灯状態のミュートをできるようにする
- 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
- 2025-12-10 [ADD] iOS SDK 向けに RTCAudioTrackSink を追加する
Expand Down
313 changes: 313 additions & 0 deletions patches/ios_audio_pause_resume.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,313 @@
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index f61cf30..aab3684 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",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

現状では audio components 関連は RTCAudioDeviceModule のみのため新たにターゲットは切らずここに置く

]

if (target_platform != "tvos") {
@@ -1369,6 +1370,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/api/peerconnection/RTCPeerConnectionFactory.h b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h
index 8287bcf..7090921 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h
@@ -11,6 +11,7 @@
#import <Foundation/Foundation.h>

#import "sdk/objc/base/RTCMacros.h"
+#import "sdk/objc/components/audio/RTCAudioDeviceModule.h"

NS_ASSUME_NONNULL_BEGIN

@@ -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);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@protocol~ の下に置いていたのを @class~ の並びの方に移動しました

@protocol RTC_OBJC_TYPE
(RTCPeerConnectionDelegate);
@protocol RTC_OBJC_TYPE
@@ -61,6 +63,17 @@ RTC_OBJC_EXPORT
audioDevice:
(nullable id<RTC_OBJC_TYPE(RTCAudioDevice)>)audioDevice;

+/**
+ * Video encoder/decorder ファクトリと RTCAudioDeviceModule 差し込みによる初期化
+ */
+- (instancetype)
+ initWithEncoderFactory:
+ (nullable id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)>)encoderFactory
+ decoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)
+ decoderFactory
+ 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..0c20512 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm
+++ b/sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm
@@ -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"
@@ -189,6 +190,43 @@ - (instancetype)init {
#endif
}

+// RTCAudioDeviceModule* により ADM を初期化する
+// audioDeviceModule から Native ADM を取得して dependencies.adm にセットする処理以外は
+// initWithEncoderFactory:decoderFactory:audioDevice: と同様の実装
+- (instancetype)
+ initWithEncoderFactory:
+ (nullable id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)>)encoderFactory
+ decoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)
+ decoderFactory
+ audioDeviceModule:
+ (nullable RTC_OBJC_TYPE(RTCAudioDeviceModule)*)audioDeviceModule {
+#ifdef HAVE_NO_MEDIA
+ return [self initWithNoMedia];
+#else
+ 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);
+ }
+ if (audioDeviceModule) {
+ auto adm_ptr = [audioDeviceModule nativeAudioDeviceModule];
+ dependencies.adm = adm_ptr;
+ } else {
+ dependencies.adm = webrtc::CreateAudioDeviceModule(*dependencies.env);
+ }
+ return [self initWithMediaAndDependencies:dependencies];
+#endif
+}
+
- (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..3e67c85
--- /dev/null
+++ b/sdk/objc/components/audio/RTCAudioDeviceModule+Private.h
@@ -0,0 +1,11 @@
+// 公開APIで隠している C++ 型のネイティブ ADM ポインタ webrtc::AudioDeviceModule* を安全に取得するためのヘッダ
+// C++ 用の型 webrtc::AudioDeviceModule を扱うため ObjC++ からのみインクルードされる想定
+#import "RTCAudioDeviceModule.h"
+
+#include "api/audio/audio_device.h"
+
+@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) ()
+
+- (webrtc::scoped_refptr<webrtc::AudioDeviceModule>)nativeAudioDeviceModule;
+
+@end
diff --git a/sdk/objc/components/audio/RTCAudioDeviceModule.h b/sdk/objc/components/audio/RTCAudioDeviceModule.h
new file mode 100644
index 0000000..bd3c425
--- /dev/null
+++ b/sdk/objc/components/audio/RTCAudioDeviceModule.h
@@ -0,0 +1,17 @@
+// iOS 用の AudioDeviceModule を生成し、pauseRecording()/resumeRecording() を公開するためのラッパー
+#import <Foundation/Foundation.h>
+
+#import "sdk/objc/base/RTCMacros.h"
+
+RTC_OBJC_EXPORT
+@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) : NSObject
+
+// 内部で AudioDeviceModuleIOS を生成する
+- (instancetype)init;
+
+// 録音を一時停止する。内部で 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..d1e495f
--- /dev/null
+++ b/sdk/objc/components/audio/RTCAudioDeviceModule.mm
@@ -0,0 +1,40 @@
+#import "RTCAudioDeviceModule.h"
+
+#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"
+
+@interface RTC_OBJC_TYPE(RTCAudioDeviceModule) () {
+ webrtc::scoped_refptr<webrtc::AudioDeviceModule> _adm;
+}
+@end
+
+@implementation RTC_OBJC_TYPE(RTCAudioDeviceModule)
+
+- (instancetype)init {
+ self = [super init];
+ if (self) {
+ auto env = webrtc::CreateEnvironment();
+ _adm = webrtc::CreateAudioDeviceModule(env);
+ }
+ return self;
+}
+
+- (webrtc::scoped_refptr<webrtc::AudioDeviceModule>)nativeAudioDeviceModule {
+ return _adm;
+}
+
+- (NSInteger)pauseRecording {
+ auto ptr =
+ static_cast<webrtc::ios_adm::AudioDeviceModuleIOS*>(_adm.get());
+ return ptr->PauseRecording();
+}
+
+- (NSInteger)resumeRecording {
+ auto ptr =
+ static_cast<webrtc::ios_adm::AudioDeviceModuleIOS*>(_adm.get());
+ return ptr->ResumeRecording();
+}
+
+@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
--- 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;

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
--- 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() {
int32_t AudioDeviceIOS::StopRecording() {
LOGI() << "StopRecording";
RTC_DCHECK_RUN_ON(thread_);
- if (!audio_is_initialized_ || !recording_.load()) {
+ // 元々は !recording_.load() との OR 判定だったが、PauseRecording 追加により
+ // StopRecording 実行前に recording_ が 0 となることがあるため分岐を修正している
+ if (!audio_is_initialized_) {
return 0;
}
if (!playing_.load()) {
@@ -340,6 +342,36 @@ static void LogDeviceInfo() {
return 0;
}

+int32_t AudioDeviceIOS::PauseRecording() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PauseRecording/ResumeRecording って、StartRecording/StopRecording と何が違うんでしょうか。見てる感じ StartRecording と StopRecording だけで事足りるように見えます

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StopRecording は内部で ShutdownPlayOrRecord() によりデバイス解放する部分が異なっています

ResumeRecording() は直接 StartRecording() を呼んでよいかもしれないです。確認します

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AudioDeviceIOS 内の PauseRecording/ResumeRecording は recording_ フラグの操作のみを行い、
startRecording() 等を呼ばないように修正しました

+ LOGI() << "PauseRecording";
+ RTC_DCHECK_RUN_ON(thread_);
+ if (!audio_is_initialized_) {
+ RTC_LOG(LS_WARNING) << "PauseRecording called before audio is initialized";
+ return 0;
+ }
+ if (!recording_.load()) {
+ RTC_LOG(LS_WARNING) << "PauseRecording called while not recording";
+ return 0;
+ }
+ recording_.store(0, std::memory_order_release);
+ return 0;
+}
+
+int32_t AudioDeviceIOS::ResumeRecording() {
+ LOGI() << "ResumeRecording";
+ RTC_DCHECK_RUN_ON(thread_);
+ if (!audio_is_initialized_) {
+ RTC_LOG(LS_WARNING) << "ResumeRecording called before audio is initialized";
+ return 0;
+ }
+ if (recording_.load()) {
+ RTC_LOG(LS_WARNING) << "ResumeRecording called while recording";
+ return 0;
+ }
+ recording_.store(1, std::memory_order_release);
+ return 0;
+}
+
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..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 {
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;

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
+++ b/sdk/objc/native/src/audio/audio_device_module_ios.mm
@@ -652,6 +652,30 @@
return result;
}

+int32_t AudioDeviceModuleIOS::PauseRecording() {
+ RTC_DLOG(LS_INFO) << __FUNCTION__;
+ CHECKinitialized_();
+ int32_t result = audio_device_->PauseRecording();
+ audio_device_buffer_.get()->StopRecording();
+ 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();
+ audio_device_buffer_.get()->StartRecording();
+ if (result < 0) {
+ ReportError(kRecordingFailed);
+ }
+ RTC_DLOG(LS_INFO) << "output: " << result;
+ return result;
+}
+
int32_t AudioDeviceModuleIOS::StopRecording() {
RTC_DLOG(LS_INFO) << __FUNCTION__;
CHECKinitialized_();
1 change: 1 addition & 0 deletions run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down