IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 8.1 系统裁剪、定制化实践 snd-aloop 内录音 -> 正文阅读

[移动开发]Android 8.1 系统裁剪、定制化实践 snd-aloop 内录音

背景描述:

此篇是对《Android音频框架之一 详解audioPolicy流程及HAL驱动加载》、《Android音频框架之二 用户录音启动流程源码走读》 和
《Android音频框架之三 用户录音启动流程源码走读 startRecord》的延续内容;本篇描述是 android8.1 源码中,如果增加 TinyAlsaHAL
的源码,并配置 Android 系统启动和加载库项目,移植 tinyalsa 至 hikey960-Androi8.1 平台,以完成这个系列博文所实现的功能。

Android 7.0 引入了一种新的音频政策配置文件格式 (XML),用于描述音频拓扑,Android 7.0 弃用了 audio_policy.conf,并增加了
对使用 XML 文件格式来定义音频拓扑的支持,这种文件格式更通俗易懂,具有多种编辑和解析工具,并且足够灵活,可以描述复杂的音频拓扑。

第一步 配置 audio_policy_configuration.xml 模式有效

1.1> Android7.1-RK3288 配置方法:

开启 USE_XML_AUDIO_POLICY_CONF 功能,并把配置文件内容拷贝至系统文件系统

@ device/rockchip/rk3288/device.mk 
## config audio policy by ljb
USE_XML_AUDIO_POLICY_CONF := 1
PRODUCT_COPY_FILES += frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml:system/etc/audio_policy_configuration.xml\
frameworks/av/services/audiopolicy/config/a2dp_audio_policy_configuration.xml:system/etc/a2dp_audio_policy_configuration.xml\
frameworks/av/services/audiopolicy/config/usb_audio_policy_configuration.xml:system/etc/usb_audio_policy_configuration.xml\
frameworks/av/services/audiopolicy/config/r_submix_audio_policy_configuration.xml:system/etc/r_submix_audio_policy_configuration.xml\
frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:system/etc/audio_policy_volumes.xml\
frameworks/av/services/audiopolicy/config/default_volume_tables.xml:system/etc/default_volume_tables.xml

添加库文件及调试工具的支持

@ device/rockchip/common/device.mk 
# audio lib
PRODUCT_PACKAGES += \
    audio_policy.$(TARGET_BOARD_HARDWARE) \
    audio.primary.$(TARGET_BOARD_HARDWARE) \
    audio.r_submix.default\
    libaudioroute

# audio lib
PRODUCT_PACKAGES += \
    libasound \
    alsa.default \
    acoustics.default \
    libtinyalsa \
    tinymix \
    tinyplay \
    tinycap \
    tinypcminfo

1.2> Android8.1-hikey960 配置方法:

@ device/linaro/hikey/hikey960/device-hikey960.mk
增加如下配置内容

# Build HiKey960 HDMI audio HAL. Experimental only may not work. FIXME
USE_XML_AUDIO_POLICY_CONF := 1
PRODUCT_COPY_FILES += frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml:system/etc/audio_policy_configuration.xml\
frameworks/av/services/audiopolicy/config/a2dp_audio_policy_configuration.xml:system/etc/a2dp_audio_policy_configuration.xml\
frameworks/av/services/audiopolicy/config/usb_audio_policy_configuration.xml:system/etc/usb_audio_policy_configuration.xml\
frameworks/av/services/audiopolicy/config/r_submix_audio_policy_configuration.xml:system/etc/r_submix_audio_policy_configuration.xml\
frameworks/av/services/audiopolicy/config/audio_policy_volumes.xml:system/etc/audio_policy_volumes.xml\
frameworks/av/services/audiopolicy/config/default_volume_tables.xml:system/etc/default_volume_tables.xml

# audio.primary configuration
PRODUCT_PACKAGES += audio.primary.$(TARGET_BOARD_PLATFORM)\
                    audio.r_submix.default
                    
