1 当前audio结构图

img

2 社区当前录音流程

img

录音类型如下:

enum SourceType {
    SOURCE_TYPE_INVALID = -1,
    SOURCE_TYPE_MIC,                          // 本地录音
    SOURCE_TYPE_VOICE_RECOGNITION = 1,        //
    SOURCE_TYPE_PLAYBACK_CAPTURE = 2,         // 内录(录屏)
    SOURCE_TYPE_WAKEUP = 3,                   // 语言唤醒
    SOURCE_TYPE_VOICE_CALL = 4,               // 通话中录音
    SOURCE_TYPE_VOICE_COMMUNICATION = 7,      // VOIP
    SOURCE_TYPE_ULTRASONIC = 8,
    SOURCE_TYPE_VIRTUAL_CAPTURE = 9, // only for voice call 打电话
    SOURCE_TYPE_MAX = SOURCE_TYPE_VIRTUAL_CAPTURE
};

3 开发者手机的蓝牙录音流程

开发者手机pcm设备列表如下:

# cat proc/asound/pcm
00-01: DisplayPort MultiMedia (*) :  : playback 1
00-02: FE_ST_NORMAL_AP01 (*) :  : playback 1 : capture 1    // 本地播放和录音
00-03: FE_ST_NORMAL_AP23 (*) :  : playback 1 : capture 1
00-04: FE_ST_CAPTURE_DSP (*) :  : capture 1
00-05: FE_ST_FAST (*) :  : playback 1
00-07: FE_ST_VOICE (*) :  : playback 1 : capture 1         // 打电话设备
00-08: FE_ST_VOIP (*) :  : playback 1 : capture 1          // VOIP设备
00-09: FE_ST_FM (*) :  : playback 1
00-10: FE_ST_FM_C (*) :  : capture 1
00-11: FE_ST_VOICE_C (*) :  : capture 1                    // 通话录音设备
00-12: FE_ST_LOOP (*) :  : playback 1 : capture 1
00-14: FE_ST_A2DP_PCM (*) :  : playback 1
00-15: FE_ST_CAPTURE_FM_DSP (*) :  : capture 1
00-16: FE_ST_CAPTURE_BTSCO_DSP (*) :  : capture 1          // 蓝牙录音设备
00-17: FE_ST_FM_DSP (*) :  : playback 1
00-18: FE_ST_DUMP (*) :  : capture 1
00-19: FE_ST_BTCAP_AP (*) :  : capture 1
00-51: FE_ST_TEST_CODEC (*) :  : playback 1 : capture 1
00-55: FE_ST_VOICE_PCM_P (*) :  : playback 1
00-57: FE_ST_MM_P (*) :  : playback 1

# amixer cget numid=149
numid=149,iface=MIXER,name='VBC_DSP_VOICE_CAPTURE_TYPE'
  ; type=ENUMERATED,access=rw------,values=1,items=3
  ; Item #0 'VOICE_CAPTURE_DOWNLINK'                 // 下行
  ; Item #1 'VOICE_CAPTURE_UPLINK'                   // 上行
  ; Item #2 'VOICE_CAPTURE_UPLINK_DOWNLINK'          // 上下行
  : values=0

录音本身:

audio_framework层到HDF层:

  1. 有蓝牙遥控器rcu hdiadapter,往下进入到audio_host拉起rcu驱动
  2. 有蓝牙遥控器rcu impl接口,打开相关声卡设备。

4 基于社区的方案实现录音流程

