OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #if !defined(__has_feature) || !__has_feature(objc_arc) | 11 #if !defined(__has_feature) || !__has_feature(objc_arc) |
12 #error "This file requires ARC support." | 12 #error "This file requires ARC support." |
13 #endif | 13 #endif |
14 | 14 |
15 #import <AVFoundation/AVFoundation.h> | 15 #import <AVFoundation/AVFoundation.h> |
16 #import <Foundation/Foundation.h> | 16 #import <Foundation/Foundation.h> |
17 | 17 |
18 #include "webrtc/modules/audio_device/ios/audio_device_ios.h" | 18 #include "webrtc/modules/audio_device/ios/audio_device_ios.h" |
19 | 19 |
20 #include "webrtc/base/atomicops.h" | 20 #include "webrtc/base/atomicops.h" |
21 #include "webrtc/base/checks.h" | 21 #include "webrtc/base/checks.h" |
22 #include "webrtc/base/criticalsection.h" | 22 #include "webrtc/base/criticalsection.h" |
23 #include "webrtc/base/logging.h" | 23 #include "webrtc/base/logging.h" |
24 #include "webrtc/base/thread_annotations.h" | 24 #include "webrtc/base/thread_annotations.h" |
25 #include "webrtc/modules/audio_device/fine_audio_buffer.h" | 25 #include "webrtc/modules/audio_device/fine_audio_buffer.h" |
26 #include "webrtc/modules/utility/include/helpers_ios.h" | 26 #include "webrtc/modules/utility/include/helpers_ios.h" |
27 | 27 |
| 28 #import "webrtc/modules/audio_device/ios/objc/RTCAudioSession.h" |
| 29 |
28 namespace webrtc { | 30 namespace webrtc { |
29 | 31 |
30 // Protects |g_audio_session_users|. | |
31 static rtc::GlobalLockPod g_lock; | |
32 | |
33 // Counts number of users (=instances of this object) who needs an active | |
34 // audio session. This variable is used to ensure that we only activate an audio | |
35 // session for the first user and deactivate it for the last. | |
36 // Member is static to ensure that the value is counted for all instances | |
37 // and not per instance. | |
38 static int g_audio_session_users GUARDED_BY(g_lock) = 0; | |
39 | |
40 #define LOGI() LOG(LS_INFO) << "AudioDeviceIOS::" | 32 #define LOGI() LOG(LS_INFO) << "AudioDeviceIOS::" |
41 | 33 |
42 #define LOG_AND_RETURN_IF_ERROR(error, message) \ | 34 #define LOG_AND_RETURN_IF_ERROR(error, message) \ |
43 do { \ | 35 do { \ |
44 OSStatus err = error; \ | 36 OSStatus err = error; \ |
45 if (err) { \ | 37 if (err) { \ |
46 LOG(LS_ERROR) << message << ": " << err; \ | 38 LOG(LS_ERROR) << message << ": " << err; \ |
47 return false; \ | 39 return false; \ |
48 } \ | 40 } \ |
49 } while (0) | 41 } while (0) |
(...skipping 40 matching lines...) Loading... |
90 // ADM instances. A fall-back solution is to allow multiple sequential calls | 82 // ADM instances. A fall-back solution is to allow multiple sequential calls |
91 // with as small delay between each. This factor sets the max number of allowed | 83 // with as small delay between each. This factor sets the max number of allowed |
92 // initialization attempts. | 84 // initialization attempts. |
93 const int kMaxNumberOfAudioUnitInitializeAttempts = 5; | 85 const int kMaxNumberOfAudioUnitInitializeAttempts = 5; |
94 | 86 |
95 | 87 |
96 using ios::CheckAndLogError; | 88 using ios::CheckAndLogError; |
97 | 89 |
98 // Verifies that the current audio session supports input audio and that the | 90 // Verifies that the current audio session supports input audio and that the |
99 // required category and mode are enabled. | 91 // required category and mode are enabled. |
100 static bool VerifyAudioSession(AVAudioSession* session) { | 92 static bool VerifyAudioSession(RTCAudioSession* session) { |
101 LOG(LS_INFO) << "VerifyAudioSession"; | 93 LOG(LS_INFO) << "VerifyAudioSession"; |
102 // Ensure that the device currently supports audio input. | 94 // Ensure that the device currently supports audio input. |
103 if (!session.isInputAvailable) { | 95 if (!session.inputAvailable) { |
104 LOG(LS_ERROR) << "No audio input path is available!"; | 96 LOG(LS_ERROR) << "No audio input path is available!"; |
105 return false; | 97 return false; |
106 } | 98 } |
107 | 99 |
108 // Ensure that the required category and mode are actually activated. | 100 // Ensure that the required category and mode are actually activated. |
109 if (![session.category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) { | 101 if (![session.category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) { |
110 LOG(LS_ERROR) | 102 LOG(LS_ERROR) |
111 << "Failed to set category to AVAudioSessionCategoryPlayAndRecord"; | 103 << "Failed to set category to AVAudioSessionCategoryPlayAndRecord"; |
112 return false; | 104 return false; |
113 } | 105 } |
114 if (![session.mode isEqualToString:AVAudioSessionModeVoiceChat]) { | 106 if (![session.mode isEqualToString:AVAudioSessionModeVoiceChat]) { |
115 LOG(LS_ERROR) << "Failed to set mode to AVAudioSessionModeVoiceChat"; | 107 LOG(LS_ERROR) << "Failed to set mode to AVAudioSessionModeVoiceChat"; |
116 return false; | 108 return false; |
117 } | 109 } |
118 return true; | 110 return true; |
119 } | 111 } |
120 | 112 |
121 // Activates an audio session suitable for full duplex VoIP sessions when | 113 // Activates an audio session suitable for full duplex VoIP sessions when |
122 // |activate| is true. Also sets the preferred sample rate and IO buffer | 114 // |activate| is true. Also sets the preferred sample rate and IO buffer |
123 // duration. Deactivates an active audio session if |activate| is set to false. | 115 // duration. Deactivates an active audio session if |activate| is set to false. |
124 static bool ActivateAudioSession(AVAudioSession* session, bool activate) | 116 static bool ActivateAudioSession(RTCAudioSession* session, bool activate) { |
125 EXCLUSIVE_LOCKS_REQUIRED(g_lock) { | |
126 LOG(LS_INFO) << "ActivateAudioSession(" << activate << ")"; | 117 LOG(LS_INFO) << "ActivateAudioSession(" << activate << ")"; |
127 @autoreleasepool { | |
128 NSError* error = nil; | |
129 BOOL success = NO; | |
130 | 118 |
131 if (!activate) { | 119 NSError* error = nil; |
132 // Deactivate the audio session using an extra option and then return. | 120 BOOL success = NO; |
133 // AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation is used to | |
134 // ensure that other audio sessions that were interrupted by our session | |
135 // can return to their active state. It is recommended for VoIP apps to | |
136 // use this option. | |
137 success = [session | |
138 setActive:NO | |
139 withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation | |
140 error:&error]; | |
141 return CheckAndLogError(success, error); | |
142 } | |
143 | 121 |
144 // Go ahead and active our own audio session since |activate| is true. | 122 [session lockForConfiguration]; |
145 // Use a category which supports simultaneous recording and playback. | 123 if (!activate) { |
146 // By default, using this category implies that our app’s audio is | 124 success = [session setActive:NO |
147 // nonmixable, hence activating the session will interrupt any other | 125 error:&error]; |
148 // audio sessions which are also nonmixable. | 126 [session unlockForConfiguration]; |
149 if (session.category != AVAudioSessionCategoryPlayAndRecord) { | 127 return CheckAndLogError(success, error); |
150 error = nil; | 128 } |
151 success = [session setCategory:AVAudioSessionCategoryPlayAndRecord | |
152 withOptions:AVAudioSessionCategoryOptionAllowBluetooth | |
153 error:&error]; | |
154 RTC_DCHECK(CheckAndLogError(success, error)); | |
155 } | |
156 | 129 |
157 // Specify mode for two-way voice communication (e.g. VoIP). | 130 // Go ahead and active our own audio session since |activate| is true. |
158 if (session.mode != AVAudioSessionModeVoiceChat) { | 131 // Use a category which supports simultaneous recording and playback. |
159 error = nil; | 132 // By default, using this category implies that our app’s audio is |
160 success = [session setMode:AVAudioSessionModeVoiceChat error:&error]; | 133 // nonmixable, hence activating the session will interrupt any other |
161 RTC_DCHECK(CheckAndLogError(success, error)); | 134 // audio sessions which are also nonmixable. |
162 } | 135 if (session.category != AVAudioSessionCategoryPlayAndRecord) { |
| 136 error = nil; |
| 137 success = [session setCategory:AVAudioSessionCategoryPlayAndRecord |
| 138 withOptions:AVAudioSessionCategoryOptionAllowBluetooth |
| 139 error:&error]; |
| 140 RTC_DCHECK(CheckAndLogError(success, error)); |
| 141 } |
163 | 142 |
164 // Set the session's sample rate or the hardware sample rate. | 143 // Specify mode for two-way voice communication (e.g. VoIP). |
165 // It is essential that we use the same sample rate as stream format | 144 if (session.mode != AVAudioSessionModeVoiceChat) { |
166 // to ensure that the I/O unit does not have to do sample rate conversion. | |
167 error = nil; | 145 error = nil; |
168 success = | 146 success = [session setMode:AVAudioSessionModeVoiceChat error:&error]; |
169 [session setPreferredSampleRate:kPreferredSampleRate error:&error]; | |
170 RTC_DCHECK(CheckAndLogError(success, error)); | 147 RTC_DCHECK(CheckAndLogError(success, error)); |
| 148 } |
171 | 149 |
172 // Set the preferred audio I/O buffer duration, in seconds. | 150 // Set the session's sample rate or the hardware sample rate. |
173 error = nil; | 151 // It is essential that we use the same sample rate as stream format |
174 success = [session setPreferredIOBufferDuration:kPreferredIOBufferDuration | 152 // to ensure that the I/O unit does not have to do sample rate conversion. |
175 error:&error]; | 153 error = nil; |
176 RTC_DCHECK(CheckAndLogError(success, error)); | 154 success = |
| 155 [session setPreferredSampleRate:kPreferredSampleRate error:&error]; |
| 156 RTC_DCHECK(CheckAndLogError(success, error)); |
177 | 157 |
178 // Activate the audio session. Activation can fail if another active audio | 158 // Set the preferred audio I/O buffer duration, in seconds. |
179 // session (e.g. phone call) has higher priority than ours. | 159 error = nil; |
180 error = nil; | 160 success = [session setPreferredIOBufferDuration:kPreferredIOBufferDuration |
181 success = [session setActive:YES error:&error]; | 161 error:&error]; |
182 if (!CheckAndLogError(success, error)) { | 162 RTC_DCHECK(CheckAndLogError(success, error)); |
183 return false; | |
184 } | |
185 | 163 |
186 // Ensure that the active audio session has the correct category and mode. | 164 // Activate the audio session. Activation can fail if another active audio |
187 if (!VerifyAudioSession(session)) { | 165 // session (e.g. phone call) has higher priority than ours. |
188 LOG(LS_ERROR) << "Failed to verify audio session category and mode"; | 166 error = nil; |
189 return false; | 167 success = [session setActive:YES error:&error]; |
190 } | 168 if (!CheckAndLogError(success, error)) { |
| 169 [session unlockForConfiguration]; |
| 170 return false; |
| 171 } |
191 | 172 |
192 // Try to set the preferred number of hardware audio channels. These calls | 173 // Ensure that the active audio session has the correct category and mode. |
193 // must be done after setting the audio session’s category and mode and | 174 if (!VerifyAudioSession(session)) { |
194 // activating the session. | 175 LOG(LS_ERROR) << "Failed to verify audio session category and mode"; |
195 // We try to use mono in both directions to save resources and format | 176 [session unlockForConfiguration]; |
196 // conversions in the audio unit. Some devices does only support stereo; | 177 return false; |
197 // e.g. wired headset on iPhone 6. | |
198 // TODO(henrika): add support for stereo if needed. | |
199 error = nil; | |
200 success = | |
201 [session setPreferredInputNumberOfChannels:kPreferredNumberOfChannels | |
202 error:&error]; | |
203 RTC_DCHECK(CheckAndLogError(success, error)); | |
204 error = nil; | |
205 success = | |
206 [session setPreferredOutputNumberOfChannels:kPreferredNumberOfChannels | |
207 error:&error]; | |
208 RTC_DCHECK(CheckAndLogError(success, error)); | |
209 return true; | |
210 } | 178 } |
| 179 |
| 180 // Try to set the preferred number of hardware audio channels. These calls |
| 181 // must be done after setting the audio session’s category and mode and |
| 182 // activating the session. |
| 183 // We try to use mono in both directions to save resources and format |
| 184 // conversions in the audio unit. Some devices does only support stereo; |
| 185 // e.g. wired headset on iPhone 6. |
| 186 // TODO(henrika): add support for stereo if needed. |
| 187 error = nil; |
| 188 success = |
| 189 [session setPreferredInputNumberOfChannels:kPreferredNumberOfChannels |
| 190 error:&error]; |
| 191 RTC_DCHECK(CheckAndLogError(success, error)); |
| 192 error = nil; |
| 193 success = |
| 194 [session setPreferredOutputNumberOfChannels:kPreferredNumberOfChannels |
| 195 error:&error]; |
| 196 RTC_DCHECK(CheckAndLogError(success, error)); |
| 197 [session unlockForConfiguration]; |
| 198 return true; |
211 } | 199 } |
212 | 200 |
213 // An application can create more than one ADM and start audio streaming | 201 // An application can create more than one ADM and start audio streaming |
214 // for all of them. It is essential that we only activate the app's audio | 202 // for all of them. It is essential that we only activate the app's audio |
215 // session once (for the first one) and deactivate it once (for the last). | 203 // session once (for the first one) and deactivate it once (for the last). |
216 static bool ActivateAudioSession() { | 204 static bool ActivateAudioSession() { |
217 LOGI() << "ActivateAudioSession"; | 205 LOGI() << "ActivateAudioSession"; |
218 rtc::GlobalLockScope ls(&g_lock); | 206 RTCAudioSession* session = [RTCAudioSession sharedInstance]; |
219 if (g_audio_session_users == 0) { | 207 return ActivateAudioSession(session, true); |
220 // The system provides an audio session object upon launch of an | |
221 // application. However, we must initialize the session in order to | |
222 // handle interruptions. Implicit initialization occurs when obtaining | |
223 // a reference to the AVAudioSession object. | |
224 AVAudioSession* session = [AVAudioSession sharedInstance]; | |
225 // Try to activate the audio session and ask for a set of preferred audio | |
226 // parameters. | |
227 if (!ActivateAudioSession(session, true)) { | |
228 LOG(LS_ERROR) << "Failed to activate the audio session"; | |
229 return false; | |
230 } | |
231 LOG(LS_INFO) << "The audio session is now activated"; | |
232 } | |
233 ++g_audio_session_users; | |
234 LOG(LS_INFO) << "Number of audio session users: " << g_audio_session_users; | |
235 return true; | |
236 } | 208 } |
237 | 209 |
238 // If more than one object is using the audio session, ensure that only the | 210 // If more than one object is using the audio session, ensure that only the |
239 // last object deactivates. Apple recommends: "activate your audio session | 211 // last object deactivates. Apple recommends: "activate your audio session |
240 // only as needed and deactivate it when you are not using audio". | 212 // only as needed and deactivate it when you are not using audio". |
241 static bool DeactivateAudioSession() { | 213 static bool DeactivateAudioSession() { |
242 LOGI() << "DeactivateAudioSession"; | 214 LOGI() << "DeactivateAudioSession"; |
243 rtc::GlobalLockScope ls(&g_lock); | 215 RTCAudioSession* session = [RTCAudioSession sharedInstance]; |
244 if (g_audio_session_users == 1) { | 216 return ActivateAudioSession(session, false); |
245 AVAudioSession* session = [AVAudioSession sharedInstance]; | |
246 if (!ActivateAudioSession(session, false)) { | |
247 LOG(LS_ERROR) << "Failed to deactivate the audio session"; | |
248 return false; | |
249 } | |
250 LOG(LS_INFO) << "Our audio session is now deactivated"; | |
251 } | |
252 --g_audio_session_users; | |
253 LOG(LS_INFO) << "Number of audio session users: " << g_audio_session_users; | |
254 return true; | |
255 } | 217 } |
256 | 218 |
257 #if !defined(NDEBUG) | 219 #if !defined(NDEBUG) |
258 // Helper method for printing out an AudioStreamBasicDescription structure. | 220 // Helper method for printing out an AudioStreamBasicDescription structure. |
259 static void LogABSD(AudioStreamBasicDescription absd) { | 221 static void LogABSD(AudioStreamBasicDescription absd) { |
260 char formatIDString[5]; | 222 char formatIDString[5]; |
261 UInt32 formatID = CFSwapInt32HostToBig(absd.mFormatID); | 223 UInt32 formatID = CFSwapInt32HostToBig(absd.mFormatID); |
262 bcopy(&formatID, formatIDString, 4); | 224 bcopy(&formatID, formatIDString, 4); |
263 formatIDString[4] = '\0'; | 225 formatIDString[4] = '\0'; |
264 LOG(LS_INFO) << "LogABSD"; | 226 LOG(LS_INFO) << "LogABSD"; |
(...skipping 72 matching lines...) Loading... |
337 | 299 |
338 int32_t AudioDeviceIOS::Terminate() { | 300 int32_t AudioDeviceIOS::Terminate() { |
339 LOGI() << "Terminate"; | 301 LOGI() << "Terminate"; |
340 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 302 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
341 if (!initialized_) { | 303 if (!initialized_) { |
342 return 0; | 304 return 0; |
343 } | 305 } |
344 StopPlayout(); | 306 StopPlayout(); |
345 StopRecording(); | 307 StopRecording(); |
346 initialized_ = false; | 308 initialized_ = false; |
347 { | |
348 rtc::GlobalLockScope ls(&g_lock); | |
349 if (g_audio_session_users != 0) { | |
350 LOG(LS_WARNING) << "Object is destructed with an active audio session"; | |
351 } | |
352 RTC_DCHECK_GE(g_audio_session_users, 0); | |
353 } | |
354 return 0; | 309 return 0; |
355 } | 310 } |
356 | 311 |
357 int32_t AudioDeviceIOS::InitPlayout() { | 312 int32_t AudioDeviceIOS::InitPlayout() { |
358 LOGI() << "InitPlayout"; | 313 LOGI() << "InitPlayout"; |
359 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 314 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
360 RTC_DCHECK(initialized_); | 315 RTC_DCHECK(initialized_); |
361 RTC_DCHECK(!play_is_initialized_); | 316 RTC_DCHECK(!play_is_initialized_); |
362 RTC_DCHECK(!playing_); | 317 RTC_DCHECK(!playing_); |
363 if (!rec_is_initialized_) { | 318 if (!rec_is_initialized_) { |
(...skipping 85 matching lines...) Loading... |
449 } | 404 } |
450 rec_is_initialized_ = false; | 405 rec_is_initialized_ = false; |
451 rtc::AtomicOps::ReleaseStore(&recording_, 0); | 406 rtc::AtomicOps::ReleaseStore(&recording_, 0); |
452 return 0; | 407 return 0; |
453 } | 408 } |
454 | 409 |
455 // Change the default receiver playout route to speaker. | 410 // Change the default receiver playout route to speaker. |
456 int32_t AudioDeviceIOS::SetLoudspeakerStatus(bool enable) { | 411 int32_t AudioDeviceIOS::SetLoudspeakerStatus(bool enable) { |
457 LOGI() << "SetLoudspeakerStatus(" << enable << ")"; | 412 LOGI() << "SetLoudspeakerStatus(" << enable << ")"; |
458 | 413 |
459 AVAudioSession* session = [AVAudioSession sharedInstance]; | 414 RTCAudioSession* session = [RTCAudioSession sharedInstance]; |
| 415 [session lockForConfiguration]; |
460 NSString* category = session.category; | 416 NSString* category = session.category; |
461 AVAudioSessionCategoryOptions options = session.categoryOptions; | 417 AVAudioSessionCategoryOptions options = session.categoryOptions; |
462 // Respect old category options if category is | 418 // Respect old category options if category is |
463 // AVAudioSessionCategoryPlayAndRecord. Otherwise reset it since old options | 419 // AVAudioSessionCategoryPlayAndRecord. Otherwise reset it since old options |
464 // might not be valid for this category. | 420 // might not be valid for this category. |
465 if ([category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) { | 421 if ([category isEqualToString:AVAudioSessionCategoryPlayAndRecord]) { |
466 if (enable) { | 422 if (enable) { |
467 options |= AVAudioSessionCategoryOptionDefaultToSpeaker; | 423 options |= AVAudioSessionCategoryOptionDefaultToSpeaker; |
468 } else { | 424 } else { |
469 options &= ~AVAudioSessionCategoryOptionDefaultToSpeaker; | 425 options &= ~AVAudioSessionCategoryOptionDefaultToSpeaker; |
470 } | 426 } |
471 } else { | 427 } else { |
472 options = AVAudioSessionCategoryOptionDefaultToSpeaker; | 428 options = AVAudioSessionCategoryOptionDefaultToSpeaker; |
473 } | 429 } |
474 NSError* error = nil; | 430 NSError* error = nil; |
475 BOOL success = [session setCategory:AVAudioSessionCategoryPlayAndRecord | 431 BOOL success = [session setCategory:AVAudioSessionCategoryPlayAndRecord |
476 withOptions:options | 432 withOptions:options |
477 error:&error]; | 433 error:&error]; |
478 ios::CheckAndLogError(success, error); | 434 ios::CheckAndLogError(success, error); |
| 435 [session unlockForConfiguration]; |
479 return (error == nil) ? 0 : -1; | 436 return (error == nil) ? 0 : -1; |
480 } | 437 } |
481 | 438 |
482 int32_t AudioDeviceIOS::GetLoudspeakerStatus(bool& enabled) const { | 439 int32_t AudioDeviceIOS::GetLoudspeakerStatus(bool& enabled) const { |
483 LOGI() << "GetLoudspeakerStatus"; | 440 LOGI() << "GetLoudspeakerStatus"; |
484 AVAudioSession* session = [AVAudioSession sharedInstance]; | 441 RTCAudioSession* session = [RTCAudioSession sharedInstance]; |
485 AVAudioSessionCategoryOptions options = session.categoryOptions; | 442 AVAudioSessionCategoryOptions options = session.categoryOptions; |
486 enabled = options & AVAudioSessionCategoryOptionDefaultToSpeaker; | 443 enabled = options & AVAudioSessionCategoryOptionDefaultToSpeaker; |
487 return 0; | 444 return 0; |
488 } | 445 } |
489 | 446 |
490 int32_t AudioDeviceIOS::PlayoutDelay(uint16_t& delayMS) const { | 447 int32_t AudioDeviceIOS::PlayoutDelay(uint16_t& delayMS) const { |
491 delayMS = kFixedPlayoutDelayEstimate; | 448 delayMS = kFixedPlayoutDelayEstimate; |
492 return 0; | 449 return 0; |
493 } | 450 } |
494 | 451 |
(...skipping 116 matching lines...) Loading... |
611 if (valid_route_change) { | 568 if (valid_route_change) { |
612 // Log previous route configuration. | 569 // Log previous route configuration. |
613 AVAudioSessionRouteDescription* prev_route = | 570 AVAudioSessionRouteDescription* prev_route = |
614 notification.userInfo[AVAudioSessionRouteChangePreviousRouteKey]; | 571 notification.userInfo[AVAudioSessionRouteChangePreviousRouteKey]; |
615 LOG(LS_INFO) << "Previous route:"; | 572 LOG(LS_INFO) << "Previous route:"; |
616 LOG(LS_INFO) << ios::StdStringFromNSString( | 573 LOG(LS_INFO) << ios::StdStringFromNSString( |
617 [NSString stringWithFormat:@"%@", prev_route]); | 574 [NSString stringWithFormat:@"%@", prev_route]); |
618 | 575 |
619 // Only restart audio for a valid route change and if the | 576 // Only restart audio for a valid route change and if the |
620 // session sample rate has changed. | 577 // session sample rate has changed. |
621 AVAudioSession* session = [AVAudioSession sharedInstance]; | 578 RTCAudioSession* session = [RTCAudioSession sharedInstance]; |
622 const double session_sample_rate = session.sampleRate; | 579 const double session_sample_rate = session.sampleRate; |
623 LOG(LS_INFO) << "session sample rate: " << session_sample_rate; | 580 LOG(LS_INFO) << "session sample rate: " << session_sample_rate; |
624 if (playout_parameters_.sample_rate() != session_sample_rate) { | 581 if (playout_parameters_.sample_rate() != session_sample_rate) { |
625 if (!RestartAudioUnitWithNewFormat(session_sample_rate)) { | 582 if (!RestartAudioUnitWithNewFormat(session_sample_rate)) { |
626 LOG(LS_ERROR) << "Audio restart failed"; | 583 LOG(LS_ERROR) << "Audio restart failed"; |
627 } | 584 } |
628 } | 585 } |
629 } | 586 } |
630 }; | 587 }; |
631 | 588 |
(...skipping 33 matching lines...) Loading... |
665 if (route_change_observer_ != nullptr) { | 622 if (route_change_observer_ != nullptr) { |
666 id observer = (__bridge_transfer id)route_change_observer_; | 623 id observer = (__bridge_transfer id)route_change_observer_; |
667 [center removeObserver:observer]; | 624 [center removeObserver:observer]; |
668 route_change_observer_ = nullptr; | 625 route_change_observer_ = nullptr; |
669 } | 626 } |
670 } | 627 } |
671 | 628 |
672 void AudioDeviceIOS::SetupAudioBuffersForActiveAudioSession() { | 629 void AudioDeviceIOS::SetupAudioBuffersForActiveAudioSession() { |
673 LOGI() << "SetupAudioBuffersForActiveAudioSession"; | 630 LOGI() << "SetupAudioBuffersForActiveAudioSession"; |
674 // Verify the current values once the audio session has been activated. | 631 // Verify the current values once the audio session has been activated. |
675 AVAudioSession* session = [AVAudioSession sharedInstance]; | 632 RTCAudioSession* session = [RTCAudioSession sharedInstance]; |
676 LOG(LS_INFO) << " sample rate: " << session.sampleRate; | 633 LOG(LS_INFO) << " sample rate: " << session.sampleRate; |
677 LOG(LS_INFO) << " IO buffer duration: " << session.IOBufferDuration; | 634 LOG(LS_INFO) << " IO buffer duration: " << session.IOBufferDuration; |
678 LOG(LS_INFO) << " output channels: " << session.outputNumberOfChannels; | 635 LOG(LS_INFO) << " output channels: " << session.outputNumberOfChannels; |
679 LOG(LS_INFO) << " input channels: " << session.inputNumberOfChannels; | 636 LOG(LS_INFO) << " input channels: " << session.inputNumberOfChannels; |
680 LOG(LS_INFO) << " output latency: " << session.outputLatency; | 637 LOG(LS_INFO) << " output latency: " << session.outputLatency; |
681 LOG(LS_INFO) << " input latency: " << session.inputLatency; | 638 LOG(LS_INFO) << " input latency: " << session.inputLatency; |
682 | 639 |
683 // Log a warning message for the case when we are unable to set the preferred | 640 // Log a warning message for the case when we are unable to set the preferred |
684 // hardware sample rate but continue and use the non-ideal sample rate after | 641 // hardware sample rate but continue and use the non-ideal sample rate after |
685 // reinitializing the audio parameters. Most BT headsets only support 8kHz or | 642 // reinitializing the audio parameters. Most BT headsets only support 8kHz or |
(...skipping 261 matching lines...) Loading... |
947 } | 904 } |
948 | 905 |
949 bool AudioDeviceIOS::InitPlayOrRecord() { | 906 bool AudioDeviceIOS::InitPlayOrRecord() { |
950 LOGI() << "InitPlayOrRecord"; | 907 LOGI() << "InitPlayOrRecord"; |
951 // Activate the audio session if not already activated. | 908 // Activate the audio session if not already activated. |
952 if (!ActivateAudioSession()) { | 909 if (!ActivateAudioSession()) { |
953 return false; | 910 return false; |
954 } | 911 } |
955 | 912 |
956 // Ensure that the active audio session has the correct category and mode. | 913 // Ensure that the active audio session has the correct category and mode. |
957 AVAudioSession* session = [AVAudioSession sharedInstance]; | 914 RTCAudioSession* session = [RTCAudioSession sharedInstance]; |
958 if (!VerifyAudioSession(session)) { | 915 if (!VerifyAudioSession(session)) { |
959 DeactivateAudioSession(); | 916 DeactivateAudioSession(); |
960 LOG(LS_ERROR) << "Failed to verify audio session category and mode"; | 917 LOG(LS_ERROR) << "Failed to verify audio session category and mode"; |
961 return false; | 918 return false; |
962 } | 919 } |
963 | 920 |
964 // Start observing audio session interruptions and route changes. | 921 // Start observing audio session interruptions and route changes. |
965 RegisterNotificationObservers(); | 922 RegisterNotificationObservers(); |
966 | 923 |
967 // Ensure that we got what what we asked for in our active audio session. | 924 // Ensure that we got what what we asked for in our active audio session. |
(...skipping 135 matching lines...) Loading... |
1103 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches | 1060 // Read decoded 16-bit PCM samples from WebRTC (using a size that matches |
1104 // the native I/O audio unit) to a preallocated intermediate buffer and | 1061 // the native I/O audio unit) to a preallocated intermediate buffer and |
1105 // copy the result to the audio buffer in the |io_data| destination. | 1062 // copy the result to the audio buffer in the |io_data| destination. |
1106 SInt8* source = playout_audio_buffer_.get(); | 1063 SInt8* source = playout_audio_buffer_.get(); |
1107 fine_audio_buffer_->GetPlayoutData(source); | 1064 fine_audio_buffer_->GetPlayoutData(source); |
1108 memcpy(destination, source, dataSizeInBytes); | 1065 memcpy(destination, source, dataSizeInBytes); |
1109 return noErr; | 1066 return noErr; |
1110 } | 1067 } |
1111 | 1068 |
1112 } // namespace webrtc | 1069 } // namespace webrtc |
OLD | NEW |