降低iPod音量以播放应用程序声音(如本机SMS应用程序)

时间:2010-01-16 18:21:29

标签: ios cocoa-touch iphone-sdk-3.0 avaudioplayer avaudiosession

我制作了一款可在运动时使用的iPhone应用程序。它会播放铃声,表示您(用户)应该从练习例程的一个步骤切换到下一个步骤。我设计了应用程序,以便您在使用应用程序时可以在iPod上听音乐,我希望音调可以在音乐上充分发声。我已经让这个工作......有点......

当音乐响亮时,很难听到音调。我理想的解决方案类似于iPod应用程序处理传入短信或电子邮件的方式。音乐音量降低,声音播放,音乐音量逐渐消失。

以下是我迄今为止尝试过的方法:

  1. 我用AudioServicesPlaySystemSound来播放声音。

    我将声音初始化为:

    CFBundleRef mainBundle = CFBundleGetMainBundle();
    soundFileURLRef = CFBundleCopyResourceURL(mainBundle, CFSTR ("bell"), CFSTR ("wav"), NULL);
    AudioServicesCreateSystemSoundID (soundFileURLRef, &soundFileID);
    

    我在适当的时候使用以下方式播放声音:

    AudioServicesPlaySystemSound (self.soundFileID);
    

    这听起来很好,但听到嘈杂的音乐太难了。在尝试2 ...

  2. 我尝试降低iPod音量,播放声音,然后将音量恢复到之前的水平。

    如果当前步骤还剩1秒,则开始降低音量:

    if ([self.intervalSet currentStepTimeRemainingInSeconds] == 1) {
        self.volumeIncrement = originalVolume/5.0f;
        [NSTimer scheduledTimerWithTimeInterval:0.5f 
                                         target:self 
                                       selector:@selector(fadeVolumeOut:) 
                                       userInfo:[NSNumber numberWithInt:1]
                                        repeats:NO];
    }
    

    以下是fadeVolumeOut:方法:

    - (void) fadeVolumeOut:(NSTimer *)timer {
        if (!TARGET_IPHONE_SIMULATOR) {
            NSNumber *volumeStep = (NSNumber *)[timer userInfo];
            int vStep = [(NSNumber *)volumeStep intValue];
            float volume = [[MPMusicPlayerController iPodMusicPlayer] volume];
            volume = volume - self.volumeIncrement;
            if (volume < 0.0f) {
                volume = 0.0f;
            }
            [[MPMusicPlayerController iPodMusicPlayer] setVolume:volume];
            if (vStep < 5) {
                vStep = vStep + 1;
                [NSTimer scheduledTimerWithTimeInterval:0.1f 
                                                 target:self 
                                               selector:@selector(fadeVolumeOut:) 
                                               userInfo:[NSNumber numberWithInt:vStep]
                                                repeats:NO];
            }
        }
    }
    

    然后,当步骤结束时,播放警报声并将音量淡入:

     [NSTimer scheduledTimerWithTimeInterval:0.1f 
                                      target:self 
                                    selector:@selector(alertAndFadeVolumeIn) 
                                    userInfo:nil
                                     repeats:NO];
    

    以下是alertAndFadeVolumeIn方法:

     - (void) alertAndFadeVolumeIn {
         [self alert];
         [NSTimer scheduledTimerWithTimeInterval:0.25f 
                                          target:self 
                                        selector:@selector(fadeVolumeIn:) 
                                        userInfo:[NSNumber numberWithInt:1]
                                         repeats:NO];
     }
    

    fadeVolumeIn:基本上与上面的fadeVolumeOut:相反。

    此功能正常,音量消失,声音播放,音量逐渐消失。问题是音量降低了与iPod相同的音量,因此听起来不容易听在音乐上。

  3. 我切换到AVAudioSession播放声音,并设置会话,以便在应用程序使用时iPod音乐将继续播放。这是我正在初始化会话的方式:

     AVAudioSession *session = [AVAudioSession sharedInstance];
     [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    
     OSStatus propertySetError = 0;
     UInt32 allowMixing = true;
     propertySetError = AudioSessionSetProperty (
         kAudioSessionProperty_OverrideCategoryMixWithOthers,
         sizeof (allowMixing),
         &allowMixing
     );
    
     NSError *activationError = nil;
     [session setActive:YES error:&activationError];
    
     NSString *audioFile = [[NSBundle mainBundle] pathForResource:@"bell"
                                                           ofType:@"wav"];
     player = [[AVAudioPlayer alloc] initWithContentsOfURL:
         [NSURL fileURLWithPath:audioFile] error:NULL];
    

    要播放声音,我会在适当的时候拨打[self.player play]。同样,音量与iPod音量一起降低,音调也不容易听到。

  4. 我尝试在发出提示音之前放[[MPMusicPlayerController applicationMusicPlayer] setVolume:1.0f];。结果好坏参半。第一次按照我的预期,音量以满音量播放,但随后音量会低很多。此外,音乐不会平滑淡出。似乎iPodMusicPlayerapplicationMusicPlayer共享相同的音量。这是使用[AVAudioSession sharedInstance];的结果吗?是否有其他方法可以初始化AVAudioSession

  5. 接下来,我尝试使用AVAudioSession“躲避”:

     OSStatus propertySetError = 0;
     UInt32 allowDucking = true;
     propertySetError = AudioSessionSetProperty (
         kAudioSessionProperty_OtherMixableAudioShouldDuck,
         sizeof (allowDucking),
         &allowDucking
     );
    

    不幸的是,当音频会话被激活时,iPod音乐会“躲避”,就像我一样装载viewController一样。

  6. 最后,我改变了我的代码,以便音频会话在步骤结束前一秒激活,声音在步骤结束时播放,一秒钟后,会话被停用。此时我已经删除了所有淡入淡出的代码。以下是相关的代码段:

    if ([self.intervalSet currentStepTimeRemainingInSeconds] == 1) {
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setActive:YES error:nil];
    }
    

    ...

    if (self.shouldRing) {
        [self.player play]; 
        [NSTimer scheduledTimerWithTimeInterval:1.0f 
                                         target:self 
                                       selector:@selector(stopSound)
                                       userInfo:nil
                                        repeats:NO];
    }
    

    ...

    - (void) stopSound {
        [self.player stop];
        AVAudioSession *session = [AVAudioSession sharedInstance];
        [session setActive:NO error:nil];
    }
    

    这让我陷入了困境。这在第一步结束后完美地起作用。 iPod音量下降,声音大声播放,iPod音量在一秒后消失。然而,第二次步骤结束时,声音播放的声音稍微不那么大,第三次几乎听不到声音,第四次声音静音。然后,第五次,它再次大声播放,循环重复。

    最重要的是,激活和停用似乎是非常繁重的操作,它们会导致定时器略微断断续续。

  7. 有没有人试图做类似的事情?有没有一种首选的方法来播放iPod音乐?

