Подтвердить что ты не робот

Обнаружение активных AVAudioSessions на устройстве iOS

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

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

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

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

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

Спасибо заранее.

4b9b3361

Ответ 1

Как вы управляете своим приложением. Audio Session имеет ряд существенных изменений с тех пор, как 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 по программированию сеансов Apple на момент написания этого кода не включает примеры кода, использующие уведомления для обработки прерываний.

Ответ 2

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

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

[self handleIfAudioIsPlaying: otherAudioIsPlaying];

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