web-dev-qa-db-ja.com

iOSデバイスでアクティブなAVAudioSessionsを検出する

私はこれが可能かどうかを把握しようとしています-私のアプリは次のように初期化されたオーディオセッションをアクティブにします:

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

別のアプリまたはOSから発生した追加のオーディオセッションがいつ再生されるかを理解したいと思います。

デリゲートメソッドを実装する機能について知っていますbeginInterruption:endInterruptionが、使用しているAVAudioSessionCategoryOptionMixWithOthersオプションのため、これらは呼び出されません。

プライベートAPIを使用せずにこれを達成する方法はありますか?

前もって感謝します。

26
Stavash

iOS 6.以降、アプリケーションのオーディオセッションを管理する方法にいくつかの重要な変更が加えられ、最初に簡単に言及する価値があります。 iOS 6.の前に、AVAudioSessionおよびAudioSessionServicesクラスを使用し、それぞれ委任とプロパティリスニングを組み込みます。 iOS 6.以降は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でアプリケーションのオーディオセッションの状態を確認する限り、何もポーリングする必要はありません。アプリケーションのオーディオセッションに対する以降の変更は、これら2つの主要な通知によって通知されます。 NSLogステートメントを、スイッチに含まれるケースに基づいてコードが実行する必要があるものに置き換えます。

AVAudioSessionInterruptionTypeKeyおよびAVAudioSessionRouteChangeReasonKeyの詳細については、AVAudioSessionクラスリファレンスドキュメントを参照してください。

長い答えをおaびしますが、iOSでのオーディオセッション管理はかなり面倒だと思います。これを書いている時点で、Appleのオーディオセッションプログラミングガイドには、割り込み処理の通知を使用したコード例は含まれていません。

68
Bamsworld

他のオーディオが次のように再生されているかどうかを確認できます。

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

[self handleIfAudioIsPlaying: otherAudioIsPlaying];

その後、ループを追加して、何か変更があった場合はX秒ごとに確認できます。

5
BlackMouse