Уменьшите громкость iPod, чтобы воспроизвести звук приложения (например, родное приложение SMS) - PullRequest
12 голосов
/ 16 января 2010

Я сделал приложение для 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]; прямо перед звуком оповещения. Это имело смешанные результаты. В первый раз звук воспроизводится на полной громкости, как я и надеялся, но в последующие времена громкость намного ниже. Кроме того, музыка не исчезает гладко. Похоже, что iPodMusicPlayer и applicationMusicPlayer имеют одинаковую громкость. Это результат использования [AVAudioSession sharedInstance];? Есть ли другой способ инициализации AVAudioSession?

  5. Далее я попытался использовать AVAudioSession "ducking":

     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 снижается через секунду. Однако во второй раз, когда шаг завершается, звук воспроизводится чуть менее громко, в третий раз он едва слышен, а в четвертый раз тише. Затем, в пятый раз, он снова играет громко, и цикл повторяется.

    Кроме того, активация и деактивация кажутся довольно тяжелыми операциями, и они приводят к небольшому заиканию таймера.

Кто-нибудь пытался сделать что-то подобное? Есть ли предпочтительный подход к воспроизведению звука поверх музыки iPod?

Ответы [ 4 ]

11 голосов
/ 24 июня 2010

AVAudioSession - это правильный способ обработки " поведения звука на уровнях приложений, взаимодействия и устройств. " Я использовал слегка модифицированный # 6 на iOS 4 без проблем. Фоновый звук исчез, мой звук заиграл, а фоновый звук вернулся.

  1. Инициализация аудио сеанса (код обработки ошибок удален):

    AVAudioSession* audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil]
    [audioSession setActive:NO error:nil];
    
  2. Воспроизведение звука (AVAudioPlayer воспроизведение / prepareToPlay будет активировать аудио сеанс для вас ):

    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) указывает системе уведомлять фоновое аудио о возобновлении воспроизведения.

11 голосов
/ 09 января 2011

Правильный способ сделать то, что вы первоначально сказали, что вы хотели сделать, это ваш (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];
4 голосов
/ 17 января 2010

Почему бы не вернуться к # 2? Вместо:

  1. Исчезает
  2. Воспроизвести оповещение
  3. Fade in

Использование:

  1. Исчезает
  2. Пауза музыки
  3. Увеличение громкости
  4. Воспроизвести оповещение
  5. Уменьшить громкость
  6. Воспроизведение музыки
  7. Fade in
0 голосов
/ 13 апреля 2017

Для 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];
}
...