# TinyAlsaHAL configuration
PRODUCT_PACKAGES += \
    libasound \
    libaudioroute \
    alsa.default \
    acoustics.default \
    libtinyalsa \
    tinymix \
    tinyplay \
    tinycap \
    tinypcminfo

第二处 修改 BOARD_USES_ALSA_AUDIO 有效
@ device/linaro/hikey/BoardConfigCommon.mk

#BOARD_USES_GENERIC_AUDIO := true     # 关闭 GENERIC_AUDIO
BOARD_USES_ALSA_AUDIO := true         # 开启 ALSA_AUDIO 

第二步 修改音频配置文件

用文件夹中audio_policy_configuration.xml文件,把此文件覆盖
@ frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml
文件。
配置文件内容如下:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
    <!-- version section contains a “version” tag in the form “major.minor” e.g version=1.0-->

    <!-- Global configuration Decalaration -->
    <globalConfiguration speaker_drc_enabled="true"/>
    
    <modules>
        <!-- Primary Audio HAL -->
        <module name="primary" halVersion="2.5">
            <attachedDevices>
                <item>Speaker</item>
                <item>Remote Submix Out</item>
                <item>Built-In Mic</item>
                <item>Remote Submix In</item>
            </attachedDevices>
            <defaultOutputDevice>Speaker</defaultOutputDevice>

            <!-- “mixPorts”: listing all output and input streams exposed by the audio HAL -->
            <mixPorts>
                <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" 
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="primary input" role="sink">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
                </mixPort>
                <!-- r_submix -->
                <mixPort name="r_submix output" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" 
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="r_submix input" role="sink">
                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="44100,48000" 
                            channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
                </mixPort>
            </mixPorts>

            <!-- “devicePorts”: a list of device descriptors for all input and output devices 
            accessible via this module. -->
            <devicePorts>
                <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
                <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="48000" 
                             channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                    <gains>
                        <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT"
                              minValueMB="-8400"
                              maxValueMB="4000"
                              defaultValueMB="0"
                              stepValueMB="100"/>
                    </gains>
                </devicePort>
                <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                             samplingRates="44100,48000"
                             channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
                </devicePort>
                <!-- add remote deviceport by ljb -->
                <devicePort tagName="Remote Submix Out" role="sink" type="AUDIO_DEVICE_OUT_REMOTE_SUBMIX">
                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="48000" 
                            channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
               </devicePort>
               <devicePort tagName="Remote Submix In" type="AUDIO_DEVICE_IN_REMOTE_SUBMIX" role="source">
                   <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                            samplingRates="44100,48000" 
                            channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
                </devicePort>
            </devicePorts>
            <!-- route declaration, i.e. list all available sources for a given sink -->
            <routes>
                <route type="mix" sink="Speaker"
                       sources="primary output"/>          
                <route type="mix" sink="primary input"
                       sources="Built-In Mic"/>
                <!-- r_submix route -->
                <route type="mix" sink="Remote Submix Out"
                       sources="r_submix output"/>
                <route type="mix" sink="r_submix input"
                       sources="Remote Submix In"/>
                </routes>
        </module>
    </modules>
    <!-- End of Modules section -->

    <!-- Volume section -->

    <xi:include href="audio_policy_volumes.xml"/>
    <xi:include href="default_volume_tables.xml"/>

    <!-- End of Volume section -->

</audioPolicyConfiguration>

第三步 移植TinyAlsaHAL 声卡驱动

在安卓系统源码中,把 device/linaro/hikey/audio 路径下文件夹内容清除掉,
把此文件夹下 audio.tar.bz2 文件解压至 device/linaro/hikey/ 路径下。
audio文件夹中 Android.mk 配置内容如下:

