写点什么

AudioTracker 实用封装

用户头像
Changing Lin
关注
发布于: 16 小时前
AudioTracker实用封装

1.AudioTracker


The AudioTrack class manages and plays a single audio resource for Java applications. It allows streaming of PCM audio buffers to the audio sink for playback. This is achieved by "pushing" the data to the AudioTrack object using one of the write(byte[], int, int)write(short[], int, int), and write(float[], int, int, int) methods.

简单来讲,这个类是系统提供的一个接口用于播放耽搁音频源。它可以通过 write 方法,发送 PCM 格式数据到 AudioTrack 对象,来实现播放。

2.代码

  • AudioTrackerApi 接口类


import android.media.AudioManager;import android.media.MediaCodec;
import androidx.lifecycle.LiveData;
public interface AudioTrackerApi { /** * 实例化一个AudioTrackerImpl对象 * @return */ boolean open(int streamType);
/** * 释放资源 * @return */ boolean close(); boolean play(byte[] audioData, int offsetInBytes, int sizeInBytes); boolean pause(); boolean setEnable(boolean enable);
/** * 向系统服务 申请音频权限,会让其他音频业务失去焦点 * @param manager * @return */ boolean request(AudioManager manager,int streamType);
LiveData<Integer> getWorkingStatusLiveData();
MediaCodec getMediaCodec();}
复制代码
  • AudioTrackerProxy 代理类


/** * 通过代理类进行实例化对象 */public class AudioTrackerProxy {
public static AudioTrackerImpl create(int sampleRate) { return new AudioTrackerImpl(sampleRate); }}
复制代码
  • AudioTrackerImpl 实体类


