summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/sdk/objc/components/audio/RTCAudioSessionConfiguration.m
blob: 39e9ac13ecc185b826b09718a3a4086cfee9d7de (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 *  Copyright 2016 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#import "RTCAudioSessionConfiguration.h"
#import "RTCAudioSession.h"

#import "helpers/RTCDispatcher.h"
#import "helpers/UIDevice+RTCDevice.h"

// Try to use mono to save resources. Also avoids channel format conversion
// in the I/O audio unit. Initial tests have shown that it is possible to use
// mono natively for built-in microphones and for BT headsets but not for
// wired headsets. Wired headsets only support stereo as native channel format
// but it is a low cost operation to do a format conversion to mono in the
// audio unit. Hence, we will not hit a RTC_CHECK in
// VerifyAudioParametersForActiveAudioSession() for a mismatch between the
// preferred number of channels and the actual number of channels.
const int kRTCAudioSessionPreferredNumberOfChannels = 1;

// Preferred hardware sample rate (unit is in Hertz). The client sample rate
// will be set to this value as well to avoid resampling the the audio unit's
// format converter. Note that, some devices, e.g. BT headsets, only supports
// 8000Hz as native sample rate.
const double kRTCAudioSessionHighPerformanceSampleRate = 48000.0;

// A lower sample rate will be used for devices with only one core
// (e.g. iPhone 4). The goal is to reduce the CPU load of the application.
const double kRTCAudioSessionLowComplexitySampleRate = 16000.0;

// Use a hardware I/O buffer size (unit is in seconds) that matches the 10ms
// size used by WebRTC. The exact actual size will differ between devices.
// Example: using 48kHz on iPhone 6 results in a native buffer size of
// ~10.6667ms or 512 audio frames per buffer. The FineAudioBuffer instance will
// take care of any buffering required to convert between native buffers and
// buffers used by WebRTC. It is beneficial for the performance if the native
// size is as an even multiple of 10ms as possible since it results in "clean"
// callback sequence without bursts of callbacks back to back.
const double kRTCAudioSessionHighPerformanceIOBufferDuration = 0.02;

// Use a larger buffer size on devices with only one core (e.g. iPhone 4).
// It will result in a lower CPU consumption at the cost of a larger latency.
// The size of 60ms is based on instrumentation that shows a significant
// reduction in CPU load compared with 10ms on low-end devices.
// TODO(henrika): monitor this size and determine if it should be modified.
const double kRTCAudioSessionLowComplexityIOBufferDuration = 0.06;

static RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *gWebRTCConfiguration = nil;

@implementation RTC_OBJC_TYPE (RTCAudioSessionConfiguration)

@synthesize category = _category;
@synthesize categoryOptions = _categoryOptions;
@synthesize mode = _mode;
@synthesize sampleRate = _sampleRate;
@synthesize ioBufferDuration = _ioBufferDuration;
@synthesize inputNumberOfChannels = _inputNumberOfChannels;
@synthesize outputNumberOfChannels = _outputNumberOfChannels;

- (instancetype)init {
  if (self = [super init]) {
    // Use a category which supports simultaneous recording and playback.
    // By default, using this category implies that our app’s audio is
    // nonmixable, hence activating the session will interrupt any other
    // audio sessions which are also nonmixable.
    _category = AVAudioSessionCategoryPlayAndRecord;
    _categoryOptions = AVAudioSessionCategoryOptionAllowBluetooth;

    // Specify mode for two-way voice communication (e.g. VoIP).
    _mode = AVAudioSessionModeVoiceChat;

    // Set the session's sample rate or the hardware sample rate.
    // It is essential that we use the same sample rate as stream format
    // to ensure that the I/O unit does not have to do sample rate conversion.
    // Set the preferred audio I/O buffer duration, in seconds.
    NSUInteger processorCount = [NSProcessInfo processInfo].processorCount;
    // Use best sample rate and buffer duration if the CPU has more than one
    // core.
    if (processorCount > 1 && [UIDevice deviceType] != RTCDeviceTypeIPhone4S) {
      _sampleRate = kRTCAudioSessionHighPerformanceSampleRate;
      _ioBufferDuration = kRTCAudioSessionHighPerformanceIOBufferDuration;
    } else {
      _sampleRate = kRTCAudioSessionLowComplexitySampleRate;
      _ioBufferDuration = kRTCAudioSessionLowComplexityIOBufferDuration;
    }

    // We try to use mono in both directions to save resources and format
    // conversions in the audio unit. Some devices does only support stereo;
    // e.g. wired headset on iPhone 6.
    // TODO(henrika): add support for stereo if needed.
    _inputNumberOfChannels = kRTCAudioSessionPreferredNumberOfChannels;
    _outputNumberOfChannels = kRTCAudioSessionPreferredNumberOfChannels;
  }
  return self;
}

+ (void)initialize {
  gWebRTCConfiguration = [[self alloc] init];
}

+ (instancetype)currentConfiguration {
  RTC_OBJC_TYPE(RTCAudioSession) *session = [RTC_OBJC_TYPE(RTCAudioSession) sharedInstance];
  RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *config =
      [[RTC_OBJC_TYPE(RTCAudioSessionConfiguration) alloc] init];
  config.category = session.category;
  config.categoryOptions = session.categoryOptions;
  config.mode = session.mode;
  config.sampleRate = session.sampleRate;
  config.ioBufferDuration = session.IOBufferDuration;
  config.inputNumberOfChannels = session.inputNumberOfChannels;
  config.outputNumberOfChannels = session.outputNumberOfChannels;
  return config;
}

+ (instancetype)webRTCConfiguration {
  @synchronized(self) {
    return (RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)gWebRTCConfiguration;
  }
}

+ (void)setWebRTCConfiguration:(RTC_OBJC_TYPE(RTCAudioSessionConfiguration) *)configuration {
  @synchronized(self) {
    gWebRTCConfiguration = configuration;
  }
}

@end