1.修改音频场景,会另起一个线程,异步的修改音频场景。以下是几种常规场景。

enum AudioScene : int32_t {
    /**
     * Invalid
     */
    AUDIO_SCENE_INVALID = -1,
    /**
     * Default audio scene
     */
    AUDIO_SCENE_DEFAULT,//媒体场景
    /**
     * Ringing audio scene
     * Only available for system api.
     */
    AUDIO_SCENE_RINGING,
    /**
     * Phone call audio scene
     * Only available for system api.
     */
    AUDIO_SCENE_PHONE_CALL,//通话场景
    /**
     * Voice chat audio scene
     */
    AUDIO_SCENE_PHONE_CHAT,
    /**
     * AvSession set call start flag
     */
    AUDIO_SCENE_CALL_START,
    /**
     * AvSession set call end flag
     */
    AUDIO_SCENE_CALL_END,
    /**
     * Voice ringing audio scene
     * Only available for system api.
     */
    AUDIO_SCENE_VOICE_RINGING,
    /**
     * Max
     */
    AUDIO_SCENE_MAX,
};
void AudioInterruptService::UpdateAudioSceneFromInterrupt(const AudioScene audioScene,
    AudioInterruptChangeType changeType)
{
    ...
    std::thread setAudioSceneThread([this, audioScene] {
        this->policyServer_->SetAudioSceneInternal(audioScene);
    });
    setAudioSceneThread.detach();
}

2.进入AudioServer::SetAudioScene,这里会同时修改render的音频场景,和capture的音频场景,并且对通话场景额外对pcm设备做停止和开启操作。

int32_t AudioServer::SetAudioScene(AudioScene audioScene, std::vector<DeviceType> &activeOutputDevices,
    DeviceType activeInputDevice, BluetoothOffloadState a2dpOffloadFlag)
{
    ...
    if (audioScene != audioScene_ && (audioScene == AUDIO_SCENE_PHONE_CALL || audioScene_ == AUDIO_SCENE_PHONE_CALL)) {
        if (audioCapturerSourceInstance == nullptr || !audioCapturerSourceInstance->IsInited()) {
            AUDIO_WARNING_LOG("Capturer is not initialized.");
        } else {
            audioCapturerSourceInstance->Stop();
        }

        if (audioRendererSinkInstance == nullptr || !audioRendererSinkInstance->IsInited()) {
            AUDIO_WARNING_LOG("Renderer is not initialized.");
        } else {
            audioRendererSinkInstance->Stop();
        }
    }

    if (audioCapturerSourceInstance != nullptr) {
        if (!audioCapturerSourceInstance->IsInited()) {
            AUDIO_WARNING_LOG("Capturer is not initialized.");
        }
        audioCapturerSourceInstance->SetAudioScene(audioScene, activeInputDevice);
    }

    if (audioRendererSinkInstance == nullptr || !audioRendererSinkInstance->IsInited()) {
        AUDIO_WARNING_LOG("Renderer is not initialized.");
    } else {
        if (activeOutputDevice == DEVICE_TYPE_BLUETOOTH_A2DP && a2dpOffloadFlag != A2DP_OFFLOAD) {
            activeOutputDevices[0] = DEVICE_TYPE_NONE;
        }
        audioRendererSinkInstance->SetAudioScene(audioScene, activeOutputDevices);
    }

    if ((audioScene == AUDIO_SCENE_PHONE_CALL || audioScene_ == AUDIO_SCENE_PHONE_CALL) ||
        (audioScene == AUDIO_SCENE_RINGING && audioScene_ != AUDIO_SCENE_RINGING)) {
        if (audioCapturerSourceInstance == nullptr || !audioCapturerSourceInstance->IsInited()) {
            AUDIO_WARNING_LOG("Capturer is not initialized.");
        } else {
            AUDIO_WARNING_LOG("Capturer audioCapturerSourceInstance->Start");
            audioCapturerSourceInstance->Start();
        }

        if (audioRendererSinkInstance == nullptr || !audioRendererSinkInstance->IsInited()) {
            AUDIO_WARNING_LOG("Renderer is not initialized.");
        } else {
            AUDIO_WARNING_LOG("Renderer audioRendererSinkInstance->Start");
            audioRendererSinkInstance->Start();
        }
    }

    audioScene_ = audioScene;
    return SUCCESS;
}

