有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

模拟器中的java Android AudioTrack速度异常

我在Android emulator中遇到了一些与AudioTrack相关的奇怪行为。然而,我似乎无法确定这是我的一个编码错误,还是模拟器中的一个错误(可能与我在M1 Mac上运行的事实有关)。我确实有一个物理Android设备(它没有遇到这个问题),但它是在旧版本的Android上,所以可以想象,在新版本中,这是一个行为差异,而不是实际的模拟器问题

问题:

有了我提供的代码(这是一个最小的、可复制的样本——真正的应用程序是一个节拍器,它将动态生成的样本数据输入到AudioTrack)中),我希望每秒播放两次短暂的静态脉冲(例如每分钟120次)。相反,我所经历的是短暂的、有点随机的静电爆发。最终,在开始/停止赛道几次后,爆发以我预期的时间结束。这首有声曲目似乎需要“迎头赶上”,所以一开始播放得太快了

你可以在这里看到这个问题:https://youtu.be/iI4msI5ay60——第一次按下按钮就说明了这个问题。在第二次按下按钮时,几秒钟后计时“固定”。所有随后的按钮按下都将在正确的时间

我注意到,如果每次调用start时创建一个新的AudioTrack,这个问题会变得不那么频繁,但不会完全消失

问题:

我是不是在做什么导致这个问题(比如,我可以改成代码来解决它)?这是一个模拟器错误,还是如果我不解决这个问题,我会让人们在他们的设备上体验到同样的行为

代码:

import 安卓.content.Context;
import 安卓.media.AudioFormat;
import 安卓.media.AudioManager;
import 安卓.media.AudioTrack;
import 安卓.os.Bundle;
import 安卓.util.Log;
import 安卓.view.View;

public class MainActivity extends AppCompatActivity {

    ExampleAudioManager audioManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        audioManager = new ExampleAudioManager(this.getApplicationContext());
    }

    public void buttonPressed(View view) {
        if (audioManager.isRunning()) {
            audioManager.stop();
        } else {
            audioManager.start();
        }
    }
}

class ExampleAudioManager {
    private static final int INT16_MAX = Short.MAX_VALUE;

    private final AudioTrack audioTrack;

    int sampleSizeInFrames = 44100 / 20;

    Thread m_audioThread;
    private boolean stopFlag;

    AudioManager.OnAudioFocusChangeListener focusListener;
    Context appContext;

    public ExampleAudioManager(Context context) {
        this.appContext = context;
        int sampleRate = 44100;
        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
                AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
                sampleSizeInFrames * 4, AudioTrack.MODE_STREAM);
    }

    public boolean isRunning() {
        if (m_audioThread == null) return false;
        return m_audioThread.isAlive();
    }

    Runnable m_AudioThreadRunnable = () -> {
        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
        play();
    };

    public void start() {
        Log.d("AudioTrackDebug","Start...");
//        audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
//                AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT,
//                sampleSizeInFrames * 4, AudioTrack.MODE_STREAM);

        if (focusListener == null) {
            focusListener = focusChange -> {
                Log.i("audio","Audio focus change");
                if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
                    // Pause playback
                    ExampleAudioManager.this.stop();
                } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
                    // Resume playback
                    if (!ExampleAudioManager.this.isRunning()) {
                        ExampleAudioManager.this.start();
                    }
                } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
                    ExampleAudioManager.this.stop();
                    // Stop playback
                }
            };
        }

        AudioManager am = (AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE);
        int result = am.requestAudioFocus(focusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
        if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            stopFlag = false;
            m_audioThread = new Thread(m_AudioThreadRunnable);
            m_audioThread.start();
        } else {
            Log.e("AudioFocus","Focus not granted: " + result);
        }
    }

    public void stop() {
        AudioManager am = (AudioManager) appContext.getSystemService(Context.AUDIO_SERVICE);
        am.abandonAudioFocus(focusListener);

        stopFlag = true;
        audioTrack.stop();
    }

    public void cleanUp() {
        audioTrack.release();
    }

    private void play() {
        audioTrack.setPlaybackHeadPosition(0);
        audioTrack.play();

        int sampleSizeInBytes = sampleSizeInFrames * 4;
        int sampleSizeInShorts = sampleSizeInBytes / 2;

        short[] frameBuffer = new short[sampleSizeInBytes];
        long currentTimeInFrames;

        int inNumberFrames = sampleSizeInFrames;
        currentTimeInFrames = -inNumberFrames;

        while (!stopFlag) {

            currentTimeInFrames += inNumberFrames;

            for (int i = 0; i < sampleSizeInShorts; i++) {
                if ((currentTimeInFrames + i) % 22050 < 2000) {
                    frameBuffer[i] = (short) (Math.random() * INT16_MAX);
                } else {
                    frameBuffer[i] = 0;
                }
            }

            audioTrack.write(frameBuffer, 0, sampleSizeInShorts);

        }
        stopFlag = false;
    }

}

或者:https://github.com/jnpdx/AudioTrackTest


共 (0) 个答案