音频会话“闪避” iOS 4 坏了……?

发布于 2024-09-11 00:52:45 字数 4292 浏览 2 评论 0 原文

我有一个应用程序,它使用 MPAudioPlayerController 来访问 iPod 音乐库,并使用 AVAudioPlayer 将音频覆盖在音乐之上。我用过 本文档作为指南。具体来说:

最后,您可以增强一个类别,以便在播放您的音频时自动降低其他音频的音量。例如,这可以用于锻炼应用程序。假设用户正在边听着 iPod 边锻炼,您的应用程序想要叠加一条口头消息,例如“您已经划船 10 分钟了”。为了确保应用程序中的消息易于理解,请将 kAudioSessionProperty_OtherMixableAudioShouldDuck 属性应用于音频会话。进行闪避时,设备上的所有其他音频(电话音频除外)的音量都会降低。

但我没有看到这种行为。事实上,我看到(或者听到的是)的是,如果我将 AudioSession 设置为 kAudioSessionProperty_OtherMixableAudioShouldDuck 设置为 true,则 MPAudioPlayerController 初始音量会减小,如果我随后在 MPAudioPlayerController 上调用暂停(然后再次播放)音量级别增加到“正常”水平。播放 AVAudioPlayer 对音频电平没有任何影响...

所以我设置了一个简单的测试用例来重现这一点。

在 ViewController 标头中:

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>

@interface MusicPlayerVolumeTestViewController : UIViewController <AVAudioPlayerDelegate>
{
    UIButton *musicButton;
    UIButton *soundButton;
    AVAudioPlayer *audioPlayer;
    MPMusicPlayerController *musicPlayerController;
}
@property (nonatomic, retain) IBOutlet UIButton *musicButton;
@property (nonatomic, retain) IBOutlet UIButton *soundButton;
@property (nonatomic, retain) MPMusicPlayerController *musicPlayerController;

- (IBAction)musicAction;
- (IBAction)soundAction;

@end

以及在实现中:

- (void)viewDidLoad
{
    [super viewDidLoad];

    //Setup our Audio Session
    OSStatus status = AudioSessionInitialize(NULL, NULL, NULL, NULL);    
    //We want our audio to play if the screen is locked or the mute switch is on
    UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
    status = AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (sessionCategory), &sessionCategory);
    //We want our audio to mix with other app's audio
    UInt32 shouldMix = true;
    status = AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof (shouldMix), &shouldMix);
    //Enable "ducking" of the iPod volume level while our sounds are playing
    UInt32 shouldDuck = true;
    AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(shouldDuck), &shouldDuck);
    //Activate our audio session
    AudioSessionSetActive(YES);

    //Setup the Music Player to access the iPod music library
    self.musicPlayerController = [MPMusicPlayerController applicationMusicPlayer];
    [self.musicPlayerController setShuffleMode: MPMusicShuffleModeSongs];
    [self.musicPlayerController setRepeatMode: MPMusicRepeatModeNone];
    [self.musicPlayerController setQueueWithQuery:[MPMediaQuery songsQuery]];

    //Setup a AVAudioPlayer sound to overlay against the Music Player audio
    NSURL *soundURL = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"overlay" ofType:@"mp3"]];
    NSError *error = nil;
    audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error: &error];
    if (!audioPlayer)
    {
        NSLog(@"Could not create audio effect player: %@", [error localizedDescription]);
    }
    [audioPlayer prepareToPlay];
}

- (IBAction)musicAction
{
    if (self.musicPlayerController.playbackState == MPMusicPlaybackStatePlaying)
    {
        [self.musicPlayerController pause];
    }
    else if (self.musicPlayerController.playbackState == MPMusicPlaybackStateStopped
          || self.musicPlayerController.playbackState == MPMusicPlaybackStatePaused)
    {
        [self.musicPlayerController play];
    }
}

- (IBAction)soundAction
{
    if (audioPlayer.playing)
    {
        [audioPlayer pause];
    }
    else
    {
        [audioPlayer play];
    }
}

我连接了几个 UIButton。一种用于 musicAction(用于播放/暂停 MPMusicPlayerController),另一种用于 soundAction(用于播放/暂停 AVAudioPlayer)。

如前所述,如果我点击 musicAction 按钮,则会播放音乐,但音量会降低;如果我点击 soundAction 按钮,则会播放叠加层,但不会影响 MPMusicPlayerController 的音量。而且,更类似错误的是,当我暂停然后播放 MPMusicPlayerController 时,音乐的音量会增加到我没有设置 AudioSession 时的水平。

我很想知道其他人是否有过这种经历,如果有的话,您是否找到了解决方法(或者可以告诉我我做错了什么)。否则,我想我要去雷达了。

非常感谢,

利维

I've an app which uses the MPAudioPlayerController to access the iPod music library, and an AVAudioPlayer to overlay audio on top of the music. I've used this documentation as a guide. Specifically:

