背景
有整车客户项目,要将一块平板设备集成到座舱内,也就是作为车载平板使用。该平板移除了电池,并加入了 MCU,MIC 和 Speaker 也被去掉改为使用座舱上的 MIC 和 Speaker。整块平板仅供电与座舱物理连接,MIC 和 Speaker 的数据则通过无线方式进行传输。此外,平板上还特意添加了一个 USB Type-C 接口,用于实现 DP in 功能。传统的有线投屏通常是将音视频从平板投放到外部显示器,而 DP in 则让平板充当显示器,将音视频投射到平板上。
虚拟麦克风
问:如何将座舱内麦克风的录音传输给平板上的第三方应用程序,比如会议类应用?这个问题主要针对未连接耳机的场景。
答:上层的任何应用程序在获取录音时,最终都会通过 Android 的标准 API 调用到 AudioFlinger,从 HAL 获取录音。因此,我们可以在 AudioFlinger 中创建一个 IPC,并添加一个read
接口。当 AudioFlinger 从 HAL 读取麦克风录音时,进行场景区分,调用这个 IPC 的read
接口。该接口需要在应用程序中实现,因此平板上会有一个应用程序通过局域网与座舱保持连接,并且具备足够的权限。当 IPC read
接口被调用时,这个应用程序将从座舱获取录音并返回。参考代码如下:
未经测试
status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle)
{
status_t status = NO_ERROR;
... ...
if (inDeviceType() == AUDIO_DEVICE_IN_BUILTIN_MIC && sock <= 0) {
struct sockaddr_in addr;
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("10.106.246.70");
addr.sin_port = htons(2333);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
sendto(sock, &mBufferSize, sizeof(mBufferSize), 0, NULL, 0);
} else
ALOGE("%d, error: %s.\n", __LINE__, strerror(errno));
}
return status;
}
bool AudioFlinger::RecordThread::threadLoop()
{
... ...
ATRACE_BEGIN("read");
size_t bytesRead;
status_t result;
ALOGE("%p, %s, inDeviceType() == AUDIO_DEVICE_IN_BUILTIN_MIC %d, sock %d, mBufferSize %zu",
this, __func__, inDeviceType() == AUDIO_DEVICE_IN_BUILTIN_MIC, sock, mBufferSize);
if (inDeviceType() == AUDIO_DEVICE_IN_BUILTIN_MIC && sock > 0) {
bytesRead = recvfrom(sock, (uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize, 0, NULL, 0);
result = bytesRead;
} else {
result = mSource->read((uint8_t*)mRsmpInBuffer + rear * mFrameSize, mBufferSize, &bytesRead);
}
ATRACE_END();
}
IPC可以选择其他方案,比如 Binder,或者直接使用 AudioControl。如果使用基于网络的 socket,是否可以绕过应用程序这一环节,直接与座舱连接,从而省去一层中转?
补充一下,AudioControl 是一个独立的进程,可以参考以下示例:
#include <android/hardware/automotive/audiocontrol/2.0/IAudioControl.h>
using namespace android::hardware::automotive::audiocontrol::V2_0;
android::sp<IAudioControl> audiocontrol = IAudioControl::getService();
int32_t main(int argc, char** argv) {<