Освой программирование играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

AudioManager

Управление громкостью и воспроизведением

Управление аудиофокусом

Управление микрофоном

Использование динамиков

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

У класса достаточно большое количество констант и методов, но сам класс прост в использовании.

Пользователи могут слышать звук через встроенный динамик, разъём для проводной гарнитуры, Bluetooth (A2DP аудио). Вы можете через AudioManager определить, куда в настоящее время направляется аудиопоток и выполнить какое-нибудь действие, например, приглушить звук:


// Получаем доступ к менеджеру звуков
AudioManager manager = (AudioManager) this
		.getSystemService(Context.AUDIO_SERVICE);

if (manager.isBluetoothA2dpOn()) {
	// через Bluetooth
} else if (manager.isSpeakerphoneOn()) {
	// через динамик телефона
} else if (manager.isWiredHeadsetOn()) {
	// Устарело в API 14
	// через проводные наушники
} else {
	// может стоит выключить звук?
}

Система оповещает через широковещательное намерение ACTION_AUDIO_BECOMING_NOISY о смене источника звука. Зарегистрируйте BroadcastReceiver и прослушивайте нужное намерение.


private class NoisyAudioStreamReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
            // Pause the playback
        }
    }
}
 
private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
 
private void startPlayback() {
    registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
}
 
private void stopPlayback() {
    unregisterReceiver(myNoisyAudioStreamReceiver);
}

В некоторых других примерах на сайте также используется AudioManager.

Управление громкостью и воспроизведением

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

Также вы можете управлять воспроизведением аудиопотока - пауза, стоп и т.д.

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

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

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


setVolumeControlStream(AudioManager.STREAM_MUSIC);

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

Кнопки контроля воспроизведения, такие как воспроизведение, "пауза", "стоп", "вперёд" и "назад" доступны на некоторых телефонах и многих проводных или беспроводных гарнитурах. Когда пользователь нажимает одну из этих аппаратных кнопок, система рассылает намерение с действием ACTION_MEDIA_BUTTON.

Чтобы обработать нажатие медиа-кнопки, вам необходимо зарегистрировать BroadcastReceiver в файле манифеста:


<receiver android:name=".RemoteControlReceiver">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_BUTTON" />
    </intent-filter>
</receiver>

Реализация приёмника сама должна извлекать нажатую клавишу, переданную в оповещении. Объект Intent включает в себя ключ EXTRA_KEY_EVENT, класс KeyEvent включает в себя список статических констант KEYCODE_MEDIA_*, который содержит все возможные медиа-кнопки, такие как KEYCODE_MEDIA_PLAY_PAUSE и KEYCODE_MEDIA_NEXT.

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


public class RemoteControlReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
            KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
            if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()) {
                // Реагируем на нажатие
            }
        }
    }
}

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


AudioManager manager = this.getSystemService(Context.AUDIO_SERVICE);
...
 
// Начинаем прослушивать нажатия кнопок
manager.registerMediaButtonEventReceiver(RemoteControlReceiver);
...
 
// Больше не слушаем
manager.unregisterMediaButtonEventReceiver(RemoteControlReceiver);

Как правило, приложения должны отключать приёмники, когда они становятся неактивными или невидимыми. Однако, это не так просто для приложений, воспроизводящих мультимедиа – на самом деле отвечать на нажатия кнопок воспроизведения наиболее важно, когда приложение не видно и, следовательно, не может управляться с экрана пользовательского интерфейса. Лучший подход заключается в регистрации и отмене регистрации приемника событий медиа-кнопок, когда ваше приложение получает и теряет аудиофокус.

Управление аудиофокусом

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

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

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

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


AudioManager manager = this.getSystemService(Context.AUDIO_SERVICE);

int result = manager.requestAudioFocus(afChangeListener,
        AudioManager.STREAM_MUSIC,
        AudioManager.AUDIOFOCUS_GAIN);
 
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    manager.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
    // начинаем воспроизведение
}

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


manager.abandonAudioFocus(afChangeListener);

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


int result = manager.requestAudioFocus(afChangeListener,
        AudioManager.STREAM_MUSIC,
        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
 
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
    // начинаем воспроизведение
}

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

Ваше приложение может потерять фокус, когда его запросит другое приложение. Обратный вызов метода 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) {
            manager.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
            manager.abandonAudioFocus(afChangeListener);
            // Stop playback
        }
    }
};

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

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


OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
            // Приглушаем звук
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Возвращаем громкость на прежний уровень
        }
    }
};

Управление микрофоном

Проверить, выключен ли микрофон, можно с помощью метода isMicrophoneMute():


if (audioManager.isMicrophoneMute()) {
    // stop streaming audio input
}

Включить или выключить микрофон можно с помощью метод setMicrophoneMute():


audioManager.setMicrophoneMute(true);

Использование динамиков

Метод isSpeakerphoneOn() позволяет определить, играет ли музыка через динамики.


if (audioManager.isSpeakerphoneOn()) {
    // disable speakerphone button
}

Переключиться на динамики или отключить их можно через метод setSpeakerphoneOn():


audioManager.setSpeakerphoneOn(true);

Дополнительное чтение

Режим «Без звука» - управление режимами Обычный, Без звука, Вибрация.

Управление громкостью

Реклама