3.AudioCapturerSourceInner::SetAudioScene是对capture的场景的修改,并且修改路由。

int32_t AudioCapturerSourceInner::SetAudioScene(AudioScene audioScene, DeviceType activeDevice)
{
    ...
    if (openMic_) {
        AudioPortPin audioSceneInPort = PIN_IN_MIC;
        if (halName_ == "usb") {
            audioSceneInPort = PIN_IN_USB_HEADSET;
        }

        int32_t ret = SUCCESS;
        std::lock_guard<std::mutex> lock(sourceAttrMutex_);
        ret = SetInputRoute(activeDevice, audioSceneInPort, static_cast<SourceType>(attr_.sourceTy
        if (ret < 0) {
            AUDIO_WARNING_LOG("Update route FAILED: %{public}d", ret);
        }
        struct AudioSceneDescriptor scene;
        scene.scene.id = GetAudioCategory(audioScene);
        scene.desc.pins = audioSceneInPort;
        scene.desc.desc = const_cast<char *>("");

        ret = audioCapture_->SelectScene(audioCapture_, &scene);
        CHECK_AND_RETURN_RET_LOG(ret >= 0, ERR_OPERATION_FAILED,
            "Select scene FAILED: %{public}d", ret);
        currentAudioScene_ = audioScene;

    }
    AUDIO_DEBUG_LOG("Select audio scene SUCCESS: %{public}d", audioScene);
    return SUCCESS;
}

4.进入HDF层,CaptureSelectSceneImpl中,如果需要进行场景切换,则会调用ReOpenPcmAndSetParams来切换对应的场景并重新打开pcm设备。

static int32_t CaptureSelectSceneImpl(struct AlsaCapture *captureIns, const struct AudioHwCaptureParam *handleData)
{
    CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
    CHECK_NULL_PTR_RETURN_DEFAULT(captureIns);
    int32_t ret = HDF_SUCCESS;
    AUDIO_FUNC_LOGI("CaptureSelectSceneImpl enter");
    captureIns->descPins = handleData->captureMode.hwInfo.deviceDescript.pins;
    enum AudioCategory scene = handleData->frameCaptureMode.attrs.type;

    // 实现通话录音场景时切换pcm设备流程,设置对应路由信息

    if (CheckSceneIsChange(scene)) {
        AUDIO_FUNC_LOGI("CaptureSelectSceneImpl change scene");
        if (g_currentScene == AUDIO_MMAP_NOIRQ) {
            AUDIO_FUNC_LOGI("CaptureSelectSceneImpl scene is AUDIO_MMAP_NOIRQ");
            ret = UpdateAudioCaptureRoute(captureIns, handleData);
            if (ret < 0) {
                AUDIO_FUNC_LOGE("capture UpdateAudioCaptureRoute fail");
                return HDF_FAILURE;
            }
            g_currentScene = scene;
        } else {
            AUDIO_FUNC_LOGI("CaptureSelectSceneImpl scene is not AUDIO_MMAP_NOIRQ scene: %{public}d", scene);
            if (captureIns->soundCard.pcmHandle != NULL) {
                snd_pcm_drop(captureIns->soundCard.pcmHandle);
            }
            PcmCloseHandle(&captureIns->soundCard);
            if (!SndisBusy(&captureIns->soundCard)) {
                AUDIO_FUNC_LOGI("CaptureSelectSceneImpl pcm is NULL");
                g_currentScene = scene;
                if (scene == AUDIO_IN_CALL) {
                    ret = ReOpenPcmAndSetParams(captureIns, handleData);
                    if (ret < 0) {
                        AUDIO_FUNC_LOGE("ReOpenPcmAndSetParams fail");
                        return HDF_FAILURE;
                    }
                }
            }
        } 
    } else {
        g_currentScene = scene;
        if (scene == AUDIO_IN_CALL) {
            AUDIO_FUNC_LOGI("CaptureSelectSceneImpl change device");
            ret = UpdateAudioCaptureRoute(captureIns, handleData);
            if (ret < 0) {
                AUDIO_FUNC_LOGE("capture UpdateAudioCaptureRoute fail");
                return HDF_FAILURE;
            }
        }
    }

    AUDIO_FUNC_LOGI("CaptureSelectSceneImpl end");

    return HDF_SUCCESS;
}

5.HDF层,RenderSelectSceneImpl是进行对render的场景切换。*在这里启动render的pcm设备和capture的pcm设备**。

static int32_t RenderSelectSceneImpl(struct AlsaRender *renderIns, const struct AudioHwRenderParam *handleData)
{
    CHECK_NULL_PTR_RETURN_DEFAULT(handleData);
    CHECK_NULL_PTR_RETURN_DEFAULT(renderIns);
    int32_t ret = HDF_SUCCESS;

    renderIns->descPins = handleData->renderMode.hwInfo.deviceDescript.pins;
    enum AudioCategory scene = handleData->frameRenderMode.attrs.type;
    AUDIO_FUNC_LOGI("RenderSelectSceneImpl enter scene: %{public}d, device: %{public}d", scene, renderIns->descPins
    if (CheckSceneIsChange(scene)) {
        AUDIO_FUNC_LOGI("RenderSelectSceneImpl change scene");
        if (g_currentScene == AUDIO_MMAP_NOIRQ) {
            AUDIO_FUNC_LOGI("RenderSelectSceneImpl scene is AUDIO_MMAP_NOIRQ");
            ret = UpdateAudioRenderRoute(renderIns, handleData);
            if (ret < 0) {
                AUDIO_FUNC_LOGE("render UpdateAudioRenderRoute fail");
                return HDF_FAILURE;
            }
            g_currentScene = scene;
        } else {
            if (ChangeScene(renderIns, handleData, scene) < 0) {
                AUDIO_FUNC_LOGE("ChangeScene fail");
                return HDF_FAILURE;
            }
        }
    } else {
        g_currentScene = scene; 
        AUDIO_FUNC_LOGI("RenderSelectSceneImpl not need change scene");
        if (scene == AUDIO_IN_CALL) {
            // change device 
            AUDIO_FUNC_LOGI("RenderSelectSceneImpl change device");
            ret = UpdateAudioRenderRoute(renderIns, handleData);
            if (ret < 0) {
                AUDIO_FUNC_LOGE("render UpdateAudioRenderRoute fail");
                return HDF_FAILURE;
            }
            if (!g_dlHandle) {
                AUDIO_FUNC_LOGE("open libsprd_mock_effect_lib.z.so failed!");
                return HDF_FAILURE;
            }
            UpdateFunc updateDevice = (UpdateFunc)dlsym(g_dlHandle, "update_device");
            if (updateDevice == NULL) {
                AUDIO_FUNC_LOGE("update_device not defined or exported!");
                return HDF_FAILURE;
            }
            ret = updateDevice(handleData->renderMode.hwInfo.deviceDescript.pins);
            if (ret < 0) {
                AUDIO_FUNC_LOGE("render update_device failed");
                return HDF_FAILURE;
            }
        }
        ret = UpdateAudioRenderRoute(renderIns, handleData);
        if (ret < 0) {
            AUDIO_FUNC_LOGE("render UpdateAudioRenderRoute fail");
            return HDF_FAILURE;
        }
    }
    
    AUDIO_FUNC_LOGI("RenderSelectSceneImpl end");
    return HDF_SUCCESS;
}
Logo

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

更多推荐