Finally, you can enhance a category to automatically lower the volume of other audio when your audio is playing. This could be used, for example, in an exercise application. Say the user is exercising along to their iPod when your application wants to overlay a verbal message—for instance, “You’ve been rowing for 10 minutes.” To ensure that the message from your application is intelligible, apply the kAudioSessionProperty_OtherMixableAudioShouldDuck property to the audio session. When ducking takes place, all other audio on the device—apart from phone audio—lowers in volume.

But I'm not seeing this behavior. In fact, what I see (or hear, rather) is that if I setup the AudioSession with kAudioSessionProperty_OtherMixableAudioShouldDuck set to true, the MPAudioPlayerController initial volume gets reduced, and if I then call pause (and then play again) on the MPAudioPlayerController the volume level gets increased to "normal" levels. Playing the AVAudioPlayer does not have any affect on the audio level...

So I've set up a simple test case to reproduce this.

In a ViewController header:

#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#import <AudioToolbox/AudioToolbox.h>
#import <AVFoundation/AVFoundation.h>

@interface MusicPlayerVolumeTestViewController : UIViewController <AVAudioPlayerDelegate>
{
    UIButton *musicButton;
    UIButton *soundButton;
    AVAudioPlayer *audioPlayer;
    MPMusicPlayerController *musicPlayerController;
}
@property (nonatomic, retain) IBOutlet UIButton *musicButton;
@property (nonatomic, retain) IBOutlet UIButton *soundButton;
@property (nonatomic, retain) MPMusicPlayerController *musicPlayerController;

- (IBAction)musicAction;
- (IBAction)soundAction;

@end

and in the implementation:

- (void)viewDidLoad
{
    [super viewDidLoad];

    //Setup our Audio Session
    OSStatus status = AudioSessionInitialize(NULL, NULL, NULL, NULL);    
    //We want our audio to play if the screen is locked or the mute switch is on
    UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
    status = AudioSessionSetProperty (kAudioSessionProperty_AudioCategory, sizeof (sessionCategory), &sessionCategory);
    //We want our audio to mix with other app's audio
    UInt32 shouldMix = true;
    status = AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof (shouldMix), &shouldMix);
    //Enable "ducking" of the iPod volume level while our sounds are playing
    UInt32 shouldDuck = true;
    AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(shouldDuck), &shouldDuck);
    //Activate our audio session
    AudioSessionSetActive(YES);

    //Setup the Music Player to access the iPod music library
    self.musicPlayerController = [MPMusicPlayerController applicationMusicPlayer];
    [self.musicPlayerController setShuffleMode: MPMusicShuffleModeSongs];
    [self.musicPlayerController setRepeatMode: MPMusicRepeatModeNone];
    [self.musicPlayerController setQueueWithQuery:[MPMediaQuery songsQuery]];

    //Setup a AVAudioPlayer sound to overlay against the Music Player audio
    NSURL *soundURL = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"overlay" ofType:@"mp3"]];
    NSError *error = nil;
    audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error: &error];
    if (!audioPlayer)
    {
        NSLog(@"Could not create audio effect player: %@", [error localizedDescription]);
    }
    [audioPlayer prepareToPlay];
}

- (IBAction)musicAction
{
    if (self.musicPlayerController.playbackState == MPMusicPlaybackStatePlaying)
    {
        [self.musicPlayerController pause];
    }
    else if (self.musicPlayerController.playbackState == MPMusicPlaybackStateStopped
          || self.musicPlayerController.playbackState == MPMusicPlaybackStatePaused)
    {
        [self.musicPlayerController play];
    }
}

- (IBAction)soundAction
{
    if (audioPlayer.playing)
    {
        [audioPlayer pause];
    }
    else
    {
        [audioPlayer play];
    }
}

I've wired up a couple UIButtons. One for the musicAction (used for playing/pausing the MPMusicPlayerController) and one for the soundAction (used for playing/pausing the AVAudioPlayer).

As mentioned, If I tap the musicAction button, the music plays, but at a reduced volume level, and if I tap the soundAction button, the overlay plays, but has no affect on the volume of the MPMusicPlayerController. And, more bug-like, is that when I pause and then play the MPMusicPlayerController the volume of the music increases to the level it would have been if I did not setup the AudioSession.

