【问题标题】:Cannot Control Volume of AVAudioPlayer via Hardware Buttons when AudioSessionActive is NO当 AudioSessionActive 为 NO 时,无法通过硬件按钮控制 AVAudioPlayer 的音量
【发布时间】:2013-05-10 03:34:29
【问题描述】:

我正在构建一个逐向导航应用程序,它会播放周期性的短声音片段。无论屏幕是否被锁定,声音都应该播放,应该与其他音乐混合播放,并且在该音频播放时应该让其他音乐回避。

Apple 在 29:20 分钟的“WWDC 2010 session 412 Audio Development for iPhone OS part 1”视频中详细讨论了逐步使用案例。该实现效果很好,但有一个问题 - 当应用程序运行时,按下硬件音量控件会调整铃声音量,而不是应用程序音量。如果要更改应用音量,则必须在播放提示时按音量按钮。

Apple 在视频中非常具体,您不应该让 AVAudioSession 处于活动状态,但如果 AVAudioSession 处于非活动状态,则音量按钮将无法控制我的应用程序的音量。

这是我用来设置的代码:

UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
propertySetError = AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(sessionCategory), &sessionCategory);

UInt32 allowMixing = true;
propertySetError = AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);

UInt32 shouldDuck = true;
propertySetError = AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(shouldDuck), &shouldDuck);

OSStatus activationResult = AudioSessionSetActive(true);

NSError* err = nil;
_player = [[AVAudioPlayer alloc] initWithData:audioData error:&err];
_player.delegate = self;
[_player play];

按照 Apple 的建议,我在最后将会话活动设置为 NO:

OSStatus activationResult = AudioSessionSetActive(false);
NSAssert(activationResult == kAudioSessionNoError, @"Error deactivating audio session");

是我遗漏了什么,还是我必须违背他们在视频中推荐的内容?

【问题讨论】:

  • Apple 是否有可能让用户在看到或听到没有活动的音频时假定他们正在控制铃声?不是你的应用?
  • @hotpaw2 好问题。 Core Audio 开发人员在设计此行为时可能已经考虑到这一点,但如果您研究 Apple Maps 在导航模式下的工作方式,硬件按钮会在不播放提示时控制应用音量。显然有一种方法可以做到这一点,Apple 认为这是正确的行为,因为他们的 Turn-by-turn 应用程序的工作方式。
  • 我创建了一个 github 项目,该项目使用 WWDC 演讲中的代码并展示了该问题。你想在真实硬件上运行它:github.com/marcregan/core-audio-volume-problems/tree/master/…

标签: objective-c core-audio avaudioplayer avaudiosession


【解决方案1】:

在您的情况下,您不想将音频会话设置为非活动状态。您需要做的是使用两种方法,一种将会话设置为播放声音,另一种将其设置为空闲。第一种方法设置混合+鸭子音频模式,第二种方法使用背景音频友好模式,如环境。

类似这样的:

- (void)setActive {
    UInt32 mix  = 1;
    UInt32 duck = 1;
    NSError* errRet;

    AVAudioSession* session = [AVAudioSession sharedInstance];
    [session setActive:NO error:&errRet];

    [session setCategory:AVAudioSessionCategoryPlayback error:&errRet];
    NSAssert(errRet == nil, @"setCategory!");

    AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(mix), &mix);
    AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(duck), &duck);

    [session setActive:YES error:&errRet];
}

- (void)setIdle {
    NSError* errRet;

    AVAudioSession* session = [AVAudioSession sharedInstance];
    [session setActive:NO error:&errRet];

    [session setCategory:AVAudioSessionCategoryAmbient error:&errRet];
    NSAssert(errRet == nil, @"setCategory!");

    [session setActive:YES error:&errRet];
}

然后调用它:

[self setActive];
[self _playAudio:nil];

播放后清理:

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer*)player
                   successfully:(BOOL)flag {
[self setIdle];

}

要成为一个好公民,您的应用应该在不导航(即执行其主要功能)时将音频会话设置为非活动状态,但是当它处于活动状态时,保持音频会话处于活动状态并且绝对没有错使用模式与其他应用程序和平共处。您可以使用上面的代码复制 Apple 的导航应用功能。

【讨论】:

    猜你喜欢
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-03
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多