iOS: Force audio output to speakers while headphones are plugged in

iOS: Force audio output to speakers while headphones are plugged in 
After much searching through Apple documentation and scarce examples of what I wanted to do, I came up with the following code. A client wanted to play audio through the iPhone/iPad speakers while a microphone was plugged in. While this solution can't do both at the same time, it will let you switch back and forth between playing sounds through the speakers, then record through a microphone or a headset, without unplugging anything. It will also default to use the internal microphone and speakers if nothing is plugged in. Note that by calling the setup method, audio output will initially be forced through the speakers, rather than the headphones, if plugged in. Hopefully this code helps someone facing similar issues.

AudioRouter.h

 
  
  1. @interface AudioRouter : NSObject
  2. + (void) initAudioSessionRouting;
  3. + (void) switchToDefaultHardware;
  4. + (void) forceOutputToBuiltInSpeakers;
  5. @end

AudioRouter.m

 
  
  1. #import "AudioRouter.h"
  2. #import
  3. #import
  4. @implementation AudioRouter
  5. #define IS_DEBUGGING NO
  6. #define IS_DEBUGGING_EXTRA_INFO NO
  7. + (void) initAudioSessionRouting {
  8. // Called once to route all audio through speakers, even if something's plugged into the headphone jack
  9. static BOOL audioSessionSetup = NO;
  10. if (audioSessionSetup == NO) {
  11. // set category to accept properties assigned below
  12. NSError *sessionError = nil;
  13. [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error: &sessionError];
  14. // Doubly force audio to come out of speaker
  15. UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
  16. AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
  17. // fix issue with audio interrupting video recording - allow audio to mix on top of other media
  18. UInt32 doSetProperty = 1;
  19. AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(doSetProperty), &doSetProperty);
  20. // set active
  21. [[AVAudioSession sharedInstance] setDelegate:self];
  22. [[AVAudioSession sharedInstance] setActive: YES error: nil];
  23. // add listener for audio input changes
  24. AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange, onAudioRouteChange, nil );
  25. AudioSessionAddPropertyListener (kAudioSessionProperty_AudioInputAvailable, onAudioRouteChange, nil );
  26. }
  27. // Force audio to come out of speaker
  28. [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
  29. // set flag
  30. audioSessionSetup = YES;
  31. }
  32. + (void) switchToDefaultHardware {
  33. // Remove forcing to built-in speaker
  34. UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None;
  35. AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
  36. }
  37. + (void) forceOutputToBuiltInSpeakers {
  38. // Re-force audio to come out of speaker
  39. UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
  40. AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);
  41. }
  42. void onAudioRouteChange (void* clientData, AudioSessionPropertyID inID, UInt32 dataSize, const void* inData) {
  43. if( IS_DEBUGGING == YES ) {
  44. NSLog(@"==== Audio Harware Status ====");
  45. NSLog(@"Current Input: %@", [AudioRouter getAudioSessionInput]);
  46. NSLog(@"Current Output: %@", [AudioRouter getAudioSessionOutput]);
  47. NSLog(@"Current hardware route: %@", [AudioRouter getAudioSessionRoute]);
  48. NSLog(@"==============================");
  49. }
  50. if( IS_DEBUGGING_EXTRA_INFO == YES ) {
  51. NSLog(@"==== Audio Harware Status (EXTENDED) ====");
  52. CFDictionaryRef dict = (CFDictionaryRef)inData;
  53. CFNumberRef reason = CFDictionaryGetValue(dict, kAudioSession_RouteChangeKey_Reason);
  54. CFDictionaryRef oldRoute = CFDictionaryGetValue(dict, kAudioSession_AudioRouteChangeKey_PreviousRouteDescription);
  55. CFDictionaryRef newRoute = CFDictionaryGetValue(dict, kAudioSession_AudioRouteChangeKey_CurrentRouteDescription);
  56. NSLog(@"Audio old route: %@", oldRoute);
  57. NSLog(@"Audio new route: %@", newRoute);
  58. NSLog(@"=========================================");
  59. }
  60. }
  61. + (NSString*) getAudioSessionInput {
  62. UInt32 routeSize;
  63. AudioSessionGetPropertySize(kAudioSessionProperty_AudioRouteDescription, &routeSize);
  64. CFDictionaryRef desc; // this is the dictionary to contain descriptions
  65. // make the call to get the audio description and populate the desc dictionary
  66. AudioSessionGetProperty (kAudioSessionProperty_AudioRouteDescription, &routeSize, &desc);
  67. // the dictionary contains 2 keys, for input and output. Get output array
  68. CFArrayRef outputs = CFDictionaryGetValue(desc, kAudioSession_AudioRouteKey_Inputs);
  69. // the output array contains 1 element - a dictionary
  70. CFDictionaryRef diction = CFArrayGetValueAtIndex(outputs, 0);
  71. // get the output description from the dictionary
  72. CFStringRef input = CFDictionaryGetValue(diction, kAudioSession_AudioRouteKey_Type);
  73. return [NSString stringWithFormat:@"%@", input];
  74. }
  75. + (NSString*) getAudioSessionOutput {
  76. UInt32 routeSize;
  77. AudioSessionGetPropertySize(kAudioSessionProperty_AudioRouteDescription, &routeSize);
  78. CFDictionaryRef desc; // this is the dictionary to contain descriptions
  79. // make the call to get the audio description and populate the desc dictionary
  80. AudioSessionGetProperty (kAudioSessionProperty_AudioRouteDescription, &routeSize, &desc);
  81. // the dictionary contains 2 keys, for input and output. Get output array
  82. CFArrayRef outputs = CFDictionaryGetValue(desc, kAudioSession_AudioRouteKey_Outputs);
  83. // the output array contains 1 element - a dictionary
  84. CFDictionaryRef diction = CFArrayGetValueAtIndex(outputs, 0);
  85. // get the output description from the dictionary
  86. CFStringRef output = CFDictionaryGetValue(diction, kAudioSession_AudioRouteKey_Type);
  87. return [NSString stringWithFormat:@"%@", output];
  88. }
  89. + (NSString*) getAudioSessionRoute {
  90. /*
  91. returns the current session route:
  92. * ReceiverAndMicrophone
  93. * HeadsetInOut
  94. * Headset
  95. * HeadphonesAndMicrophone
  96. * Headphone
  97. * SpeakerAndMicrophone
  98. * Speaker
  99. * HeadsetBT
  100. * LineInOut
  101. * Lineout
  102. * Default
  103. */
  104. UInt32 rSize = sizeof (CFStringRef);
  105. CFStringRef route;
  106. AudioSessionGetProperty (kAudioSessionProperty_AudioRoute, &rSize, &route);
  107. if (route == NULL) {
  108. NSLog(@"Silent switch is currently on");
  109. return @"None";
  110. }
  111. return [NSString stringWithFormat:@"%@", route];
  112. }
  113. @end

你可能感兴趣的:(ios,ios)