Audio Playback of Audio Study Notes

Play a frame of audio
The Android SDK provides 3 sets of audio playback APIs, namely MediaPlayer (more suitable for playing local music files in the background for a long time), SoundPool (suitable for relatively short audio clips, such as game sounds, button sounds), AudioTrack ( closer to the bottom, providing very powerful control capabilities)

AudioTrack workflow
(1) configure parameters, initialize the internal audio playback buffer
(2) start playing
(3) need a thread to continuously "write" audio data to the AudioTrack buffer, this process should be timely, otherwise There will be an "underrun" error, which means that the application layer did not "send" the audio data in time, causing the internal audio playback buffer to be null
(4) Stop playing and release resources

AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)

Parameters:
1>streamType: This parameter represents which audio management strategy the current application uses. When the system has multiple processes that need to play audio, this management strategy will determine the final presentation effect. The optional value of this parameter is in the form of a constant Defined in the AudioManager class
STREAM_VOCIE_CALL: telephone sound
STREAM_SYSTEM: system sound
STREAM_RING: ringtone
STREAM_MUSCI: music sound
STREAM_ALARM: warning sound
STREAM_NOTIFICATION: notification sound

2>sampleRateInHz: The sampling rate range must be between 4000HZ~192000Hz
3>channelConfig: channel Number configuration, the optional constant form is defined in the AudioFormat class, the commonly used is CHANNEL_IN_MINO: (single channel)
CHANNEL_IN_STEREOP (dual channel)
4>audioFormat: data bit width, in the AudioFormat class, commonly used 16BIT, 8BIT
5>bufferSizeInBytes: Buffer size, use the method provided in the AudioTrack class to obtain
6>mode: AudioTrack provides two playback modes, one is static mode, the other is streaming mode
static: mode: write all data into the playback buffer at one time, Simple and efficient, usually used to play ringtones, audio clips of system reminders.
Streaming mode: write audio data continuously according to a certain time interval, theoretically it can be used in any audio playback scene

package com.example.audiodemo;

import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;

public class AudioPlayer {
    private static final String TAG = "AudioPlayer";

    /**
     * 第一个参数:音频管理策略当系统有多个进程需要播放音频时,这个管理策略会决定最终的展现效果,该参数的可选常量定义在AudioManager类中
     */
    private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;

    /** 第二个参数:采样率 */
    private static final int DEFAULT_SAMPLE_RATE = 44100;

    /**
     * 第三个参数通道数的配置,可选的值以常量的形式定义在 AudioFormat 类中,常用的是 CHANNEL_IN_MONO(单通道),CHANNEL_IN_STEREO(双通道)
     */
    private static final int DEFAULT_CHANNEL_CONFIG = AudioFormat.CHANNEL_IN_STEREO;

    /** 第四个参数 数据位宽 */
    private static final int DEFAULT_SAMPLE = AudioFormat.ENCODING_PCM_16BIT;

    /** 第五个参数 是AudioTrack 内部的音频缓冲区的大小, */
    private int mMinBufferSize;

    /**第六个参数
     * AudioTrack 提供了两种播放模式,一种是 static 方式,一种是 streaming 方式,
     * 前者需要一次性将所有的数据都写入播放缓冲区,简单高效,通常用于播放铃声、系统提醒的音频片段;
     * 后者则是按照一定的时间间隔不间断地写入音频数据,理论上它可用于任何音频播放的场景。
     */
    private static final int DEFAULT_PLAY_MODE = AudioTrack.MODE_STREAM;

    private boolean mIsPlayStarted = false;
    private AudioTrack mAudioTrack;

    public boolean startPlay(){
        return startPlay(DEFAULT_STREAM_TYPE,DEFAULT_SAMPLE_RATE,DEFAULT_CHANNEL_CONFIG,DEFAULT_SAMPLE,DEFAULT_PLAY_MODE);
    }

    private boolean startPlay(int streamType,int sampleRate,int channelConfig,int sampleFormat,int mode){
        if (mIsPlayStarted){
            Log.d(TAG, "音频播放已经开始");
            return false;
        }

        mMinBufferSize = AudioTrack.getMinBufferSize(sampleRate,channelConfig,sampleFormat);
        if (mMinBufferSize == AudioTrack.ERROR_BAD_VALUE){
            Log.d(TAG, "无效参数");
            return false;
        }
        Log.d(TAG, "音频最小缓冲区为:" + mMinBufferSize + "bytes");
        mAudioTrack = new AudioTrack(streamType,sampleRate,channelConfig,sampleFormat,mMinBufferSize,mode);
        if (mAudioTrack.getState() == AudioTrack.STATE_UNINITIALIZED){
            Log.d(TAG, "初始化失败");
            return false;
        }

        mIsPlayStarted = true;

        return true;
    }

    public int getMinBufferSize() {
        return mMinBufferSize;
    }

    public boolean play(byte[] audioData, int offsetInBytes, int sizeInBytes){
        if (!mIsPlayStarted) {
            Log.e(TAG, "Player not started !");
            return false;
        }

        if (sizeInBytes < mMinBufferSize) {
            Log.e(TAG, "audio data is not enough !");
            return false;
        }

        if (mAudioTrack.write(audioData,offsetInBytes,sizeInBytes) != sizeInBytes) {
            Log.e(TAG, "Could not write all the samples to the audio device !");
        }

        mAudioTrack.play();

        return true;
    }

    public void stopPlayer() {

        if (!mIsPlayStarted) {
            return;
        }

        if (mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
            mAudioTrack.stop();
        }

        mAudioTrack.release();
        mIsPlayStarted = false;

        Log.d(TAG, "Stop audio player success !");
    }

}

Guess you like

Origin blog.csdn.net/qq_42447739/article/details/127676978