Управление активизацией аудио

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

Перед тем, как ваше приложение начнет воспроизведение аудио оно должна запросить — и получить — аудио фокус. Кроме того, оно должно уметь слушать событие потери аудио фокуса, и реагировать соответствующим образом, когда это произойдет.

Запросить аудио фокус

Перед тем, как ваше приложение начнет проигрывать любой звук, оно должно удерживать аудио фокус для потока, который оно будет использовать. Это делается с помощью вызова requestAudioFocus() который возвращает AUDIOFOCUS_REQUEST_GRANTED если ваш запрос успешно выполнен.

Вы должны указать, какие потоки вы используете, и ожидаете ли вы получить кратковременный или постоянный аудио фокус. Запросите кратковременный фокус, если вы собираетесь проигрывать аудио лишь короткое время (например при воспроизведении навигационных инструкций). Запросите постоянный аудио фокус, если вы планируете воспроизводить аудио в обозримом будущем (например, при воспроизведении музыки).

Следующий фрагмент запрашивает постоянный аудио фокус для музыкального аудиопотока. Вы должны запросить аудио фокус непосредственно перед тем как начать воспроизведение, например, когда пользователь нажимает играть или начинается фоновая музыка для следующего уровня игры.

AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...

// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
                                 // Use the music stream.
                                 AudioManager.STREAM_MUSIC,
                                 // Request permanent focus.
                                 AudioManager.AUDIOFOCUS_GAIN);
   
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    am.registerMediaButtonEventReceiver(RemoteControlReceiver);
    // Start playback.
}

После того, как вы закончили воспроизведение не забудьте вызвать abandonAudioFocus(). Это уведомляет систему, что вы больше не нуждаетесь в фокусе и отменяет регистрацию связанных с ним AudioManager.OnAudioFocusChangeListener. Отказа от кратковременного фокуса позволяет любому прерванному приложению продолжить воспроизведение.

// Abandon audio focus when playback complete    
am.abandonAudioFocus(afChangeListener);

При запросе кратковременного аудио фокуса у вас есть дополнительные опции: хотите ли вы позволить "приглушить звук". Обычно, когда хорошо разработанное аудио приложение теряет аудио фокус, оно сразу останавливают своё воспроизведение. Запрашивая кратковременный аудио фокус, который позволяет приглушить звук, вы рассказываете другим аудио приложениям, что приемлемо, если они продолжат играть, снизив их громкость, пока фокус к ним не вернется.

// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
                             // Use the music stream.
                             AudioManager.STREAM_MUSIC,
                             // Request permanent focus.
                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
   
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // Start playback.
}

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

Всякий раз, когда другое приложение запрашивает аудио фокус, как описано выше, его выбор между постоянным и переходным (с или без поддержки приглушения) аудио фокусом получает обработчик, который вы зарегистрировали при запросе фокуса.

Обработка потери аудио фокуса

Если ваше приложение может запросить аудио фокус, отсюда следует, что оно, в свою очередь, может потерять этот фокус, когда другое приложение его запросит. Как ваше приложение отреагирует на потерю аудио фокуса, зависит от способа его потери.

onAudioFocusChange() метод обратного вызова обработчика смены звукового фокуса, который вы зарегистрировали при запросе аудио фокуса, получает параметр, описывающий событие изменения фокуса. В частности, событие возможной потери фокуса отражает тип запрошенного фокуса из предыдущего раздела — постоянная потеря, временная потеря и кратковременная с разрешенным приглушением.

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

Если потеря аудио фокуса является постоянной, предполагается, что другое приложение в настоящее время используется для прослушивания аудио, и ваше приложение должно эффективно завершить себя. В практическом плане это означает, прекращение воспроизведения, удаления обработчиков событий медиа кнопок — позволяя новому аудиоплееру исключительно обрабатывать эти события — и отказ от вашего аудио фокуса. В тот состоянии, вы можете ожидать действие пользователя (нажатие кнопки играть в вашем приложении), для возобновления воспроизведения аудио.

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

OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
            // Pause playback
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Resume playback 
        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
            am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
            am.abandonAudioFocus(afChangeListener);
            // Stop playback
        }
    }
};

В случае временной потери аудио фокуса, где приглушение разрешено, вместо приостановки воспроизведения, вы можете "приглушить" звук.

Затухание!

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

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

OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
            // Lower the volume
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Raise it back to normal
        }
    }
};

Потеря аудио фокуса является наиболее важным событием, на которое нужно реагировать, но не единственное. Система рассылает ряд намерений, чтобы предупредить вас об изменениям в аудио опыты пользователя. Следующий урок демонстрирует, как отслеживать и улучшать общий опыт пользователя.