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

Как воспроизводить звуки в определенные периоды времени на разных устройствах в Android

Я разрабатываю игру на Android, и я наткнулся на очень раздражающую, труднодоступную ошибку. Проблема в том, что, когда вы используете SoundPool для воспроизведения ваших звуков, вы можете на самом деле зацикливать любой звук, который вы играете. В этом случае проблема заключается в звуке "бегущих шагов"; этот звук выполняется довольно быстро и постоянно (вокруг каждого 400ms), когда главный символ работает.

Теперь при воспроизведении звука на обычном (не очень мощном) устройстве, например. Samsung SII, звук воспроизводится каждый 500ms - однако, если я запускаю тот же самый код на другом устройстве (скажем, Samsung SIV, Samsung SIII), звук воспроизводится дважды или даже в три раза быстрее.

Похоже, что чем мощнее аппаратные спецификации устройства, тем быстрее он играет. На некоторых устройствах он работает так быстро, что вы почти слышите один сплошной непрерывный звук. Я искал методы, чтобы установить определенный коэффициент в промежуток времени между звуковыми играми, но он не работает должным образом, и проблема остается. Кто-нибудь знает, как исправить это, используя SoundPool, MediaPlayer или любой другой управляющий звуком API на Android?

4b9b3361

Ответ 1

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

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

Ответ 2

Вы можете использовать AudioTrack для воспроизведения непрерывного потока данных PCM, так как вы передадите поток, вы можете быть уверены в интервал между звуками. недостатком может быть небольшая задержка при первом запуске звука, но это зависит от минимального размера буфера, и это зависит, на мой взгляд, от версии и устройства Android. На моей галактике s2 android 4.1 было около 20 мс. Если вы считаете, что это может быть вариант, я могу опубликовать код

Ответ 3

Я не могу воспроизвести проблему на Galaxy Nexus и Nexus S, значит ли это, что я ее исправил? Или, может быть, вы могли бы показать, что вы делаете иначе:

SoundPool soundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 100);
Integer sound1 = soundPool.load(this, R.raw.file1, 1);
Integer sound2 = soundPool.load(this, R.raw.file2, 1);
playSound(sound1);

public void playSound(int sound) {
  AudioManager mgr = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
  float volume = mgr.getStreamVolume(AudioManager.STREAM_MUSIC)
               / mgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC);  
  soundPool.play(sound, volume, volume, 1, -1, 1.0f);
}

Ответ 4

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

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

Вот какой код, чтобы проиллюстрировать то, о чем я говорю.

Вот реализация обработчика, которую вы могли бы использовать:

    handler = new Handler() {

        /* (non-Javadoc)
         * @see android.os.Handler#handleMessage(android.os.Message)
         */
        @Override
        public void handleMessage(Message msg) {
            if (msg.what == NEXT_ITEM_MSG) {
                playNextSound();
            }
            else if (msg.what == SEQUENCE_COMPLETE_MSG) {
                // notify a listener
                listener.onSoundComplete()
            }
        }
    };

Затем вы можете написать playNextSound следующим образом:

private void playNextSound() {
    if (mRunning) {
        // Get the first item
        SoundSequenceItem item = currentSequence.getNextSequenceItem();
        if (item == null) {
            Message msg = handler.obtainMessage(SEQUENCE_COMPLETE_MSG);
            handler.sendMessage(msg);
            return;
        }
        // Play the sound
        int iSoundResId = item.getSoundResId();
        if (iSoundResId != -1) {
            player.playSoundNow(soundResId);
        }

        // schedule a message to advance to next item after duration
        Message msg = handler.obtainMessage(NEXT_ITEM_MSG);
        handler.sendMessageDelayed(msg, item.getDuration());
    }
}

и ваш SoundSequenceItem может просто быть простым классом, который имеет идентификатор файла звукового файла и продолжительность. Если вы хотите продолжать воспроизведение звука во время движения персонажа, вы можете сделать что-то вроде этого:

public void onSoundComplete() {
    if (character.isRunning()) {
        currentSequence.addSequenceItem(new SoundSequenceItem(R.id.footsteps,500);
        playNextSound();
    }
}

Или вы можете изменить playNextSound, чтобы постоянно воспроизводить тот же звук. Mine написано таким образом, чтобы воспроизводить разные звуки в последовательности.

Ответ 5

У меня было много проблем с разработкой приложений, которые использовали звуки и тому подобное. Я бы не предложил вам использовать SoundPool, так как он поврежден, и также помните, что звуки цикла с SoundPool не будут работать на устройствах с 4.3 и выше, см. этот открытый вопрос, на AOSP - Отслеживание проблем. Я думаю, что решение состоит в том, чтобы пойти на родной язык и использовать OpenSL ES o аналогичные библиотеки.