2013-12-04 1 views
25

Я пытаюсь выяснить, если это возможно - мое приложение активирует аудио сеанс, который инициализируется как:Обнаружение активных AVAudioSessions на IOS устройства

[[[AVAudioSession alloc] init] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error]; 

Я хотел бы быть в состоянии понять, когда дополнительный звуковой сеанс, созданный из другого приложения или операционной системы.

Я знаю о возможности реализовать методы делегата beginInterruption: и endInterruption, но они не будут вызваны из-за опции AVAudioSessionCategoryOptionMixWithOthers, которую я использую.

Есть ли способ достичь этого, не используя частный API?

Заранее спасибо.

+0

Интересно .... – Maulik

ответ

61

Как вы управляете аудиозаписью приложения, произошли значительные изменения с iOS 6.0, и он заслуживает краткого упоминания в первую очередь. Перед тем, как iOS 6.0 вы использовали бы AVAudioSession и AudioSessionServices классы, включающие делегирование и прослушивание свойств соответственно. От iOS 6.0 и последующее использование AVAudioSession класс и включение уведомлений.

Для iOS 6.0 и далее.

Чтобы узнать, есть ли другие аудио вне вашего приложения песочнице играет использование -

// query if other audio is playing 
BOOL isPlayingWithOthers = [[AVAudioSession sharedInstance] isOtherAudioPlaying]; 
// test it with... 
(isPlayingWithOthers) ? NSLog(@"other audio is playing") : NSLog(@"no other audio is playing"); 

Как для прерывания обработки вы должны будете наблюдать AVAudioSessionInterruptionNotification и AVAudioSessionRouteChangeNotification. Таким образом, в классе, который управляет вашим аудиосеансом, вы можете добавить что-то вроде следующего: это нужно вызывать один раз в начале жизненного цикла приложения и не забывать удалять наблюдателя в методе dealloc того же класса.

// ensure we already have a singleton object 
    [AVAudioSession sharedInstance]; 
    // register for notifications 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(interruption:) 
               name:AVAudioSessionInterruptionNotification 
               object:nil]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(routeChange:) 
               name:AVAudioSessionRouteChangeNotification 
               object:nil]; 

И, наконец, добавьте следующие селекторы interruption: и routeChange: - они получат NSNotification объект, который имеет свойство USERINFO типа NSDictionary, что вы читаете, чтобы помочь либо условным ваше приложение имеет.

- (void)interruption:(NSNotification*)notification { 
// get the user info dictionary 
NSDictionary *interuptionDict = notification.userInfo; 
// get the AVAudioSessionInterruptionTypeKey enum from the dictionary 
NSInteger interuptionType = [[interuptionDict valueForKey:AVAudioSessionInterruptionTypeKey] integerValue]; 
// decide what to do based on interruption type here... 
switch (interuptionType) { 
    case AVAudioSessionInterruptionTypeBegan: 
     NSLog(@"Audio Session Interruption case started."); 
     // fork to handling method here... 
     // EG:[self handleInterruptionStarted]; 
     break; 

    case AVAudioSessionInterruptionTypeEnded: 
     NSLog(@"Audio Session Interruption case ended."); 
     // fork to handling method here... 
     // EG:[self handleInterruptionEnded]; 
     break; 

    default: 
     NSLog(@"Audio Session Interruption Notification case default."); 
     break; 
} } 

И точно так же ...

- (void)routeChange:(NSNotification*)notification { 

NSDictionary *interuptionDict = notification.userInfo; 

NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; 

switch (routeChangeReason) { 
    case AVAudioSessionRouteChangeReasonUnknown: 
     NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonUnknown"); 
     break; 

    case AVAudioSessionRouteChangeReasonNewDeviceAvailable: 
     // a headset was added or removed 
     NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonNewDeviceAvailable"); 
     break; 

    case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: 
     // a headset was added or removed 
     NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonOldDeviceUnavailable"); 
     break; 

    case AVAudioSessionRouteChangeReasonCategoryChange: 
     // called at start - also when other audio wants to play 
     NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonCategoryChange");//AVAudioSessionRouteChangeReasonCategoryChange 
     break; 

    case AVAudioSessionRouteChangeReasonOverride: 
     NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonOverride"); 
     break; 

    case AVAudioSessionRouteChangeReasonWakeFromSleep: 
     NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonWakeFromSleep"); 
     break; 

    case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: 
     NSLog(@"routeChangeReason : AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory"); 
     break; 

    default: 
     break; 
} } 

Там нет необходимости опрашивать ничего до тех пор, как вы проверить состояние ваших приложений сказать аудио сессии, например, в viewDidLoad вашего контроллера зрения корень, в начале жизненного цикла приложений. Любые изменения с этого момента на аудиозапись приложений будут известны с помощью этих двух основных уведомлений. Замените операторы NSLog тем, что ваш код должен делать на основе случаев, содержащихся в коммутаторе.

Дополнительную информацию о AVAudioSessionInterruptionTypeKey и AVAudioSessionRouteChangeReasonKey в справочной документации по классу AVAudioSession.

Приносим извинения за длинный ответ, но я считаю, что управление аудио сеансами в iOS довольно затруднительно, и руководство по программированию аудиозаписей Apple на момент написания этого документа не включает примеры кода с использованием уведомлений об обработке прерываний.

+0

Спасибо за очень проницательный и подробный ответ. Я пробовал зарегистрироваться для этих уведомлений, а затем играл музыку через внешнее приложение (например, settings-> ringtones), но они никогда не вызываются. Есть идеи? – Stavash

+0

Уведомления отправляются по основному потоку. Чтобы подтвердить это, попытайтесь создать устройство, а затем фоном ваше приложение. Затем откройте музыкальное приложение и начните воспроизведение аудиодорожки. Теперь верните приложение на передний план и получите уведомление об изменении маршрута. Поведение аудио сеанса зависит не только от вашей аудио сессии, но и от всех задействованных и их текущего состояния. Я использую музыкальное приложение для тестирования, потому что я знаю, что это сеанс аудио позволяет ему играть с другими, тогда как я не уверен, что приложение настроек позволяет ему вести себя одинаково. Также не проверяйте это в симуляторе. – Bamsworld

+0

Спасибо, я проверю это и отчитаюсь с выводами – Stavash

5

Вы можете проверить, если другая аудио играет так:

UInt32 otherAudioIsPlaying; 
UInt32 propertySize = sizeof (otherAudioIsPlaying); 
AudioSessionGetProperty (kAudioSessionProperty_OtherAudioIsPlaying, &propertySize, &otherAudioIsPlaying); 

[self handleIfAudioIsPlaying: otherAudioIsPlaying]; 

Затем вы можете добавить петлю и проверить каждую секунду X, если что-то изменилось.

+1

Спасибо, хотя я хочу воздержаться от подхода «опроса». Я хотел бы получить уведомление, когда это произойдет. – Stavash

+0

Возможно, это могло бы помочь: AudioSessionAddPropertyListener (kAudioSessionProperty_OtherAudioIsPlaying, callBack, (__bridge void *) (self)); – BlackMouse

+0

Звучит интересно, я попробую его – Stavash

 Смежные вопросы

  • Нет связанных вопросов^_^