【Android Audio】AAudio 架构讲解以及实现范例 (附带visio流程图)

1、Google官方说明

Audio Hal 适配: https://source.android.google.cn/devices/audio/aaudio
AAudio 上层应用使用说明:https://developer.android.google.cn/ndk/guides/audio/aaudio/aaudio
AAudio API说明文档:https://developer.android.com/ndk/reference/group/audio

“AAudio 是在 Android O 版本中引入的全新 Android C API。此 API 专为需要低延迟的高性能音频应用而设计。”相对于之前的AudioFlinger音频引擎来说,AAudio整个通路的缓存都设置很小,同时也对我们vendor的音频处理实时性要求更高,最终降低整个音频通路的延时,为对实时性要求高的音频流的第三方apk提供帮助。

特征:
低延时、仅支持PCM流、不支持自动化路由

2、AAudio内部架构图

Code路径:
libaaudio.so: frameworks/av/media/libaaudio (运行在客户端进程)
libaaudioservice.so: frameworks/av/services/oboeservice (运行在audioserver进程的服务)
原流程图下载地址:https://download.csdn.net/download/u013120422/11937875

2.1、控制流

调用流程图

2.2、数据流

在这里插入图片描述

2.2.1、共享buffer分配顺序

  1. 分配AAudioServiceStreamShared的up msg buffer;(AAudioServiceStreamBase::open)
  2. 分配AAudioServiceStreamMMAP的up msg buffer; (AAudioServiceStreamBase::open)
  3. get到alsa的pcm_open mmap的fd;(AAudioServiceEndpointMMAP::open)
  4. 分配AAudioServiceStreamShared的audioData buffer;(AAudioServiceStreamShared::open)
    upMessageQueue; // server to client
    downMessageQueue; // client to server
    DataQueue; // capture or playback

2.2.2、客户端和oboeservice共享buffer大小设置

函数:AAudioServiceStreamShared::calculateBufferCapacity
未指定BufferCapacity时,AAudioStream_getBufferCapacityInFrames值是AAudioStream_getFramesPerBurst值的16倍(DEFAULT_BURSTS_PER_BUFFER)
在这里插入图片描述

2.2.2、client和oboeservice 的FifoBuffer实例构造顺序

①.service端 service-client msg管理buffer (AAudioServiceStreamShared父类open中分配mUpMessageQueue[SharedRingBuffer]->mFifoBuffer);
②.MMAP端MMAP-service msg管理buffer (AAudioServiceStreamMMAP父类open中分配mUpMessageQueue[SharedRingBuffer]->mFifoBuffer);③.service端service-MMAP msg管理buffer (mUpCommandQueue);
④.service端service-ION data管理buffer (mDataQueue);
⑤.service端service-client data管理 buffer (AAudioServiceStreamShared::open中分配mAudioDataQueue[SharedRingBuffer]->mFifoBuffer);
⑥.client端client-service msg管理buffer (mUpCommandQueue);
⑦.client端client-service data管理buffer (mDataQueue);

2.2.3、共享和独占模式

一个AAudioServiceStreamShared实例为一路Track,AAudioServiceStreamShared.cpp可为多个实例;
AAudioServiceStreamMMAP.cpp为专有模式,只能拥有一个实例

2.3、AAudio 共享ring buffer

在这里插入图片描述

3、AAudio audio hal实现实例

  • Audio Hal 需适配一下4个接口

    int (*start)(const struct audio_stream_out stream);
    int (*stop)(const struct audio_stream_out stream);
    int (*create_mmap_buffer)(const struct audio_stream_out *stream,
    int32_t min_size_frames,
    struct audio_mmap_buffer_info *info);
    int (*get_mmap_position)(const struct audio_stream_out *stream,
    struct audio_mmap_position *position);

3.1、软件实现代码

  • 无DSP、无ms12的软件AAudio实现之后的框架
    在这里插入图片描述

3.1.1、hippo_mmap_audio.c

