5

我有一个可以同时收听和播放声音的应用程序。默认情况下,声音输出通过耳机。因此,我使用以下代码将其路由到扬声器:

UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);

这工作正常。但是现在,我想在连接耳机或外部扬声器时通过耳机路由声音。我将如何实现这一目标?

理想情况下,应用程序启动时所有其他声音(即音乐等)都应静音。

谢谢!

4

3 回答 3

11

为此,您必须在设置音频会话时添加属性侦听器:

AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, audioSessionPropertyListener, nil);

在哪里

void audioSessionPropertyListener(void* inClientData, AudioSessionPropertyID inID,
                                          UInt32 inDataSize, const void* inData) {
          UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;

          if (!isHeadsetPluggedIn()) 
            AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);
        }

BOOL isHeadsetPluggedIn() {
  UInt32 routeSize = sizeof (CFStringRef);
  CFStringRef route;

  OSStatus error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
                                            &routeSize,
                                            &route
                                            );



     if (!error && (route != NULL) && ([(NSString*)route rangeOfString:@"Head"].location != NSNotFound)) {
        NSLog(@"HeadsetPluggedIn");
        return YES;
      }
      NSLog(@"Headset_NOT_PluggedIn");
      return NO;
    }

因此,当插入或拔出耳机时,您会收到通知并更改音频输出方向。

于 2010-09-09T16:10:49.033 回答
1

这是一种快速而肮脏的方式,似乎对我有用:

void sessionPropertyListener(void *                  inClientData,
                             AudioSessionPropertyID  inID,
                             UInt32                  inDataSize,
                             const void *            inData){

  if (inID == kAudioSessionProperty_AudioRouteChange)
  {
    CFStringRef newRoute;
    UInt32 size = sizeof(CFStringRef);
    AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &size, &newRoute);
    if (newRoute)
    {
      CFShow(newRoute);
      if (CFStringCompare(newRoute, CFSTR("ReceiverAndMicrophone"),
                          (UInt32)NULL) == kCFCompareEqualTo)//if receiver, play through speakers
      {
        UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
        AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,
                                 sizeof(audioRouteOverride),
                                 &audioRouteOverride);
      }
      else if (CFStringCompare(newRoute, CFSTR("HeadsetInOut"),
                               (UInt32)NULL) == kCFCompareEqualTo)//headset
      {
        UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None;
        AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,
                                 sizeof(audioRouteOverride),
                                 &audioRouteOverride);
      }
    }
  }
}
于 2012-12-28T01:25:32.937 回答
0

从 iOS 7 开始不推荐使用 AudioSessionSetProperty,我们应该使用 AVFoundation AVAudioSession。由于所需的操作是允许用户操作覆盖通过扬声器的路由,因此您可能会考虑 AVAudioSessionPortOverrideSpeaker 和 AVAudioSessionCategoryOptionDefaultToSpeaker 之间的区别。

根据技术公告 Q&A QA1754:“使用 AVAudioSessionCategoryOptionDefaultToSpeaker 时,将尊重用户手势。例如,插入耳机将导致路由更改为耳机麦克风/耳机,拔下耳机将导致路由更改为内置麦克风/扬声器”。

请注意,技术公告解释说 AVAudioSessionPortOverrideSpeaker 更适合与扬声器按钮一起使用,例如,这不是原始帖子所要求的。

https://developer.apple.com/library/ios/qa/qa1754/_index.html

在调用播放器之前调用我自己的实现,如下所示:

NSError *error;
AVAudioSession* audioSession   = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:&error];
// handle any error
// initiate the player or recorder
[_player play];

此外,这个问题与另一篇不同但相关的帖子中提到的问题相似。

根据此处提到的相同技术公告“考虑使用 overrideOutputAudioPort:就您可能用来实现扬声器按钮的方式而言,您希望能够在扬声器 (AVAudioSessionPortOverrideSpeaker) 和正常输出路由 (AVAudioSessionPortOverrideNone) 之间切换。 "

如果您正在寻找实现扬声器覆盖 overrideOutputPort 类别,请参阅该帖子: 如何在不使用 AudioSessionSetProperty 的情况下将音频路由到扬声器?

于 2015-10-23T16:52:00.983 回答