Skip to content

Commit 68167af

Browse files
authored
Allow custom audio processing by exposing AudioProcessingModule (#85)
* apm * progress * expose raw buffer * config * runtime delegate update * always create audio processing adapter * delegate nullable * dynamic delegate update thread safety * fix delegate life cycle when swapped * refactor * avoid crash when no apm is passed in * format * make delegate weak & docs * fix memory issue
1 parent ebaa79b commit 68167af

19 files changed

+875
-140
lines changed

sdk/BUILD.gn

Lines changed: 152 additions & 129 deletions
Large diffs are not rendered by default.

sdk/objc/api/peerconnection/RTCAudioTrack.mm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ - (instancetype)initWithFactory:(RTC_OBJC_TYPE(RTCPeerConnectionFactory) *)facto
209209
NSParameterAssert(type == RTCMediaStreamTrackTypeAudio);
210210
if (self = [super initWithFactory:factory nativeTrack:nativeTrack type:type]) {
211211
RTC_LOG(LS_INFO) << "RTCAudioTrack init";
212+
_lock = OS_UNFAIR_LOCK_INIT;
212213
_renderers = [NSHashTable weakObjectsHashTable];
213214
_audioConverter = new rtc::RefCountedObject<webrtc::AudioSinkConverter>(self, &_lock);
214215
}

sdk/objc/api/peerconnection/RTCPeerConnectionFactory+Native.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,6 @@ NS_ASSUME_NONNULL_BEGIN
7373
initWithEncoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)>)encoderFactory
7474
decoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)decoderFactory;
7575

76-
- (instancetype)
77-
initWithBypassVoiceProcessing:(BOOL)bypassVoiceProcessing
78-
encoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)>)encoderFactory
79-
decoderFactory:
80-
(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)decoderFactory;
81-
8276
/** Initialize an RTCPeerConnection with a configuration, constraints, and
8377
* dependencies.
8478
*/

sdk/objc/api/peerconnection/RTCPeerConnectionFactory.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ typedef NS_ENUM(NSInteger, RTCRtpMediaType);
3838
(RTCSSLCertificateVerifier);
3939
@protocol RTC_OBJC_TYPE
4040
(RTCAudioDevice);
41+
@protocol RTC_OBJC_TYPE
42+
(RTCAudioProcessingModule);
4143

4244
RTC_OBJC_EXPORT
4345
@interface RTC_OBJC_TYPE (RTCPeerConnectionFactory) : NSObject
@@ -60,8 +62,9 @@ RTC_OBJC_EXPORT
6062
- (instancetype)
6163
initWithBypassVoiceProcessing:(BOOL)bypassVoiceProcessing
6264
encoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)>)encoderFactory
63-
decoderFactory:
64-
(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)decoderFactory;
65+
decoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)decoderFactory
66+
audioProcessingModule:
67+
(nullable id<RTC_OBJC_TYPE(RTCAudioProcessingModule)>)audioProcessingModule;
6568

6669
@property(nonatomic, readonly) RTCAudioDeviceModule *audioDeviceModule;
6770

sdk/objc/api/peerconnection/RTCPeerConnectionFactory.mm

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@
5353
#include "sdk/objc/native/src/objc_video_decoder_factory.h"
5454
#include "sdk/objc/native/src/objc_video_encoder_factory.h"
5555

