Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect audio to speakers in the AppRTC iOS example?

I'm trying to redirect audio to speakers in the AppRTC iOS example.

I tried:

AVAudioSession* session = [AVAudioSession sharedInstance];

//error handling
BOOL success;
NSError* error;

//set the audioSession category. 
//Needs to be Record or PlayAndRecord to use audioRouteOverride:  

success = [session setCategory:AVAudioSessionCategoryPlayAndRecord
                         error:&error];

if (!success)  NSLog(@"AVAudioSession error setting category:%@",error);

//set the audioSession override
success = [session overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
                                      error:&error];
if (!success)  NSLog(@"AVAudioSession error overrideOutputAudioPort:%@",error);

//activate the audio session
success = [session setActive:YES error:&error];
if (!success) NSLog(@"AVAudioSession error activating: %@",error);
else NSLog(@"audioSession active");

There are no errors, but it doesn't work. How can I fix this?

like image 729
Alon Gubkin Avatar asked Jul 06 '14 11:07

Alon Gubkin


4 Answers

I found solution in the end.

Reason was that you need to set AVAudioSession category to AVAudioSessionCategoryPlayback. But for some reason after establishing webRTC call it was set back to AVAudioSessionCategoryPlayAndRecord. In the end I decided to add observer for AVAudioSessionRouteChangeNotification and switch to AVAudioSessionCategoryPlayback each time I detected unwanted category change. A bit of hack solution but worked in the end. You can check it here.

like image 156
Josip B. Avatar answered Nov 14 '22 12:11

Josip B.


I solved it by the solution. Just listen AVAudioSessionRouteChangeNotification

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didSessionRouteChange:) name:AVAudioSessionRouteChangeNotification object:nil];

And using the didSessionRouteChange selector as below:

- (void)didSessionRouteChange:(NSNotification *)notification
{
  NSDictionary *interuptionDict = notification.userInfo;
  NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];

  switch (routeChangeReason) {
      case AVAudioSessionRouteChangeReasonCategoryChange: {
          // Set speaker as default route
          NSError* error;
          [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:&error];
      }
      break;

    default:
      break;
  }
}
like image 36
phuongle Avatar answered Nov 14 '22 13:11

phuongle


Still seems to be an issue, phuongle answer worked for me. Swift 4 version:

NotificationCenter.default.addObserver(forName: .AVAudioSessionRouteChange, object: nil, queue: nil, using: routeChange)    

private func routeChange(_ n: Notification) {
    guard let info = n.userInfo,
        let value = info[AVAudioSessionRouteChangeReasonKey] as? UInt,
        let reason = AVAudioSessionRouteChangeReason(rawValue: value) else { return }
    switch reason {
    case .categoryChange: try? AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
    default: break
    }
}
like image 28
Joe Maher Avatar answered Nov 14 '22 11:11

Joe Maher


For anyone who came here, searching for a solution in Swift that also accounts for changes back from (BT-)earphones. The below sample (Swift 5) does that.
Adopted in part from @Teivaz

@objc func handleRouteChange(notification: Notification) {
    guard let info = notification.userInfo,
        let value = info[AVAudioSessionRouteChangeReasonKey] as? UInt,
        let reason = AVAudioSession.RouteChangeReason(rawValue: value) else { return }

    switch reason {
    case .categoryChange:
        try? AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
    case .oldDeviceUnavailable:
        try? AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker)
    default:
        l.debug("other")
    }
}
like image 25
Martin Avatar answered Nov 14 '22 12:11

Martin