在iOS设备上检测活动的AVAudioSessions [英] Detecting active AVAudioSessions on iOS device

查看:700
本文介绍了在iOS设备上检测活动的AVAudioSessions的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

 我尝试找出这是否可能 - 我的应用程序激活一个音频会话, [[[AVAudioSession alloc] init] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:& error]; 

我希望能够理解何时发起另一个应用程序或操作系统



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



有没有办法实现这个而不使用私人API?



提前感谢。

解决方案

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



以下是iOS 6.0 。



告诉应用程序沙盒外的其他音频是否正在播放 -

  //查询是否正在播放其他音频
BOOL isPlayingWithOthers = [[AVAudioSession sharedInstance] isOtherAudioPlaying];
//用...测试...
(isPlayingWithOthers)? NSLog(@其他音频正在播放):NSLog(@没有其他音频正在播放);

对于中断处理,您需要观察 AVAudioSessionInterruptionNotification AVAudioSessionRouteChangeNotification 。所以在管理你的音频会话的类中,你可以放置类似下面的东西 - 这应该在应用程序生命周期开始时调用一次,不要忘记删除同一类的dealloc方法中的observer。

  //确保我们已经有一个单例对象
[AVAudioSession sharedInstance];
//注册通知
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(interrupt :)
name:AVAudioSessionInterruptionNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(routeChange :)
name:AVAudioSessionRouteChangeNotification
object:nil];

最后添加以下选择器 interrupt: routeChange: - 这些将收到一个 NSNotification 对象,它有一个名为userInfo的属性类型

   - (void)中断:( NSDictionary  NSNotification *)notification {
//获取用户信息字典
NSDictionary * interuptionDict = notification.userInfo;
//从字典中获取AVAudioSessionInterruptionTypeKey枚举
NSInteger interuptionType = [[interuptionDict valueForKey:AVAudioSessionInterruptionTypeKey] integerValue];
//根据中断类型决定做什么...
switch(interuptionType){
case AVAudioSessionInterruptionTypeBegan:
NSLog(@Audio Session Interrupt case started。 ;
// fork to handling method here ...
// EG:[self handleInterruptionStarted];
break;

case AVAudioSessionInterruptionTypeEnded:
NSLog(@音频会话中断结束。
// fork到这里的处理方法...
// EG:[self handleInterruptionEnded];
break;

默认值:
NSLog(@音频会话中断通知大小写默认值。
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:
//添加或删除耳机
NSLog(@routeChangeReason:AVAudioSessionRouteChangeReasonNewDeviceAvailable);
break;

case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
//添加或删除耳机
NSLog(@routeChangeReason:AVAudioSessionRouteChangeReasonOldDeviceUnavailable);
break;

case AVAudioSessionRouteChangeReasonCategoryChange:
//在开始时调用 - 当其他音频要播放时
NSLog(@routeChangeReason:AVAudioSessionRouteChangeReasonCategoryChange); // AVAudioSessionRouteChangeReasonCategoryChange
break ;

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

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

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

默认值:
break;
}}

没有必要轮询任何东西,只要检查状态您的应用程序音频会话例如在应用程序生命周期开始时的根视图控制器的 viewDidLoad 中。从那里开始到您的应用程序音频会话的任何更改将通过这两个主要通知。将 NSLog 语句替换为您的代码根据交换机中包含的案例需要做什么。



可以在 AVAudioSession 中找到有关 AVAudioSessionInterruptionTypeKey AVAudioSessionRouteChangeReasonKey 类参考文档。



我的答案很长,但我认为在iOS中的音频会话管理是相当fiddly和苹果的音频会话编程指南,在写这篇文章的时候,不包括使用通知进行中断处理的代码示例。


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 endInterruption but these won't get invoked because of the AVAudioSessionCategoryOptionMixWithOthers option I'm using.

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

Thanks in advance.

解决方案

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.0 you would make use of AVAudioSession and AudioSessionServices classes, incorporating delegation and property listening respectively. From iOS 6.0 onwards use AVAudioSession class and incorporate notifications.

The following is for iOS 6.0 onwards.

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 AVAudioSessionInterruptionNotification and 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.

// 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 NSNotification object that has a property called userInfo of type NSDictionary that you read to assist any conditionals your application has.

- (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 viewDidLoad of 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 NSLog statements with what ever your code needs to do based on the cases contained in the switch.

You can find more information about AVAudioSessionInterruptionTypeKey and AVAudioSessionRouteChangeReasonKey in the AVAudioSession class reference documentation.

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设备上检测活动的AVAudioSessions的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