2010-12-15 3 views
15

테스트하는 동안 클라이언트는 헤드폰이 연결되어 있지 않을 때 iPhone에서 비디오 재생이 일시 중지되었음을 확인했습니다. 그는 오디오 재생과 비슷한 기능과 메시지 팝업 기능을 원했습니다.헤드폰 플러그가 뽑히는 이벤트가 있습니까?

가능하게 만들 수있는 종류의 이벤트가 있다면 누구에게 알리십니까?

답변

18

오디오 세션 프로그래밍 가이드의 Responding to Route Changes을 참조하십시오.

+0

감사! 이 페이지는 http://developer.apple.com/library/ios/#documentation/Audio/Conceptual/AudioSessionProgrammingGuide/Cookbook/Cookbook.html#//apple_ref/doc/uid/TP40007875-CH6-SW8에서 링크되어 있습니다. '사용자가 헤드셋을 꽂거나 뺄 때 콜백을 호출하거나 장치를 도킹하거나 도킹 해제하여 오디오 연결을 추가하거나 제거 할 때 시스템이 콜백을 호출합니다.' 아직 시도하지 않았지만 완벽 해 보입니다. 헤드 업을위한 환호. –

+0

굉장 :). 콜백을위한 두통 없음 – iEinstein

1

-marc

는 여기에 내가 결국 헤드폰 연결 (및 분리) 할 때 이벤트를 보내는 데 사용 전체 구현입니다.

앱이 백그라운드에서 반환 된 후에도 계속 작업 할 수 있도록 처리해야하는 복잡성이 상당했습니다.

이 아이폰 OS 7 변경

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

, 당신은 단지 AVAudioSessionRouteChangeNotification

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

이것은 'AVAudioSession'을 사용하는 경우에만 비디오 플레이어에서 작동합니다. – Legoless

2

스위프트라는 이름의 통지를들을 필요 3.0 @ snakeoil의 솔루션 :

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

그것은 훌륭합니다! 고마워요! –

관련 문제