【问题标题】:AudioTrack will only play audio onceAudioTrack 只会播放一次音频
【发布时间】:2011-10-01 09:17:02
【问题描述】:

我正在开发一个需要以非常精确的时间重复播放音频文件的 Android 程序(音乐程序)。

我现在正在使用一个“AudioTrack”,它从 WAV 样本中加载了 PCM 数据。

这是我测试此功能的代码。它只是循环直到播放样本的时间,然后播放它,并重复此 8 次。

这是我正在使用的代码,如果您需要查看更多信息,请告诉我:

class Sequencer {
    private final double BPM = 120;
    private final double BPMS = (BPM / 60 / 1000);
    private long QUARTER_NOTE_DELAY = (long)(1/BPMS);

    private final int PCM_BYTE_OFFSET = 44;

    private long lastTick;
    private long now = 0;

    private int sampleRate = 8000;
    private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
    private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    private int bufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat)*5;

    private AudioTrack playbackBuffer = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRate,
            channelConfig,audioFormat,bufferSize,AudioTrack.MODE_STATIC);;

    private byte[] pcmArray;

    public Sequencer()
    {
        Log.d("AudioTrack", "BUFFER SIZE: " +bufferSize);

        String path = "samples/classical_guitar_c5_16bit.wav";
        try {
            pcmArray = parsePCMData(path);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Log.e("Error Initializng Sequencer", "File not Found: " + path );
            e.printStackTrace();
        }


    }

    public void play() {
        new Thread() {
            public void run() {

                lastTick = 0;
                // play 10 times
                Log.d("Sequencer", "QUARTER-NOTE = " + QUARTER_NOTE_DELAY + "ms");
                for (int i = 0; i < 8; i++) 
                {
                    lastTick = System.currentTimeMillis();
                    while (!update(i));
                }

                playbackBuffer.flush();

            }
        }.start();

    }

    public void stop() {

    }

    //load PCM data into the buffer
    private void loadPCMData(byte[] pcmData)
    { 
        int numBytesWritten = playbackBuffer.write(pcmData, PCM_BYTE_OFFSET, (pcmData.length-PCM_BYTE_OFFSET));
        Log.d("AudioTrack", "LOADED " + numBytesWritten + " BYTES" + " IN " + (System.currentTimeMillis()- now) + "ms!");
    }

    private byte[] parsePCMData(String path) throws IOException
    {
        InputStream fileIn  = assetManager.open(path);
        BufferedInputStream buffIn = new BufferedInputStream(fileIn, 8000);
        DataInputStream dataIn = new DataInputStream(buffIn); 
        byte[] pcmArray;
        ArrayList<Byte> pcmVector = new ArrayList<Byte>();
        int numBytes;

        //Read the file into the "music" array
        for(int i=0; dataIn.available() > 0; i++)
        {
            pcmVector.add(dataIn.readByte());  
        }
        //Close the input streams
        dataIn.close();                                                        
        buffIn.close();
        fileIn.close();
        numBytes = pcmVector.size();
        pcmArray = new byte[numBytes];

        //Copy the data from the arrayLast to the byte array
        for(int i=0; i<numBytes; i++)
        {
            pcmArray[i] = (Byte) pcmVector.get(i);
        }

        return pcmArray;
    }

    //Start Playback of PCM data
    private void startPlayback()
    {
        //stop playback
        if(playbackBuffer.getState() != AudioTrack.STATE_NO_STATIC_DATA)
        {
            playbackBuffer.stop();
            playbackBuffer.flush();
        }

        //start loading the next batch of sounds
        loadPCMData(pcmArray);

        //reset head position
        playbackBuffer.setPlaybackHeadPosition(0);
        //playbacksounds
        playbackBuffer.play();
    }

    private boolean update(int i) {

        now = System.currentTimeMillis();

        if (now - lastTick >= QUARTER_NOTE_DELAY) {
            //start Sounds
            Log.d("AudioTrack: ", "Starting Playback. Current State: " + Integer.toString(playbackBuffer.getState()));
            startPlayback();
            Log.d("AudioTrack: ", "Playback Started. Current State: " + Integer.toString(playbackBuffer.getState()));
            Log.d("MainMenu.java: ", "Event Triggered after " + Long.toString(now-lastTick) +"ms");
            lastTick = now;
            //update UI in a seperate thread 
            beatCounter.post(updateUI);
            return true;
        } 

        else{
            return false;
        }
    }

}