I'm interested to know if anyone else has had this experience, and if so if you've found a work around (or can tell me that I'm doing something wrong). Otherwise, I guess I'm off to Radar.

Many thanks,

Levi

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

撩起发的微风 2024-09-18 00:52:46

当我遇到类似问题并且无法使其一致工作时,我使用了这篇文章。它会工作一段时间,然后就会陷入“隐藏”状态。我花了很多时间研究和调试这个问题,最后才给苹果打电话。他们告诉我查看面包屑示例代码。我按照这个例子进行操作,一切正常。

这是Apple的示例代码:

http://developer.apple .com/library/ios/#samplecode/Breadcrumb/Introduction/Intro.html

苹果的支持/开发人员还表示要观察他们设置会话属性的方式和时间的顺序。这显然就是其中的伎俩。在阅读了这里和其他地方的很多帖子后,我的设置相互冲突。从头开始并遵循面包屑示例使其发挥作用。从那以后我再也没有遇到过问题。

我在这里发布了相同的答案:

如何取消 AVAudioSession

对我来说这个答案是边缘商业秘密,因为它很难工作,而且市场上有可用的应用程序。对我来说,看到一个工作示例(几乎只是声音闪避和取消闪避)是值得的。

另外,我向苹果提到这是一个已知问题,但他们不同意。他们不知道这里有任何问题。果然,如果您遵循面包屑示例,它就可以正常工作,不会出现任何奇怪的会话停用和反应等情况。

I used this post when I was having a similar issue and had trouble getting it to work consistently. It would work for a while and then just get stuck "ducked". I spent a lot of time researching and debugging this and finally just called Apple. They told me to look at the breadcrumb sample code. I followed that example and everything worked fine.

Here is Apple's sample code:

http://developer.apple.com/library/ios/#samplecode/Breadcrumb/Introduction/Intro.html

The support/developer at Apple also said to watch the order of how and when they set the session properties. That apparently was the trick. After reading a lot of posts here and elsewhere, I had settings that conflicted with each other. Starting from scratch and following the bread crumb example made it work. I have not had an issue since.

I posted the same answer here:

How to unduck AVAudioSession

To me this answer was borderline trade secret since it was so difficult to get working and there were working apps in the market. For me, seeing a working example, which was pretty much just the sound ducking and unducking was worth its weight in gold.

Also, I mentioned to Apple that this was a known issue and they did not agree. They were not aware of any issue here. Sure enough if you follow the breadcrumb example it works with out any strange session deactivate and reactive, etc., etc.

鸩远一方 2024-09-18 00:52:46

闪避不会以任何方式自动与您的演奏声音相关。当您打开闪避时,背景声音会闪避。当您关闭闪避并停用音频会话时,背景声音会恢复到其原始级别。

因此,不要viewDidLoad 中启用闪避。在真正要播放声音之前不要打开它。这会导致背景声音减弱。声音播放完毕后,关闭闪避并再次将音频会话切换为非活动状态和活动状态。这会导致背景声音消失:

UInt32 duck = 0;
AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, 
                        sizeof(duck), &duck);
AudioSessionSetActive(false);
AudioSessionSetActive(true);

Ducking is not automatically related to your playing sounds in any way. When you turn on ducking, background sound ducks. When you turn off ducking and deactivate your audio session, background sound comes back to its original level.

So don't turn on ducking in your viewDidLoad. Don't turn it on until you are actually about to play the sound. That causes the background sound to duck. When your sound is done playing, turn ducking back off and toggle your audio session inactive and active again. That causes the background sound to unduck:

UInt32 duck = 0;
AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, 
                        sizeof(duck), &duck);
AudioSessionSetActive(false);
AudioSessionSetActive(true);
伪心 2024-09-18 00:52:46

该文档不清楚闪避的预期行为应该是什么,但我发现,如果您将音频会话设置为闪避,那么当您激活音频会话时,它会闪避,而当您停用音频会话时,它会闪避它,它解开。因此,您必须不断激活和停用音频会话,以避开音乐以获取声音提示。

我发现的一个错误是,如果您在 AVAudioPlayerDelegateaudioPlayerDidFinishPlaying:successively: 方法内停用音频会话,则不会删除闪避,并且会保留音量处于同一水平。我已经就此提交了雷达,但如果其他人也提交类似的雷达,也没什么坏处。事实上,这可能会给他们带来一些修复问题的压力。

您要做的就是启动音频会话并保持打开状态,这样它就会立即闪避并保持闪避状态,这样当您播放声音时它就不会进一步闪避音乐。暂停和播放音乐后音乐音量恢复的问题听起来像是一个错误。

The documentation isn't clear about what the expected behavior of ducking is supposed to be, but what I've found is that if you set up your audio session for ducking, when you activate the audio session, it ducks, and when you deactivate it, it unducks. So you have to keep activating and deactivating the audio session to duck the music just for your sound cue.

One bug I found is that if you deactivate the audio session while inside the audioPlayerDidFinishPlaying:successfully: method of your AVAudioPlayerDelegate, the ducking isn't removed, and the volume is kept at the same level. I've already filed a Radar on this, but it doesn't hurt if other file similar ones. In fact it'll probably put some pressure on them to fix it.

What you're doing is starting the audio session and keeping it on, so it ducks immediately and stays ducked, so that it won't duck the music any further when you play a sound. The issue with the music volume going back up after pausing and playing the music sounds like a bug.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文