img

  1. audio_framework侧增加framework的设备连接,以及ble蓝牙低功耗与hdi层的对接。

  2. HDI侧a. 在CreateCapture中实现蓝牙录音流程,创建capture实现蓝牙录音流程

    int32_t BluetoothCapturerSourceInner::CreateCapture(struct AudioPort &capturePort)
    {

     Trace trace("BluetoothCapturerSourceInner::CreateCapture");
    
     struct AudioSampleAttributes param;
     // User needs to set
     InitAttrsCapture(param);
     param.sampleRate = attr_.sampleRate;
     param.format = ConvertToHdiFormat(attr_.format);
     param.isBigEndian = attr_.isBigEndian;
     param.channelCount = attr_.channel;
     param.silenceThreshold = attr_.bufferSize;
     param.frameSize = param.format * param.channelCount;
     param.startThreshold = DEEP_BUFFER_CAPTURE_PERIOD_SIZE / (param.frameSize);
    
     struct AudioDeviceDescriptor deviceDesc;
     deviceDesc.portId = capturePort.portId;
     deviceDesc.pins = PIN_IN_MIC;
     deviceDesc.desc = nullptr;
    
     AUDIO_INFO_LOG("create capture sourceName:%{public}s, " \
         "rate:%{public}u channel:%{public}u format:%{public}u, devicePin:%{public}u",
         halName_.c_str(), param.sampleRate, param.channelCount, param.format, deviceDesc.pins);
     int32_t ret = audioAdapter_->CreateCapture(audioAdapter_, &deviceDesc, &param, &audioCapture_);
     CHECK_AND_RETURN_RET_LOG(audioCapture_ != nullptr && ret >=0, ERR_NOT_STARTED, "create capture failed");
    
     return 0;
    

    }

b. 在BluetoothCapturerSourceInner::Start中用于启动蓝牙音频捕获功能

int32_t BluetoothCapturerSourceInner::Start(void)
{
    std::lock_guard<std::mutex> statusLock(statusMutex_);

    AUDIO_INFO_LOG("sourceName %{public}s", halName_.c_str());
    Trace trace("BluetoothCapturerSourceInner::Start");

    InitLatencyMeasurement();
#ifdef FEATURE_POWER_MANAGER
    std::shared_ptr<PowerMgr::RunningLock> keepRunningLock;
    if (runningLockManager_ == nullptr) {
        keepRunningLock = PowerMgr::PowerMgrClient::GetInstance().CreateRunningLock("AudioBluetoothCapturer",
            PowerMgr::RunningLockType::RUNNINGLOCK_BACKGROUND_AUDIO);
        if (keepRunningLock) {
            runningLockManager_ = std::make_shared<AudioRunningLockManager<PowerMgr::RunningLock>> (keepRunningLock);
        }
    }

    if (runningLockManager_ != nullptr) {
        AUDIO_INFO_LOG("keepRunningLock lock result: %{public}d",
            runningLockManager_->Lock(RUNNINGLOCK_LOCK_TIMEOUTMS_LASTING));
    } else {
        AUDIO_WARNING_LOG("keepRunningLock is null, capture can not work well");
    }
#endif
    dumpFileName_ = halName_ + "_" + std::to_string(attr_.sourceType) + "_" + GetTime()
        + "_bluetooth_source_" + std::to_string(attr_.sampleRate) + "_" + std::to_string(attr_.channel)
        + "_" + std::to_string(attr_.format) + ".pcm";
    DumpFileUtil::OpenDumpFile(DUMP_SERVER_PARA, dumpFileName_, &dumpFile_);

    if (!started_) {
        if (audioCapturerSourceCallback_ != nullptr) {
            audioCapturerSourceCallback_->OnCapturerState(true);
        }

        int32_t ret = audioCapture_->control.Start(reinterpret_cast<AudioHandle>(audioCapture_));
        if (ret < 0) {
#ifdef FEATURE_POWER_MANAGER
            if (runningLockManager_ != nullptr) {
                AUDIO_WARNING_LOG("capturer start failed, keepRunningLock unLock");
                runningLockManager_->UnLock();
            } else {
                AUDIO_WARNING_LOG("capturer start failed, try unlock but KeepRunningLock is null!");
            }
#endif
            return ERR_NOT_STARTED;

        }
        started_ = true;
    }

    return SUCCESS;
}

c. SetVolume设置音量的实现

int32_t BluetoothCapturerSourceInner::SetVolume(float left, float right)
{
    float volume;
    CHECK_AND_RETURN_RET_LOG(audioCapture_ != nullptr, ERR_INVALID_HANDLE,
        "SetVolume failed audioCapture_ null");

    rightVolume_ = right;
    leftVolume_ = left;
    if ((leftVolume_ == 0) && (rightVolume_ != 0)) {
        volume = rightVolume_;
    } else if ((leftVolume_ != 0) && (rightVolume_ == 0)) {
        volume = leftVolume_;
    } else {
        volume = (leftVolume_ + rightVolume_) / HALF_FACTOR;
    }

    audioCapture_->volume.SetVolume(reinterpret_cast<AudioHandle>(audioCapture_), volume);

    return SUCCESS;
}

