AudioTrack播放pcm格式音頻

AudioTrack播放pcm格式音頻

package com.zero.demo;

import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.AsyncTask;
import android.os.Build;
import android.util.Log;
import com.zero.demo.util.FileUtils;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
* Created by yingkun_che on 19-6-18.
* 使用AudioTrack 播放pcm音頻測試
*/
public class DemoPlay {
    private String TAG="DemoPlay";
    /**
     * 採樣率,現在能夠保證在所有設備上使用的採樣率是44100Hz, 但是其他的採樣率(22050, 16000, 11025)在一些設備上也可以使用。
     */
    private static final int SAMPLE_RATE_INHZ = 44100;
    /**
     * 聲道數。CHANNEL_IN_MONO and CHANNEL_IN_STEREO. 其中CHANNEL_IN_MONO是可以保證在所有設備能夠使用的。
     */
    private static final int CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_MONO;
    /**
     * 返回的音頻數據的格式。 ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, and ENCODING_PCM_FLOAT.
     */
    private static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    AudioTrack audioTrack;
    private Context context;

    public DemoPlay(Context context) {
        this.context = context;
    }

    /**
     * 播放,使用stream模式
     */
    public void playInModeStream() {
        /*
        * SAMPLE_RATE_INHZ 對應pcm音頻的採樣率
        * channelConfig 對應pcm音頻的聲道
        * AUDIO_FORMAT 對應pcm音頻的格式
        * */
        int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
        final int minBufferSize = AudioTrack.getMinBufferSize(SAMPLE_RATE_INHZ, channelConfig, AUDIO_FORMAT);
        audioTrack=createAudioTrackTo();
        audioTrack.play();
//        File file = new File("/storage/emulated/0/Android/data/com.zero.demo/files/zero_editor_kuato/resources/themes/satura/Stratosphere.aac");
        File externalAssetsDir = null;
        try {
            externalAssetsDir = FileUtils.getResourcesRootDir();
        } catch (IOException e) {
            e.printStackTrace();
        }
        File pcmFile = new File(externalAssetsDir, "test.pcm");
        try {
            FileInputStream fileInputStream = new FileInputStream(pcmFile);
            final DataInputStream dataInputStream = new DataInputStream(new BufferedInputStream(fileInputStream));
            new Thread(new Runnable() {
                @Override public void run() {
                    try {
                        byte[] tempBuffer = new byte[minBufferSize];
                        while (dataInputStream.available() > 0) {
                            int readCount = dataInputStream.read(tempBuffer);
                            if (readCount == AudioTrack.ERROR_INVALID_OPERATION ||
                                    readCount == AudioTrack.ERROR_BAD_VALUE) {
                                continue;
                            }
                            if (readCount != 0 && readCount != -1) {
                                audioTrack.write(tempBuffer, 0, readCount);
                            }
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }finally {
                        try {
                            if (dataInputStream!=null){
                                dataInputStream.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private AudioTrack createAudioTrackTo() throws IllegalStateException{
        int mBufferSizeInBytes = AudioTrack.getMinBufferSize(SAMPLE_RATE_INHZ, AudioFormat.CHANNEL_OUT_STEREO, AUDIO_FORMAT);
        if (mBufferSizeInBytes <= 0) {
            throw new IllegalStateException("AudioTrack is not available " + mBufferSizeInBytes);
        }
        AudioTrack mAudioTrack;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mAudioTrack = new AudioTrack.Builder()
                    .setAudioAttributes(new AudioAttributes.Builder()
                            .setUsage(AudioAttributes.USAGE_MEDIA)
                            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                            .setLegacyStreamType(AudioManager.STREAM_MUSIC)
                            .build())
                    .setAudioFormat(new AudioFormat.Builder()
                            .setEncoding(AUDIO_FORMAT)
                            .setSampleRate(SAMPLE_RATE_INHZ)
                            .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
                            .build())
                    .setTransferMode(AudioTrack.MODE_STREAM)
                    .setBufferSizeInBytes(mBufferSizeInBytes)
                    .build();
        } else {
            mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE_INHZ, AudioFormat.CHANNEL_OUT_STEREO, AUDIO_FORMAT,
                    mBufferSizeInBytes, AudioTrack.MODE_STREAM);
        }
        return mAudioTrack;
    }

    byte [] audioData;
    /**
     * 播放,使用static模式
     */
    public void playInModeStatic() {
        // static模式,需要將音頻數據一次性write到AudioTrack的內部緩衝區
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                try {
                    InputStream in = context.getResources().openRawResource(R.raw.test);
                    try {
                        ByteArrayOutputStream out = new ByteArrayOutputStream();
                        for (int b; (b = in.read()) != -1; ) {
                            out.write(b);
                        }
                        Log.d(TAG, "Got the data");
                        audioData = out.toByteArray();
                    } finally {
                        in.close();
                    }
                } catch (IOException e) {
                    Log.wtf(TAG, "Failed to read", e);
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void v) {
                Log.i(TAG, "Creating track...audioData.length = " + audioData.length);
                // R.raw.ding鈴聲文件的相關屬性爲 22050Hz, 8-bit, Mono
                if (Build.VERSION.SDK_INT >Build.VERSION_CODES.KITKAT) {
                    audioTrack = new AudioTrack(
                            new AudioAttributes.Builder()
                                    .setUsage(AudioAttributes.USAGE_MEDIA)
                                    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                                    .build(),
                            new AudioFormat.Builder().setSampleRate(48000)
                                    .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
                                    .setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
                                    .build(),
                            audioData.length,
                            AudioTrack.MODE_STATIC,
                            AudioManager.AUDIO_SESSION_ID_GENERATE);
                } else {
                    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
                            48000,
                            AudioFormat.CHANNEL_OUT_MONO,
                            AudioFormat.ENCODING_PCM_16BIT,
                            audioData.length,
                            AudioTrack.MODE_STREAM);
                }
                Log.d(TAG, "Writing audio data...");
                audioTrack.write(audioData, 0, audioData.length);
                Log.d(TAG, "Starting playback");
                audioTrack.play();
                Log.d(TAG, "Playing");
            }
        }.execute();
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章