import android.media.AudioFormat;import android.media.AudioManager;import android.media.AudioTrack;import android.media.MediaCodec;import android.media.MediaFormat;import android.os.Build;
import androidx.lifecycle.LiveData;import androidx.lifecycle.MutableLiveData;
import com.nufront.hardware.HardwareWorkingStatus;import com.nufront.hardware.MediaConfig;import com.nufront.trunking.common.system.LogUtil;
import java.nio.ByteBuffer;
import static android.media.AudioManager.AUDIOFOCUS_REQUEST_GRANTED;import static com.nufront.hardware.MediaConfig.AUDIO_BITRATE;import static com.nufront.hardware.MediaConfig.AUDIO_MIME_TYPE;
class AudioTrackerImpl implements AudioTrackerApi {
private final static String TAG = "AudioTrackerImpl";
private AudioTrack mAudioTrack; private AudioManager audioManager; private final AudioManager.OnAudioFocusChangeListener audioFocusChangeListener = focusChange -> { if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { AudioTrack audioTrack = mAudioTrack; if (audioTrack != null) {// audioTrack.setStereoVolume(1.0f, 1.0f); audioTrack.setVolume(1.0f); if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED) { audioTrack.flush(); audioTrack.play(); } } } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { AudioTrack audioTrack = mAudioTrack; if (audioTrack != null) { if (audioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { audioTrack.pause(); } } } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { AudioTrack audioTrack = mAudioTrack; if (audioTrack != null) {// audioTrack.setStereoVolume(0.5f, 0.5f); audioTrack.setVolume(1.0f); } } }; private final int minBufferSize; private final MutableLiveData<Integer> workingStatusLiveData = new MutableLiveData<>(HardwareWorkingStatus.DEFAULT);
private int audioSampleRate = MediaConfig.AUDIO_SAMPLE_RATE;
public AudioTrackerImpl(int rate) { this.audioSampleRate = rate; minBufferSize = AudioTrack.getMinBufferSize(audioSampleRate, MediaConfig.AUDIO_OUT_CHANNEL_CONFIG, MediaConfig.AUDIO_FORMAT)<<1; }
private int getSampleRateIndex(int rate){ int i = 0; for (; i < MediaConfig.AUDIO_SAMPLING_RATES.length; i++) { if (MediaConfig.AUDIO_SAMPLING_RATES[i] == rate) { break; } } return i; }
@Override public LiveData<Integer> getWorkingStatusLiveData() { return workingStatusLiveData; }
@Override public MediaCodec getMediaCodec() { MediaCodec decoder = null; try { MediaFormat audioFormat = MediaFormat.createAudioFormat(AUDIO_MIME_TYPE, audioSampleRate, MediaConfig.AUDIO_CHANNELS); audioFormat.setInteger(MediaFormat.KEY_IS_ADTS, 1); audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, AUDIO_BITRATE); audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaConfig.AUDIO_AAC_PROFILE);
int profile = MediaConfig.AUDIO_AAC_PROFILE; //AAC LC int freqIdx = getSampleRateIndex(audioSampleRate); //44.1KHz int chanCfg = MediaConfig.AUDIO_CHANNELS; //CPE ByteBuffer csd = ByteBuffer.allocate(2); csd.put(0, (byte) (profile << 3 | freqIdx >> 1)); csd.put(1, (byte)((freqIdx & 0x01) << 7 | chanCfg << 3)); audioFormat.setByteBuffer("csd-0", csd);
decoder = MediaCodec.createDecoderByType(AUDIO_MIME_TYPE); decoder.configure(audioFormat, null, null, 0); decoder.start(); } catch (Exception e) { e.printStackTrace(); } return decoder; }
@Override public boolean open(int streamType) { LogUtil.printI(TAG, String.format("open 打开AudioTrackImpl: %s-%d", mAudioTrack, streamType)); if (null == mAudioTrack) { AudioTrack audioTrack = new AudioTrack(streamType, audioSampleRate, MediaConfig.AUDIO_OUT_CHANNEL_CONFIG, MediaConfig.AUDIO_FORMAT, minBufferSize, AudioTrack.MODE_STREAM); audioTrack.setVolume(AudioTrack.getMaxVolume() * 0.9f); mAudioTrack = audioTrack; workingStatusLiveData.postValue(HardwareWorkingStatus.OPEN); return true; } return false; }
@Override public boolean close() { LogUtil.printI(TAG, String.format("close 关闭AudioTrackImpl: %s-%s", audioManager, mAudioTrack)); if (null != audioManager) audioManager.abandonAudioFocus(audioFocusChangeListener); audioManager = null; pause(); AudioTrack audioTrack = mAudioTrack; if (null != audioTrack) { audioTrack.release(); mAudioTrack = null; } workingStatusLiveData.postValue(HardwareWorkingStatus.CLOSE); return true; }
@Override public boolean play(byte[] audioData, int offsetInBytes, int sizeInBytes) { AudioTrack audioTrack = mAudioTrack; if (null != audioTrack) { int result = audioTrack.write(audioData, offsetInBytes, sizeInBytes); LogUtil.i(TAG, String.format("播放的数据大小: %d-%d", result, sizeInBytes)); }
return true; }
@Override public boolean pause() { return setEnable(false); }
@Override public boolean setEnable(boolean enable) { AudioTrack at = mAudioTrack; if (at != null) { LogUtil.printI(TAG, String.format("audio will be %s", enable ? "enabled" : "disabled")); synchronized (at) { if (enable) { at.flush(); at.play(); workingStatusLiveData.postValue(HardwareWorkingStatus.RUNNING); } else { try{ at.pause(); at.flush(); }catch (IllegalStateException e) { e.printStackTrace(); LogUtil.printException(e); }

workingStatusLiveData.postValue(HardwareWorkingStatus.IDLE); } } } return true; }
@Override public boolean request(AudioManager am,int streamType) { if(streamType == AudioManager.STREAM_MUSIC){ am.setSpeakerphoneOn(true); am.setMode(AudioManager.MODE_NORMAL); // TODO: 2020/9/16 可能会出错 int volume = am.getStreamVolume(streamType); LogUtil.printI(TAG, "当前音量: "+volume); am.setStreamVolume( streamType , volume //am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL)>>1 , AudioManager.FLAG_PLAY_SOUND); audioManager = am; int requestCode = am.requestAudioFocus(audioFocusChangeListener, streamType, AudioManager.AUDIOFOCUS_GAIN); return requestCode == AUDIOFOCUS_REQUEST_GRANTED; } return true; }
}
复制代码

3.总结

通过几个文件的封装,简化使用 API,实现使用 AudioTracker 播放音频的功能,便于后续扩展开发。

发布于: 16 小时前阅读数: 3
用户头像

Changing Lin

关注

获得机遇的手段远超于固有常规之上~ 2020.04.29 加入

我能做的,就是调整好自己的精神状态,以最佳的面貌去面对那些未曾经历过得事情,对生活充满热情和希望。

评论

发布
暂无评论
AudioTracker实用封装