d. 停止蓝牙音频录制的实现

int32_t BluetoothCapturerSourceInner::Stop(void)
{
    Trace trace("BluetoothCapturerSourceInner::Stop");
    std::promise<void> promiseEnsueThreadLock;
    auto futureWaitThreadLock = promiseEnsueThreadLock.get_future();
    std::thread threadAsyncStop([&promiseEnsueThreadLock, this] {
        std::lock_guard<std::mutex> statusLock(statusMutex_);
        promiseEnsueThreadLock.set_value();
        DoStop();
    });
    futureWaitThreadLock.get();
    threadAsyncStop.detach();

    return SUCCESS;
}

1.定义rcu相关接口,通过audiohost拉起rcu驱动。

struct AudioDeviceDescriptor devDesc;中的

enum AudioPortPin {

    PIN_NONE                     = 0x0u,       /**< Invalid pin */

    PIN_OUT_SPEAKER              = 0x1u,       /**< Speaker output pin */

    PIN_OUT_HEADSET              = 0x2u,       /**< Wired headset pin for output */

    PIN_OUT_LINEOUT              = 0x4u,       /**< Line-out pin */

    PIN_OUT_HDMI                 = 0x8u,       /**< HDMI output pin */

    PIN_OUT_USB                  = 0x10u,      /**< USB output pin */

    PIN_OUT_USB_EXT              = 0x20u,      /**< Extended USB output pin*/

    PIN_OUT_EARPIECE             = 0x30u,      /**< Earpiece output pin */

    PIN_OUT_BLUETOOTH_SCO        = 0x40u,      /**< Bluetooth SCO output pin */

    PIN_OUT_DAUDIO_DEFAULT       = 0x80u,

    PIN_OUT_HEADPHONE            = 0x100u,     /**< Wired headphone output pin*/

    PIN_OUT_USB_HEADSET          = 0x200u,     /**< ARM USB out pin */

    PIN_OUT_BLUETOOTH_A2DP       = 0x300u,     /**< Bluetooth a2dp output pin */

    PIN_IN_MIC                   = 0x8000001u, /**< Microphone input pin */

    PIN_IN_HS_MIC                = 0x8000002u, /**< Wired headset microphone pin for input */

    PIN_IN_LINEIN                = 0x8000004u, /**< Line-in pin */

    PIN_IN_USB_EXT               = 0x8000008u, /**< Extended USB input pin*/

    PIN_IN_BLUETOOTH_SCO_HEADSET = 0x8000010u, /**< Bluetooth SCO headset input pin */

    PIN_IN_USB_HEADSET           = 0x8000040u, /**< ARM USB input pin */

};在枚举中添加PIN_IN_RCU的引脚定义

a.HdiServiceCreateCapture创建音频捕获(录音)服务

