如何在 AppRTC iOS 示例中将音频重定向到扬声器?

问题描述 投票:0回答:6

我正在尝试将音频重定向到 AppRTC iOS 示例中的扬声器。

我尝试过:

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");

没有错误,但是不起作用。我该如何解决这个问题?

ios audio avfoundation webrtc apprtcdemo
6个回答
15
投票

我按照解决方案解决了。 只需听 AVAudioSessionRouteChangeNotification

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

并使用 didSessionRouteChange 选择器,如下所示:

- (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;
  }
}

6
投票

似乎仍然是一个问题,phuongle 答案对我有用。 Swift 4 版本:

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
    }
}

5
投票

对于来到这里的任何人,在 Swift 中寻找解决方案,该解决方案也可以解决 (BT-) 耳机的变化。下面的示例(Swift 5)就是这样做的。
部分采用@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")
    }
}

2
投票

我最终找到了解决方案。

原因是您需要将

AVAudioSession
类别设置为
AVAudioSessionCategoryPlayback
。但由于某种原因,在建立 webRTC 呼叫后,它被设置回
AVAudioSessionCategoryPlayAndRecord
。 最后,我决定为
AVAudioSessionRouteChangeNotification
添加观察者,并在每次检测到不需要的类别更改时切换到
AVAudioSessionCategoryPlayback
。 一些黑客解决方案,但最终成功了。您可以在这里查看。


1
投票

phuongle的回答是正确的。不过,当您启用覆盖时,即使用户插入耳机,这实际上也会覆盖音频输出。当用户使用耳机时,通过扬声器播放音频没有多大意义。为此,请使用以下代码:

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

    if (routeChangeReason == AVAudioSessionRouteChangeReasonRouteConfigurationChange) {
        [self enableLoudspeaker];
    }
}

- (void)enableLoudspeaker {
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    AVAudioSessionCategoryOptions options = audioSession.categoryOptions;
    if (options & AVAudioSessionCategoryOptionDefaultToSpeaker) return;
    options |= AVAudioSessionCategoryOptionDefaultToSpeaker;
    [audioSession setActive:YES error:nil];
    [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:options error:nil];
}

1
投票

我已经面临这个问题一段时间了,我已经找到了解决方案。该问题是由于我们在WebRTC完成配置之前设置AVAudioSessionCategory而引起的。我们可以通过更新 AudioSessionRouteChange 发生时的音频配置来解决此问题。有两种方法可以找到 AudioSessionRouteChange 并更新配置。

1。使用 RTCAudioSessionDelegate

let rtcAudioSession = RTCAudioSession.sharedInstance()

// set RTCAudioSessionDelegate to your class
rtcAudioSession.add(self)

// MARK: - RTCAudioSessionDelegate
extension YourClass: RTCAudioSessionDelegate {
    
    func audioSessionDidChangeRoute(_ session: RTCAudioSession,
                                    reason: AVAudioSession.RouteChangeReason,
                                    previousRoute: AVAudioSessionRouteDescription) {
        // set audio configurations
        rtcAudioSession.lockForConfiguration()
        do {
            try rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.defaultToSpeaker, .allowBluetoothA2DP, .allowBluetooth])
            try rtcAudioSession.setMode(AVAudioSession.Mode.videoChat.rawValue)
            try rtcAudioSession.setActive(true)
            
        } catch let error {
            debugPrint("Error changeing AVAudioSession category: \(error)")
        }
        rtcAudioSession.unlockForConfiguration()
    }
    
}

1。 AVAudioSession.routeChangeNotification

let rtcAudioSession = RTCAudioSession.sharedInstance()

NotificationCenter.default.addObserver(forName: AVAudioSession.routeChangeNotification,
                                       object: nil,
                                       queue: nil,
                                       using: onRouteChange)

private func onRouteChange(_ notification: Notification) {
    // set audio configurations
    rtcAudioSession.lockForConfiguration()
    do {
        try rtcAudioSession.setCategory(AVAudioSession.Category.playAndRecord.rawValue, with: [.defaultToSpeaker, .allowBluetoothA2DP, .allowBluetooth])
        try rtcAudioSession.setMode(AVAudioSession.Mode.videoChat.rawValue)
        try rtcAudioSession.setActive(true)
        
    } catch let error {
        debugPrint("Error changeing AVAudioSession category: \(error)")
    }
    rtcAudioSession.unlockForConfiguration()
}
© www.soinside.com 2019 - 2024. All rights reserved.