blob: af94c554059082fa03f5f4017e2285f11b07d548 [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.
*/
#define LOG_TAG "PAL: Device"
#include "Device.h"
#include <tinyalsa/asoundlib.h>
#include "ResourceManager.h"
#include "SessionAlsaUtils.h"
#include "Device.h"
#include "Speaker.h"
#include "SpeakerProtection.h"
#include "Headphone.h"
#include "USBAudio.h"
#include "SpeakerMic.h"
#include "Stream.h"
#include "HeadsetMic.h"
#include "HandsetMic.h"
#include "HandsetVaMic.h"
#include "HeadsetVaMic.h"
#include "Handset.h"
#include "Bluetooth.h"
#include "DisplayPort.h"
#include "RTProxy.h"
#include "FMDevice.h"
#include "HapticsDev.h"
#include "UltrasoundDevice.h"
#include "ExtEC.h"
#ifdef EC_REF_CAPTURE_ENABLED
#include "ECRefDevice.h"
#endif
#define MAX_CHANNEL_SUPPORTED 2
std::shared_ptr<Device> Device::getInstance(struct pal_device *device,
std::shared_ptr<ResourceManager> Rm)
{
if (!device || !Rm) {
PAL_ERR(LOG_TAG, "Invalid input parameters");
return NULL;
}
PAL_VERBOSE(LOG_TAG, "Enter device id %d", device->id);
//TBD: decide on supported devices from XML and not in code
switch (device->id) {
case PAL_DEVICE_NONE:
PAL_DBG(LOG_TAG,"device none");
return nullptr;
case PAL_DEVICE_OUT_HANDSET:
PAL_VERBOSE(LOG_TAG, "handset device");
return Handset::getInstance(device, Rm);
case PAL_DEVICE_OUT_SPEAKER:
PAL_VERBOSE(LOG_TAG, "speaker device");
return Speaker::getInstance(device, Rm);
case PAL_DEVICE_IN_VI_FEEDBACK:
PAL_VERBOSE(LOG_TAG, "speaker feedback device");
return SpeakerFeedback::getInstance(device, Rm);
case PAL_DEVICE_OUT_WIRED_HEADSET:
case PAL_DEVICE_OUT_WIRED_HEADPHONE:
PAL_VERBOSE(LOG_TAG, "headphone device");
return Headphone::getInstance(device, Rm);
case PAL_DEVICE_OUT_USB_DEVICE:
case PAL_DEVICE_OUT_USB_HEADSET:
case PAL_DEVICE_IN_USB_DEVICE:
case PAL_DEVICE_IN_USB_HEADSET:
PAL_VERBOSE(LOG_TAG, "USB device");
return USB::getInstance(device, Rm);
case PAL_DEVICE_IN_HANDSET_MIC:
PAL_VERBOSE(LOG_TAG, "HandsetMic device");
return HandsetMic::getInstance(device, Rm);
case PAL_DEVICE_IN_SPEAKER_MIC:
PAL_VERBOSE(LOG_TAG, "speakerMic device");
return SpeakerMic::getInstance(device, Rm);
case PAL_DEVICE_IN_WIRED_HEADSET:
PAL_VERBOSE(LOG_TAG, "HeadsetMic device");
return HeadsetMic::getInstance(device, Rm);
case PAL_DEVICE_IN_HANDSET_VA_MIC:
PAL_VERBOSE(LOG_TAG, "HandsetVaMic device");
return HandsetVaMic::getInstance(device, Rm);
case PAL_DEVICE_IN_BLUETOOTH_SCO_HEADSET:
case PAL_DEVICE_OUT_BLUETOOTH_SCO:
PAL_VERBOSE(LOG_TAG, "BTSCO device");
return BtSco::getInstance(device, Rm);
case PAL_DEVICE_IN_BLUETOOTH_A2DP:
case PAL_DEVICE_OUT_BLUETOOTH_A2DP:
PAL_VERBOSE(LOG_TAG, "BTA2DP device");
return BtA2dp::getInstance(device, Rm);
case PAL_DEVICE_OUT_AUX_DIGITAL:
case PAL_DEVICE_OUT_AUX_DIGITAL_1:
case PAL_DEVICE_OUT_HDMI:
PAL_VERBOSE(LOG_TAG, "Display Port device");
return DisplayPort::getInstance(device, Rm);
case PAL_DEVICE_IN_HEADSET_VA_MIC:
PAL_VERBOSE(LOG_TAG, "HeadsetVaMic device");
return HeadsetVaMic::getInstance(device, Rm);
case PAL_DEVICE_OUT_PROXY:
PAL_VERBOSE(LOG_TAG, "RTProxyOut device");
return RTProxyOut::getInstance(device, Rm);
case PAL_DEVICE_OUT_HEARING_AID:
PAL_VERBOSE(LOG_TAG, "RTProxy Hearing Aid device");
return RTProxyOut::getInstance(device, Rm);
case PAL_DEVICE_OUT_HAPTICS_DEVICE:
PAL_VERBOSE(LOG_TAG, "Haptics Device");
return HapticsDev::getInstance(device, Rm);
case PAL_DEVICE_IN_PROXY:
PAL_VERBOSE(LOG_TAG, "RTProxy device");
return RTProxy::getInstance(device, Rm);
case PAL_DEVICE_IN_TELEPHONY_RX:
PAL_VERBOSE(LOG_TAG, "RTProxy Telephony Rx device");
return RTProxy::getInstance(device, Rm);
case PAL_DEVICE_IN_FM_TUNER:
PAL_VERBOSE(LOG_TAG, "FM device");
return FMDevice::getInstance(device, Rm);
case PAL_DEVICE_IN_ULTRASOUND_MIC:
case PAL_DEVICE_OUT_ULTRASOUND:
PAL_VERBOSE(LOG_TAG, "Ultrasound device");
return UltrasoundDevice::getInstance(device, Rm);
case PAL_DEVICE_IN_EXT_EC_REF:
PAL_VERBOSE(LOG_TAG, "ExtEC device");
return ExtEC::getInstance(device, Rm);
#ifdef EC_REF_CAPTURE_ENABLED
case PAL_DEVICE_IN_ECHO_REF:
PAL_VERBOSE(LOG_TAG, "Echo ref device");
return ECRefDevice::getInstance(device, Rm);
#endif
default:
PAL_ERR(LOG_TAG,"Unsupported device id %d",device->id);
return nullptr;
}
}
std::shared_ptr<Device> Device::getObject(pal_device_id_t dev_id)
{
switch(dev_id) {
case PAL_DEVICE_NONE:
PAL_DBG(LOG_TAG,"device none");
return nullptr;
case PAL_DEVICE_OUT_HANDSET:
PAL_VERBOSE(LOG_TAG, "handset device");
return Handset::getObject();
case PAL_DEVICE_OUT_SPEAKER:
PAL_VERBOSE(LOG_TAG, "speaker device");
return Speaker::getObject();
case PAL_DEVICE_OUT_WIRED_HEADSET:
case PAL_DEVICE_OUT_WIRED_HEADPHONE:
PAL_VERBOSE(LOG_TAG, "headphone device");
return Headphone::getObject(dev_id);
case PAL_DEVICE_OUT_USB_DEVICE:
case PAL_DEVICE_OUT_USB_HEADSET:
case PAL_DEVICE_IN_USB_DEVICE:
case PAL_DEVICE_IN_USB_HEADSET:
PAL_VERBOSE(LOG_TAG, "USB device");
return USB::getObject(dev_id);
case PAL_DEVICE_OUT_AUX_DIGITAL:
case PAL_DEVICE_OUT_AUX_DIGITAL_1:
case PAL_DEVICE_OUT_HDMI:
PAL_VERBOSE(LOG_TAG, "Display Port device");
return DisplayPort::getObject(dev_id);
case PAL_DEVICE_IN_HANDSET_MIC:
PAL_VERBOSE(LOG_TAG, "handset mic device");
return HandsetMic::getObject();
case PAL_DEVICE_IN_SPEAKER_MIC:
PAL_VERBOSE(LOG_TAG, "speaker mic device");
return SpeakerMic::getObject();
case PAL_DEVICE_IN_WIRED_HEADSET:
PAL_VERBOSE(LOG_TAG, "headset mic device");
return HeadsetMic::getObject();
case PAL_DEVICE_OUT_BLUETOOTH_A2DP:
case PAL_DEVICE_IN_BLUETOOTH_A2DP:
PAL_VERBOSE(LOG_TAG, "BT A2DP device %d", dev_id);
return BtA2dp::getObject(dev_id);
case PAL_DEVICE_OUT_BLUETOOTH_SCO:
case PAL_DEVICE_IN_BLUETOOTH_SCO_HEADSET:
PAL_VERBOSE(LOG_TAG, "BT SCO device %d", dev_id);
return BtSco::getObject(dev_id);
case PAL_DEVICE_OUT_PROXY:
case PAL_DEVICE_OUT_HEARING_AID:
PAL_VERBOSE(LOG_TAG, "RTProxyOut device %d", dev_id);
return RTProxyOut::getObject();
case PAL_DEVICE_IN_PROXY:
case PAL_DEVICE_IN_TELEPHONY_RX:
PAL_VERBOSE(LOG_TAG, "RTProxy device %d", dev_id);
return RTProxy::getObject();
case PAL_DEVICE_IN_FM_TUNER:
PAL_VERBOSE(LOG_TAG, "FMDevice %d", dev_id);
return FMDevice::getObject();
case PAL_DEVICE_IN_ULTRASOUND_MIC:
case PAL_DEVICE_OUT_ULTRASOUND:
PAL_VERBOSE(LOG_TAG, "Ultrasound device %d", dev_id);
return UltrasoundDevice::getObject(dev_id);
case PAL_DEVICE_IN_EXT_EC_REF:
PAL_VERBOSE(LOG_TAG, "ExtEC device %d", dev_id);
return ExtEC::getObject();
case PAL_DEVICE_IN_HANDSET_VA_MIC:
PAL_VERBOSE(LOG_TAG, "Handset VA Mic device %d", dev_id);
return HandsetVaMic::getObject();
case PAL_DEVICE_IN_HEADSET_VA_MIC:
PAL_VERBOSE(LOG_TAG, "Headset VA Mic device %d", dev_id);
return HeadsetVaMic::getObject();
#ifdef EC_REF_CAPTURE_ENABLED
case PAL_DEVICE_IN_ECHO_REF:
PAL_VERBOSE(LOG_TAG, "Echo ref device %d", dev_id);
return ECRefDevice::getObject();
#endif
default:
PAL_ERR(LOG_TAG,"Unsupported device id %d",dev_id);
return nullptr;
}
}
Device::Device(struct pal_device *device, std::shared_ptr<ResourceManager> Rm)
{
rm = Rm;
memset(&deviceAttr, 0, sizeof(struct pal_device));
ar_mem_cpy(&deviceAttr, sizeof(struct pal_device), device,
sizeof(struct pal_device));
mPALDeviceName.clear();
customPayload = NULL;
customPayloadSize = 0;
strlcpy(mSndDeviceName, "", DEVICE_NAME_MAX_SIZE);
mCurrentPriority = MIN_USECASE_PRIORITY;
PAL_DBG(LOG_TAG,"device instance for id %d created", device->id);
}
Device::Device()
{
strlcpy(mSndDeviceName, "", DEVICE_NAME_MAX_SIZE);
mCurrentPriority = MIN_USECASE_PRIORITY;
mPALDeviceName.clear();
}
Device::~Device()
{
if (customPayload)
free(customPayload);
customPayload = NULL;
customPayloadSize = 0;
mCurrentPriority = MIN_USECASE_PRIORITY;
PAL_DBG(LOG_TAG,"device instance for id %d destroyed", deviceAttr.id);
}
int Device::getDeviceAttributes(struct pal_device *dattr)
{
if (!dattr) {
PAL_ERR(LOG_TAG, "Invalid device attributes");
return -EINVAL;
}
ar_mem_cpy(dattr, sizeof(struct pal_device),
&deviceAttr, sizeof(struct pal_device));
return 0;
}
int Device::getCodecConfig(struct pal_media_config *config __unused)
{
return 0;
}
int Device::getDefaultConfig(pal_param_device_capability_t capability __unused)
{
return 0;
}
int Device::setDeviceAttributes(struct pal_device dattr)
{
int status = 0;
mDeviceMutex.lock();
PAL_INFO(LOG_TAG,"DeviceAttributes for Device Id %d updated", dattr.id);
ar_mem_cpy(&deviceAttr, sizeof(struct pal_device), &dattr,
sizeof(struct pal_device));
mDeviceMutex.unlock();
return status;
}
int Device::updateCustomPayload(void *payload, size_t size)
{
if (!customPayloadSize) {
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;
}
void* Device::getCustomPayload()
{
return customPayload;
}
size_t Device::getCustomPayloadSize()
{
return customPayloadSize;
}
int Device::getSndDeviceId()
{
PAL_VERBOSE(LOG_TAG,"Device Id %d acquired", deviceAttr.id);
return deviceAttr.id;
}
void Device::getCurrentSndDevName(char *name){
strlcpy(name, mSndDeviceName, DEVICE_NAME_MAX_SIZE);
}
std::string Device::getPALDeviceName()
{
PAL_VERBOSE(LOG_TAG, "Device name %s acquired", mPALDeviceName.c_str());
return mPALDeviceName;
}
int Device::init(pal_param_device_connection_t device_conn __unused)
{
return 0;
}
int Device::deinit(pal_param_device_connection_t device_conn __unused)
{
return 0;
}
int Device::open()
{
int status = 0;
mDeviceMutex.lock();
mPALDeviceName = rm->getPALDeviceName(this->deviceAttr.id);
PAL_INFO(LOG_TAG, "Enter. deviceCount %d for device id %d (%s)", deviceCount,
this->deviceAttr.id, mPALDeviceName.c_str());
devObj = Device::getInstance(&deviceAttr, rm);
if (deviceCount == 0) {
std::string backEndName;
rm->getBackendName(this->deviceAttr.id, backEndName);
if (strlen(backEndName.c_str())) {
SessionAlsaUtils::setDeviceMediaConfig(rm, backEndName, &(this->deviceAttr));
}
status = rm->getAudioRoute(&audioRoute);
if (0 != status) {
PAL_ERR(LOG_TAG, "Failed to get the audio_route address status %d", status);
goto exit;
}
status = rm->getSndDeviceName(deviceAttr.id , mSndDeviceName); //getsndName
if (!UpdatedSndName.empty()) {
PAL_DBG(LOG_TAG,"Update sndName %s, currently %s",
UpdatedSndName.c_str(), mSndDeviceName);
strlcpy(mSndDeviceName, UpdatedSndName.c_str(), DEVICE_NAME_MAX_SIZE);
}
PAL_DBG(LOG_TAG, "audio_route %pK SND device name %s", audioRoute, mSndDeviceName);
if (0 != status) {
PAL_ERR(LOG_TAG, "Failed to obtain the device name from ResourceManager status %d", status);
goto exit;
}
enableDevice(audioRoute, mSndDeviceName);
}
++deviceCount;
exit:
PAL_INFO(LOG_TAG, "Exit. deviceCount %d for device id %d (%s), exit status: %d", deviceCount,
this->deviceAttr.id, mPALDeviceName.c_str(), status);
mDeviceMutex.unlock();
return status;
}
int Device::close()
{
int status = 0;
mDeviceMutex.lock();
PAL_INFO(LOG_TAG, "Enter. deviceCount %d for device id %d (%s)", deviceCount,
this->deviceAttr.id, mPALDeviceName.c_str());
if (deviceCount > 0) {
--deviceCount;
if (deviceCount == 0) {
PAL_DBG(LOG_TAG, "Disabling device %d with snd dev %s", deviceAttr.id, mSndDeviceName);
disableDevice(audioRoute, mSndDeviceName);
mCurrentPriority = MIN_USECASE_PRIORITY;
deviceStartStopCount = 0;
}
}
PAL_INFO(LOG_TAG, "Exit. deviceCount %d for device id %d (%s), exit status %d", deviceCount,
this->deviceAttr.id, mPALDeviceName.c_str(), status);
mDeviceMutex.unlock();
return status;
}
int Device::prepare()
{
return 0;
}
int Device::start()
{
int status = 0;
mDeviceMutex.lock();
status = start_l();
mDeviceMutex.unlock();
return status;
}
// must be called with mDeviceMutex held
int Device::start_l()
{
int status = 0;
std::string backEndName;
PAL_DBG(LOG_TAG, "Enter. deviceCount %d deviceStartStopCount %d"
" for device id %d (%s)", deviceCount, deviceStartStopCount,
this->deviceAttr.id, mPALDeviceName.c_str());
if (0 == deviceStartStopCount) {
rm->getBackendName(this->deviceAttr.id, backEndName);
if (!strlen(backEndName.c_str())) {
PAL_ERR(LOG_TAG, "Error: Backend name not defined for %d in xml file\n", this->deviceAttr.id);
status = -EINVAL;
goto exit;
}
SessionAlsaUtils::setDeviceMediaConfig(rm, backEndName, &(this->deviceAttr));
if (customPayloadSize) {
status = SessionAlsaUtils::setDeviceCustomPayload(rm, backEndName,
customPayload, customPayloadSize);
if (status)
PAL_ERR(LOG_TAG, "Error: Dev setParam failed for %d\n",
this->deviceAttr.id);
}
}
deviceStartStopCount++;
exit :
PAL_DBG(LOG_TAG, "Exit, status %d", status);
return status;
}
int Device::stop()
{
int status = 0;
mDeviceMutex.lock();
status = stop_l();
mDeviceMutex.unlock();
return status;
}
// must be called with mDeviceMutex held
int Device::stop_l()
{
PAL_DBG(LOG_TAG, "Enter. deviceCount %d deviceStartStopCount %d"
" for device id %d (%s)", deviceCount, deviceStartStopCount,
this->deviceAttr.id, mPALDeviceName.c_str());
if (deviceStartStopCount > 0) {
--deviceStartStopCount;
}
return 0;
}
int32_t Device::setDeviceParameter(uint32_t param_id __unused, void *param __unused)
{
return 0;
}
int32_t Device::getDeviceParameter(uint32_t param_id __unused, void **param __unused)
{
return 0;
}
int32_t Device::setParameter(uint32_t param_id __unused, void *param __unused)
{
return 0;
}
int32_t Device::getParameter(uint32_t param_id __unused, void **param __unused)
{
return 0;
}
int32_t Device::configureDeviceClockSrc(char const *mixerStrClockSrc, const uint32_t clockSrc)
{
struct mixer *hwMixerHandle = NULL;
struct mixer_ctl *clockSrcCtrl = NULL;
int32_t ret = 0;
if (!mixerStrClockSrc) {
PAL_ERR(LOG_TAG, "Invalid argument - mixerStrClockSrc");
ret = -EINVAL;
goto exit;
}
ret = rm->getHwAudioMixer(&hwMixerHandle);
if (ret) {
PAL_ERR(LOG_TAG, "getHwAudioMixer() failed %d", ret);
goto exit;
}
/* Hw mixer control registration is optional in case
* clock source selection is not required
*/
clockSrcCtrl = mixer_get_ctl_by_name(hwMixerHandle, mixerStrClockSrc);
if (!clockSrcCtrl) {
PAL_DBG(LOG_TAG, "%s hw mixer control not identified", mixerStrClockSrc);
goto exit;
}
PAL_DBG(LOG_TAG, "HwMixer set %s = %d", mixerStrClockSrc, clockSrc);
ret = mixer_ctl_set_value(clockSrcCtrl, 0, clockSrc);
if (ret)
PAL_ERR(LOG_TAG, "HwMixer set %s = %d failed", mixerStrClockSrc, clockSrc);
exit:
return ret;
}