int32_t HdiServiceCreateCapture(const struct HdfDeviceIoClient *client,
    struct HdfSBuf *data, struct HdfSBuf *reply)
{
    if (client == nullptr || data == nullptr || reply == nullptr) {
        return AUDIO_HAL_ERR_INVALID_PARAM;
    }
    struct AudioAdapter *adapter = nullptr;
    struct AudioDeviceDescriptor devDesc;
    struct AudioSampleAttributes attrs;
    struct AudioCapture *capture = nullptr;
    const char *adapterName = nullptr;
    uint32_t capturePid = 0;
    if ((adapterName = HdfSbufReadString(data)) == nullptr) {
        HDF_LOGE("%{public}s: adapterNameCase Is NULL", __func__);
        return AUDIO_HAL_ERR_INVALID_PARAM;
    }
    if (!HdfSbufReadUint32(data, &capturePid)) {
        return AUDIO_HAL_ERR_INTERNAL;
    }
    HDF_LOGE("HdiServiceCreatRender: capturePid = %{public}u", capturePid);
    int32_t ret = GetInitCapturePara(data, &devDesc, &attrs);
    if (ret < 0) {
        HDF_LOGE("%{public}s: GetInitCapturePara fail", __func__);
        return AUDIO_HAL_ERR_INTERNAL;
    }
    if (AudioAdapterListGetAdapter(adapterName, &adapter)) {
        HDF_LOGE("%{public}s: fail", __func__);
        return AUDIO_HAL_ERR_INTERNAL;
    }
    if (adapter == nullptr) {
        HDF_LOGE("%{public}s: adapter is NULL!", __func__);
        return AUDIO_HAL_ERR_INVALID_PARAM;
    }
    const int32_t priority = attrs.type;
    ret = AudioCreateCaptureCheck(adapterName, priority);
    if (ret < 0) {
        HDF_LOGE("%{public}s: AudioCreateCaptureCheck: Capture is working can not replace!", __func__);
        return ret;
    }
    ret = adapter->CreateCapture(adapter, &devDesc, &attrs, &capture);
    if (capture == nullptr || ret < 0) {
        HDF_LOGE("%{public}s: Failed to CreateCapture", __func__);
        return AUDIO_HAL_ERR_INTERNAL;
    }
    if (AudioAddCaptureInfoInAdapter(adapterName, capture, adapter, priority, capturePid)) {
        HDF_LOGE("%{public}s: AudioAddCaptureInfoInAdapter", __func__);
        adapter->DestroyCapture(adapter, capture);
        return AUDIO_HAL_ERR_INTERNAL;
    }
    return AUDIO_HAL_SUCCESS;
}

b.AudioAddCaptureInfoInAdapter添加关于音频捕获实例的参数。

int32_t AudioAddCaptureInfoInAdapter(const char *adapterName, struct AudioCapture *capture,
    const struct AudioAdapter *adapter, const int32_t priority, uint32_t capturePid)
{
    int32_t i;
    int32_t num;
    if (adapterName == nullptr || adapter == nullptr || capture == nullptr) {
        HDF_LOGE("%{public}s: input para is NULL. ", __func__);
        return HDF_FAILURE;
    }
    if (g_renderAndCaptureManage == nullptr) {
        return HDF_FAILURE;
    }
    num = (g_serverAdapterNum > MAX_AUDIO_ADAPTER_NUM_SERVER) ? MAX_AUDIO_ADAPTER_NUM_SERVER : g_serverAdapterNum;
    for (i = 0; i < num; i++) {
        if (g_renderAndCaptureManage[i].adapterName == nullptr) {
            return HDF_FAILURE;
        }
        if (!strcmp(g_renderAndCaptureManage[i].adapterName, adapterName)) {
            g_renderAndCaptureManage[i].captureStatus = 1;
            g_renderAndCaptureManage[i].capturePriority = priority;
            g_renderAndCaptureManage[i].capture = capture;
            g_renderAndCaptureManage[i].capturePid = capturePid;
            return HDF_SUCCESS;
        }
    }
    HDF_LOGE("%{public}s: Can not find Adapter! ", __func__);
    return HDF_FAILURE;
}

c.SetupRcuInterface基于适配器名称来设置RCU接口

bool SetupRcuInterface(struct AudioHwAdapter *hwAdapter, const struct AudioAdapterDescriptor *desc)
{
    bool ret = false;
    if (strcmp(desc->adapterName, "rcu_fast") == 0) {
        HDF_LOGI("%{public}s, fast set up", __func__);
        ret = OHOS::Rcu::FastSetUp();
    } else if (strcmp(desc->adapterName, "rcu_hdap") == 0) {
        HDF_LOGI("%{public}s, hdap set up", __func__);
        ret = OHOS::Rcu::SetUpCapture();
    } else {
        HDF_LOGI("%{public}s, normal set up", __func__);
        ret = OHOS::Rcu::SetUp();
    }
    return ret;
#endif
}

d.HdiServiceCaptureStart用于启动音频捕获服务

int32_t HdiServiceCaptureStart(const struct HdfDeviceIoClient *client, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    if (client == nullptr || data == nullptr || reply == nullptr) {
        return AUDIO_HAL_ERR_INVALID_PARAM;
    }
    struct AudioCapture *capture = nullptr;
    int ret = AudioAdapterListCheckAndGetCapture(&capture, data);
    if (ret < 0) {
        return ret;
    }
    return capture->control.Start((AudioHandle)capture);
}
Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