Android Pcm播放器
用于播放分段的pcm流,适用于长连接形式多次分段返回pcm流,边返回边播放场景。播放器音频焦点处理器。
·
用于播放分段的pcm流,适用于长连接形式多次分段返回pcm流,边返回边播放场景
class PcmPlayer @JvmOverloads constructor(
private val sampleRateInHz: Int = 16000
) {
/**
* AudioTrack
*/
private var mAudioTrack: AudioTrack? = null
/**
* 缓存大小
*/
private val bufferSize = 2 * AudioTrack.getMinBufferSize(
sampleRateInHz,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT
)
/**
* mAudioTrackLock
*/
private val mAudioTrackLock = Any()
// Lock
private val mListLock = ReentrantLock()
// AudioTrack 获取数据 的 Condition
private val mTakeData = mListLock.newCondition()
// 接收的数据缓存 LinkedList
private val mDataBufferList = LinkedList<ByteArray>()
// 添加数据完毕标识
@Volatile
private var mFinishPut = false
private val mScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
/**
* 音频焦点处理
*/
private var audioFocusManager = AudioFocusManager(ApplicationUtil.application)
/**
* 播放完毕回调
*/
private var mListener: PlayAudioListener? = null
/**
* 播放器是否在播放
*/
val isPlaying: Boolean
get() {
synchronized(mAudioTrackLock) {
return if (mAudioTrack == null) {
false
} else {
mAudioTrack?.playState == AudioTrack.PLAYSTATE_PLAYING
}
}
}
val isStop: Boolean
get() {
synchronized(mAudioTrackLock) {
return if (mAudioTrack == null) false else mAudioTrack?.playState == AudioTrack.PLAYSTATE_STOPPED
}
}
/**
* 开始播放
*/
@JvmOverloads
fun startPlay(streamType: Int = AudioManager.STREAM_MUSIC, isAutoPlay: Boolean = true) {
Logger.i(TAG, "startPlay,isAutoPlay=$isAutoPlay")
mFinishPut = false
mAudioTrack = AudioTrack(
streamType,
sampleRateInHz,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize,
AudioTrack.MODE_STREAM
)
if (isAutoPlay) {
play()
}
}
/**
* 清除数据
*/
fun clearData() {
mDataBufferList.clear()
}
/**
* 添加数据
*/
fun put(buffer: ByteArray) {
try {
mListLock.lock()
if (mFinishPut) {
return
}
if (buffer.isEmpty()) return
val byteArrayList = splitByteArray(buffer, bufferSize)
mDataBufferList.addAll(byteArrayList)
mTakeData.signal()
} finally {
mListLock.unlock()
}
}
/**
* 停止播放
*/
fun stop() {
Logger.w(TAG, "stop")
try {
if (isStop) {
Logger.d(TAG, "音频播放器-已经停止,不需要停止")
return
}
finishPut()
synchronized(mAudioTrackLock) {
mAudioTrack?.stop()
mListener?.onStop()
mAudioTrack = null
}
} catch (e: Exception) {
Logger.e(
TAG,
"停止播报异常${e.message}",
PlayerException(e, "播放器停止异常${e.message}")
)
mListener?.onPlayError(e.message, e)
}
}
/**
* 暂停
*/
fun pause(): Boolean {
Logger.i(TAG, "pause")
try {
synchronized(mAudioTrackLock) {
if (isPlaying) {
mAudioTrack?.pause()
mListener?.onPause()
return true
}
}
} catch (e: Exception) {
Logger.e(
TAG,
"暂停播报异常${e.message}",
PlayerException(e, "播放器暂停异常${e.message}")
)
mListener?.onPlayError(e.message, e)
}
return false
}
/**
* 播放器是否暂停
*/
val isPause: Boolean
get() {
synchronized(mAudioTrackLock) {
return if (mAudioTrack == null) {
false
} else {
mAudioTrack?.playState == AudioTrack.PLAYSTATE_PAUSED
}
}
}
/**
* 播放器继续
*/
fun resume(): Boolean {
Logger.i(TAG, "resume ")
synchronized(mAudioTrackLock) {
if (!isPause) {
// 回调给外面,不然外面状态会乱,导致一直在onPause和onResume之间来回切换
mListener?.onStop()
return false
}
play()
mListener?.onResume()
return true
}
}
/**
* 播放器 release
*/
fun release() {
try {
synchronized(mAudioTrackLock) {
mScope.cancel()
mAudioTrack?.flush()
if (isPlaying) {
mAudioTrack?.stop()
mListener?.onStop()
}
mAudioTrack?.release()
mAudioTrack = null
mListener = null
}
} catch (e: Exception) {
mListener?.onPlayError("release 播放器异常!", e)
Logger.e(
TAG,
"释放资源异常${e.message}",
PlayerException(e, "播放器释放资源异常${e.message}")
)
}
}
/**
* 设置播放器音量
*/
fun setVolume(volume: Float) {
if (mAudioTrack != null) {
mAudioTrack?.setVolume(volume)
}
}
/**
* 给播放器添加数据完毕
*/
fun finishPut() {
mFinishPut = true
try {
mListLock.lock()
if (mDataBufferList.isEmpty()) {
// 如果当前已经没有待播放的数据了 发个信号,避免因为take线程没有数据卡死在那里
mTakeData.signal()
}
} finally {
mListLock.unlock()
}
}
/**
* resetFinishPut
*/
fun resetFinishPut() {
mFinishPut = false
}
/**
* 设置播放回调
*/
fun setPlayListener(listener: PlayAudioListener?) {
mListener = listener
}
/**
* 获取数据给播放器
*/
private fun take(): ByteArray? {
return try {
// 上锁
mListLock.lock()
val empty = mDataBufferList.isEmpty()
if (empty && mFinishPut) {
return null
}
if (empty) {
// 合成数据已经播放完,等待引擎返回数据时 线程等待
try {
mTakeData.await()
} catch (e: InterruptedException) {
e.printStackTrace()
mListener?.onPlayError("获取数据出错", e)
}
}
mDataBufferList.poll() ?: null
} finally {
mListLock.unlock()
}
}
/**
* 播放音频
*/
private fun play() {
Logger.i(TAG, "play")
mScope.launch {
try {
if (!isPlaying) {
audioFocusManager.requestFocus()
mAudioTrack?.play()
mListener?.onPlayStart()
}
while (isPlaying && isActive) {
val buffer = take()
if (isPlaying && isActive) {
if (buffer != null) {
writeToAudioTrack(mAudioTrack, buffer)
} else {
break
}
} else {
// 当前是暂停,把这一帧扔回去
if (buffer != null && isPause) {
mDataBufferList.offerFirst(buffer)
} else {
break
}
}
}
Logger.i(TAG, "播放完毕${hashCode()}:finishPut=$mFinishPut,isPause=$isPause")
// 播放结束回调
if (mFinishPut && !isPause) {
mListener?.onPlayCompletion()
}
} catch (e: Exception) {
Logger.i(TAG, "PCM播放错误:${e.message}", e)
mListener?.onPlayError(e.message, e)
} finally {
audioFocusManager.releaseAudioFocus()
}
}
}
/**
* 写入数据到播放器
*/
private fun writeToAudioTrack(audioTrack: AudioTrack?, bytes: ByteArray) {
var count = 0
while (count < bytes.size) {
val written = audioTrack?.write(bytes, count, bytes.size)
if ((written ?: 0) < 0) {
return
}
count += (written ?: 0)
}
}
companion object {
/**
* TAG
*/
private const val TAG = "TtsPcmPlayer"
/**
* splitByteArray
*/
fun splitByteArray(src: ByteArray, frameSize: Int): List<ByteArray> {
val result: MutableList<ByteArray> = ArrayList()
val length = src.size
var i = 0
while (i < length) {
val endIndex = (i + frameSize).coerceAtMost(length)
val size = endIndex - i
val dst = ByteArray(size)
System.arraycopy(src, i, dst, 0, size)
result.add(dst)
i += size
}
return result
}
}
}
播放器音频焦点处理器
class AudioFocusManager(context: Context) : AudioManager.OnAudioFocusChangeListener {
private val mAudioManager: AudioManager =
context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
private var mFocusRequest: AudioFocusRequest? = null
private var mAudioAttributes: AudioAttributes? = null
private var mOnRequestFocusResultListener: OnRequestFocusResultListener? = null
private var mAudioFocusChangeListener: OnAudioFocusChangeListener? = null
/**
* Request audio focus.
*/
fun requestFocus() {
var result: Int = AudioManager.AUDIOFOCUS_NONE
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (mFocusRequest == null) {
if (mAudioAttributes == null) {
mAudioAttributes = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build()
}
mAudioAttributes?.let {
mFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setAudioAttributes(it)
.setWillPauseWhenDucked(true)
.setOnAudioFocusChangeListener(this)
.build()
}
}
mFocusRequest?.let {
result = mAudioManager.requestAudioFocus(it)
}
} else {
result = mAudioManager.requestAudioFocus(
this,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN
)
}
mOnRequestFocusResultListener?.onHandleResult(result)
}
override fun onAudioFocusChange(focusChange: Int) {
mAudioFocusChangeListener?.onAudioFocusChange(focusChange)
}
/**
* Release audio focus.
*/
fun releaseAudioFocus() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mFocusRequest?.let {
mAudioManager.abandonAudioFocusRequest(it)
}
} else {
mAudioManager.abandonAudioFocus(this)
}
}
/**
* Handle the result of audio focus.
*/
interface OnRequestFocusResultListener {
/**
* onHandleResult
*/
fun onHandleResult(result: Int)
}
/**
* setOnHandleResultListener 获得焦点时播放(暂不使用)
*/
fun setOnHandleResultListener(listener: OnRequestFocusResultListener?) {
mOnRequestFocusResultListener = listener
}
/**
* Same as AudioManager.OnAudioFocusChangeListener.
*/
interface OnAudioFocusChangeListener {
/**
* onAudioFocusChange
*/
fun onAudioFocusChange(focusChange: Int)
}
/**
* setOnAudioFocusChangeListener
*/
fun setOnAudioFocusChangeListener(listener: OnAudioFocusChangeListener?) {
mAudioFocusChangeListener = listener
}
}
播放器回调
interface PlayAudioListener {
/**
* 播放开始回调
*/
fun onPlayStart()
/**暂停*/
fun onPause()
/**停止*/
fun onStop()
/**
* 播放结束回调
*/
fun onPlayCompletion()
/**
* 播放出错
*/
fun onPlayError(errorMsg: String?, throwable: Throwable?)
/**resume*/
fun onResume()
}
更多推荐
所有评论(0)