您的位置:华清远见教育科技集团 >> 新闻动态 >> Android资料 >> Android AudioTrack音频播放分析  
 
Android AudioTrack音频播放分析
分享到:

音频资源在播放时,会经常出现冲突的情况,如在进行音乐播放时有电话呼入、有新消息的提示音需要播放等,此类的并发处理就需要有一个统一的处理策略。在Android系统开发中,通过为不同的场景配置不同的播放接口,在底层执行统一的并发策略,使得开发者可以将精力更集中在应用本身。

AudioTrack、MediaPlayer、SoundPool、Ringtone、JetPlayer等都是Android音频处理中常用接口,本文将针对AudioTrack接口进行详细说明。

AudioTrack

AudioTrack用于管理单个的音频资源。 在构造AudioTrack实例时,会涉及到流类型、采样率、通道配置、音频格式、缓冲大小、播放模式等因素。

AudioTrack支持STREAM_VOICE_CALL、STREAM_SYSTEM、STREAM_RING、STREAM_MUSIC和STREAM_ALARM等流类型。

AudioTrack支持44100Hz、22050Hz、11025Hz等采样率。

AudioTrack支持单声道(CHANNEL_OUT_MONO)、立体声(CHANNEL_OUT_STEREO)等两种通道。

AudioTrack支持ENCODING_PCM_16BIT、ENCODING_PCM_8BIT等两种编码格式。

AudioTrack支持两种播放模式:静态模式(static mode)和流模式(Streaming mode)。其中静态模式由于没有从Java层向原生层传递数据造成的延迟,时延很小,当然受限于音频缓冲的大小,通常在游戏场景中用于播放时长很短的音频资源。当音频流较大不足以在音频缓冲中一次写入时,可采用流模式。

AudioTrack的播放状态包括PLAYSTATE_STOPPED、PLAYSTATE_PAUSED、PLAYSTATE_PLAYING等。

AudioTrack实例的状态包括STATE_INITIALIZED、STATE_NO_STATIC_DATA、STATE_UNINITIALIZED等。

向音频缓冲中添加数据的方法为write()。在设置音频缓冲时,其大小与采样率、通道和音频格式有关。其计算公式为:

缓冲大小=小帧数×(通道==CHANNEL_OUT_STEREO?2:1)×(音频格式== PCM16?2:1)
而小帧数则受制于采样率和音频设备的延迟等因素。

另外,在Android 2.3中,还引入了会话的概念,便于对单曲的音效进行处理。相应的方法包括:attachAuxEffect()、getAudioSessionId()、setAuxEffectSendLevel()等。

通过AudioTrack.OnPlaybackPositionUpdateListener监听器可以监听播放进度。

下面是一个背景音频的播放过程:

代码10-3 AudioTrack播放音频文件

public class BackgroundAudio extends Thread {
    public static final int SAMPLE_RATE = 16000;
    public static final int AUDIO_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
    public static final int BYTES_PER_SAMPLE = 2;
    public static final int PLAYBACK_STREAM = AudioManager.STREAM_MUSIC;
    ……
    public BackgroundAudio(byte[] data) {
        //计算缓冲大小
        final int minBufferSize = (BUFFER_TIME *SAMPLE_RATE*BYTES_PER_SAMPLE) / 1000;
        //计算硬件的小缓冲
        final int minHardwareBufferSize =
            AudioTrack.getMinBufferSize(SAMPLE_RATE,
    AudioFormat.CHANNEL_OUT_MONO,AUDIO_FORMAT);
        mBufferSize = Math.max(minHardwareBufferSize, minBufferSize);
        mAudioTrack = new AudioTrack(PLAYBACK_STREAM,
            SAMPLE_RATE, AudioFormat.CHANNEL_OUT_MONO,
            AUDIO_FORMAT, mBufferSize, AudioTrack.MODE_STREAM);
        if (mAudioTrack.getState() == AudioTrack.STATE_INITIALIZED) {
            writeAudio();
            start(); // 启动背景线程去推送音频数据
            mAudioTrack.play();
        } else {
            Log.e(TAG, "Error initializing audio track.");
        }
    }
    ……
    private void writeAudio() {
        int len = mData.length;
        int count;
        int maxBytes = Math.min(mBufferSize, len - mPos);

    count = mAudioTrack.write(mData, mPos, maxBytes);
        if (count < 0) {
            Log.e(TAG, "Error writing looped audio data");
            halt();
            return;
        }
        mPos += count;
        if (mPos == len) {
        mPos = 0; // Wraparound
        }
    }
    }

 
 更多相关文章

·Android AudioManager音量控制流程
·Android音频处理的基本接口
·Android编译过程详解(三)
·Android HAL 开发
·Android编译过程详解(二)