2010-12-15 60 views
15

在测试过程中,客户注意到拔下耳机时iPhone中的视频播放暂停。他想要类似的音频播放功能,也许可以弹出消息。耳机拔出时是否有事件发生?

是否有人知道是否有某种事件可以让我做到这一点?

回答

18

请参阅音频会话编程指南中的Responding to Route Changes

-Marc

+0

谢谢!此页面从此链接,http://developer.apple.com/library/ios/#documentation/Audio/Conceptual/AudioSessionProgrammingGuide/Cookbook/Cookbook.html#//apple_ref/doc/uid/TP40007875-CH6-SW8。有'用户插入或拔出耳机,或停靠或取消锁定设备,从而添加或删除音频连接时调用回调'的示例代码。还没有尝试过,但看起来很完美。欢呼的单挑。 – 2010-12-15 17:06:00

+0

真棒:)。没有头痛的回调 – iEinstein 2014-06-04 15:14:43

1

这里是全面落实我最终用于当插入耳机(和不插电)发送事件。

我需要处理一些相当复杂的事情,以确保应用程序从后台返回后仍能正常工作。

CVAudioSession.h文件

#import <Foundation/Foundation.h> 

#define kCVAudioInputChangedNotification @"kCVAudioInputChangedNotification" 
#define kCVAudioInterruptionEnded @"kCVAudioInterruptionEnded" 

@interface CVAudioSession : NSObject 
+(void) setup; 
+(void) destroy; 
+(NSString*) currentAudioRoute; 
+(BOOL) interrupted; 
@end 

CVAudioSession.m文件

#import "CVAudioSession.h" 
#import <AudioToolbox/AudioToolbox.h> 

@implementation CVAudioSession 

static BOOL _isInterrupted = NO; 

+(void) setup { 
    NSLog(@"CVAudioSession setup"); 

    // Set up the audio session for recording 
    OSStatus error = AudioSessionInitialize(NULL, NULL, interruptionListener, (__bridge void*)self); 

    if (error) NSLog(@"ERROR INITIALIZING AUDIO SESSION! %ld\n", error); 
    if (!error) { 
     UInt32 category = kAudioSessionCategory_RecordAudio; // NOTE CANT PLAY BACK WITH THIS 
     error = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category); 
     if (error) NSLog(@"couldn't set audio category!"); 

     error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, (__bridge void*) self); 
     if (error) NSLog(@"ERROR ADDING AUDIO SESSION PROP LISTENER! %ld\n", error); 
     UInt32 inputAvailable = 0; 
     UInt32 size = sizeof(inputAvailable); 

     // we do not want to allow recording if input is not available 
     error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &size, &inputAvailable); 
     if (error) NSLog(@"ERROR GETTING INPUT AVAILABILITY! %ld\n", error); 

     // we also need to listen to see if input availability changes 
     error = AudioSessionAddPropertyListener(kAudioSessionProperty_AudioInputAvailable, propListener, (__bridge void*) self); 
     if (error) NSLog(@"ERROR ADDING AUDIO SESSION PROP LISTENER! %ld\n", error); 

     error = AudioSessionSetActive(true); 
     if (error) NSLog(@"CVAudioSession: AudioSessionSetActive (true) failed"); 
    } 
} 

+ (NSString*) currentAudioRoute { 
    UInt32 routeSize = sizeof (CFStringRef); 
    CFStringRef route; 

    AudioSessionGetProperty (kAudioSessionProperty_AudioRoute, 
          &routeSize, 
          &route); 

    NSString* routeStr = (__bridge NSString*)route; 
    return routeStr; 
} 

+(void) destroy { 
    NSLog(@"CVAudioSession destroy"); 

    // Very important - remove the listeners, or we'll crash when audio routes etc change when we're no longer on screen 
    OSStatus stat = AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_AudioRouteChange, propListener, (__bridge void*)self); 
    NSLog(@".. AudioSessionRemovePropertyListener kAudioSessionProperty_AudioRouteChange returned %ld", stat); 

    stat = AudioSessionRemovePropertyListenerWithUserData(kAudioSessionProperty_AudioInputAvailable, propListener, (__bridge void*)self); 
    NSLog(@".. AudioSessionRemovePropertyListener kAudioSessionProperty_AudioInputAvailable returned %ld", stat); 

    AudioSessionSetActive(false); // disable audio session. 
    NSLog(@"AudioSession is now inactive"); 
} 

