NCAudioController.m 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /**
  2. * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. #import "NCAudioController.h"
  6. #import "CallKitManager.h"
  7. #import "NextcloudTalk-Swift.h"
  8. NSString * const AudioSessionDidChangeRouteNotification = @"AudioSessionDidChangeRouteNotification";
  9. NSString * const AudioSessionWasActivatedByProviderNotification = @"AudioSessionWasActivatedByProviderNotification";
  10. NSString * const AudioSessionDidChangeRoutingInformationNotification = @"AudioSessionDidChangeRoutingInformationNotification";
  11. @implementation NCAudioController
  12. + (NCAudioController *)sharedInstance
  13. {
  14. static NCAudioController *sharedInstance = nil;
  15. static dispatch_once_t onceToken;
  16. dispatch_once(&onceToken, ^{
  17. sharedInstance = [[NCAudioController alloc] init];
  18. });
  19. return sharedInstance;
  20. }
  21. - (id)init
  22. {
  23. self = [super init];
  24. if (self) {
  25. RTCAudioSessionConfiguration *configuration = [RTCAudioSessionConfiguration webRTCConfiguration];
  26. configuration.category = AVAudioSessionCategoryPlayAndRecord;
  27. configuration.mode = AVAudioSessionModeVoiceChat;
  28. [RTCAudioSessionConfiguration setWebRTCConfiguration:configuration];
  29. _rtcAudioSession = [RTCAudioSession sharedInstance];
  30. [_rtcAudioSession lockForConfiguration];
  31. NSError *error = nil;
  32. [_rtcAudioSession setConfiguration:configuration error:&error];
  33. if (error) {
  34. NSLog(@"Error setting configuration: %@", error.localizedDescription);
  35. }
  36. [_rtcAudioSession unlockForConfiguration];
  37. if ([CallKitManager isCallKitAvailable]) {
  38. _rtcAudioSession.useManualAudio = YES;
  39. }
  40. [_rtcAudioSession addDelegate:self];
  41. [self updateRouteInformation];
  42. }
  43. return self;
  44. }
  45. #pragma mark - Audio session configuration
  46. - (void)setAudioSessionToVoiceChatMode
  47. {
  48. [self changeAudioSessionConfigurationModeTo:AVAudioSessionModeVoiceChat];
  49. }
  50. - (void)setAudioSessionToVideoChatMode
  51. {
  52. [self changeAudioSessionConfigurationModeTo:AVAudioSessionModeVideoChat];
  53. }
  54. - (void)changeAudioSessionConfigurationModeTo:(NSString *)mode
  55. {
  56. [[WebRTCCommon shared] assertQueue];
  57. RTCAudioSessionConfiguration *configuration = [RTCAudioSessionConfiguration webRTCConfiguration];
  58. configuration.category = AVAudioSessionCategoryPlayAndRecord;
  59. configuration.mode = mode;
  60. [_rtcAudioSession lockForConfiguration];
  61. BOOL hasSucceeded = NO;
  62. NSError *error = nil;
  63. if (_rtcAudioSession.isActive) {
  64. hasSucceeded = [_rtcAudioSession setConfiguration:configuration error:&error];
  65. } else {
  66. hasSucceeded = [_rtcAudioSession setConfiguration:configuration
  67. active:YES
  68. error:&error];
  69. }
  70. if (!hasSucceeded) {
  71. NSLog(@"Error setting configuration: %@", error.localizedDescription);
  72. }
  73. [_rtcAudioSession unlockForConfiguration];
  74. [self updateRouteInformation];
  75. }
  76. - (void)disableAudioSession
  77. {
  78. [[WebRTCCommon shared] assertQueue];
  79. [_rtcAudioSession lockForConfiguration];
  80. NSError *error = nil;
  81. BOOL hasSucceeded = [_rtcAudioSession setActive:NO error:&error];
  82. if (!hasSucceeded) {
  83. NSLog(@"Error setting configuration: %@", error.localizedDescription);
  84. }
  85. [_rtcAudioSession unlockForConfiguration];
  86. }
  87. - (void)updateRouteInformation
  88. {
  89. AVAudioSession *audioSession = self.rtcAudioSession.session;
  90. AVAudioSessionPortDescription *currentOutput = [audioSession.currentRoute.outputs firstObject];
  91. self.numberOfAvailableInputs = audioSession.availableInputs.count;
  92. if ([_rtcAudioSession mode] == AVAudioSessionModeVideoChat || [currentOutput.portType isEqualToString:AVAudioSessionPortBuiltInSpeaker]) {
  93. self.isSpeakerActive = YES;
  94. } else {
  95. self.isSpeakerActive = NO;
  96. }
  97. [[NSNotificationCenter defaultCenter] postNotificationName:AudioSessionDidChangeRoutingInformationNotification
  98. object:self
  99. userInfo:nil];
  100. }
  101. - (BOOL)isAudioRouteChangeable
  102. {
  103. if (self.numberOfAvailableInputs > 1) {
  104. return YES;
  105. }
  106. if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
  107. // A phone always supports a speaker and earpiece output
  108. return YES;
  109. }
  110. return NO;
  111. }
  112. - (void)providerDidActivateAudioSession:(AVAudioSession *)audioSession
  113. {
  114. [[WebRTCCommon shared] assertQueue];
  115. [_rtcAudioSession audioSessionDidActivate:audioSession];
  116. _rtcAudioSession.isAudioEnabled = YES;
  117. [[NSNotificationCenter defaultCenter] postNotificationName:AudioSessionWasActivatedByProviderNotification
  118. object:self
  119. userInfo:nil];
  120. }
  121. - (void)providerDidDeactivateAudioSession:(AVAudioSession *)audioSession
  122. {
  123. [[WebRTCCommon shared] assertQueue];
  124. [_rtcAudioSession audioSessionDidDeactivate:audioSession];
  125. _rtcAudioSession.isAudioEnabled = NO;
  126. }
  127. #pragma mark - RTCAudioSessionDelegate
  128. - (void)audioSessionDidChangeRoute:(RTCAudioSession *)session reason:(AVAudioSessionRouteChangeReason)reason previousRoute:(AVAudioSessionRouteDescription *)previousRoute
  129. {
  130. [self updateRouteInformation];
  131. [[NSNotificationCenter defaultCenter] postNotificationName:AudioSessionDidChangeRouteNotification
  132. object:self
  133. userInfo:nil];
  134. }
  135. @end