音频流式播放器AudioTrack配合WebSocket的完整案例

音频流式播放器AudioTrack配合WebSocket的完整案例

本文理论涉及较少,偏向应用。文章涉及如下几个模块功能:

  1. AudioTrack播放器
  2. WebSocket的使用
  3. 阻塞队列BlockingDeque的使用
  4. 额外的录音AudioRecord

一、 为什么选择AudioTrack

支持音频播放的播放器有很多,比如Android自带的MediaPlayer,第三方ExoPlayer等等。但要是支持流式播放的还得是AudioTrack,MediaPlayer(底层也是AudioTrack)虽然也可以实现流式播放,但会有很多问题:

  1. 他们需要读取文件或者URL,这就需要先把音频数据保存本地,然后把file地址设置到播放器。
  2. 服务器如果返回数据比较慢,或者网络延迟,WebSocket每一帧数据间隔较长的时候,会导致上一帧数据播放完,MediaPlayer就默认数据播放完了,再有数据也不再播放了,所以需要自己维护这个状态。

当然,AudioTrack由于是更偏向底层,所以很多功能需要用户自己实现:

  • 播放器是否准备好播放的回调;
  • 监听是否播放完毕;

二、AudioTrack播放器

先看实现逻辑:

import android.annotation.SuppressLint;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
public class AudioTrackImpl implements AudioPlayerInterface {
   
    private static final String TAG = "AudioTrackImpl";
    private AudioTrack audioTrack;
    private volatile boolean isPlaying = true;
    /**
     * 二进制数据流统计,当大于1时,通知View层可以播放数据。
     */
    private int mBytdDataCount = 0;
    /**
     * 服务端是否全部返回数据
     */
    private volatile boolean isWriteAudioFinish = false;

    private final BlockingDeque<byte[]> audioDataQueue = new LinkedBlockingDeque<>();
    /**
     * 重新播放需要的数据
     */
    private final LinkedList<byte[]> mReplayData = new LinkedList<>();

    private final PlayerListener mListener;
    public AudioTrackImpl(PlayerListener listener) {
   
        AudioAttributes audioAttributes = new AudioAttributes.Builder()
                .setUsage(AudioAttributes.USAGE_MEDIA)
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                .build();
        AudioFormat audioFormat = new AudioFormat.Builder()
                .setSampleRate(AudioConfig.sampleRateInHz)
                .setEncoding(AudioConfig.audioFormat)
                .setChannelMask(AudioConfig.channelOutConfig)
                .build();
        audioTrack = new AudioTrack(audioAttributes, audioFormat,AudioConfig.BUFFER_SIZE_IN_BYTES, AudioTrack.MODE_STREAM,
                AudioManager.AUDIO_SESSION_ID_GENERATE);
        mListener = listener;
    }

    @Override
    public void writeAudioChunk(byte[] audioData) {
   
        try {
   
            if (mBytdDataCount == 0) {
   
                ThreadDispatcher.getInstance().postToMainThread(new Runnable() {
   
                    @Override
                    public void run() {
   
                        mListener.onPlaybackStateChanged(PlayerListener.PLAYBACK_READY);
                    }
                });
            }
            mBytdDataCount++;
            audioDataQueue.put(audioData);
            mReplayData.add(audioData);
        } catch (InterruptedException e) {
   
            throw new RuntimeException(e);
        }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值