4 个答案:

答案 0 :(得分:11)

AVAudioSession是处理“audio behavior at the application, interapplication, and device levels.的正确方法”我在iOS 4上使用了略微修改的#6而没有任何问题。背景音频淡出,我的声音播放,背景音频消失了。

  1. 初始化音频会话(删除错误处理代码):

    AVAudioSession* audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]
    [audioSession setActive:NO error:nil];
    
  2. 播放声音(AVAudioPlayer的播放/ prepareToPlay将activate the audio session for you):

    AVAudioPlayer* audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
    [audioPlayer play];
    
  3. 停止声音:

    [audioPlayer stop];
    [[AVAudioSession sharedInstance] setActive:NO withFlags:AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation error:nil];
    

    标志kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation(iOS 4新增功能)告诉系统通知背景音频以继续播放。

答案 1 :(得分:11)

按照你原来所说的你想做的正确方法是你的(5) - 使用闪避。这是交易。使用允许其他应用播放声音的音频会话类型(播放)。在你即将播放声音之前不要打开闪避。当您即将播放声音时,请打开闪避!背景音乐会立即消失,因此可以听到您的声音。然后,当你的声音播放完毕后,关闭闪避现在(这是技巧)停用音频会话并再次激活它,使背景音乐立即恢复原来的响度:

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

编辑:在iOS 6中,您可以(并且应该)仅使用Objective-C API完成所有这些操作。所以,开始躲避其他音频:

[[AVAudioSession sharedInstance] 
    setCategory: AVAudioSessionCategoryAmbient
    withOptions: AVAudioSessionCategoryOptionDuckOthers
          error: nil];

完成播放声音后,请关闭闪避:

[[AVAudioSession sharedInstance] setActive:NO withOptions:0 error:nil];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient
                                 withOptions: 0
                                       error: nil];
[[AVAudioSession sharedInstance] setActive:YES withOptions: 0 error:nil];

答案 2 :(得分:4)

为什么不回到#2?而不是:

  1. 淡出
  2. 播放提醒
  3. 淡入
  4. 使用:

    1. 淡出
    2. 暂停音乐
    3. 提高音量
    4. 播放提醒
    5. 降低音量
    6. 播放音乐
    7. 淡入

答案 3 :(得分:0)

适用于Xcode 8,iOS 10

<强>目的:

  

像在导航应用中一样工作(Waze / Google Maps / RideAustin)   播放您的声音,减少背景音乐音量。播放声音后,恢复背景音乐音量

<强>实施

初​​始化:

{
    NSError *error = nil;
    [[AVAudioSession sharedInstance] 
        setCategory: AVAudioSessionCategoryPlayback
        withOptions: AVAudioSessionCategoryOptionDuckOthers | AVAudioSessionCategoryOptionMixWithOthers
              error: nil];
    [[AVAudioSession sharedInstance] setPreferredIOBufferDuration:0.005 error:&error];
    ...
}
播放声音时

{
    ...
    NSError *error = nil;
    AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];

    //set delegate
    player.delegate = self
    ...
    [player play]
}

确保其他音乐播放器应用量将恢复工具

#pragma mark - AVAudioPlayerDelegate
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    ...
    [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
}