blob: 60131286a8cb84c9003991bc20eb808de405a130 [file] [log] [blame]
/*
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Changes from Qualcomm Innovation Center, Inc. are provided under the following license:
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#define LOG_TAG "PAL: Session"
#include "Session.h"
#include "Stream.h"
#include "ResourceManager.h"
#include "SessionGsl.h"
#include "SessionAlsaPcm.h"
#include "SessionAlsaCompress.h"
#include "SessionAgm.h"
#include "SessionAlsaUtils.h"
#include "SessionAlsaVoice.h"
#include <sstream>
struct pcm *Session::pcmEcTx = NULL;
std::vector<int> Session::pcmDevEcTxIds = {0};
int Session::extECRefCnt = 0;
std::mutex Session::extECMutex;
Session::Session()
{
isMixerEventCbRegd = false;
isPauseRegistrationDone = false;
}
Session::~Session()
{
}
void Session::setPmQosMixerCtl(pmQosVote vote)
{
struct mixer *hwMixer;
struct mixer_ctl *ctl;
if (0 == rm->getHwAudioMixer(&hwMixer)) {
ctl = mixer_get_ctl_by_name(hwMixer, "PM_QOS Vote");
if (!ctl) {
PAL_ERR(LOG_TAG, "Invalid mixer control: %s\n",
"PM_QOS Vote");
} else {
if (vote == PM_QOS_VOTE_DISABLE) {
mixer_ctl_set_enum_by_string(ctl, "Disable");
PAL_DBG(LOG_TAG,"mixer control disabled for PM_QOS Vote \n");
} else if (vote == PM_QOS_VOTE_ENABLE) {
mixer_ctl_set_enum_by_string(ctl, "Enable");
PAL_DBG(LOG_TAG,"mixer control enabled for PM_QOS Vote \n");
}
}
}
else
PAL_ERR(LOG_TAG,"could not get hwMixer, not setting mixer control for PM_QOS \n");
}
Session* Session::makeSession(const std::shared_ptr<ResourceManager>& rm, const struct pal_stream_attributes *sAttr)
{
if (!rm || !sAttr) {
PAL_ERR(LOG_TAG, "Invalid parameters passed");
return nullptr;
}
Session* s = (Session*) nullptr;
switch (sAttr->type) {
//create compressed if the stream type is compressed
case PAL_STREAM_COMPRESSED:
s = new SessionAlsaCompress(rm);
break;
case PAL_STREAM_VOICE_CALL:
s = new SessionAlsaVoice(rm);
break;
case PAL_STREAM_NON_TUNNEL:
s = new SessionAgm(rm);
break;
default:
s = new SessionAlsaPcm(rm);
break;
}
return s;
}
Session* Session::makeACDBSession(const std::shared_ptr<ResourceManager>& rm,
const struct pal_stream_attributes *sAttr)
{
if (!rm || !sAttr) {
PAL_ERR(LOG_TAG,"Invalid parameters passed");
return nullptr;
}
Session* s = (Session*) nullptr;
s = new SessionAgm(rm);
return s;
}
void Session::getSamplerateChannelBitwidthTags(struct pal_media_config *config,
uint32_t &mfc_sr_tag, uint32_t &ch_tag, uint32_t &bitwidth_tag)
{
switch (config->sample_rate) {
case SAMPLINGRATE_8K :
mfc_sr_tag = MFC_SR_8K;
break;
case SAMPLINGRATE_16K :
mfc_sr_tag = MFC_SR_16K;
break;
case SAMPLINGRATE_32K :
mfc_sr_tag = MFC_SR_32K;
break;
case SAMPLINGRATE_44K :
mfc_sr_tag = MFC_SR_44K;
break;
case SAMPLINGRATE_48K :
mfc_sr_tag = MFC_SR_48K;
break;
case SAMPLINGRATE_96K :
mfc_sr_tag = MFC_SR_96K;
break;
case SAMPLINGRATE_192K :
mfc_sr_tag = MFC_SR_192K;
break;
case SAMPLINGRATE_384K :
mfc_sr_tag = MFC_SR_384K;
break;
default:
mfc_sr_tag = MFC_SR_48K;
break;
}
switch (config->ch_info.channels) {
case CHANNELS_1:
ch_tag = CHS_1;
break;
case CHANNELS_2:
ch_tag = CHS_2;
break;
case CHANNELS_3:
ch_tag = CHS_3;
break;
case CHANNELS_4:
ch_tag = CHS_4;
break;
case CHANNELS_5:
ch_tag = CHS_5;
break;
case CHANNELS_6:
ch_tag = CHS_6;
break;
case CHANNELS_7:
ch_tag = CHS_7;
break;
case CHANNELS_8:
ch_tag = CHS_8;
break;
default:
ch_tag = CHS_1;
break;
}
switch (config->bit_width) {
case BITWIDTH_16:
bitwidth_tag = BW_16;
break;
case BITWIDTH_24:
bitwidth_tag = BW_24;
break;
case BITWIDTH_32:
bitwidth_tag = BW_32;
break;
default:
bitwidth_tag = BW_16;
break;
}
}
int Session::getEffectParameters(Stream *s __unused, effect_pal_payload_t *effectPayload)
{
int status = 0;
uint8_t *ptr = NULL;
uint8_t *payloadData = NULL;
size_t payloadSize = 0;
int device = 0;
uint32_t miid = 0;
const char *control = "getParam";
struct mixer_ctl *ctl;
pal_effect_custom_payload_t *effectCustomPayload = nullptr;
std::ostringstream CntrlName;
PayloadBuilder builder;
PAL_DBG(LOG_TAG, "Enter.");
ctl = getFEMixerCtl(control, &device);
if (!ctl) {
PAL_ERR(LOG_TAG, "Invalid mixer control: %s\n", CntrlName.str().data());
status = -ENOENT;
goto exit;
}
if (!rxAifBackEnds.empty()) { /** search in RX GKV */
status = SessionAlsaUtils::getModuleInstanceId(mixer, device, rxAifBackEnds[0].second.data(),
effectPayload->tag, &miid);
if (status) /** if not found, reset miid to 0 again */
miid = 0;
}
if (!txAifBackEnds.empty()) { /** search in TX GKV */
status = SessionAlsaUtils::getModuleInstanceId(mixer, device, txAifBackEnds[0].second.data(),
effectPayload->tag, &miid);
if (status)
miid = 0;
}
if (miid == 0) {
PAL_ERR(LOG_TAG, "failed to look for module with tagID 0x%x",
effectPayload->tag);
status = -EINVAL;
goto exit;
}
effectCustomPayload = (pal_effect_custom_payload_t *)(effectPayload->payload);
if (effectPayload->payloadSize < sizeof(pal_effect_custom_payload_t)) {
status = -EINVAL;
PAL_ERR(LOG_TAG, "memory for retrieved data is too small");
goto exit;
}
builder.payloadQuery(&payloadData, &payloadSize,
miid, effectCustomPayload->paramId,
effectPayload->payloadSize - sizeof(uint32_t));
status = mixer_ctl_set_array(ctl, payloadData, payloadSize);
if (0 != status) {
PAL_ERR(LOG_TAG, "Set custom config failed, status = %d", status);
goto exit;
}
status = mixer_ctl_get_array(ctl, payloadData, payloadSize);
if (0 != status) {
PAL_ERR(LOG_TAG, "Get custom config failed, status = %d", status);
goto exit;
}
ptr = (uint8_t *)payloadData + sizeof(struct apm_module_param_data_t);
ar_mem_cpy(effectCustomPayload->data, effectPayload->payloadSize,
ptr, effectPayload->payloadSize);
exit:
if (payloadData)
free(payloadData);
PAL_ERR(LOG_TAG, "Exit. status %d", status);
return status;
}
int Session::rwACDBParameters(void *payload, uint32_t sampleRate,
bool isParamWrite)
{
int status = 0;
uint8_t *payloadData = NULL;
size_t payloadSize = 0;
int device = 0;
uint32_t miid = 0;
char const *control = "setParamTagACDB";
struct mixer_ctl *ctl;
pal_effect_custom_payload_t *effectCustomPayload = nullptr;
std::ostringstream CntrlName;
PayloadBuilder builder;
pal_param_payload *paramPayload = nullptr;
agm_acdb_param *effectACDBPayload = nullptr;
paramPayload = (pal_param_payload *)payload;
if (!paramPayload)
return -EINVAL;
effectACDBPayload = (agm_acdb_param *)(paramPayload->payload);
if (!effectACDBPayload)
return -EINVAL;
PAL_DBG(LOG_TAG, "Enter.");
ctl = getFEMixerCtl(control, &device);
if (!ctl) {
PAL_ERR(LOG_TAG, "Invalid mixer control: %s\n", CntrlName.str().data());
status = -ENOENT;
goto exit;
}
if (!rxAifBackEnds.empty()) { /** search in RX GKV */
status = SessionAlsaUtils::getModuleInstanceId(mixer, device,
rxAifBackEnds[0].second.data(),
effectACDBPayload->tag, &miid);
if (status) /** if not found, reset miid to 0 again */
miid = 0;
}
if (!txAifBackEnds.empty()) { /** search in TX GKV */
status = SessionAlsaUtils::getModuleInstanceId(mixer, device, txAifBackEnds[0].second.data(),
effectACDBPayload->tag, &miid);
if (status)
miid = 0;
}
if (miid == 0) {
PAL_ERR(LOG_TAG, "failed to look for module with tagID 0x%x",
effectACDBPayload->tag);
status = -EINVAL;
goto exit;
}
effectCustomPayload =
(pal_effect_custom_payload_t *)(effectACDBPayload->blob);
status = builder.payloadACDBParam(&payloadData, &payloadSize,
(uint8_t *)effectACDBPayload,
miid, sampleRate);
if (!payloadData) {
PAL_ERR(LOG_TAG, "failed to create payload data.");
goto exit;
}
if (isParamWrite) {
status = mixer_ctl_set_array(ctl, payloadData, payloadSize);
if (0 != status) {
PAL_ERR(LOG_TAG, "Set custom config failed, status = %d", status);
goto exit;
}
}
exit:
free(payloadData);
PAL_ERR(LOG_TAG, "Exit. status %d", status);
return status;
}
int Session::rwACDBParamTunnel(void *payload, pal_device_id_t palDeviceId,
pal_stream_type_t palStreamType, uint32_t sampleRate,
uint32_t instanceId, bool isParamWrite, Stream * s)
{
int status = -EINVAL;
struct pal_stream_attributes sAttr;
PAL_DBG(LOG_TAG, "Enter");
status = s->getStreamAttributes(&sAttr);
streamHandle = s;
if (0 != status) {
PAL_ERR(LOG_TAG,"getStreamAttributes Failed \n");
goto exit;
}
PAL_INFO(LOG_TAG, "PAL device id=0x%x", palDeviceId);
status = SessionAlsaUtils::rwACDBTunnel(s, rm, palDeviceId, payload, isParamWrite, instanceId);
if (status) {
PAL_ERR(LOG_TAG, "session alsa open failed with %d", status);
}
exit:
PAL_DBG(LOG_TAG, "Exit status: %d", status);
return status;
}
int Session::updateCustomPayload(void *payload, size_t size)
{
if (!customPayloadSize || !customPayload) {
customPayload = calloc(1, size);
} else {
customPayload = realloc(customPayload, customPayloadSize + size);
}
if (!customPayload) {
PAL_ERR(LOG_TAG, "failed to allocate memory for custom payload");
return -ENOMEM;
}
memcpy((uint8_t *)customPayload + customPayloadSize, payload, size);
customPayloadSize += size;
PAL_INFO(LOG_TAG, "customPayloadSize = %zu", customPayloadSize);
return 0;
}
int Session::getCustomPayload(uint8_t **payload, size_t *payloadSize)
{
if (customPayloadSize) {
*payload = (uint8_t *)customPayload;
*payloadSize = customPayloadSize;
}
return 0;
}
int Session::freeCustomPayload(uint8_t **payload, size_t *payloadSize)
{
if (*payload) {
free(*payload);
*payload = NULL;
*payloadSize = 0;
}
return 0;
}
int Session::freeCustomPayload()
{
if (customPayload) {
free(customPayload);
customPayload = NULL;
customPayloadSize = 0;
}
return 0;
}
int Session::pause(Stream * s __unused)
{
return 0;
}
int Session::resume(Stream * s __unused)
{
return 0;
}
int Session::handleDeviceRotation(Stream *s, pal_speaker_rotation_type rotation_type,
int device, struct mixer *mixer, PayloadBuilder* builder,
std::vector<std::pair<int32_t, std::string>> rxAifBackEnds)
{
int status = 0;
struct pal_stream_attributes sAttr;
struct pal_device dAttr;
struct sessionToPayloadParam deviceData;
uint32_t miid = 0;
uint8_t* alsaParamData = NULL;
size_t alsaPayloadSize = 0;
int mfc_tag = TAG_MFC_SPEAKER_SWAP;
std::vector<std::shared_ptr<Device>> associatedDevices;
status = s->getStreamAttributes(&sAttr);
if (status != 0) {
PAL_ERR(LOG_TAG, "stream get attributes failed");
return status;
}
if (PAL_AUDIO_OUTPUT== sAttr.direction) {
status = s->getAssociatedDevices(associatedDevices);
if (0 != status) {
PAL_ERR(LOG_TAG, "getAssociatedDevices Failed\n");
return status;
}
for (int i = 0; i < associatedDevices.size(); i++) {
status = associatedDevices[i]->getDeviceAttributes(&dAttr);
if (0 != status) {
PAL_ERR(LOG_TAG, "get Device Attributes Failed\n");
return status;
}
if ((PAL_DEVICE_OUT_SPEAKER == dAttr.id) &&
(2 == dAttr.config.ch_info.channels)) {
/* Get DevicePP MFC MIID and configure to match to device config */
/* This has to be done after sending all mixer controls and
* before connect
*/
if (sAttr.type == PAL_STREAM_ULTRA_LOW_LATENCY) {
/* ULL playback don't have PP module. Thus we need to swap
channels in PSPD MFC
*/
mfc_tag = TAG_DEVICE_MFC_SR;
PAL_INFO(LOG_TAG, "Speake Swap in ULL use case");
}
status =
SessionAlsaUtils::getModuleInstanceId(mixer,
device,
rxAifBackEnds[i].second.data(),
mfc_tag, &miid);
if (status != 0) {
PAL_ERR(LOG_TAG, "getModuleInstanceId failed");
return status;
}
PAL_DBG(LOG_TAG, "miid : %x id = %d, data %s, dev id = %d\n", miid,
device, rxAifBackEnds[i].second.data(), dAttr.id);
if (rm->activeGroupDevConfig) {
if (rm->activeGroupDevConfig->devpp_mfc_cfg.sample_rate)
dAttr.config.sample_rate = rm->activeGroupDevConfig->devpp_mfc_cfg.sample_rate;
if (rm->activeGroupDevConfig->devpp_mfc_cfg.channels)
dAttr.config.ch_info.channels = rm->activeGroupDevConfig->devpp_mfc_cfg.channels;
}
deviceData.bitWidth = dAttr.config.bit_width;
deviceData.sampleRate = dAttr.config.sample_rate;
deviceData.numChannel = dAttr.config.ch_info.channels;
deviceData.rotation_type = rotation_type;
deviceData.ch_info = nullptr;
builder->payloadMFCConfig((uint8_t **)&alsaParamData,
&alsaPayloadSize, miid, &deviceData);
if (alsaPayloadSize) {
status = updateCustomPayload(alsaParamData, alsaPayloadSize);
delete alsaParamData;
if (0 != status) {
PAL_ERR(LOG_TAG, "updateCustomPayload Failed\n");
return status;
}
}
status = SessionAlsaUtils::setMixerParameter(mixer,
device,
customPayload,
customPayloadSize);
freeCustomPayload();
if (status != 0) {
PAL_ERR(LOG_TAG, "setMixerParameter failed");
return status;
}
}
}
}
return status;
}
/* This set slot mask tag for device with virtual port enabled */
int Session::setSlotMask(const std::shared_ptr<ResourceManager>& rm, struct pal_stream_attributes &sAttr,
struct pal_device &dAttr, const std::vector<int> &pcmDevIds)
{
int status = 0;
std::vector <std::pair<int, int>> tkv;
struct agm_tag_config* tagConfig = NULL;
const char *setParamTagControl = " setParamTag";
const char *streamPcm = "PCM";
const char *streamComp = "COMPRESS";
const char *streamVoice = "VOICEMMODE";
const char *feCtl = " control";
struct mixer_ctl *ctl;
std::ostringstream tagCntrlName;
std::ostringstream feName;
std::string backendname;
int tkv_size = 0;
tkv.push_back(std::make_pair(TAG_KEY_SLOT_MASK,rm->activeGroupDevConfig->grp_dev_hwep_cfg.slot_mask));
tagConfig = (struct agm_tag_config*)malloc(sizeof(struct agm_tag_config) +
(tkv.size() * sizeof(agm_key_value)));
if (!tagConfig) {
status = -EINVAL;
goto exit;
}
status = SessionAlsaUtils::getTagMetadata(TAG_DEVICE_MUX, tkv, tagConfig);
if (0 != status) {
goto exit;
}
if (PAL_STREAM_COMPRESSED == sAttr.type) {
tagCntrlName<<streamComp<<pcmDevIds.at(0)<<setParamTagControl;
feName<<streamComp<<pcmDevIds.at(0)<<feCtl;
} else if (PAL_STREAM_VOICE_CALL == sAttr.type) {
if (sAttr.info.voice_call_info.VSID == VOICEMMODE1 ||
sAttr.info.voice_call_info.VSID == VOICELBMMODE1){
tagCntrlName<<streamVoice<<1<<"p"<<setParamTagControl;
feName<<streamVoice<<1<<"p"<<feCtl;
} else {
tagCntrlName<<streamVoice<<2<<"p"<<setParamTagControl;
feName<<streamVoice<<2<<"p"<<feCtl;
}
} else {
tagCntrlName<<streamPcm<<pcmDevIds.at(0)<<setParamTagControl;
feName << streamPcm<<pcmDevIds.at(0)<<feCtl;
}
// set FE ctl to BE first in case this is called from connectionSessionDevice
rm->getBackendName(dAttr.id, backendname);
ctl = mixer_get_ctl_by_name(mixer, feName.str().data());
if (!ctl) {
PAL_ERR(LOG_TAG, "Invalid mixer control: %s\n", feName.str().data());
status = -EINVAL;
goto exit;
}
mixer_ctl_set_enum_by_string(ctl, backendname.c_str());
ctl = NULL;
// set tag data
ctl = mixer_get_ctl_by_name(mixer, tagCntrlName.str().data());
if (!ctl) {
PAL_ERR(LOG_TAG, "Invalid mixer control: %s\n", tagCntrlName.str().data());
status = -EINVAL;
goto exit;
}
tkv_size = tkv.size()*sizeof(struct agm_key_value);
status = mixer_ctl_set_array(ctl, tagConfig, sizeof(struct agm_tag_config) + tkv_size);
if (status != 0) {
PAL_ERR(LOG_TAG, "failed to set the tag calibration %d", status);
}
exit:
if (tagConfig)
free(tagConfig);
return status;
}
/* This is to set devicePP MFC(if exists) and PSPD MFC */
int Session::configureMFC(const std::shared_ptr<ResourceManager>& rm, struct pal_stream_attributes &sAttr,
struct pal_device &dAttr, const std::vector<int> &pcmDevIds, const char* intf)
{
int status = 0;
std::shared_ptr<Device> dev = nullptr;
uint8_t* payload = NULL;
size_t payloadSize = 0;
struct pal_media_config codecConfig;
struct sessionToPayloadParam mfcData;
PayloadBuilder* builder = new PayloadBuilder();
uint32_t miid = 0;
bool devicePPMFCSet = true;
// clear any cached custom payload
freeCustomPayload();
/* Prepare devicePP MFC payload */
/* Try to set devicePP MFC for virtual port enabled device to match to DMA config */
if (rm->activeGroupDevConfig &&
(dAttr.id == PAL_DEVICE_OUT_SPEAKER ||
dAttr.id == PAL_DEVICE_OUT_HANDSET ||
dAttr.id == PAL_DEVICE_OUT_ULTRASOUND)) {
status = SessionAlsaUtils::getModuleInstanceId(mixer, pcmDevIds.at(0), intf,
TAG_DEVICE_PP_MFC, &miid);
if (status == 0) {
PAL_DBG(LOG_TAG, "miid : %x id = %d, data %s, dev id = %d\n", miid,
pcmDevIds.at(0), intf, dAttr.id);
if (rm->activeGroupDevConfig->devpp_mfc_cfg.bit_width)
mfcData.bitWidth = rm->activeGroupDevConfig->devpp_mfc_cfg.bit_width;
else
mfcData.bitWidth = dAttr.config.bit_width;
if (rm->activeGroupDevConfig->devpp_mfc_cfg.sample_rate)
mfcData.sampleRate = rm->activeGroupDevConfig->devpp_mfc_cfg.sample_rate;
else
mfcData.sampleRate = dAttr.config.sample_rate;
if (rm->activeGroupDevConfig->devpp_mfc_cfg.channels)
mfcData.numChannel = rm->activeGroupDevConfig->devpp_mfc_cfg.channels;
else
mfcData.numChannel = dAttr.config.ch_info.channels;
mfcData.rotation_type = PAL_SPEAKER_ROTATION_LR;
mfcData.ch_info = nullptr;
builder->payloadMFCConfig((uint8_t**)&payload, &payloadSize, miid, &mfcData);
if (!payloadSize) {
PAL_ERR(LOG_TAG, "payloadMFCConfig failed\n");
status = -EINVAL;
goto exit;
}
status = updateCustomPayload(payload, payloadSize);
freeCustomPayload(&payload, &payloadSize);
if (0 != status) {
PAL_ERR(LOG_TAG, "updateCustomPayload Failed\n");
goto exit;
}
} else {
PAL_INFO(LOG_TAG, "deviePP MFC doesn't exist for stream %d \n", sAttr.type);
devicePPMFCSet = false;
}
/* set TKV for slot mask */
setSlotMask(rm, sAttr, dAttr, pcmDevIds);
}
/* Prepare PSPD MFC payload */
/* Get PSPD MFC MIID and configure to match to device config */
/* This has to be done after sending all mixer controls and before connect */
status = SessionAlsaUtils::getModuleInstanceId(mixer, pcmDevIds.at(0), intf,
TAG_DEVICE_MFC_SR, &miid);
if (status == 0) {
PAL_DBG(LOG_TAG, "miid : %x id = %d, data %s, dev id = %d\n", miid,
pcmDevIds.at(0), intf, dAttr.id);
if (dAttr.id == PAL_DEVICE_OUT_BLUETOOTH_A2DP ||
dAttr.id == PAL_DEVICE_OUT_BLUETOOTH_SCO) {
dev = Device::getInstance((struct pal_device *)&dAttr , rm);
if (!dev) {
PAL_ERR(LOG_TAG, "Device getInstance failed");
status = -EINVAL;
goto exit;
}
status = dev->getCodecConfig(&codecConfig);
if(0 != status) {
PAL_ERR(LOG_TAG, "getCodecConfig Failed \n");
goto exit;
}
mfcData.bitWidth = codecConfig.bit_width;
mfcData.sampleRate = codecConfig.sample_rate;
mfcData.numChannel = codecConfig.ch_info.channels;
mfcData.rotation_type = PAL_SPEAKER_ROTATION_LR;
mfcData.ch_info = nullptr;
} else {
mfcData.bitWidth = dAttr.config.bit_width;
if (!devicePPMFCSet && rm->activeGroupDevConfig->devpp_mfc_cfg.sample_rate)
mfcData.sampleRate = rm->activeGroupDevConfig->devpp_mfc_cfg.sample_rate;
else
mfcData.sampleRate = dAttr.config.sample_rate;
if (!devicePPMFCSet && rm->activeGroupDevConfig->devpp_mfc_cfg.channels)
mfcData.numChannel = rm->activeGroupDevConfig->devpp_mfc_cfg.channels;
else
mfcData.numChannel = dAttr.config.ch_info.channels;
mfcData.rotation_type = PAL_SPEAKER_ROTATION_LR;
mfcData.ch_info = nullptr;
}
if ((PAL_DEVICE_OUT_SPEAKER == dAttr.id) &&
(2 == dAttr.config.ch_info.channels)) {
// Stereo Speakers. Check for the rotation type
if (PAL_SPEAKER_ROTATION_RL == rm->getCurrentRotationType()) {
// Rotation is of RL, so need to swap the channels
mfcData.rotation_type = PAL_SPEAKER_ROTATION_RL;
}
}
if (dAttr.id == PAL_DEVICE_OUT_AUX_DIGITAL ||
dAttr.id == PAL_DEVICE_OUT_AUX_DIGITAL_1 ||
dAttr.id == PAL_DEVICE_OUT_HDMI)
mfcData.ch_info = &dAttr.config.ch_info;
builder->payloadMFCConfig((uint8_t **)&payload, &payloadSize, miid, &mfcData);
if (!payloadSize) {
PAL_ERR(LOG_TAG, "payloadMFCConfig failed\n");
status = -EINVAL;
goto exit;
}
status = updateCustomPayload(payload, payloadSize);
freeCustomPayload(&payload, &payloadSize);
if (0 != status) {
PAL_ERR(LOG_TAG, "updateCustomPayload Failed\n");
goto exit;
}
} else {
PAL_ERR(LOG_TAG, "getModuleInstanceId failed");
if (sAttr.direction == (PAL_AUDIO_INPUT | PAL_AUDIO_OUTPUT))
status = 0;
}
exit:
if (builder) {
delete builder;
builder = NULL;
}
return status;
}
int Session::checkAndSetExtEC(const std::shared_ptr<ResourceManager>& rm,
Stream *s, bool is_enable)
{
struct pcm_config config;
struct pal_stream_attributes sAttr;
int32_t status = 0;
std::shared_ptr<Device> dev = nullptr;
std::vector <std::shared_ptr<Device>> extEcTxDeviceList;
int32_t extEcbackendId;
std::vector <std::string> extEcbackendNames;
struct pal_device device;
PAL_DBG(LOG_TAG, "Enter.");
extECMutex.lock();
status = s->getStreamAttributes(&sAttr);
if (status != 0) {
PAL_ERR(LOG_TAG,"stream get attributes failed");
status = -EINVAL;
goto exit;
}
device.id = PAL_DEVICE_IN_EXT_EC_REF;
rm->getDeviceConfig(&device, &sAttr);
dev = Device::getInstance(&device, rm);
if (!dev) {
PAL_ERR(LOG_TAG, "dev get instance failed");
status = -EINVAL;
goto exit;
}
if(!is_enable) {
if (extECRefCnt > 0)
extECRefCnt --;
if (extECRefCnt == 0) {
if (pcmEcTx) {
status = pcm_stop(pcmEcTx);
if (status) {
PAL_ERR(LOG_TAG, "pcm_stop - ec_tx failed %d", status);
}
dev->stop();
status = pcm_close(pcmEcTx);
if (status) {
PAL_ERR(LOG_TAG, "pcm_close - ec_tx failed %d", status);
}
dev->close();
rm->freeFrontEndEcTxIds(pcmDevEcTxIds);
pcmEcTx = NULL;
}
}
} else {
extECRefCnt ++;
if (extECRefCnt == 1) {
extECMutex.unlock();
rm->disableInternalECRefs(s);
extECMutex.lock();
extEcTxDeviceList.push_back(dev);
pcmDevEcTxIds = rm->allocateFrontEndExtEcIds();
if (pcmDevEcTxIds.size() == 0) {
PAL_ERR(LOG_TAG, "ResourceManger::getBackEndNames returned no EXT_EC device Ids");
status = -EINVAL;
goto exit;
}
status = dev->open();
if (0 != status) {
PAL_ERR(LOG_TAG, "dev open failed");
status = -EINVAL;
rm->freeFrontEndEcTxIds(pcmDevEcTxIds);
goto exit;
}
status = dev->start();
if (0 != status) {
PAL_ERR(LOG_TAG, "dev start failed");
dev->close();
rm->freeFrontEndEcTxIds(pcmDevEcTxIds);
status = -EINVAL;
goto exit;
}
extEcbackendId = extEcTxDeviceList[0]->getSndDeviceId();
extEcbackendNames = rm->getBackEndNames(extEcTxDeviceList);
status = SessionAlsaUtils::openDev(rm, pcmDevEcTxIds, extEcbackendId,
extEcbackendNames.at(0).c_str());
if (0 != status) {
PAL_ERR(LOG_TAG, "SessionAlsaUtils::openDev failed");
dev->stop();
dev->close();
rm->freeFrontEndEcTxIds(pcmDevEcTxIds);
status = -EINVAL;
goto exit;
}
pcmEcTx = pcm_open(rm->getVirtualSndCard(), pcmDevEcTxIds.at(0), PCM_IN, &config);
if (!pcmEcTx) {
PAL_ERR(LOG_TAG, "Exit pcm-ec-tx open failed");
dev->stop();
dev->close();
rm->freeFrontEndEcTxIds(pcmDevEcTxIds);
status = -EINVAL;
goto exit;
}
if (!pcm_is_ready(pcmEcTx)) {
PAL_ERR(LOG_TAG, "Exit pcm-ec-tx open not ready");
pcmEcTx = NULL;
dev->stop();
dev->close();
rm->freeFrontEndEcTxIds(pcmDevEcTxIds);
status = -EINVAL;
goto exit;
}
status = pcm_start(pcmEcTx);
if (status) {
PAL_ERR(LOG_TAG, "pcm_start ec_tx failed %d", status);
pcm_close(pcmEcTx);
pcmEcTx = NULL;
dev->stop();
dev->close();
rm->freeFrontEndEcTxIds(pcmDevEcTxIds);
status = -EINVAL;
goto exit;
}
}
}
exit:
if (is_enable && status) {
PAL_DBG(LOG_TAG, "Reset extECRefCnt as EXT EC graph fails to setup");
extECRefCnt = 0;
}
extECMutex.unlock();
PAL_DBG(LOG_TAG, "Exit.");
return status;
}
int32_t Session::setInitialVolume() {
int32_t status = 0;
struct volume_set_param_info vol_set_param_info = {};
uint16_t volSize = 0;
uint8_t *volPayload = nullptr;
struct pal_stream_attributes sAttr = {};
bool isStreamAvail = false;
struct pal_vol_ctrl_ramp_param ramp_param = {};
Session *session = NULL;
PAL_DBG(LOG_TAG, "Enter status: %d", status);
if (!streamHandle) {
PAL_ERR(LOG_TAG, "streamHandle is invalid");
goto exit;
}
status = streamHandle->getStreamAttributes(&sAttr);
if (status != 0) {
PAL_ERR(LOG_TAG, "stream get attributes failed");
goto exit;
}
memset(&vol_set_param_info, 0, sizeof(struct volume_set_param_info));
rm->getVolumeSetParamInfo(&vol_set_param_info);
isStreamAvail = (find(vol_set_param_info.streams_.begin(),
vol_set_param_info.streams_.end(), sAttr.type) !=
vol_set_param_info.streams_.end());
if (isStreamAvail && vol_set_param_info.isVolumeUsingSetParam) {
if (sAttr.direction == PAL_AUDIO_OUTPUT) {
/* DSP default volume is highest value, non-0 rampping period
* brings volume burst from highest amplitude to new volume
* at the begining, that makes pop noise heard.
* set ramp period to 0 ms before pcm_start only for output,
* so desired volume can take effect instantly at the begining.
*/
ramp_param.ramp_period_ms = 0;
status = setParameters(streamHandle, TAG_STREAM_VOLUME,
PAL_PARAM_ID_VOLUME_CTRL_RAMP, &ramp_param);
}
// apply if there is any cached volume
if (streamHandle->mVolumeData) {
volSize = (sizeof(struct pal_volume_data) +
(sizeof(struct pal_channel_vol_kv) *
(streamHandle->mVolumeData->no_of_volpair)));
volPayload = new uint8_t[sizeof(pal_param_payload) +
volSize]();
pal_param_payload *pld = (pal_param_payload *)volPayload;
pld->payload_size = sizeof(struct pal_volume_data);
memcpy(pld->payload, streamHandle->mVolumeData, volSize);
status = setParameters(streamHandle, TAG_STREAM_VOLUME,
PAL_PARAM_ID_VOLUME_USING_SET_PARAM, (void *)pld);
delete[] volPayload;
}
if (sAttr.direction == PAL_AUDIO_OUTPUT) {
//set ramp period back to default.
ramp_param.ramp_period_ms = DEFAULT_RAMP_PERIOD;
status = setParameters(streamHandle, TAG_STREAM_VOLUME,
PAL_PARAM_ID_VOLUME_CTRL_RAMP, &ramp_param);
}
} else {
// Setting the volume as in stream open, no default volume is set.
if (sAttr.type != PAL_STREAM_ACD &&
sAttr.type != PAL_STREAM_VOICE_UI &&
sAttr.type != PAL_STREAM_ULTRASOUND &&
sAttr.type != PAL_STREAM_SENSOR_PCM_DATA &&
sAttr.type != PAL_STREAM_HAPTICS) {
if (setConfig(streamHandle, CALIBRATION, TAG_STREAM_VOLUME) != 0) {
PAL_ERR(LOG_TAG,"Setting volume failed");
}
}
}
exit:
PAL_DBG(LOG_TAG, "Exit status: %d", status);
return status;
}
#if 0
int setConfig(Stream * s, pal_stream_type_t sType, configType type, uint32_t tag1,
uint32_t tag2, uint32_t tag3)
{
int status = 0;
uint32_t tagsent = 0;
struct agm_tag_config* tagConfig = nullptr;
std::ostringstream tagCntrlName;
char const *stream = "PCM";
const char *setParamTagControl = "setParamTag";
struct mixer_ctl *ctl = nullptr;
uint32_t tkv_size = 0;
if (sType == PAL_STREAM_COMPRESSED)
stream = "COMPRESS";
switch (type) {
case MODULE:
tkv.clear();
if (tag1)
builder->populateTagKeyVector(s, tkv, tag1, &tagsent);
if (tag2)
builder->populateTagKeyVector(s, tkv, tag2, &tagsent);
if (tag3)
builder->populateTagKeyVector(s, tkv, tag3, &tagsent);
if (tkv.size() == 0) {
status = -EINVAL;
goto exit;
}
tagConfig = (struct agm_tag_config*)malloc (sizeof(struct agm_tag_config) +
(tkv.size() * sizeof(agm_key_value)));
if(!tagConfig) {
status = -ENOMEM;
goto exit;
}
status = SessionAlsaUtils::getTagMetadata(tagsent, tkv, tagConfig);
if (0 != status) {
goto exit;
}
tagCntrlName << stream << pcmDevIds.at(0) << " " << setParamTagControl;
ctl = mixer_get_ctl_by_name(mixer, tagCntrlName.str().data());
if (!ctl) {
PAL_ERR(LOG_TAG, "Invalid mixer control: %s\n", tagCntrlName.str().data());
return -ENOENT;
}
tkv_size = tkv.size() * sizeof(struct agm_key_value);
status = mixer_ctl_set_array(ctl, tagConfig, sizeof(struct agm_tag_config) + tkv_size);
if (status != 0) {
PAL_ERR(LOG_TAG, "failed to set the tag calibration %d", status);
goto exit;
}
ctl = NULL;
tkv.clear();
break;
default:
status = 0;
break;
}
exit:
return status;
}
#endif