在iOS设备上检测活动的AVAudioSessions

Sta*_*ash 26 cocoa-touch objective-c ios avaudiosession

我想知道这是否可行 - 我的应用程序激活一个初始化为的音频会话:

[[[AVAudioSession alloc] init] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
Run Code Online (Sandbox Code Playgroud)

我希望能够理解何时播放来自其他应用程序或操作系统的其他音频会话.

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

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

提前致谢.

Bam*_*rld 68

iOS 6.0以来,您管理应用程序的音频会话的方式发生了一些重大变化,值得一提.在iOS 6.0之前,您将使用AVAudioSessionAudioSessionServices类,分别包含委托和属性侦听.从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");
Run Code Online (Sandbox Code Playgroud)

至于中断处理,你需要观察AVAudioSessionInterruptionNotificationAVAudioSessionRouteChangeNotification.因此,在管理音频会话的类中,您可以添加如下内容 - 这应该在应用程序生命周期的开始时调用一次,并且不要忘记在同一个类的dealloc方法中删除observer.

// 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];
Run Code Online (Sandbox Code Playgroud)

最后添加下面的选择interruption:routeChange:-这些将获得NSNotification的是有一个名为类型的用户信息属性对象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;
} }
Run Code Online (Sandbox Code Playgroud)

同样......

- (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;
} }
Run Code Online (Sandbox Code Playgroud)

只要您检查应用程序音频会话的状态,例如在viewDidLoad您的根视图控制器中,在应用程序生命周期的开始时,就不需要轮询任何内容.通过这两个主要通知,可以了解从那里到应用程序音频会话的任何更改.NSLog根据交换机中包含的案例,将语句替换为代码需要执行的操作.

你可以找到更多的信息AVAudioSessionInterruptionTypeKey,并 AVAudioSessionRouteChangeReasonKey在在AVAudioSession类的参考文档.

我很抱歉答案很长,但我认为iOS中的音频会话管理相当繁琐,而Apple的音频会话编程指南在撰写本文时并未包含使用通知进行中断处理的代码示例.

  • 用户拨打电话或挂断电话是否会触发路由改变或中断。我希望能够检测麦克风是否可用于录制视频,以及用户是否正在通话麦克风不可用。考虑到电话,检测麦克风可用性的最佳方法是什么。 (3认同)

Bla*_*use 5

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

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

[self handleIfAudioIsPlaying: otherAudioIsPlaying];
Run Code Online (Sandbox Code Playgroud)

然后你可以添加一个循环并检查每一个X秒是否有变化.

  • 不推荐使用AudioSessionAddPropertyListener.还有其他选择 (2认同)