Подтвердить что ты не робот

Уменьшение громкости iPod для воспроизведения звука приложения (например, родного SMS-приложения)

Я сделал приложение для iPhone, которое будет использоваться во время упражнений. Он воспроизводит сигнал звонка, чтобы указать, что вы (пользователь) должны переключаться с одного шага вашей тренировочной процедуры на следующую. Я разработал приложение, чтобы вы могли слушать музыку на iPod при использовании приложения, и я хочу, чтобы звук воспроизводился достаточно громко над музыкой. Я получил это, чтобы работать... вроде...

Когда музыка звучит громко, трудно услышать тон. Мое идеальное решение похоже на то, как приложение iPod обрабатывает входящее текстовое сообщение или электронную почту. Громкость музыки снижается, звук воспроизводится, затем громкость музыки исчезает.

Вот те подходы, которые я пробовал до сих пор:

  • Я использовал AudioServicesPlaySystemSound для воспроизведения звука.

    Я инициализировал звук следующим образом:

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

    И я играю звук в соответствующее время, используя:

    AudioServicesPlaySystemSound (self.soundFileID);
    

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

  • Я переключился на 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, и звук не слышнее.

  • Я попытался поставить [[MPMusicPlayerController applicationMusicPlayer] setVolume:1.0f]; прямо перед звуком предупреждения. Это привело к неоднозначным результатам. В первый раз звук воспроизводится на полном объеме, как я надеялся, но в последующие времена громкость намного ниже. Кроме того, музыка не исчезает гладко. Кажется, что iPodMusicPlayer и applicationMusicPlayer используют один и тот же том. Является ли это результатом использования [AVAudioSession sharedInstance];? Есть ли другой способ инициализировать AVAudioSession?

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

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

    К сожалению, музыка iPod "утирается", когда звуковая сессия активирована, что сразу же, как загрузчик viewController загружен, как у меня были вещи.

  • Наконец, я изменил свой код, чтобы сеанс аудио был активирован за одну секунду до окончания действия, звук воспроизводится, когда шаг заканчивается, и через секунду сеанс деактивируется. В этот момент я удалил весь код моего угасания. Вот соответствующие фрагменты кода:

    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?

4b9b3361

Ответ 1

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

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

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

    AVAudioPlayer* audioPlayer = [[[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:nil];
    [audioPlayer play];
    
  • Остановка звука:

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

    Флаг kAudioSessionSetActiveFlag_NotifyOthersOnDeactivation (новый для iOS 4) сообщает системе уведомлять фоновый звук для возобновления воспроизведения.

Ответ 2

Правильный способ сделать то, что вы изначально сказали, что хотите сделать, - это ваше (5) - использовать утенок. Здесь сделка. Используйте тип аудиосоединения, который позволяет другим приложениям воспроизводить звук (воспроизведение). Не включайте ducking, пока вы не собираетесь воспроизводить свой звук. Когда вы собираетесь играть в свой звук, включите ducking! Фоновая музыка сразу утирается, так что ваш звук можно услышать. Затем, когда ваш звук закончит играть, выключите утилизацию и теперь (это трюк) деактивируйте свою сессию аудио и снова активируйте ее, чтобы фоновая музыка немедленно возобновила прежнюю громкость:

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

EDIT: в iOS 6 вы можете (и должны) делать все, используя только API Objective-C. Итак, чтобы начать ducking другой звук:

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

После того, как вы закончите воспроизведение своего звука, выключите ducking:

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

Ответ 3

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

  • Затухание
  • Воспроизвести предупреждение
  • Затухание

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

  • Затухание
  • Приостановить музыку
  • Увеличьте громкость
  • Воспроизвести предупреждение
  • Уменьшить громкость
  • Воспроизведение музыки
  • Затухание

Ответ 4

Для Xcode 8, iOS 10

Цель:

Чтобы работать как в навигационных приложениях (Waze/Google Maps/RideAustin) Воспроизводите звук, уменьшите объем фоновой музыки. После воспроизведения звука восстановите объем фоновой музыки

Реализация:

Initialize:

{
    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];
}