56+
#import "components/audio/RTCAudioProcessingModule.h"
57+
#import "components/audio/RTCDefaultAudioProcessingModule+Private.h"
58+
5659
#if defined(WEBRTC_IOS)
5760
#import "sdk/objc/native/api/audio_device_module.h"
5861
#endif
@@ -62,6 +65,7 @@ @implementation RTC_OBJC_TYPE (RTCPeerConnectionFactory) {
6265
std::unique_ptr<rtc::Thread> _workerThread;
6366
std::unique_ptr<rtc::Thread> _signalingThread;
6467
rtc::scoped_refptr<webrtc::AudioDeviceModule> _nativeAudioDeviceModule;
68+
RTCDefaultAudioProcessingModule *_defaultAudioProcessingModule;
6569

6670
BOOL _hasStartedAecDump;
6771
}
@@ -144,8 +148,9 @@ - (instancetype)init {
144148
- (instancetype)
145149
initWithBypassVoiceProcessing:(BOOL)bypassVoiceProcessing
146150
encoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoEncoderFactory)>)encoderFactory
147-
decoderFactory:
148-
(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)decoderFactory {
151+
decoderFactory:(nullable id<RTC_OBJC_TYPE(RTCVideoDecoderFactory)>)decoderFactory
152+
audioProcessingModule:
153+
(nullable id<RTC_OBJC_TYPE(RTCAudioProcessingModule)>)audioProcessingModule {
149154
#ifdef HAVE_NO_MEDIA
150155
return [self initWithNoMedia];
151156
#else
@@ -158,12 +163,21 @@ - (instancetype)init {
158163
native_decoder_factory = webrtc::ObjCToNativeVideoDecoderFactory(decoderFactory);
159164
}
160165
rtc::scoped_refptr<webrtc::AudioDeviceModule> audio_device_module = [self createAudioDeviceModule:bypassVoiceProcessing];
166+
167+
if ([audioProcessingModule isKindOfClass:[RTCDefaultAudioProcessingModule class]]) {
168+
_defaultAudioProcessingModule = (RTCDefaultAudioProcessingModule *)audioProcessingModule;
169+
} else {
170+
_defaultAudioProcessingModule = [[RTCDefaultAudioProcessingModule alloc] init];
171+
}
172+
173+
NSLog(@"AudioProcessingModule: %@", _defaultAudioProcessingModule);
174+
161175
return [self initWithNativeAudioEncoderFactory:webrtc::CreateBuiltinAudioEncoderFactory()
162176
nativeAudioDecoderFactory:webrtc::CreateBuiltinAudioDecoderFactory()
163177
nativeVideoEncoderFactory:std::move(native_encoder_factory)
164178
nativeVideoDecoderFactory:std::move(native_decoder_factory)
165179
audioDeviceModule:audio_device_module.get()
166-
audioProcessingModule:nullptr
180+
audioProcessingModule:_defaultAudioProcessingModule.nativeAudioProcessingModule
167181
bypassVoiceProcessing:bypassVoiceProcessing];
168182
#endif
169183
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2023 LiveKit
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import "RTCAudioBuffer.h"
18+
19+
#include "modules/audio_processing/audio_buffer.h"
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
@interface RTC_OBJC_TYPE (RTCAudioBuffer)()
24+
25+
- (instancetype)initWithNativeType: (webrtc::AudioBuffer *) audioBuffer;
26+
27+
@end
28+
29+
NS_ASSUME_NONNULL_END
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2023 LiveKit
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <Foundation/Foundation.h>
18+
19+
#import "RTCMacros.h"
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
RTC_OBJC_EXPORT
24+
@interface RTC_OBJC_TYPE (RTCAudioBuffer) : NSObject
25+
26+
@property(nonatomic, readonly) size_t channels;
27+
@property(nonatomic, readonly) size_t frames;
28+
@property(nonatomic, readonly) size_t framesPerBand;
29+
@property(nonatomic, readonly) size_t bands;
30+
31+
// Returns pointer arrays. Index range from 0 to `frames`.
32+
- (float* _Nonnull)rawBufferForChannel:(size_t)channel;
33+
34+
// TODO: More convenience methods...
35+
36+
@end
37+
38+
NS_ASSUME_NONNULL_END
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2023 LiveKit
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import "RTCAudioBuffer.h"
18+
19+
#include "modules/audio_processing/audio_buffer.h"
20+
21+
@implementation RTC_OBJC_TYPE (RTCAudioBuffer) {
22+
// Raw
23+
webrtc::AudioBuffer *_audioBuffer;
24+
}
25+
26+
- (size_t)channels {
27+
return _audioBuffer->num_channels();
28+
}
29+
30+
- (size_t)frames {
31+
return _audioBuffer->num_frames();
32+
}
33+
34+
- (size_t)framesPerBand {
35+
return _audioBuffer->num_frames_per_band();
36+
}
37+
38+
- (size_t)bands {
39+
return _audioBuffer->num_bands();
40+
}
41+
42+
- (float *)rawBufferForChannel:(size_t)channel {
43+
return _audioBuffer->channels()[channel];
44+
}
45+
46+
#pragma mark - Private
47+
48+
- (instancetype)initWithNativeType:(webrtc::AudioBuffer *)audioBuffer {
49+
if (self = [super init]) {
50+
_audioBuffer = audioBuffer;
51+
}
52+
return self;
53+
}
54+
55+
@end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2023 LiveKit
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import "RTCAudioCustomProcessingAdapter.h"
18+
#import "RTCAudioCustomProcessingDelegate.h"
19+
#import "RTCMacros.h"
20+
21+
#include "modules/audio_processing/include/audio_processing.h"
22+
23+
NS_ASSUME_NONNULL_BEGIN
24+
25+
@interface RTCAudioCustomProcessingAdapter ()
26+
27+
// Thread safe set/get with os_unfair_lock.
28+
@property(nonatomic, weak, nullable) id<RTCAudioCustomProcessingDelegate>
29+
audioCustomProcessingDelegate;
30+
31+
// Direct read access without lock.
32+
@property(nonatomic, readonly, weak, nullable) id<RTCAudioCustomProcessingDelegate>
33+
rawAudioCustomProcessingDelegate;
34+
35+
@property(nonatomic, readonly) std::unique_ptr<webrtc::CustomProcessing>
36+
nativeAudioCustomProcessingModule;
37+
38+
- (instancetype)initWithDelegate:
39+
(nullable id<RTCAudioCustomProcessingDelegate>)audioCustomProcessingDelegate;
40+
41+
@end
42+
43+
NS_ASSUME_NONNULL_END
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2023 LiveKit
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#import <Foundation/Foundation.h>
18+
#import "RTCMacros.h"
19+
20+
NS_ASSUME_NONNULL_BEGIN
21+
22+
@interface RTCAudioCustomProcessingAdapter : NSObject
23+
24+
- (instancetype)init NS_UNAVAILABLE;
25+
26+
@end
27+
28+
NS_ASSUME_NONNULL_END

0 commit comments

Comments
 (0)