# Copyright (C) 2012 The Android Open Source Project
#
# 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.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM)
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := \
    audio_setting.c \
    audio_bitstream.c \
    audio_hw.c \
    alsa_route.c \
    alsa_mixer.c \
    voice_preprocess.c \
    audio_hw_hdmi.c

LOCAL_C_INCLUDES += \
    external/tinyalsa/include \
    $(call include-path-for, audio-utils) \
    $(call include-path-for, audio-route) \
    $(call include-path-for, speex)

LOCAL_CFLAGS := -Wno-unused-parameter

ifeq ($(AUD_VOICE_CONFIG),voice_support)
LOCAL_CFLAGS += -DVOICE_SUPPORT
endif

LOCAL_CFLAGS += -Wno-error
LOCAL_SHARED_LIBRARIES := liblog libcutils libtinyalsa libaudioutils libaudioroute libhardware_legacy libspeexresampler
LOCAL_STATIC_LIBRARIES := libspeex
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_CFLAGS += -Wno-error
LOCAL_SRC_FILES:= amix.c alsa_mixer.c
LOCAL_MODULE:= amix
LOCAL_PROPRIETARY_MODULE := true
LOCAL_SHARED_LIBRARIES := liblog libc libcutils
LOCAL_MODULE_TAGS:= debug
include $(BUILD_EXECUTABLE)

此 TinyAlsaHAL 中的 audio_hw.c 文件中;
此源码在RK3288平台上实现TinyAlsaHAL基础上修改如下:

@ hardware/rockchip/audio/tinyalsa_hal/audio_hw.c 
static int start_input_stream(struct stream_in *in)
{
    struct audio_device *adev = in->dev;
    int  ret = 0;
    //ALOGV("Debug_dump_info: %s : %d , in->device: 0x%04x \n ", __func__, __LINE__, in->device);
    ALOGD("Debug_dump_info: %s : %d enter process", __func__, __LINE__ );
    in_dump(in, 0);
    route_pcm_open(getRouteFromDevice(in->device | AUDIO_DEVICE_BIT_IN));

    if(in->input_source == 0x08){ //> 修改对 Remote_submix 类型支持
        ALOGD("Debug_dump_info: %s : %d ,PCM_CARD:%d PCM_DEVICE:%d PCM_IN:%d ", __func__, __LINE__, PCM_CARD, PCM_DEVICE_SCO, PCM_IN);
        in->pcm = pcm_open(PCM_CARD, PCM_DEVICE_SCO, PCM_IN, in->config);
    }else{
        ALOGD("Debug_dump_info: %s : %d ,PCM_CARD:%d PCM_DEVICE:%d PCM_IN:%d ", __func__, __LINE__, PCM_CARD, PCM_DEVICE, PCM_IN);
        in->pcm = pcm_open(PCM_CARD, PCM_DEVICE, PCM_IN, in->config);
    }

    if (in->pcm && !pcm_is_ready(in->pcm)) {
        ALOGE("Debug_dump_info: pcm_open() failed: %s", pcm_get_error(in->pcm));
        pcm_close(in->pcm);
        return -ENOMEM;
    }

    /* if no supported sample rate is available, use the resampler */
    if (in->resampler)
        in->resampler->reset(in->resampler);

    in->frames_in = 0;
    adev->input_source = in->input_source;
    adev->in_device = in->device;
    adev->in_channel_mask = in->channel_mask;
    ALOGD("Debug_dump_info: %s : %d , sourceType: %4x \n ", __func__, __LINE__, in->input_source);
    if (in->device & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)
        start_bt_sco(adev);

    /* initialize volume ramp */
    in->ramp_frames = (CAPTURE_START_RAMP_MS * in->requested_rate) / 1000;
    in->ramp_step = (uint16_t)(USHRT_MAX / in->ramp_frames);
    in->ramp_vol = 0;;
    ALOGD("Debug_dump_info: %s : %d exit process", __func__, __LINE__ );
    return 0;
}