/*
 * Copyright (C) 2019 hippo Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "hippo_mmap_audio"

#include <sys/mman.h>
#include <sys/prctl.h>
#include <stdlib.h>
#include <cutils/log.h>

#include "audio_virtual_buf.h"
#include "audio_hw.h"
#include "hippo_android_utils.h"
#include "hippo_volume_utils.h"
#include "audio_hw_utils.h"
#include "hippo_mmap_audio.h"
#include "audio_hw_ms12.h"
#include "hippo_audio_timer.h"


#define MMAP_FRAME_SIZE_BYTE            (4)
#define MMAP_SAMPLE_RATE_HZ             (48000)
#define MMAP_BUFFER_SIZE_BYTE           (MMAP_SAMPLE_RATE_HZ * MMAP_FRAME_SIZE_BYTE * 32 / 1000)
#define MMAP_WRITE_SIZE_BYTE            (MMAP_SAMPLE_RATE_HZ * MMAP_FRAME_SIZE_BYTE * 8 / 1000)  // every time to write 8ms data
#define MMAP_WRITE_SIZE_FRAME           (MMAP_WRITE_SIZE_BYTE / MMAP_FRAME_SIZE_BYTE)
#define MMAP_WRITE_PERIOD_TIME_NANO     (MMAP_WRITE_SIZE_FRAME * 1000000000LL / MMAP_SAMPLE_RATE_HZ)

enum {
   
    MMAP_INIT,
    MMAP_START,
    MMAP_START_DONE,
    MMAP_STOP,
    MMAP_STOP_DONE
};

static FILE *g_pFile = NULL;

static void *outMmapThread(void *pArg) {
   
    struct hippo_stream_out       *out = (struct hippo_stream_out *) pArg;
    hippo_mmap_audio_param_st     *pstParam = (hippo_mmap_audio_param_st *)out->pstMmapAudioParam;
    struct audio_virtual_buf    *pstVirtualBuffer = NULL;
    unsigned char               *pu8CurReadAddr = pstParam->pu8MmapAddr;
    unsigned char               *pu8StartAddr = pstParam->pu8MmapAddr;
    unsigned char               *pu8TempBufferAddr = NULL;
    hippo_mmap_thread_param_st    *pstThread = &pstParam->stThreadParam;
    struct timespec timestamp;

    ALOGI("[%s:%d] enter threadloop bExitThread:%d, bStopPlay:%d, mmap addr:%p, out:%p", __func__, __LINE__,
        pstThread->bExitThread, pstThread->bStopPlay, pu8StartAddr, out);
    if (NULL == pu8StartAddr) {
   
        ALOGE("[%s:%d] pu8MmapAddr is null", __func__, __LINE__);
        return NULL;
    }
    prctl(PR_SET_NAME, "outMmapThread");
    hippo_set_thread_priority("outMmapThread", pstThread->threadId);
    pu8TempBufferAddr = (unsigned char *)malloc(MMAP_WRITE_SIZE_BYTE);
    while (false == pstThread->bExitThread) {
   
        if (false == pstThread->bStopPlay) {
   

            if (pstThread->status == MMAP_START) {
   
                ALOGI("MMAP status: start");
                pu8CurReadAddr = pu8StartAddr;
                pstParam->u32FramePosition = 0;
                pstThread->status = MMAP_START_DONE;
                if (pstVirtualBuffer) {
   
                    audio_virtual_buf_reset(pstVirtualBuffer);
                    audio_virtual_buf_process((void *)pstVirtualBuffer, MMAP_WRITE_PERIOD_TIME_NANO * 4);
                }
            }

            if (pstVirtualBuffer == NULL) {
   
                audio_virtual_buf_open((void **)&pstVirtualBuffer, "aaudio mmap",
                        MMAP_WRITE_PERIOD_TIME_NANO * 4, MMAP_WRITE_PERIOD_TIME_NANO * 4, 0);
                audio_virtual_buf_process((void *)pstVirtualBuffer, MMAP_WRITE_PERIOD_TIME_NANO * 4);
            }
            unsigned int u32RemainSizeByte =  (MMAP_BUFFER_SIZE_BYTE + pu8StartAddr) - pu8CurReadAddr;
            if (u32RemainSizeByte >= MMAP_WRITE_SIZE_BYTE) {
   

                memcpy(pu8TempBufferAddr, pu8CurReadAddr, MMAP_WRITE_SIZE_BYTE);
                memset(pu8CurReadAddr, 0, MMAP_WRITE_SIZE_BYTE);
                pu8CurReadAddr += MMAP_WRITE_SIZE_BYTE;
            } else {
   
                memcpy(pu8TempBufferAddr, pu8CurReadAddr, u32RemainSizeByte);
                memset(pu8CurReadAddr, 0, u32RemainSizeByte);

                memcpy(pu8TempBufferAddr + u32RemainSizeByte, pu8StartAddr, MMAP_WRITE_SIZE_BYTE - u32RemainSizeByte);
                memset(pu8StartAddr, 0, MMAP_WRITE_SIZE_BYTE - u32RemainSizeByte);
                pu8CurReadAddr = pu8StartAddr + MMAP_WRITE_SIZE_BYTE - u32RemainSizeByte;
            }
            apply_volume(out->volume_l, pu8TempBufferAddr, 2, MMAP_WRITE_SIZE_BYTE);
            if (out->dev->useSubMix) {
   
                out->stream.write(&out->stream, pu8TempBufferAddr, MMAP_WRITE_SIZE_BYTE);
            } else 
  • 12
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
Android AAudio 是一种用于音频处理的新型API,旨在提高Android平台上的音频性能和稳定性。它于Android 8.0 Oreo版本中首次引入,并在后续版本中得到了改进和优化。 AAudio专注于解决传统音频API(如OpenSL ES)中存在的延迟和频率浮动等问题。它使用了一种低延迟的音频管道,能够以更高的效率和更精确的时间同步处理音频数据。AAudio的设计目标是提供可预测、一致和高质量的音频流,以满足实时音频应用(如音乐制作、游戏、语音通信等)的需求。 AAudio提供了一套简单易用的API,供开发人员进行音频流的读取和写入操作。开发者可以直接控制音频流的属性,如采样率、通道数和数据格式等,以满足不同应用的需求。此外,AAudio还提供了音频设备的状态查询和事件回调功能,方便开发者监控和调整音频流的运行状态。 相比于传统的音频API,AAudio提供了更低的音频输出延迟,可达到毫秒级别,从而大大降低了音频输入和输出之间的延迟。这使得实时音频应用能够更加精确地控制和处理音频数据,提供更流畅和逼真的音频体验。 总的来说,Android AAudio是一种用于音频处理的先进API,通过其低延迟和高质量的音频管道,提高了Android平台上实时音频应用的性能和稳定性。它为开发者提供了更多的控制权和灵活性,使得他们能够更好地满足用户的需求,提供更出色的音频体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值