+(BOOL) interrupted { 
    return _isInterrupted; 
} 

// Called when audio is interrupted for whatever reason. NOTE: doesn't always call the END one.. 
void interruptionListener( void * inClientData, 
          UInt32 inInterruptionState) { 

    if (inInterruptionState == kAudioSessionBeginInterruption) 
    { 
     _isInterrupted = YES; 

     NSLog(@"CVAudioSession: interruptionListener kAudioSessionBeginInterruption. Disable audio session.."); 

     // Try just deactivating the audiosession.. 
     OSStatus rc = AudioSessionSetActive(false); 
     if (rc) { 
      NSLog(@"CVAudioSession: interruptionListener kAudioSessionBeginInterruption - AudioSessionSetActive(false) returned %.ld", rc); 
     } else { 
      NSLog(@"CVAudioSession: interruptionListener kAudioSessionBeginInterruption - AudioSessionSetActive(false) ok."); 
     } 



    } else if (inInterruptionState == kAudioSessionEndInterruption) { 

     _isInterrupted = NO; 

     // Reactivate the audiosession 
     OSStatus rc = AudioSessionSetActive(true); 
     if (rc) { 
      NSLog(@"CVAudioSession: interruptionListener kAudioSessionEndInterruption - AudioSessionSetActive(true) returned %.ld", rc); 
     } else { 
      NSLog(@"CVAudioSession: interruptionListener kAudioSessionEndInterruption - AudioSessionSetActive(true) ok."); 
     } 

     [[NSNotificationCenter defaultCenter] postNotificationName:kCVAudioInterruptionEnded object:(__bridge NSObject*)inClientData userInfo:nil]; 
    } 
} 

// This is called when microphone or other audio devices are plugged in and out. Is on the main thread 
void propListener( void *     inClientData, 
        AudioSessionPropertyID inID, 
        UInt32     inDataSize, 
        const void *   inData) 
{ 
    if (inID == kAudioSessionProperty_AudioRouteChange) 
    { 
     CFDictionaryRef routeDictionary = (CFDictionaryRef)inData; 
     CFNumberRef reason = (CFNumberRef)CFDictionaryGetValue(routeDictionary, CFSTR(kAudioSession_AudioRouteChangeKey_Reason)); 
     SInt32 reasonVal; 
     CFNumberGetValue(reason, kCFNumberSInt32Type, &reasonVal); 
     if (reasonVal != kAudioSessionRouteChangeReason_CategoryChange) 
     { 
      NSLog(@"CVAudioSession: input changed"); 
      [[NSNotificationCenter defaultCenter] postNotificationName:kCVAudioInputChangedNotification object:(__bridge NSObject*)inClientData userInfo:nil]; 
     } 
    } 
    else if (inID == kAudioSessionProperty_AudioInputAvailable) 
    { 
     if (inDataSize == sizeof(UInt32)) { 
      UInt32 isAvailable = *(UInt32*)inData; 

      if (isAvailable == 0) { 
       NSLog(@"AUDIO RECORDING IS NOT AVAILABLE"); 
      } 
     } 
    } 
} 

@end 
5

这改变与iOS 7,你只需要听命名AVAudioSessionRouteChangeNotification

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

这可以用于视频播放器,但只有当你使用'AVAudioSession'。 – Legoless 2016-07-31 16:11:46

2

斯威夫特的通知3.0 @ snakeoil的解决方案:

NotificationCenter.default.addObserver(self, selector: #selector(YourViewController.yourMethodThatShouldBeCalledOnChange), name: NSNotification.Name.AVAudioSessionRouteChange, object: nil) 
+0

太棒了!非常感谢! – 2017-04-18 01:25:31