笔者在源码中修改对 Remote_submix 输入源类型支持,对应的声卡和PCM_DEVICE如源码中描述,读者如不是很了解对应关系,
请参考《ubuntu 20 使用命令行 snd-aloop 实现内录音、录制音乐播放器的音频》 博文内容,snd-aloop声卡驱动配置文件中,
已经指定此 PCM_DEVICE 为 1 时,通过 snd-aloop驱动获取的音频数据,就是系统播放音频内容。

第四步 修改源码

修改 @frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp 文件内容如下:

status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
                                             audio_io_handle_t *input,
                                             audio_session_t session,
                                             pid_t pid,
                                             uid_t uid,
                                             uint32_t samplingRate,
                                             audio_format_t format,
                                             audio_channel_mask_t channelMask,
                                             audio_input_flags_t flags,
                                             audio_port_handle_t selectedDeviceId)
{
    if (mAudioPolicyManager == NULL) {
        return NO_INIT;
    }
    ... //省略部分代码

    {
        Mutex::Autolock _l(mLock);
        // the audio_in_acoustics_t parameter is ignored by get_input()
        status = mAudioPolicyManager->getInputForAttr(attr, input, session, uid,
                                                     samplingRate, format, channelMask,
                                                     flags, selectedDeviceId,
                                                     &inputType);
        audioPolicyEffects = mAudioPolicyEffects;
        ALOGD("Debug_dump_info: %s,%d Status:%d ", __func__, __LINE__, status);
        if (status == NO_ERROR) {
            // enforce permission (if any) required for each type of input
            switch (inputType) {
            case AudioPolicyInterface::API_INPUT_LEGACY:
                break;
            case AudioPolicyInterface::API_INPUT_TELEPHONY_RX:
                // FIXME: use the same permission as for remote submix for now.
            case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
                if (!captureAudioOutputAllowed(pid, uid)) {
                    //> close this code by ljb 2022-3-14,屏蔽下面两条代码
                    //ALOGE("Debug_dump_info: getInputForAttr() permission denied: capture not allowed");
                    //status = PERMISSION_DENIED;
                }
                break;
            case AudioPolicyInterface::API_INPUT_MIX_EXT_POLICY_REROUTE:
                if (!modifyAudioRoutingAllowed()) {
                    ALOGE("Debug_dump_info: getInputForAttr() permission denied: modify audio routing not allowed");
                    status = PERMISSION_DENIED;
                }
                break;
            case AudioPolicyInterface::API_INPUT_INVALID:
            default:
                LOG_ALWAYS_FATAL("getInputForAttr() encountered an invalid input type %d",
                        (int)inputType);
                break;
            }
            ALOGD("Debug_dump_info: %s,%d Status:%d ", __func__, __LINE__, status);
        }
        if (status != NO_ERROR) {
            ALOGD("Debug_dump_info: %s,%d Status:%d ", __func__, __LINE__, status);
            if (status == PERMISSION_DENIED) {
                mAudioPolicyManager->releaseInput(*input, session);
            }
            return status;
        }
    }

此源码仅屏蔽权限授权部分,其他未做修改。

case AudioPolicyInterface::API_INPUT_MIX_CAPTURE:
                if (!captureAudioOutputAllowed(pid, uid)) {
                    //> close this code by ljb 2022-3-14,屏蔽下面两条代码
                    //ALOGE("Debug_dump_info: getInputForAttr() permission denied: capture not allowed");
                    //status = PERMISSION_DENIED;
                }
                break;

第五步 编译验证

在 android8.1 源码中,设备选择 hikey960 来验证此部分功能, Android 源码编译成功,
因笔者的安卓8.1镜像是运行在容器中,实际测试情况待时间方便会分享那部分内容。
在 android7.1 系统 rk3288 平台笔者已经成功实现此功能,第一步 中相关修改就是基于
实验成功基础上。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-03-17 22:19:09  更:2022-03-17 22:21:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 18:45:32-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码