Освой Android играючи

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

Шкодим

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

Класс SoundPool

SoundPool.Builder (API 21)

Основное отличие класса SoundPool от класса MediaPlayer - поддержка одновременного проигрывания нескольких аудиопотоков, что широко используется в играх.

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

Поддерживаются файлы практически всех популярных форматов: mp3, ogg, wav, aac, 3gp, flac. После загрузки файлы перекодируются (в 16-bit PCM моно или стерео) для упрощения воспроизведения.

Можно управлять скоростью воспроизведения аудио файла. Скорость 1,0 означает воспроизведение звука в исходном виде, 2,0 - воспроизведение в два раза быстрее, а 0,5 в два раза медленнее. Диапазон скорости воспроизведения составляет от 0,5 до 2,0.

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

Конструктор класса SoundPool

SoundPool (int maxStreams, int streamType, int srcQuality)
  • maxStreams - максимальное количество потоков, который могут воспроизводится одновременно
  • streamType - тип аудиопотока, это константа из класса AudioManager. Здесь чаще всего используется AudioManager.STREAM_MUSIC.
  • srcQuality - качество кодирования. Сейчас этот параметр не используется, поэтому всегда будем передавать 0.

В API 21 конструктор считается устаревшим. Смотри ниже.

Методы

Загрузить аудио файлы в SoundPool можно с помощью четырёх методов:

int load(AssetFileDescriptor afd, int priority)

Загрузка из папки assets. Нужно знать путь к файлу. AssetManager - класс, предоставляющий доступ к файлам в директории assets. Получить экземпляр класса для данного приложения можно методом getAssets(). AssetFileDescriptor - файловый дескриптор для файла из директории assets.

int load(Context context, int resId, int priority)

Загрузка файла по идентификатору ресурса. Звуковые файлы могут находиться в каталоге res/raw, и соответственно идентификатор будет R.raw.sound.

int load(String path, int priority)

Загрузка файла из указанного пути.

int load(FileDescriptor fd, long offset, long length, int priority)

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

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

Загрузка файлов происходит асинхронно, то есть после вызова метода load() файл не сразу будет доступен для воспроизведения, так как необходимо время для его загрузки и перекодирования. Для того чтобы отследить окончание загрузки нужно обработать событие OnLoadCompleteListener. Для этого устанавливаем обработчик события с помощью метода void setOnLoadCompleteListener(SoundPool.OnLoadCompleteListener listener), где SoundPool.OnLoadCompleteListener - это интерфейс с единственным методом void onLoadComplete(SoundPool soundPool, int sampleId, int status), который вызывается когда файл загружен. Здесь sampleId - идентификатор загруженного файла (то есть то, что вернул метод load()), а status - статус загрузки (значение 0 обозначает успешную загрузку).

Метод для проигрывания звука

int play(int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)
  • soundID - идентификатор звука (который вернул load())
  • leftVolume - уровень громкости для левого канала (от 0.0 до 1.0)
  • rightVolume - уровень громкости для правого канала (от 0.0 до 1.0)
  • priority - приоритет потока (0 - самый низкий)
  • loop - количество повторов (0 - без повторов, (-1) - зациклен)
  • rate - скорость воспроизведения (от 0.5 до 2.0)

Метод возвращает целое число int, которое используется в других методах в качестве параметра streamID.

Остановка воспроизведения

void stop(int streamID)

Приостановить воспроизведение


void pause(int streamID)

Возобновить приостановленный поток (если поток был не на паузе, то метод не даст никакого результата)


void resume(int streamID)

Установка количество повторов для потока

void setLoop(int streamID, int loop)

Установка приоритета для потока

void setPriority(int streamID, int priority)

Установка скорости для потока

void setRate(int streamID, float rate)

Установка громкости для потока

void setVolume(int streamID, float leftVolume, float rightVolume)

Приостановить все активные потоки

void autoPause()

Возобновить все потоки

void autoResume()

Удаляет звук из SoundPool. Метод возвращает true, если операция прошла успешно, и false, если такого SoundID не существует

boolean unload(int soundID)

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

void release()

Пример

Добавим на форму две кнопки, а также звуковой файл в папку ресурсов res/raw. Образцы бесплатных звуков можно взять в разделе Звуки.


package ru.alexanderklimov.SoundPoolDemo;

import ...

public class AudioPlayer extends Activity {

    private SoundPool mSoundPool;
    private int mSoundId = 1;
    private int mStreamId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
        mSoundPool.load(this, R.raw.cat, 1);

        Button playButton = findViewById(R.id.buttonPlay);
        Button pauseButton = findViewById(R.id.buttonPause);
        playButton.setOnClickListener(onPlayButtonClickListener);
        pauseButton.setOnClickListener(onPauseButtonClickListener);
    }

    Button.OnClickListener onPlayButtonClickListener
            = new Button.OnClickListener() {
        @Override
        public void onClick(View v) {
            AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
            float curVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
            float maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
            float leftVolume = curVolume / maxVolume;
            float rightVolume = curVolume / maxVolume;
            int priority = 1;
            int no_loop = 0;
            float normal_playback_rate = 1f;
            mStreamId = mSoundPool.play(mSoundId, leftVolume, rightVolume, priority, no_loop,
                    normal_playback_rate);

            Toast.makeText(getApplicationContext(),
                    "soundPool.play()",
                    Toast.LENGTH_LONG).show();
        }
    };

    Button.OnClickListener onPauseButtonClickListener
            = new Button.OnClickListener() {
        @Override
        public void onClick(View v) {
            mSoundPool.pause(mStreamId);
            Toast.makeText(getApplicationContext(),
                    "soundPool.pause()",
                    Toast.LENGTH_LONG).show();
        }
    };
}

Кнопку управления громкостью телефона можно настроить для управления громкости звуков:


context.setVolumeControlStream(AudioManager.STREAM_MUSIC);

SoundPool.Builder (API 21)

В Android 5.0 (API 21) вызов конструктора считается устаревшим. На смену ему пришёл класс SoundPool.Builder. Ниже приводится код из одного проекта.


// sSoundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0);

AudioAttributes attributes = new AudioAttributes.Builder()
        .setUsage(AudioAttributes.USAGE_GAME)
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .build();
sSoundPool = new SoundPool.Builder()
        .setAudioAttributes(attributes)
        .build();

Пример использования старого и нового способа показан в примере Кто сказал Мяу? - работаем со звуками Му, Мяу, Гав

Реклама