在 iOS 设备上检测活动的 AVAudioSessions

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20371388/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 22:36:46  来源:igfitidea点击:

Detecting active AVAudioSessions on iOS device

iosobjective-ccocoa-touchavaudiosession

提问by Stavash

I'm trying to figure out if this is possible - my app activates an audio session that is initialized as:

我试图弄清楚这是否可行 - 我的应用程序激活了一个初始化为的音频会话:

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

I would like to be able to understand when an additional audio session that originated from another app or the OS is playing.

我希望能够了解何时正在播放源自另一个应用程序或操作系统的附加音频会话。

I know about the ability to implement the delegate methods beginInterruption:and endInterruptionbut these won't get invoked because of the AVAudioSessionCategoryOptionMixWithOthersoption I'm using.

我知道实现委托方法的能力beginInterruption:endInterruption但由于AVAudioSessionCategoryOptionMixWithOthers我使用的选项,这些方法不会被调用。

Is there a way to achieve this without using private API?

有没有办法在不使用私有 API 的情况下实现这一目标?

Thanks in advance.

提前致谢。

回答by Bamsworld

The way you manage your application's Audio Session has had some significant changes since iOS 6.0, and deserves a brief mention first. Before iOS 6.0you would make use of AVAudioSessionand AudioSessionServicesclasses, incorporating delegation and property listening respectively. From iOS 6.0onwards use AVAudioSessionclass and incorporate notifications.

iOS 6.0以来,您管理应用程序音频会话的方式发生了一些重大变化,首先值得简要提及。在iOS 6.0之前,您将使用AVAudioSessionAudioSessionServices类,分别结合委托和属性侦听。从iOS 6.0开始使用AVAudioSession类并合并通知。

The following is for iOS 6.0onwards.

以下是针对iOS 6.0以后的。

To tell if other audio outside your applications sandbox is playing use -

要判断应用程序沙箱之外的其他音频是否正在播放,请使用 -

// 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");

As for interruption handling you'll need to observe AVAudioSessionInterruptionNotificationand AVAudioSessionRouteChangeNotification. So in the class that manages your audio session you could put something like the following - this should be called once at the start of the application lifecycle and don't forget to remove observer in the dealloc method of the same class.

至于中断处理,您需要观察AVAudioSessionInterruptionNotificationAVAudioSessionRouteChangeNotification。因此,在管理您的音频会话的类中,您可以放置​​类似以下内容 - 这应该在应用程序生命周期开始时调用一次,并且不要忘记在同一类的 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];

And finally add the following selectors interruption:and routeChange:- these will receive a NSNotificationobject that has a property called userInfo of type NSDictionarythat you read to assist any conditionals your application has.

最后添加以下选择器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;
} }

And similarly...

而同样...

- (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;
} }

There is no need to poll anything as long as you check the state of your applications audio session say for example in the viewDidLoadof your root view controller, at the start of you apps lifecycle. Any changes from there onwards to your applications audio session will be known via these two main notifications. Replace the NSLogstatements with what ever your code needs to do based on the cases contained in the switch.

只要您viewDidLoad在应用程序生命周期开始时检查应用程序音频会话的状态,例如在根视图控制器的状态中,就无需轮询任何内容。从那以后对您的应用程序音频会话的任何更改都将通过这两个主要通知获知。NSLog根据 switch 中包含的情况,将语句替换为您的代码需要执行的操作。

You can find more information about AVAudioSessionInterruptionTypeKeyand AVAudioSessionRouteChangeReasonKeyin the AVAudioSessionclass reference documentation.

您可以在类参考文档中找到有关AVAudioSessionInterruptionTypeKey和 的 更多信息。AVAudioSessionRouteChangeReasonKeyAVAudioSession

My apologies for the long answer but I think Audio Session management in iOS is rather fiddly and Apple's Audio Session Programming Guide, at the time of writing this, does not include code examples using notifications for interruption handling.

我对冗长的回答表示歉意,但我认为 iOS 中的音频会话管理相当繁琐,在撰写本文时,Apple 的音频会话编程指南不包括使用通知进行中断处理的代码示例。

回答by BlackMouse

You can check if other audio is playing like this:

您可以检查其他音频是否正在播放:

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

[self handleIfAudioIsPlaying: otherAudioIsPlaying];

Then you can add a loop and check every X second if something changed.

然后您可以添加一个循环并每隔 X 秒检查一次是否发生了变化。