Andoird使用AudioTrack以及OpenSLES渲染音频

本文介绍了如何在Android上使用AudioTrack和OpenSLES进行音频播放。内容涉及AudioTrack的初始化、解码线程同步、OpenSLES的引擎与混音器创建,以及播放器对象的配置和回调机制。通过ffmpeg解码mp3,利用AudioTrack或OpenSLES进行播放,详细阐述了两者在移动平台音视频渲染的应用。
摘要由CSDN通过智能技术生成

最近音视频开发学习到了第四章,这一章讲的是移动平台的音视频渲染,对于AudioTrack以及OpenSLES相当于又复习了一遍。这一章结合之前的ffmpeg解码来进行mp3文件的播放。主要的难点有linux多线程的同步,生产者消费者模型等等。如果对ffmpeg解码不熟悉的可以看https://blog.csdn.net/a568478312/article/details/80268498,这篇文章的重点在于api的使用以及多线程的控制。

使用AudioTrack播放音频

AudioTrack的API其实用起来比较方便,一般需要结合解码器来使用。首先我们需要知道pcm数据的采样率,比特率,声道数等信息,用来之后初始化AudioTrack。和之前的解码一样,这里同样使用ffmpeg。

     private boolean initMetaData(String path) {
        int[] metaArray = new int[]{
  0, 0, 0};
        decoder.getMusicMetaByPath(path, metaArray);
        this.sampleRateInHz = metaArray[0];
        this.bitRate = metaArray[1];
        this.channel=metaArray[2];
        if (sampleRateInHz <= 0 || bitRate <= 0) {
            return false;
        }
        totalCapacity = (new File(path)).length();
        mp3CapacityPerSec = bitRate / BITS_PER_BYTE;
        if (mp3CapacityPerSec == 0) {
            return false;
        }
        duration = (int) (totalCapacity / mp3CapacityPerSec);
        Log.d("tedu", " bitrate duration: " + duration);
        int byteCountPerSec = sampleRateInHz * CHANNEL_PER_FRAME * BITS_PER_CHANNEL / BITS_PER_BYTE;
        //比特率不变 采样率是被压缩的
        Log.d("tedu", "initMetaData: bitRate " + bitRate + "mp3CapacityPerSec " + mp3CapacityPerSec +
                "byteCountPerSec  " + byteCountPerSec);

        DECODE_BUFFER_SIZE = (int) ((byteCountPerSec / 2) * 0.2);

        initPlayState();
        seekBaseMillsTime = 0;
        audioTrackBaseHeadPosition = 0;
        return true;
    }

接着初始化解码的核心功能,并且计算出来之后每一个解码buffer的大小,接着初始化队列以及开启线程。PacketPool维护一个链表实现的队列,用来保存解码的裸数据。

void AccompanyDecoderController::init(const char* accompanyPath,
        float packetBufferTimePercent) {
    //初始化两个全局变量
    volume = 1.0f;
    accompanyMax = 1.0f;

    //计算计算出伴奏和原唱的bufferSize
    int accompanyByteCountPerSec = accompanySampleRate * CHANNEL_PER_FRAME
            * BITS_PER_CHANNEL / BITS_PER_BYTE;
    accompanyPacketBufferSize = (int) ((accompanyByteCountPerSec / 2)
            * packetBufferTimePercent);
    //初始化两个decoder
    initAccompanyDecoder(accompanyPath);
    //初始化队列以及开启线程
    packetPool = PacketPool::GetInstance();
    packetPool->initDecoderAccompanyPacketQueue();
    initDecoderThread();
}

下面是开启解码线程。

void AccompanyDecoderController::initDecoderThread() {
    isRunning = true;
    pthread_mutex_init(&mLock, NULL);
    pthread_cond_init(&mCondition, NULL);
    pthread_create(&songDecoderThread, NULL, startDecoderThread, this);
}

解码线程中不断去文件中解码数据,并且将解码数据放入队列中,如果队列的数量超过阈值,释放锁并进行等待。

void* AccompanyDecoderController::startDecoderThread(void* ptr) {
    LOGI("enter AccompanyDecoderController::startDecoderThread");
    AccompanyDecoderController* decoderController =
            (AccompanyDecoderController *) ptr;
    int getLockCode = pthread_mutex_lock(&decoderController->mLock);
    while (decoderController->isRunning) {
        decoderController->decodeSongPacket();
        if (decoderController->packetPool->geDecoderAccompanyPacketQueueSize() > QUEUE_SIZE_MAX_THRESHOLD) {
            pthread_cond_wait(&decoderCo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值