它在八个循环中的第一个循环中完美播放,但之后只是静默,没有可见的错误或警告。 (尽管状态将保持为 1,即“STATE_INITIALIZED”,意思是“准备使用的 AudioTrack 的状态。”

我知道 AudioTrack 具有循环功能以及“reloadStaticData”方法,但是当我开始编写实际应用程序时,我正在测试它,因为数据每次都会根据用户生成的序列而变化)

此外,我最初尝试同时使用媒体播放器和声音池来执行此操作,但两者都给了我太多延迟。

作为一项测试,我还尝试在每个循环中完全重新初始化 AudioTrack,但这给了我太多的延迟,无法真正有用。

我为凌乱的代码道歉,我真的希望它只是我做错了一些愚蠢的事情,因为我变得非常沮丧。

谢谢!

在 Android 2.2.2 上进行测试,在手机设备上(未模拟)

这是我的 LogCat 输出:

10-01 05:07:22.016: DEBUG/AndroidRuntime(23316): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
10-01 05:07:22.016: DEBUG/AndroidRuntime(23316): CheckJNI is OFF
10-01 05:07:22.016: DEBUG/dalvikvm(23316): creating instr width table
10-01 05:07:22.094: DEBUG/AndroidRuntime(23316): --- registering native functions ---
10-01 05:07:22.461: DEBUG/dalvikvm(22329): GC_EXPLICIT freed 236 objects / 13984 bytes in 39ms
10-01 05:07:23.547: DEBUG/PackageParser(1089): Scanning package: /data/app/vmdl67886.tmp
10-01 05:07:23.680: DEBUG/KeyguardViewMediator(1089): wakeWhenReadyLocked(26)
10-01 05:07:23.680: DEBUG/KeyguardViewMediator(1089): handleWakeWhenReady(26)
10-01 05:07:23.680: DEBUG/KeyguardViewMediator(1089): pokeWakelock(5000)
10-01 05:07:23.680: INFO/power(1089): *** set_screen_state 1
10-01 05:07:23.696: DEBUG/Sensors(1089): using sensors (name=sensors)
10-01 05:07:24.088: INFO/PackageManager(1089): Removing non-system package:com.android.test
10-01 05:07:24.088: INFO/Process(1089): Sending signal. PID: 23293 SIG: 9
10-01 05:07:24.088: INFO/ActivityManager(1089): Force stopping package com.android.test uid=10081
10-01 05:07:24.102: INFO/WindowManager(1089): WIN DEATH: Window{44b41118 com.android.test/com.android.test.MainMenu paused=false}
10-01 05:07:24.118: INFO/UsageStats(1089): Unexpected resume of com.android.launcher while already resumed in com.android.test
10-01 05:07:24.196: DEBUG/SurfaceFlinger(1089): Screen about to return, flinger = 0x120f38
10-01 05:07:24.446: DEBUG/PackageManager(1089): Scanning package com.android.test
10-01 05:07:24.446: INFO/PackageManager(1089): Package com.android.test codePath changed from /data/app/com.android.test-2.apk to /data/app/com.android.test-1.apk; Retaining data and using new
10-01 05:07:24.453: INFO/PackageManager(1089): /data/app/com.android.test-1.apk changed; unpacking
10-01 05:07:24.453: DEBUG/installd(1012): DexInv: --- BEGIN '/data/app/com.android.test-1.apk' ---
10-01 05:07:24.602: DEBUG/dalvikvm(23325): creating instr width table
10-01 05:07:24.641: DEBUG/dalvikvm(23325): DexOpt: load 11ms, verify 23ms, opt 0ms
10-01 05:07:24.649: DEBUG/installd(1012): DexInv: --- END '/data/app/com.android.test-1.apk' (success) ---
10-01 05:07:24.657: DEBUG/PackageManager(1089):   Activities: com.android.test.AndroidTestActivity com.android.test.MainMenu
10-01 05:07:24.657: INFO/ActivityManager(1089): Force stopping package com.android.test uid=10081
10-01 05:07:24.657: WARN/PackageManager(1089): Code path for pkg : com.android.test changing from /data/app/com.android.test-2.apk to /data/app/com.android.test-1.apk
10-01 05:07:24.657: WARN/PackageManager(1089): Resource path for pkg : com.android.test changing from /data/app/com.android.test-2.apk to /data/app/com.android.test-1.apk
10-01 05:07:24.829: INFO/installd(1012): move /data/dalvik-cache/data@app@com.android.test-1.apk@classes.dex -> /data/dalvik-cache/data@app@com.android.test-1.apk@classes.dex
10-01 05:07:24.829: DEBUG/PackageManager(1089): New package installed in /data/app/com.android.test-1.apk
10-01 05:07:24.868: DEBUG/KeyguardViewMediator(1089): pokeWakelock(5000)
10-01 05:07:25.000: DEBUG/KeyguardViewMediator(1089): pokeWakelock(5000)
10-01 05:07:25.211: WARN/InputManagerService(1089): Got RemoteException sending setActive(false) notification to pid 23293 uid 10081
10-01 05:07:25.274: INFO/ActivityManager(1089): Force stopping package com.android.test uid=10081
10-01 05:07:25.571: DEBUG/dalvikvm(1089): GC_EXPLICIT freed 24967 objects / 1341840 bytes in 159ms
10-01 05:07:25.672: DEBUG/VoiceDialerReceiver(22354): onReceive Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.android.test flg=0x10000000 cmp=com.android.voicedialer/.VoiceDialerReceiver (has extras) }
10-01 05:07:25.977: DEBUG/dalvikvm(1089): GC_EXPLICIT freed 6005 objects / 330448 bytes in 141ms
10-01 05:07:26.016: DEBUG/VoiceDialerReceiver(22354): onReceive Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.android.test flg=0x10000000 cmp=com.android.voicedialer/.VoiceDialerReceiver (has extras) }
10-01 05:07:26.250: INFO/installd(1012): unlink /data/dalvik-cache/data@app@com.android.test-2.apk@classes.dex
10-01 05:07:26.258: DEBUG/AndroidRuntime(23316): Shutting down VM
10-01 05:07:26.266: DEBUG/dalvikvm(23316): Debugger has detached; object registry had 1 entries
10-01 05:07:26.282: INFO/AndroidRuntime(23316): NOTE: attach of thread 'Binder Thread #3' failed
10-01 05:07:26.680: DEBUG/AndroidRuntime(23330): >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<
10-01 05:07:26.680: DEBUG/AndroidRuntime(23330): CheckJNI is OFF
10-01 05:07:26.680: DEBUG/dalvikvm(23330): creating instr width table
10-01 05:07:26.735: DEBUG/AndroidRuntime(23330): --- registering native functions ---
10-01 05:07:27.047: INFO/ActivityManager(1089): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10000000 cmp=com.android.test/.AndroidTestActivity }
10-01 05:07:27.110: DEBUG/AndroidRuntime(23330): Shutting down VM
10-01 05:07:27.110: DEBUG/dalvikvm(23330): Debugger has detached; object registry had 1 entries
10-01 05:07:27.110: INFO/ActivityManager(1089): Start proc com.android.test for activity com.android.test/.AndroidTestActivity: pid=23337 uid=10081 gids={}
10-01 05:07:27.125: INFO/AndroidRuntime(23330): NOTE: attach of thread 'Binder Thread #3' failed
10-01 05:07:27.203: INFO/WindowManager(1089): Setting rotation to 1, animFlags=1
10-01 05:07:27.227: INFO/ActivityManager(1089): Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=2/1/2 nav=2/2 orien=2 layout=34 uiMode=17 seq=554}
10-01 05:07:27.613: INFO/ActivityManager(1089): Displayed activity com.android.test/.AndroidTestActivity: 513 ms (total 513 ms)
10-01 05:07:27.657: WARN/IInputConnectionWrapper(17894): showStatusIcon on inactive InputConnection
10-01 05:07:28.073: INFO/ActivityManager(1089): Starting activity: Intent { act=com.android.test.CLEARSPLASH cmp=com.android.test/.MainMenu }
10-01 05:07:28.141: DEBUG/AudioTrack(23337): BUFFER SIZE: 14860
10-01 05:07:28.571: INFO/ActivityManager(1089): Displayed activity com.android.test/.MainMenu: 488 ms (total 488 ms)
10-01 05:07:29.930: DEBUG/dalvikvm(1089): GC_EXPLICIT freed 3588 objects / 165776 bytes in 182ms
10-01 05:07:40.172: DEBUG/Sequencer(23337): QUARTER-NOTE = 500ms
10-01 05:07:40.680: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 2
10-01 05:07:40.680: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms!
10-01 05:07:40.688: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1
10-01 05:07:40.688: DEBUG/MainMenu.java:(23337): Event Triggered after 502ms
10-01 05:07:41.203: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1
10-01 05:07:41.203: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms!
10-01 05:07:41.203: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1
10-01 05:07:41.203: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms
10-01 05:07:41.711: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1
10-01 05:07:41.711: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms!
10-01 05:07:41.719: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1
10-01 05:07:41.719: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms
10-01 05:07:42.227: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1
10-01 05:07:42.235: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms!
10-01 05:07:42.235: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1
10-01 05:07:42.235: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms
10-01 05:07:42.743: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1
10-01 05:07:42.743: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms!
10-01 05:07:42.750: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1
10-01 05:07:42.750: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms
10-01 05:07:43.258: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1
10-01 05:07:43.258: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms!
10-01 05:07:43.258: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1
10-01 05:07:43.258: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms
10-01 05:07:43.774: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1
10-01 05:07:43.774: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 1ms!
10-01 05:07:43.782: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1
10-01 05:07:43.782: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms
10-01 05:07:44.289: DEBUG/AudioTrack:(23337): Starting Playback. Current State: 1
10-01 05:07:44.297: DEBUG/AudioTrack(23337): LOADED 14860 BYTES IN 2ms!
10-01 05:07:44.305: DEBUG/AudioTrack:(23337): Playback Started. Current State: 1
10-01 05:07:44.305: DEBUG/MainMenu.java:(23337): Event Triggered after 500ms
10-01 05:07:44.344: DEBUG/dalvikvm(22433): GC_EXPLICIT freed 827 objects / 40752 bytes in 67ms
10-01 05:07:49.422: DEBUG/dalvikvm(20018): GC_EXPLICIT freed 596 objects / 30440 bytes in 67ms
10-01 05:07:54.563: DEBUG/dalvikvm(22329): GC_EXPLICIT freed 143 objects / 10072 bytes in 80ms
10-01 05:07:59.696: DEBUG/dalvikvm(22354): GC_EXPLICIT freed 547 objects / 30048 bytes in 68ms
10-01 05:08:09.977: DEBUG/dalvikvm(22363): GC_EXPLICIT freed 483 objects / 22512 bytes in 111ms
10-01 05:08:10.219: INFO/power(1089): *** set_screen_state 0
10-01 05:08:10.237: DEBUG/SurfaceFlinger(1089): About to give-up screen, flinger = 0x120f38
10-01 05:08:10.258: DEBUG/Sensors(1089): using accelerometer (name=accelerometer)
10-01 05:08:15.430: DEBUG/StatusBar(1089): DISABLE_EXPAND: yes
10-01 05:08:15.469: DEBUG/GoogleLoginService(16965): onBind: Intent { act=android.accounts.AccountAuthenticator cmp=com.google.android.gsf/.loginservice.GoogleLoginService }
10-01 05:08:15.469: INFO/WindowManager(1089): Setting rotation to 0, animFlags=1
10-01 05:08:15.493: INFO/ActivityManager(1089): Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=2/1/2 nav=2/2 orien=1 layout=34 uiMode=17 seq=555}
10-01 05:08:15.821: DEBUG/dalvikvm(23337): GC_FOR_MALLOC freed 1766 objects / 427920 bytes in 193ms
10-01 05:08:15.899: DEBUG/AudioTrack(23337): BUFFER SIZE: 14860

【问题讨论】:

  • 为什么要循环 8 次?检查这一行:for (int i = 0; i &lt; 8; i++)

标签: java android audio


【解决方案1】:

也许你应该尝试使用 AudioTrack 的流模式而不是静态模式。

【讨论】:

    猜你喜欢
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多