replace common qcom sources with samsung ones

This commit is contained in:
SaschaNes
2025-08-12 22:13:00 +02:00
parent ba24dcded9
commit 6f7753de11
5682 changed files with 2450203 additions and 103634 deletions

View File

@@ -0,0 +1,143 @@
/*
* 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 are provided under the following license:
*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef ACD_PLATFORM_INFO_H
#define ACD_PLATFORM_INFO_H
#include "ResourceManager.h"
#include "SoundTriggerPlatformInfo.h"
class ACDStreamConfig;
class ACDContextInfo
{
public:
ACDContextInfo(uint32_t context_id, uint32_t type);
uint32_t GetContextId() const { return context_id_; }
uint32_t GetContextType() const { return context_type_; }
private:
uint32_t context_id_;
uint32_t context_type_;
};
class ACDSoundModelInfo : public SoundTriggerXml
{
public:
ACDSoundModelInfo(ACDStreamConfig *sm_cfg);
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
std::string GetModelType() const { return model_type_; }
std::string GetModelBinName() const { return model_bin_name_; }
uint32_t GetModelUUID() const { return model_uuid_; }
uint32_t GetModelId() const { return model_id_; }
size_t GetNumContexts() const { return acd_context_info_list_.size(); }
std::vector<std::shared_ptr<ACDContextInfo>> GetSupportedContextList()const {
return acd_context_info_list_;
}
private:
std::string model_type_;
std::string model_bin_name_;
uint32_t model_id_;
uint32_t model_uuid_;
bool is_parsing_contexts;
ACDStreamConfig *sm_cfg_;
std::vector<std::shared_ptr<ACDContextInfo>> acd_context_info_list_;
};
class ACDStreamConfig : public SoundTriggerXml
{
public:
ACDStreamConfig();
ACDStreamConfig(ACDStreamConfig &rhs) = delete;
ACDStreamConfig & operator=(ACDStreamConfig &rhs) = delete;
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
UUID GetUUID() const { return vendor_uuid_; }
std::string GetStreamConfigName() const { return name_; }
std::shared_ptr<ACDSoundModelInfo> GetSoundModelInfoByModelId(uint32_t model_id);
std::shared_ptr<ACDSoundModelInfo> GetSoundModelInfoByContextId(uint32_t context_id);
void UpdateContextModelMap(uint32_t context_id);
uint32_t GetSampleRate() const { return sample_rate_; }
uint32_t GetBitWidth() const { return bit_width_; }
uint32_t GetOutChannels() const { return out_channels_; }
std::vector<std::shared_ptr<ACDSoundModelInfo>> GetSoundModelList() const {
return acd_soundmodel_info_list_;
}
std::shared_ptr<CaptureProfile> GetCaptureProfile(
std::pair<StOperatingModes, StInputModes> mode_pair) const {
return acd_op_modes_.at(mode_pair);
}
uint32_t GetAndUpdateSndMdlCnt() { return sound_model_cnt++; }
private:
std::string name_;
UUID vendor_uuid_;
uint32_t sample_rate_;
uint32_t bit_width_;
uint32_t out_channels_;
st_op_modes_t acd_op_modes_;
std::shared_ptr<SoundTriggerXml> curr_child_;
std::vector<std::shared_ptr<ACDSoundModelInfo>> acd_soundmodel_info_list_;
std::map<uint32_t, std::shared_ptr<ACDSoundModelInfo>> context_model_map_;
std::map<uint32_t, std::shared_ptr<ACDSoundModelInfo>> acd_modelinfo_map_;
uint32_t sound_model_cnt;
};
class ACDPlatformInfo : public SoundTriggerPlatformInfo
{
public:
ACDPlatformInfo();
ACDPlatformInfo(ACDStreamConfig &rhs) = delete;
ACDPlatformInfo & operator=(ACDPlatformInfo &rhs) = delete;
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
static std::shared_ptr<ACDPlatformInfo> GetInstance();
bool IsACDEnabled() const { return acd_enable_; }
std::shared_ptr<ACDStreamConfig> GetStreamConfig(const UUID& uuid) const;
private:
bool acd_enable_;
static std::shared_ptr<ACDPlatformInfo> me_;
std::shared_ptr<SoundTriggerXml> curr_child_;
std::map<UUID, std::shared_ptr<ACDStreamConfig>> acd_cfg_list_;
};
#endif

View File

@@ -0,0 +1,125 @@
/*
* 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) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef ASR_PLATFORM_INFO_H
#define ASR_PLATFORM_INFO_H
#define OUT_BUF_SIZE_DEFAULT 3072 /* In bytes. Around 30sec of text */
#define VAD_HANG_OVER_DURTION_DEFAULT_MS 1000
#include "ResourceManager.h"
typedef enum asr_param_id_type {
ASR_INPUT_CONFIG = 0,
ASR_OUTPUT_CONFIG,
ASR_INPUT_BUF_DURATON,
ASR_OUTPUT,
ASR_FORCE_OUTPUT,
ASR_MAX_PARAM_IDS
}asr_param_id_type_t;
class ASRCommonConfig : public SoundTriggerXml
{
public:
ASRCommonConfig();
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
size_t GetInputBufferSize() const { return input_buffer_size_; }
size_t GetPartialModeInputBufferSize() const { return partial_mode_input_buffer_size_; }
size_t GetBufferingModeOutBufferSize() const { return buffering_mode_out_buffer_size_; }
uint32_t GetCommandModeTimeout() const { return command_mode_timeout_; }
uint32_t GetInputBufferSize(int mode);
uint32_t GetOutputBufferSize(int mode);
private:
size_t input_buffer_size_;
size_t partial_mode_input_buffer_size_;
size_t buffering_mode_out_buffer_size_;
uint32_t command_mode_timeout_;
};
class ASRStreamConfig : public SoundTriggerXml
{
public:
ASRStreamConfig();
ASRStreamConfig(ACDStreamConfig &rhs) = delete;
ASRStreamConfig & operator=(ACDStreamConfig &rhs) = delete;
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
std::string GetStreamConfigName() const { return name_; }
uint32_t GetModuleTagId(asr_param_id_type_t param_id) const {
return module_tag_ids_[param_id];
}
uint32_t GetParamId(asr_param_id_type_t param_id) const {
return param_ids_[param_id];
}
std::shared_ptr<CaptureProfile> GetCaptureProfile(
std::pair<StOperatingModes, StInputModes> mode_pair) const {
return asr_op_modes_.at(mode_pair);
}
UUID GetUUID() const { return vendor_uuid_; }
private:
std::string name_;
st_op_modes_t asr_op_modes_;
UUID vendor_uuid_;
std::shared_ptr<SoundTriggerXml> curr_child_;
uint32_t module_tag_ids_[ASR_MAX_PARAM_IDS];
uint32_t param_ids_[ASR_MAX_PARAM_IDS];
};
class ASRPlatformInfo : public SoundTriggerPlatformInfo
{
public:
ASRPlatformInfo();
ASRPlatformInfo(ASRStreamConfig &rhs) = delete;
ASRPlatformInfo & operator=(ASRPlatformInfo &rhs) = delete;
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
static std::shared_ptr<ASRPlatformInfo> GetInstance();
std::shared_ptr<ASRStreamConfig> GetStreamConfig(const UUID& uuid) const;
std::shared_ptr<ASRCommonConfig> GetCommonConfig() const { return cm_cfg_; }
private:
static std::shared_ptr<ASRPlatformInfo> me_;
std::map<UUID, std::shared_ptr<ASRStreamConfig>> stream_cfg_list_;
std::shared_ptr<SoundTriggerXml> curr_child_;
std::shared_ptr<ASRCommonConfig> cm_cfg_;
};
#endif

View File

@@ -0,0 +1,112 @@
/*
* 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 are provided under the following license:
*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef AUDIO_HAPTICS_INTERFACE_H
#define AUDIO_HAPTICS_INTERFACE_H
#include <errno.h>
#include <stdint.h>
#include <map>
#include <expat.h>
#include <vector>
#include <memory>
#include <string>
#include "PalDefs.h"
#include "PalCommon.h"
#include "kvh2xml.h"
typedef enum {
TAG_HAPTICSCNFGXML_ROOT,
TAG_PREDEFINED_EFFECT,
TAG_HAPTICS_EFFECT,
TAG_ONESHOT_EFFECT,
TAG_RINGTONE_EFFECT,
TAG_COMPOSE_EFFECT,
} haptics_xml_tag;
struct haptics_wave_designer_config_t {
// Waveform designer mode parameters
int8_t num_channels;
int8_t channel_mask;
int8_t wave_design_mode;
int32_t auto_overdrive_brake_en;
int32_t f0_tracking_en;
int32_t f0_tracking_param_reset_flag;
uint32_t override_flag;
int32_t tracked_freq_warmup_time_ms;
int32_t settling_time_ms;
int32_t delay_time_ms;
int32_t wavegen_fstart_hz_q20;
int32_t repetition_count;
int32_t repetition_period_ms;
uint32_t pilot_tone_en;
int32_t low_pulse_intensity;
int32_t mid_pulse_intensity;
int32_t high_pulse_intensity;
int32_t pulse_width_ms;
int32_t pulse_sharpness;
int32_t num_pwl;
int32_t *pwl_time;
int32_t *pwl_acc;
};
struct haptics_xml_data{
char data_buf[1024];
size_t offs;
haptics_xml_tag hapticstag;
};
class AudioHapticsInterface
{
public:
AudioHapticsInterface();
~AudioHapticsInterface();
static int XmlParser(std::string xmlFile);
static void endTag(void *userdata, const XML_Char *tag_name);
static void startTag(void *userdata, const XML_Char *tag_name, const XML_Char **attr);
static void handleData(void *userdata, const char *s, int len);
static void resetDataBuf(struct haptics_xml_data *data);
static void process_haptics_info(struct haptics_xml_data *data, const XML_Char *tag_name);
void getTouchHapticsEffectConfiguration(int effect_id, bool isCompose, haptics_wave_designer_config_t **HConfig);
int getRingtoneHapticsEffectConfiguration() {return ringtone_haptics_wave_design_mode;}
static int init();
static std::shared_ptr<AudioHapticsInterface> GetInstance();
private:
static std::vector<haptics_wave_designer_config_t> predefined_haptics_info;
static std::vector<haptics_wave_designer_config_t> compose_haptics_info;
static std::vector<haptics_wave_designer_config_t> oneshot_haptics_info;
static std::shared_ptr<AudioHapticsInterface> me_;
static int ringtone_haptics_wave_design_mode;
};
#endif

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 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.
*/
#ifndef _CHARGER_LISTENER_H_
#define _CHARGER_LISTENER_H_
#include <sys/epoll.h>
#ifdef ANDROID
#include <bits/epoll_event.h>
#else
#include <fcntl.h>
#include <cstring>
#include <functional>
#endif
#define MAX_EVENTS 3
typedef enum {
OFFLINE = 0,
ONLINE
} charger_state_t;
typedef enum {
UNKNOWN,
CHARGING,
DISCHARGING,
NOT_CHARGING,
FULL
} batt_state_t;
enum {
PIPE_EVENT,
U_EVENT
};
typedef enum {
UNKNOWN_EVENT = -1,
CHARGER_EVENT,
BATTERY_EVENT
} uevent_type_t;
struct charger_info {
struct epoll_event events[MAX_EVENTS];
int event_count;
int epoll_fd;
int uevent_fd;
charger_state_t c_state;
batt_state_t b_state;
};
class ChargerListenerImpl {
typedef void (*func_ptr)(void *context, struct charger_info *info);
typedef std::function<void(int, int, bool)> cb_fn_t;
cb_fn_t mcb;
int intPipe[2];
int pipe_status;
std::thread poll_thread, dispatcher_thread;
std::mutex mlock;
struct charger_info *info;
int readSysfsPath(const char *path, int flag, int length, char *state);
int getInitialStatus();
void getStateUpdate(int type);
static void readEvent(void * context, struct charger_info *info);
int addEvent(func_ptr event_func, int event_type ,int fd);
int initEvent();
void chargerMonitor();
void CLImplInit();
int getConcurrentState();
public:
ChargerListenerImpl (cb_fn_t cb);
~ChargerListenerImpl ();
int setConcurrentState(bool is_boost_enable);
};
#ifdef __cplusplus
extern "C" {
#endif
/**
* \param[in] uevent_type - Charger or Battery Event.
* \param[in] status - status of charger or battery based on uevent.
* \param[in] concurrent_state - Handle ASR case only for charger event. No
* Need to set Concurrent bit by pal when bit
* is 1.
*/
typedef void (*charger_status_change_fn_t)(int, int, bool);
typedef void (*cl_init_t)(charger_status_change_fn_t);
typedef void (*cl_deinit_t)();
typedef int (*cl_set_boost_state_t)(bool);
/**
* \brief - Initialise, register uevent and pipe in epoll.
* Spawn new thread to Monitor change in event.
* \param[in] charger_status_change_fn_t - CB will be executed on initial
* status and during uevent change
* to configure pal.
*/
void chargerPropertiesListenerInit(charger_status_change_fn_t fn);
/**
* \brief - As RM deinit, main thread will write Q on pipe and epoll
* thread will be unblocked.
*/
void chargerPropertiesListenerDeinit();
/**
* \brief - Notify PMIC driver by writing 0/1 on concurrent sysfs
* node to start charging.
*
* \param[in] status - concurrent state to set.
* \return - 0 on success, error code otherwise.
*/
int chargerPropertiesListenerSetBoostState(bool status);
#ifdef __cplusplus
}
#endif
#endif /* _CHARGER_LISTENER_H_ */

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef MEMLOG_BUILDER_H
#define MEMLOG_BUILDER_H
#include "mem_logger.h"
#include "pal_state_queue.h"
#include "kpi_queue.h"
#include "ResourceManager.h"
#include "Stream.h"
#include <inttypes.h>
int palStateQueueBuilder(pal_state_queue &que, Stream *s, pal_state_queue_state state, int32_t error);
int palStateEnqueue(Stream *s, pal_state_queue_state state, int32_t error);
int palStateEnqueue(Stream *s, pal_state_queue_state state, int32_t error, union pal_mlog_str_info str_info);
pal_mlog_acdstr_info palStateACDStreamBuilder(Stream *s);
void kpiEnqueue(const char name[], bool isEnter);
#endif

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef METADATA_PARSER_H
#define METADATA_PARSER_H
#include <chrono>
#include <memory>
#include <numeric>
#include <thread>
#include <utility>
#include <vector>
#include <unordered_map>
#include "media_fmt_api_basic.h"
#include "metadata_api.h"
#include "wr_sh_mem_ep_api.h"
#include "rd_sh_mem_ep_api.h"
#define ALIGN(num, to) (((num) + (to-1)) & (~(to-1)))
static constexpr uint32_t BYTES_PER_SAMPLE(uint32_t x) { return (x / 8); }
static constexpr uint32_t GET_LSW(uint64_t num) { return static_cast<uint32_t>(num & UINT32_MAX); }
static constexpr uint32_t GET_MSW(uint64_t num) { return static_cast<uint32_t>((num & ~UINT32_MAX) >> 32); }
struct ChannelHelper {
static constexpr const int MAX_NUM_CHANNELS = 16;
};
enum MetadataType: uint8_t {
START_METADATA = 0,
END_METADATA,
MEDIA_FORMAT_EVENT
};
size_t START_METADATA_SIZE() {
return sizeof(metadata_header_t) + sizeof(module_cmn_md_buffer_start_t);
}
size_t END_METADATA_SIZE() {
return sizeof(metadata_header_t) + sizeof(module_cmn_md_buffer_end_t);
}
size_t MEDIA_FORMAT_METADATA_SIZE() {
return sizeof(metadata_header_t)
+ sizeof(struct media_format_t)
+ sizeof(payload_media_fmt_pcm_t)
+ (ChannelHelper::MAX_NUM_CHANNELS*sizeof(int8_t));
}
//update applicable lists for new metadata item added above
static std::vector<size_t> WRITE_METADATA_ITEM_SIZES = {
START_METADATA_SIZE(),
END_METADATA_SIZE()
};
static std::vector<size_t> READ_METADATA_ITEM_SIZES = {
START_METADATA_SIZE(),
END_METADATA_SIZE(),
MEDIA_FORMAT_METADATA_SIZE()
};
class MetadataParser {
public:
static size_t WRITE_METADATA_MAX_SIZE() {
return std::accumulate(WRITE_METADATA_ITEM_SIZES.begin(),
WRITE_METADATA_ITEM_SIZES.end(), 0);
}
static size_t READ_METADATA_MAX_SIZE() {
return std::accumulate(READ_METADATA_ITEM_SIZES.begin(),
READ_METADATA_ITEM_SIZES.end(), 0);
}
int parseMetadata(uint8_t* metadata, size_t metadataSize,
pal_clbk_buffer_info *bufferInfo);
void fillMetaData(uint8_t *metadata,
uint64_t frameIndex, size_t filledLength,
pal_media_config *streamMediaConfig);
};
#endif

View File

@@ -0,0 +1,146 @@
/*
* 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 are provided under the following license:
*
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include <stdlib.h>
#include <memory>
#include <mutex>
#include <vector>
#include <unordered_map>
#include <string>
#include <iostream>
#include <string.h>
#include "Stream.h"
#ifndef PALRINGBUFFER_H_
#define PALRINGBUFFER_H_
#define DEFAULT_PAL_RING_BUFFER_SIZE 4096 * 10
typedef enum {
READER_DISABLED = 0,
READER_ENABLED = 1,
READER_PREPARED = 2,
} pal_ring_buffer_reader_state;
/*
* startIdx/endIdx: index compared to beginning of the detection
* ftrtSize: linear increased during buffering, used to confirm
* if keyword data is read from adsp
*/
struct kwdConfig {
uint32_t startIdx;
uint32_t endIdx;
uint32_t ftrtSize;
};
class PalRingBuffer;
class PalRingBufferReader {
public:
PalRingBufferReader(PalRingBuffer *buffer)
: ringBuffer_(buffer),
unreadSize_(0),
readOffset_(0),
requestedSize_(0),
state_(READER_DISABLED) {}
~PalRingBufferReader() {};
size_t advanceReadOffset(size_t advanceSize);
int32_t read(void* readBuffer, size_t readSize);
void updateState(pal_ring_buffer_reader_state state);
void getIndices(Stream *s,
uint32_t *startIdx, uint32_t *endIdx, uint32_t *ftrtSize);
int32_t getKwData(Stream *s, uint8_t *data, uint32_t size);
size_t getUnreadSize();
size_t getBufferSize();
void reset();
bool isEnabled() { return state_ == READER_ENABLED; }
bool isPrepared() { return state_ == READER_PREPARED; }
bool waitForBuffers(uint32_t buffer_size);
friend class PalRingBuffer;
protected:
PalRingBuffer *ringBuffer_;
size_t unreadSize_;
size_t readOffset_;
pal_ring_buffer_reader_state state_;
std::mutex mutex_;
std::condition_variable cv_;
uint32_t requestedSize_;
};
class PalRingBuffer {
public:
explicit PalRingBuffer(size_t bufferSize)
: buffer_((char*)(new char[bufferSize])),
writeOffset_(0),
bufferEnd_(bufferSize) {}
~PalRingBuffer() {
if (buffer_)
delete buffer_;
for (int i = 0; i < readers_.size(); i++)
delete readers_[i];
}
PalRingBufferReader* newReader();
int32_t removeReader(PalRingBufferReader *reader);
size_t read(std::shared_ptr<PalRingBufferReader>reader, void* readBuffer,
size_t readSize);
size_t write(void* writeBuffer, size_t writeSize);
size_t getFreeSize();
void updateKwdConfig(Stream *s, uint32_t startIdx, uint32_t endIdx,
uint32_t preRoll);
void getIndices(Stream *s,
uint32_t *startIdx, uint32_t *endIdx, uint32_t *ftrtSize);
void reset();
size_t getBufferSize() { return bufferEnd_; };
void resizeRingBuffer(size_t bufferSize);
protected:
std::mutex mutex_;
char* buffer_;
std::unordered_map<Stream*, struct kwdConfig> kwCfg_;
size_t writeOffset_;
size_t bufferEnd_;
std::vector<PalRingBufferReader*> readers_;
void updateUnReadSize(size_t writtenSize);
friend class PalRingBufferReader;
};
#endif

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#pragma once
#include <mutex>
#include <vector>
struct PerfLockConfig {
bool usePerfLock = false;
std::string libraryName;
std::vector<int> perfLockOpts;
};
/**
* A Scoped object for real perf lock.
* Only one among the existing PerfLock instances possibly acquires real perf lock.
**/
class PerfLock final {
public:
// All Public APIs are gaurded by sMutex
PerfLock(const std::string &);
~PerfLock();
// Read config from resource_manager and set configs
static void setPerfLockOpt(const PerfLockConfig & config);
private:
// disable copy
PerfLock(const PerfLock&) = delete;
PerfLock& operator=(const PerfLock& x) = delete;
// disable move
PerfLock(PerfLock&& other) = delete;
PerfLock& operator=(PerfLock&& other) = delete;
// function mapping for dlsym
using AcquirePerfLock = int (*)(int, int, int*, int);
using ReleasePerfLock = int (*)(int);
inline static AcquirePerfLock sAcquirePerfLock{nullptr};
inline static ReleasePerfLock sReleasePerfLock{nullptr};
// this mutex is a class Mutex
inline static std::mutex sMutex;
inline static bool sIsAcquired = false;
inline static int kPerfLockOptsSize = 0;
inline static int sPerfLockCounter = 0;
inline static std::vector<int> kPerfLockOpts;
inline static int sHandle{0};
inline static bool usePerfLock;
inline static std::string sLibraryName;
std::string mCaller;
static bool init();
// Below functions needs to be called with sMutex lock held
void acquire_l();
void release_l();
};

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the
* disclaimer below) 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 Qualcomm Innovation Center, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
* GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
*/
#ifndef SIGNAL_HANDLER_H
#define SIGNAL_HANDLER_H
#include <functional>
#include <future>
#include <memory>
#include <thread>
#include <vector>
#include <unordered_map>
#include <signal.h>
#include <map>
#ifndef __SIGRTMIN
#define __SIGRTMIN 32
#endif
static const constexpr int DEBUGGER_SIGNAL = (__SIGRTMIN + 3);
static const constexpr uint32_t kDefaultSignalPendingTries = 10;
static const constexpr uint32_t kDefaultRegistrationDelayMs = 500;
static const std::map<uint32_t, std::string> sigToName {
{DEBUGGER_SIGNAL, std::string{"<debuggerd signal>"}},
{SIGABRT, std::string{"SIGABRT"}},
{SIGSEGV, std::string{"SIGSEGV"}},
};
struct SignalHandler {
static std::shared_ptr<SignalHandler> getInstance();
static void setClientCallback(std::function<void(int, pid_t, uid_t)> cb);
static void asyncRegister(int signal);
static void invokeDefaultHandler(std::shared_ptr<struct sigaction> sAct,
int code, struct siginfo *si, void *sc);
static void customSignalHandler(int code, struct siginfo *si, void *sc);
static std::vector<int> getRegisteredSignals();
void registerSignalHandler(std::vector<int> signalsToRegister);
static void setBuildDebuggable(bool debuggable) { sBuildDebuggable = debuggable;}
static bool isBuildDebuggable() { return sBuildDebuggable;}
static std::mutex sDefaultSigMapLock;
static std::unordered_map<int, std::shared_ptr<struct sigaction>> sDefaultSigMap;
static std::function<void(int, pid_t, uid_t)> sClientCb;
static std::mutex sAsyncRegisterLock;
static std::future<void> sAsyncHandle;
static bool sBuildDebuggable;
};
#endif

View File

@@ -0,0 +1,173 @@
/*
* 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 are provided under the following license:
*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#ifndef SOUND_TRIGGER_PLATFORM_INFO_H
#define SOUND_TRIGGER_PLATFORM_INFO_H
#include <errno.h>
#include <stdint.h>
#include <map>
#include <vector>
#include <memory>
#include <string>
#include "PalDefs.h"
#include "kvh2xml.h"
#include "SoundTriggerUtils.h"
#define MAX_MODULE_CHANNELS 4
#define CAPTURE_PROFILE_PRIORITY_HIGH 1
#define CAPTURE_PROFILE_PRIORITY_LOW -1
#define CAPTURE_PROFILE_PRIORITY_SAME 0
enum StOperatingModes {
ST_OPERATING_MODE_LOW_POWER,
ST_OPERATING_MODE_LOW_POWER_NS,
ST_OPERATING_MODE_LOW_POWER_TX_MACRO,
ST_OPERATING_MODE_HIGH_PERF,
ST_OPERATING_MODE_HIGH_PERF_NS,
ST_OPERATING_MODE_HIGH_PERF_TX_MACRO,
ST_OPERATING_MODE_HIGH_PERF_AND_CHARGING
};
enum StInputModes {
ST_INPUT_MODE_HANDSET,
ST_INPUT_MODE_HEADSET
};
class SoundTriggerXml
{
public:
virtual void HandleStartTag(const char *tag, const char **attribs) = 0;
virtual void HandleEndTag(struct xml_userdata *data __unused, const char *tag __unused) {};
virtual void HandleCharData(const char *data __unused) {};
virtual ~SoundTriggerXml() {};
};
class SoundTriggerUUID {
public:
SoundTriggerUUID();
SoundTriggerUUID & operator=(SoundTriggerUUID &rhs);
bool operator<(const SoundTriggerUUID &rhs) const;
bool CompareUUID(const struct st_uuid uuid) const;
static int StringToUUID(const char* str, SoundTriggerUUID& UUID);
uint32_t timeLow;
uint16_t timeMid;
uint16_t timeHiAndVersion;
uint16_t clockSeq;
uint8_t node[6];
};
class CaptureProfile : public SoundTriggerXml
{
public:
CaptureProfile(std::string name);
CaptureProfile() = delete;
CaptureProfile(CaptureProfile &rhs) = delete;
CaptureProfile & operator=(CaptureProfile &rhs) = delete;
void HandleStartTag(const char* tag, const char* * attribs) override;
std::string GetName() const { return name_; }
pal_device_id_t GetDevId() const { return device_id_; }
uint32_t GetSampleRate() const { return sample_rate_; }
uint32_t GetBitWidth() const { return bitwidth_; }
uint32_t GetChannels() const { return channels_; }
std::string GetSndName() const { return snd_name_; }
std::string GetBackend() const { return backend_; }
bool isECRequired() const { return is_ec_req_; }
void SetSampleRate(uint32_t sample_rate) { sample_rate_ = sample_rate; }
void SetBitWidth(uint32_t bit_width) { bitwidth_ = bit_width; }
void SetChannels(uint32_t channels) { channels_ = channels; }
void SetSndName(std::string snd_name) { snd_name_ = snd_name; }
std::pair<uint32_t,uint32_t> GetDevicePpKv() const { return device_pp_kv_; }
int32_t ComparePriority(std::shared_ptr<CaptureProfile> cap_prof);
private:
std::string name_;
pal_device_id_t device_id_;
uint32_t sample_rate_;
uint32_t channels_;
uint32_t bitwidth_;
std::pair<uint32_t,uint32_t> device_pp_kv_;
std::string snd_name_;
bool is_ec_req_;
std::string backend_;
};
using UUID = SoundTriggerUUID;
using st_cap_profile_map_t = std::map<std::string, std::shared_ptr<CaptureProfile>>;
using st_op_modes_t = std::map<std::pair<StOperatingModes, StInputModes>, std::shared_ptr<CaptureProfile>>;
class SoundTriggerPlatformInfo : public SoundTriggerXml
{
public:
SoundTriggerPlatformInfo();
SoundTriggerPlatformInfo(SoundTriggerPlatformInfo &rhs) = delete;
SoundTriggerPlatformInfo & operator=(SoundTriggerPlatformInfo &rhs) = delete;
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
static std::shared_ptr<SoundTriggerPlatformInfo> GetInstance();
static bool GetLpiEnable() { return lpi_enable_; }
static bool GetSupportNLPISwitch() { return support_nlpi_switch_; }
static bool GetSupportDevSwitch() { return support_device_switch_; }
static bool GetEnableDebugDumps() { return enable_debug_dumps_; }
static bool GetConcurrentCaptureEnable() { return concurrent_capture_; }
static bool GetConcurrentVoiceCallEnable() { return concurrent_voice_call_; }
static bool GetConcurrentVoipCallEnable() { return concurrent_voip_call_; }
static bool GetLowLatencyBargeinEnable() { return low_latency_bargein_enable_; }
/* reads capture profile names into member variables */
void ReadCapProfileNames(StOperatingModes mode, const char **attribs, st_op_modes_t& op_modes);
/* use capture profile name to retrieve capture profile from capture_profile_map_ */
std::shared_ptr<CaptureProfile> GetCaptureProfileFromMap(std::string cap_prof_name);
private:
static bool lpi_enable_;
static bool support_nlpi_switch_;
static bool support_device_switch_;
static bool enable_debug_dumps_;
static bool concurrent_capture_;
static bool concurrent_voice_call_;
static bool concurrent_voip_call_;
static bool low_latency_bargein_enable_;
static std::shared_ptr<SoundTriggerPlatformInfo> me_;
st_cap_profile_map_t capture_profile_map_;
std::shared_ptr<SoundTriggerXml> curr_child_;
};
#endif

View File

@@ -0,0 +1,232 @@
/*
* 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 are provided under the following license:
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the
* disclaimer below) 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 Qualcomm Innovation Center, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
* GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
*/
#ifndef VOICE_UI_PLATFORM_INFO_H
#define VOICE_UI_PLATFORM_INFO_H
#include "SoundTriggerPlatformInfo.h"
#define MAX_MODULE_CHANNELS 4
class VUISecondStageConfig : public SoundTriggerXml
{
public:
VUISecondStageConfig();
void HandleStartTag(const char *tag, const char **attribs) override;
st_sound_model_type_t GetDetectionType() const { return detection_type_; }
std::string GetLibName() const { return module_lib_; }
uint32_t GetSoundModelID() const { return sm_id_; }
uint32_t GetSampleRate() const { return sample_rate_; }
uint32_t GetBitWidth() const { return bit_width_; }
uint32_t GetChannels() const { return channels_; }
private:
st_sound_model_type_t detection_type_;
uint32_t sm_id_;
std::string module_lib_;
uint32_t sample_rate_;
uint32_t bit_width_;
uint32_t channels_;
};
class VUIFirstStageConfig : public SoundTriggerXml
{
public:
VUIFirstStageConfig();
void HandleStartTag(const char *tag, const char **attribs) override;
st_module_type_t GetModuleType() const { return module_type_; }
std::string GetModuleName() const { return module_name_; }
bool IsLpiSupported() const { return lpi_supported_; }
uint32_t GetModuleTagId(st_param_id_type_t param_id) const {
return module_tag_ids_[param_id];
}
uint32_t GetParamId(st_param_id_type_t param_id) const {
return param_ids_[param_id];
}
private:
bool lpi_supported_;
st_module_type_t module_type_;
std::string module_name_;
uint32_t module_tag_ids_[MAX_PARAM_IDS];
uint32_t param_ids_[MAX_PARAM_IDS];
};
class VUIStreamConfig : public SoundTriggerXml
{
public:
VUIStreamConfig();
VUIStreamConfig(VUIStreamConfig &rhs) = delete;
VUIStreamConfig & operator=(VUIStreamConfig &rhs) = delete;
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
UUID GetUUID() const { return vendor_uuid_; }
std::string GetVUIIntfPluginLib() const { return vui_intf_plugin_lib_name_; }
bool GetModuleVersionSupported() const {
return get_module_version_supported_;
}
bool GetMergeFirstStageSoundModels() const {
return merge_first_stage_sound_models_;
}
bool isSingleInstanceStage1() const { return supported_first_stage_engine_count_ == 1; }
bool isQCVAUUID() const { return is_qcva_uuid_; }
uint32_t GetKwDuration() const { return capture_keyword_; }
uint32_t GetCaptureReadDelay() const { return client_capture_read_delay_; }
uint32_t GetPreRollDuration() const { return pre_roll_duration_; }
uint32_t GetKwStartTolerance() const { return kw_start_tolerance_; }
uint32_t GetKwEndTolerance() const { return kw_end_tolerance_; }
uint32_t GetDataBeforeKwStart() const { return data_before_kw_start_; }
uint32_t GetDataAfterKwEnd() const { return data_after_kw_end_; }
uint32_t GetSampleRate() const { return sample_rate_; }
uint32_t GetBitWidth() const { return bit_width_; }
uint32_t GetOutChannels() const { return out_channels_; }
uint32_t GetSupportedEngineCount() const {
return supported_first_stage_engine_count_; }
bool GetConcurrentEventCapture() const { return enable_concurrent_event_capture_; }
st_module_type_t GetVUIModuleType();
std::shared_ptr<VUISecondStageConfig> GetVUISecondStageConfig(
const listen_model_indicator_enum& sm_type) const;
std::shared_ptr<VUIFirstStageConfig> GetVUIFirstStageConfig(const uint32_t type) const;
std::shared_ptr<VUIFirstStageConfig> GetVUIFirstStageConfig();
std::string GetVUIModuleName();
std::string GetVUIModuleName(st_module_type_t type) const {
return GetVUIFirstStageConfig(type)->GetModuleName();
}
std::shared_ptr<CaptureProfile> GetCaptureProfile(
std::pair<StOperatingModes, StInputModes> mode_pair) const {
return vui_op_modes_.at(mode_pair);
}
void GetDetectionPropertyList(std::vector<uint32_t> &list);
void ReadDetectionPropertyList(const char *prop_string);
bool IsDetPropSupported(uint32_t prop) const;
private:
std::string name_;
UUID vendor_uuid_;
std::string vui_intf_plugin_lib_name_;
bool is_qcva_uuid_;
bool get_module_version_supported_;
bool merge_first_stage_sound_models_;
uint32_t capture_keyword_;
uint32_t client_capture_read_delay_;
uint32_t pre_roll_duration_;
uint32_t kw_start_tolerance_;
uint32_t kw_end_tolerance_;
uint32_t data_before_kw_start_;
uint32_t data_after_kw_end_;
uint32_t sample_rate_;
uint32_t bit_width_;
uint32_t out_channels_;
uint32_t supported_first_stage_engine_count_;
bool enable_concurrent_event_capture_;
st_op_modes_t vui_op_modes_;
std::shared_ptr<SoundTriggerXml> curr_child_;
std::map<uint32_t, std::shared_ptr<VUISecondStageConfig>> vui_2nd_stage_cfg_list_;
std::map<uint32_t, std::shared_ptr<VUIFirstStageConfig>> vui_1st_stage_cfg_list_;
std::map<UUID, std::shared_ptr<VUIFirstStageConfig>> vui_uuid_1st_stage_cfg_list_;
std::vector<uint32_t> ext_det_prop_list_;
};
class VoiceUIPlatformInfo : public SoundTriggerPlatformInfo
{
public:
VoiceUIPlatformInfo();
VoiceUIPlatformInfo(VUIStreamConfig &rhs) = delete;
VoiceUIPlatformInfo & operator=(VoiceUIPlatformInfo &rhs) = delete;
void HandleStartTag(const char *tag, const char **attribs) override;
void HandleEndTag(struct xml_userdata *data, const char *tag) override;
static std::shared_ptr<VoiceUIPlatformInfo> GetInstance();
std::string GetSoundModelLib() const { return sound_model_lib_; }
bool GetEnableFailureDetection() const { return enable_failure_detection_; }
bool GetTransitToNonLpiOnCharging() const {
return transit_to_non_lpi_on_charging_;
}
bool GetMmapEnable() const { return mmap_enable_; }
bool GetNotifySecondStageFailure() { return notify_second_stage_failure_; }
uint32_t GetVersion() const { return vui_version_; }
uint32_t GetMmapBufferDuration() const { return mmap_buffer_duration_; }
uint32_t GetMmapFrameLength() const { return mmap_frame_length_; }
std::shared_ptr<VUIStreamConfig> GetStreamConfig(const UUID& uuid) const;
void GetStreamConfigForVersionQuery(std::vector<std::shared_ptr<VUIStreamConfig>> &sm_cfg_list) const;
private:
static std::shared_ptr<VoiceUIPlatformInfo> me_;
uint32_t vui_version_;
bool enable_failure_detection_;
bool transit_to_non_lpi_on_charging_;
bool notify_second_stage_failure_;
bool mmap_enable_;
uint32_t mmap_buffer_duration_;
uint32_t mmap_frame_length_;
std::string sound_model_lib_;
std::map<UUID, std::shared_ptr<VUIStreamConfig>> stream_cfg_list_;
std::shared_ptr<SoundTriggerXml> curr_child_;
};
#endif

View File

@@ -0,0 +1,314 @@
/*
* 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 are provided under the following license:
*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "ACDPlatformInfo.h"
#define LOG_TAG "PAL: ACDPlatformInfo"
ACDContextInfo::ACDContextInfo(uint32_t context_id, uint32_t type) :
context_id_(context_id),
context_type_(type)
{
}
ACDSoundModelInfo::ACDSoundModelInfo(ACDStreamConfig *sm_cfg) :
model_bin_name_(""),
is_parsing_contexts(false),
sm_cfg_(sm_cfg)
{
}
void ACDSoundModelInfo::HandleStartTag(const char* tag, const char** attribs __unused)
{
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
if (is_parsing_contexts) {
if (!strcmp(tag, "context")) {
uint32_t i = 0;
uint32_t id;
while (attribs[i]) {
if (!strcmp(attribs[i], "id")) {
std::string tagid(attribs[++i]);
id = ResourceManager::convertCharToHex(tagid);
std::shared_ptr<ACDContextInfo> context_info =
std::make_shared<ACDContextInfo>(id, model_id_);
acd_context_info_list_.push_back(context_info);
sm_cfg_->UpdateContextModelMap(id);
}
++i; /* move to next attribute */
}
}
}
if (!strcmp(tag, "contexts"))
is_parsing_contexts = true;
}
void ACDSoundModelInfo::HandleEndTag(struct xml_userdata *data, const char* tag_name)
{
PAL_DBG(LOG_TAG, "Got end tag %s", tag_name);
if (!strcmp(tag_name, "contexts"))
is_parsing_contexts = false;
if (data->offs <= 0)
return;
data->data_buf[data->offs] = '\0';
if (!strcmp(tag_name, "name")) {
std::string type(data->data_buf);
if (!strstr(type.c_str(), "ACD_SOUND_MODEL")) {
PAL_ERR(LOG_TAG, "Error:%d invalid sound model: %s", type.c_str());
} else {
model_type_ = type;
model_id_ = sm_cfg_->GetAndUpdateSndMdlCnt();
PAL_INFO(LOG_TAG, "Sound model type: %s\t\tid: %d\n", model_type_.c_str(), model_id_);
}
} else if (!strcmp(tag_name, "bin")) {
std::string bin_name(data->data_buf);
model_bin_name_ = bin_name;
} else if (!strcmp(tag_name, "uuid")) {
std::string uuid(data->data_buf);
model_uuid_ = ResourceManager::convertCharToHex(uuid);
}
return;
}
ACDStreamConfig::ACDStreamConfig() :
curr_child_(nullptr),
sound_model_cnt(0)
{
}
void ACDStreamConfig::UpdateContextModelMap(uint32_t context_id)
{
std::shared_ptr<ACDSoundModelInfo> sm_info(
std::static_pointer_cast<ACDSoundModelInfo>(curr_child_));
context_model_map_.insert(std::make_pair(context_id, sm_info));
}
std::shared_ptr<ACDSoundModelInfo> ACDStreamConfig::GetSoundModelInfoByContextId(uint32_t context_id)
{
auto contextModel = context_model_map_.find(context_id);
if (contextModel != context_model_map_.end())
return contextModel->second;
else
return nullptr;
}
std::shared_ptr<ACDSoundModelInfo> ACDStreamConfig::GetSoundModelInfoByModelId(uint32_t model_id)
{
auto modelInfo = acd_modelinfo_map_.find(model_id);
if (modelInfo != acd_modelinfo_map_.end())
return modelInfo->second;
else
return nullptr;
}
void ACDStreamConfig::HandleStartTag(const char* tag, const char** attribs)
{
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
/* Delegate to child element if currently active */
if (curr_child_) {
curr_child_->HandleStartTag(tag, attribs);
return;
}
if (!strcmp(tag, "sound_model")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
std::make_shared<ACDSoundModelInfo>(this));
return;
}
if (!strcmp(tag, "operating_modes") || !strcmp(tag, "sound_model_info")
|| !strcmp(tag, "name")) {
PAL_DBG(LOG_TAG, "tag:%s appeared, nothing to do", tag);
return;
}
std::shared_ptr<SoundTriggerPlatformInfo> st_info = SoundTriggerPlatformInfo::GetInstance();
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!strcmp(attribs[i], "vendor_uuid")) {
UUID::StringToUUID(attribs[++i], vendor_uuid_);
} else if (!strcmp(attribs[i], "sample_rate")) {
sample_rate_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "bit_width")) {
bit_width_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "out_channels")) {
if (std::stoi(attribs[++i]) <= MAX_MODULE_CHANNELS)
out_channels_ = std::stoi(attribs[i]);
} else {
PAL_ERR(LOG_TAG, "Invalid attribute %s", attribs[i++]);
}
++i; /* move to next attribute */
}
} else if (!strcmp(tag, "low_power")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_LOW_POWER, attribs, acd_op_modes_);
} else if (!strcmp(tag, "low_power_ns")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_LOW_POWER_NS, attribs, acd_op_modes_);
} else if (!strcmp(tag, "low_power_tx_macro")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_LOW_POWER_TX_MACRO, attribs, acd_op_modes_);
} else if (!strcmp(tag, "high_performance")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_HIGH_PERF, attribs, acd_op_modes_);
} else if (!strcmp(tag, "high_performance_ns")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_HIGH_PERF_NS, attribs, acd_op_modes_);
} else if (!strcmp(tag, "high_performance_tx_macro")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_HIGH_PERF_TX_MACRO, attribs, acd_op_modes_);
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", (char *)tag);
}
}
void ACDStreamConfig::HandleEndTag(struct xml_userdata *data, const char* tag)
{
PAL_DBG(LOG_TAG, "Got end tag %s", tag);
if (!strcmp(tag, "sound_model")) {
std::shared_ptr<ACDSoundModelInfo> acd_sm_info(
std::static_pointer_cast<ACDSoundModelInfo>(curr_child_));
acd_soundmodel_info_list_.push_back(acd_sm_info);
acd_modelinfo_map_.insert(std::make_pair(acd_sm_info->GetModelId(), acd_sm_info));
curr_child_ = nullptr;
}
if (curr_child_) {
curr_child_->HandleEndTag(data, tag);
return;
}
if (!strcmp(tag, "name")) {
if (data->offs <= 0)
return;
data->data_buf[data->offs] = '\0';
std::string name(data->data_buf);
name_ = name;
}
return;
}
std::shared_ptr<ACDPlatformInfo> ACDPlatformInfo::me_ = nullptr;
ACDPlatformInfo::ACDPlatformInfo() :
acd_enable_(true),
curr_child_(nullptr)
{
}
std::shared_ptr<ACDStreamConfig> ACDPlatformInfo::GetStreamConfig(const UUID& uuid) const
{
auto streamCfg = acd_cfg_list_.find(uuid);
if (streamCfg != acd_cfg_list_.end())
return streamCfg->second;
else
return nullptr;
}
std::shared_ptr<ACDPlatformInfo> ACDPlatformInfo::GetInstance()
{
if (!me_)
me_ = std::shared_ptr<ACDPlatformInfo> (new ACDPlatformInfo);
return me_;
}
void ACDPlatformInfo::HandleStartTag(const char* tag, const char** attribs)
{
/* Delegate to child element if currently active */
if (curr_child_) {
curr_child_->HandleStartTag(tag, attribs);
return;
}
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
if (!strcmp(tag, "stream_config")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
std::make_shared<ACDStreamConfig>());
return;
}
if (!strcmp(tag, "config")) {
PAL_DBG(LOG_TAG, "tag:%s appeared, nothing to do", tag);
return;
}
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!attribs[i]) {
PAL_ERR(LOG_TAG, "Error:%d missing attrib value for tag %s", -EINVAL, tag);
} else if (!strcmp(attribs[i], "acd_enable")) {
acd_enable_ = !strncasecmp(attribs[++i], "true", 4) ? true : false;
} else {
PAL_ERR(LOG_TAG, "Invalid attribute %s", attribs[i++]);
}
++i; /* move to next attribute */
}
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", tag);
}
}
void ACDPlatformInfo::HandleEndTag(struct xml_userdata *data, const char* tag)
{
PAL_DBG(LOG_TAG, "Got end tag %s", tag);
if (!strcmp(tag, "stream_config")) {
std::shared_ptr<ACDStreamConfig> acd_cfg(
std::static_pointer_cast<ACDStreamConfig>(curr_child_));
const auto res = acd_cfg_list_.insert(
std::make_pair(acd_cfg->GetUUID(), acd_cfg));
if (!res.second)
PAL_ERR(LOG_TAG, "Error:%d Failed to insert to map", -EINVAL);
curr_child_ = nullptr;
}
if (curr_child_)
curr_child_->HandleEndTag(data, tag);
return;
}

View File

@@ -0,0 +1,247 @@
/*
* 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) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "ASRPlatformInfo.h"
#include "asr_module_calibration_api.h"
#define LOG_TAG "PAL: ASRPlatformInfo"
void ASRCommonConfig::HandleStartTag(const char* tag, const char** attribs __unused)
{
PAL_INFO(LOG_TAG, "Start tag %s", tag);
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!strcmp(attribs[i], "asr_input_buffer_size")) {
input_buffer_size_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "asr_input_buffer_size_partial_mode")) {
partial_mode_input_buffer_size_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "buffering_mode_out_buf_size")) {
buffering_mode_out_buffer_size_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "command_mode_timeout")) {
command_mode_timeout_ = std::stoi(attribs[++i]);
} else {
PAL_ERR(LOG_TAG, "Invalid attribute %s", attribs[++i]);
}
}
}
}
void ASRCommonConfig::HandleEndTag(struct xml_userdata *data, const char* tag_name)
{
PAL_INFO(LOG_TAG, "Got end tag %s, nothing to handle here.", tag_name);
return;
}
ASRCommonConfig::ASRCommonConfig():
input_buffer_size_(0),
partial_mode_input_buffer_size_(0),
buffering_mode_out_buffer_size_(0),
command_mode_timeout_(0)
{
}
uint32_t ASRCommonConfig::GetOutputBufferSize(int mode) {
if (mode == BUFFERED)
return GetBufferingModeOutBufferSize();
return OUT_BUF_SIZE_DEFAULT;
}
uint32_t ASRCommonConfig::GetInputBufferSize(int mode) {
if (mode == BUFFERED)
return GetInputBufferSize();
return GetPartialModeInputBufferSize();
}
void ASRStreamConfig::HandleStartTag(const char* tag, const char** attribs)
{
PAL_INFO(LOG_TAG, "Got start tag %s", tag);
if (!strcmp(tag, "operating_modes") || !strcmp(tag, "module_Info")
|| !strcmp(tag, "name")) {
PAL_DBG(LOG_TAG, "tag:%s appeared, nothing to do", tag);
return;
}
std::shared_ptr<SoundTriggerPlatformInfo> st_info = SoundTriggerPlatformInfo::GetInstance();
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
uint32_t index = 0;
if (!strcmp(attribs[i], "vendor_uuid")) {
UUID::StringToUUID(attribs[++i], vendor_uuid_);
} else {
if (!strcmp(attribs[i], "asr_input_config_id")) {
index = ASR_INPUT_CONFIG;
} else if (!strcmp(attribs[i], "asr_output_config_id")) {
index = ASR_OUTPUT_CONFIG;
} else if (!strcmp(attribs[i], "asr_input_buffer_duration_id")) {
index = ASR_INPUT_BUF_DURATON;
} else if (!strcmp(attribs[i], "asr_output_id")) {
index = ASR_OUTPUT;
} else if (!strcmp(attribs[i], "asr_force_output_id")) {
index = ASR_FORCE_OUTPUT;
} else {
PAL_ERR(LOG_TAG, "Invalid attribute %s", attribs[i++]);
}
sscanf(attribs[++i], "%x, %x", &module_tag_ids_[index], &param_ids_[index]);
PAL_DBG(LOG_TAG, "index : %u, module_id : %x, param : %x",
index, module_tag_ids_[index], param_ids_[index]);
++i; /* move to next attribute */
}
}
} else {
if (!strcmp(tag, "low_power")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_LOW_POWER, attribs, asr_op_modes_);
} else if (!strcmp(tag, "high_performance")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_HIGH_PERF, attribs, asr_op_modes_);
}
}
}
void ASRStreamConfig::HandleEndTag(struct xml_userdata *data, const char* tag)
{
PAL_INFO(LOG_TAG, "Got end tag %s", tag);
if (!strcmp(tag, "module_Info") || !strcmp(tag, "operating_modes")) {
PAL_INFO(LOG_TAG, "Exit, Nothing to do for this %s tag.", tag);
}
if (!strcmp(tag, "name")) {
if (data->offs <= 0)
return;
data->data_buf[data->offs] = '\0';
std::string name(data->data_buf);
name_ = name;
}
PAL_INFO(LOG_TAG, "Exit, for %s tag.", tag);
return;
}
std::shared_ptr<ASRPlatformInfo> ASRPlatformInfo::me_ = nullptr;
ASRStreamConfig::ASRStreamConfig() :
curr_child_(nullptr)
{
for (int i = 0; i < ASR_MAX_PARAM_IDS; i++) {
module_tag_ids_[i] = 0;
param_ids_[i] = 0;
}
}
ASRPlatformInfo::ASRPlatformInfo() :
curr_child_(nullptr),
cm_cfg_(nullptr)
{
}
std::shared_ptr<ASRPlatformInfo> ASRPlatformInfo::GetInstance()
{
if (!me_)
me_ = std::shared_ptr<ASRPlatformInfo> (new ASRPlatformInfo);
return me_;
}
std::shared_ptr<ASRStreamConfig> ASRPlatformInfo::GetStreamConfig(const UUID& uuid) const
{
auto smCfg = stream_cfg_list_.find(uuid);
if (smCfg != stream_cfg_list_.end())
return smCfg->second;
else
return nullptr;
}
void ASRPlatformInfo::HandleStartTag(const char* tag, const char** attribs)
{
PAL_INFO(LOG_TAG, "Got start tag %s", tag);
/* Delegate to child element if currently active */
if (curr_child_) {
curr_child_->HandleStartTag(tag, attribs);
return;
}
if (!strcmp(tag, "stream_config")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
std::make_shared<ASRStreamConfig>());
return;
} else if (!strcmp(tag, "common_config")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
std::make_shared<ASRCommonConfig>());
return;
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", tag);
}
PAL_INFO(LOG_TAG, "Exit for tag %s.", tag);
}
void ASRPlatformInfo::HandleEndTag(struct xml_userdata *data, const char* tag)
{
PAL_INFO(LOG_TAG, "Got end tag %s", tag);
if (!strcmp(tag, "stream_config")) {
std::shared_ptr<ASRStreamConfig> sm_cfg(
std::static_pointer_cast<ASRStreamConfig>(curr_child_));
const auto res = stream_cfg_list_.insert(
std::make_pair(sm_cfg->GetUUID(), sm_cfg));
if (!res.second)
PAL_ERR(LOG_TAG, "Failed to insert to map");
curr_child_ = nullptr;
} else if (!strcmp(tag, "common_config")) {
std::shared_ptr<ASRCommonConfig> cm_cfg(
std::static_pointer_cast<ASRCommonConfig>(curr_child_));
cm_cfg_ = cm_cfg;
curr_child_ = nullptr;
}
if (curr_child_)
curr_child_->HandleEndTag(data, tag);
PAL_DBG(LOG_TAG, "Exit for tag %s.", tag);
return;
}

View File

@@ -0,0 +1,523 @@
/*
* 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 are provided under the following license:
*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "AudioHapticsInterface.h"
#define LOG_TAG "PAL: AudioHapticsInterface"
#define HAPTICS_XML_FILE "/vendor/etc/Hapticsconfig.xml"
#include "rx_haptics_api.h"
#include "wsa_haptics_vi_api.h"
std::shared_ptr<AudioHapticsInterface> AudioHapticsInterface::me_ = nullptr;
std::vector<haptics_wave_designer_config_t> AudioHapticsInterface::compose_haptics_info;
std::vector<haptics_wave_designer_config_t> AudioHapticsInterface::predefined_haptics_info;
std::vector<haptics_wave_designer_config_t> AudioHapticsInterface::oneshot_haptics_info;
int AudioHapticsInterface::ringtone_haptics_wave_design_mode;
AudioHapticsInterface::AudioHapticsInterface()
{
}
AudioHapticsInterface::~AudioHapticsInterface()
{
}
std::shared_ptr<AudioHapticsInterface> AudioHapticsInterface::GetInstance()
{
if (!me_)
me_ = std::shared_ptr<AudioHapticsInterface>(new AudioHapticsInterface);
return me_;
}
int AudioHapticsInterface::init()
{
int ret = 0;
int bytes_read;
predefined_haptics_info.clear();
oneshot_haptics_info.clear();
ret = AudioHapticsInterface::XmlParser(HAPTICS_XML_FILE);
if (ret) {
PAL_ERR(LOG_TAG, "error in haptics xml parsing ret %d", ret);
throw std::runtime_error("error in haptics xml parsing");
}
return ret;
}
void AudioHapticsInterface::startTag(void *userdata, const XML_Char *tag_name,
const XML_Char **attr)
{
struct haptics_xml_data *data = ( struct haptics_xml_data *)userdata;
resetDataBuf(data);
if (!strcmp(tag_name, "haptics_param_values")) {
data->hapticstag = TAG_HAPTICSCNFGXML_ROOT;
} else if (!strcmp(tag_name, "predefined_effect")) {
data->hapticstag = TAG_PREDEFINED_EFFECT;
} else if (!strcmp(tag_name, "oneshot_effect")) {
data->hapticstag = TAG_ONESHOT_EFFECT;
} else if (!strcmp(tag_name, "ringtone_effect")) {
data->hapticstag = TAG_RINGTONE_EFFECT;
} else if (!strcmp(tag_name, "compose_effect")) {
data->hapticstag = TAG_COMPOSE_EFFECT;
} else {
PAL_INFO(LOG_TAG, "No matching Tag found");
}
}
void AudioHapticsInterface::endTag(void *userdata, const XML_Char *tag_name)
{
struct haptics_xml_data *data = ( struct haptics_xml_data *)userdata;
int size = -1;
process_haptics_info(data, tag_name);
resetDataBuf(data);
return;
}
void AudioHapticsInterface::resetDataBuf(struct haptics_xml_data *data)
{
data->offs = 0;
data->data_buf[data->offs] = '\0';
}
void AudioHapticsInterface::handleData(void *userdata, const char *s, int len)
{
struct haptics_xml_data *data = (struct haptics_xml_data *)userdata;
if (len + data->offs >= sizeof(data->data_buf) ) {
data->offs += len;
/* string length overflow, return */
return;
} else {
memcpy(data->data_buf + data->offs, s, len);
data->offs += len;
}
}
int AudioHapticsInterface::XmlParser(std::string xmlFile) {
XML_Parser parser;
FILE *file = NULL;
int ret = 0;
int bytes_read;
void *buf = NULL;
struct haptics_xml_data data;
memset(&data, 0, sizeof(data));
PAL_INFO(LOG_TAG, "XML parsing started %s", xmlFile.c_str());
file = fopen(xmlFile.c_str(), "r");
if (!file) {
PAL_ERR(LOG_TAG, "Failed to open xml");
ret = -EINVAL;
goto done;
}
parser = XML_ParserCreate(NULL);
if (!parser) {
PAL_ERR(LOG_TAG, "Failed to create XML");
goto closeFile;
}
XML_SetUserData(parser,&data);
XML_SetElementHandler(parser, startTag, endTag);
XML_SetCharacterDataHandler(parser, handleData);
while (1) {
buf = XML_GetBuffer(parser, 1024);
if (buf == NULL) {
PAL_ERR(LOG_TAG, "XML_Getbuffer failed");
ret = -EINVAL;
goto freeParser;
}
bytes_read = fread(buf, 1, 1024, file);
if (bytes_read < 0) {
PAL_ERR(LOG_TAG, "fread failed");
ret = -EINVAL;
goto freeParser;
}
if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) {
PAL_ERR(LOG_TAG, "XML ParseBuffer failed ");
ret = -EINVAL;
goto freeParser;
}
if (bytes_read == 0)
break;
}
freeParser:
XML_ParserFree(parser);
closeFile:
fclose(file);
done:
return ret;
}
void AudioHapticsInterface::process_haptics_info(struct haptics_xml_data *data,
const XML_Char *tag_name)
{
int size = 0;
struct haptics_wave_designer_config_t HapticsCnfg = {};
if (data->hapticstag == TAG_PREDEFINED_EFFECT) {
if (!strcmp(tag_name, "num_channels")) {
HapticsCnfg.num_channels = atoi(data->data_buf);
predefined_haptics_info.push_back(HapticsCnfg);
} else if (!strcmp(tag_name, "channel_mask")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].channel_mask = atoi(data->data_buf);
} else if (!strcmp(tag_name, "wave_design_mode")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].wave_design_mode = atoi(data->data_buf);
} else if (!strcmp(tag_name, "auto_overdrive_brake_en")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].auto_overdrive_brake_en = atoi(data->data_buf);
} else if (!strcmp(tag_name, "f0_tracking_en")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].f0_tracking_en = atoi(data->data_buf);
} else if (!strcmp(tag_name, "f0_tracking_param_reset_flag")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].f0_tracking_param_reset_flag = atoi(data->data_buf);
} else if (!strcmp(tag_name, "override_flag")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].override_flag = atoi(data->data_buf);
} else if (!strcmp(tag_name, "tracked_freq_warmup_time_ms")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].tracked_freq_warmup_time_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "settling_time_ms")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].settling_time_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "delay_time_ms")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].delay_time_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "wavegen_fstart_hz_q20")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].wavegen_fstart_hz_q20 = atoi(data->data_buf);
} else if (!strcmp(tag_name, "repetition_count")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].repetition_count = atoi(data->data_buf);
} else if (!strcmp(tag_name, "repetition_period_ms")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].repetition_period_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "pilot_tone_en")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].pilot_tone_en = atoi(data->data_buf);
} else if (!strcmp(tag_name, "low_pulse_intensity")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].low_pulse_intensity = atoi(data->data_buf);
} else if (!strcmp(tag_name, "mid_pulse_intensity")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].mid_pulse_intensity = atoi(data->data_buf);
} else if (!strcmp(tag_name, "high_pulse_intensity")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].high_pulse_intensity = atoi(data->data_buf);
} else if (!strcmp(tag_name, "pulse_width_ms")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].pulse_width_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "pulse_sharpness")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].pulse_sharpness = atoi(data->data_buf);
} else if (!strcmp(tag_name, "num_pwl")) {
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].num_pwl = atoi(data->data_buf);
} else if (!strcmp(tag_name, "pwl_time")) {
int j = 0;
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].pwl_time = (int32_t *) calloc(predefined_haptics_info[size].num_pwl,
sizeof(int32_t));
for (int i=0; i<predefined_haptics_info[size].num_pwl ;i++) {
predefined_haptics_info[size].pwl_time[i] = atoi(&data->data_buf[j]);
PAL_DBG(LOG_TAG, "pwltime :%d", predefined_haptics_info[size].pwl_time[i]);
for (; j<strlen(data->data_buf) ;j++) {
if (data->data_buf[j] == ',') {
j = j+1;
break;
}
}
}
} else if (!strcmp(tag_name, "pwl_acc")) {
int j = 0;
size = predefined_haptics_info.size() - 1;
predefined_haptics_info[size].pwl_acc = (int32_t *) calloc(predefined_haptics_info[size].num_pwl,
sizeof(int32_t));
for (int i=0; i<predefined_haptics_info[size].num_pwl ;i++) {
predefined_haptics_info[size].pwl_acc[i] = atoi(&data->data_buf[j]);
PAL_DBG(LOG_TAG, "pwlacc :%d", predefined_haptics_info[size].pwl_acc[i]);
for (; j<strlen(data->data_buf) ;j++) {
if (data->data_buf[j] == ',') {
j = j+1;
break;
}
}
}
}
}
if (data->hapticstag == TAG_COMPOSE_EFFECT) {
if (!strcmp(tag_name, "num_channels")) {
HapticsCnfg.num_channels = atoi(data->data_buf);
compose_haptics_info.push_back(HapticsCnfg);
}
else if (!strcmp(tag_name, "channel_mask")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].channel_mask = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "wave_design_mode")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].wave_design_mode = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "auto_overdrive_brake_en")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].auto_overdrive_brake_en = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "f0_tracking_en")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].f0_tracking_en = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "f0_tracking_param_reset_flag")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].f0_tracking_param_reset_flag = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "override_flag")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].override_flag = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "tracked_freq_warmup_time_ms")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].tracked_freq_warmup_time_ms = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "settling_time_ms")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].settling_time_ms = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "delay_time_ms")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].delay_time_ms = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "wavegen_fstart_hz_q20")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].wavegen_fstart_hz_q20 = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "repetition_count")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].repetition_count = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "repetition_period_ms")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].repetition_period_ms = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "pilot_tone_en")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].pilot_tone_en = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "low_pulse_intensity")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].low_pulse_intensity = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "mid_pulse_intensity")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].mid_pulse_intensity = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "high_pulse_intensity")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].high_pulse_intensity = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "pulse_width_ms")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].pulse_width_ms = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "pulse_sharpness")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].pulse_sharpness = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "num_pwl")) {
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].num_pwl = atoi(data->data_buf);
}
else if (!strcmp(tag_name, "pwl_time")) {
int j = 0;
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].pwl_time = (int32_t*)calloc(compose_haptics_info[size].num_pwl,
sizeof(int32_t));
for (int i = 0; i < compose_haptics_info[size].num_pwl; i++) {
compose_haptics_info[size].pwl_time[i] = atoi(&data->data_buf[j]);
PAL_DBG(LOG_TAG, "pwltime :%d", compose_haptics_info[size].pwl_time[i]);
for (; j < strlen(data->data_buf); j++) {
if (data->data_buf[j] == ',') {
j = j + 1;
break;
}
}
}
}
else if (!strcmp(tag_name, "pwl_acc")) {
int j = 0;
size = compose_haptics_info.size() - 1;
compose_haptics_info[size].pwl_acc = (int32_t*)calloc(compose_haptics_info[size].num_pwl,
sizeof(int32_t));
for (int i = 0; i < compose_haptics_info[size].num_pwl; i++) {
compose_haptics_info[size].pwl_acc[i] = atoi(&data->data_buf[j]);
PAL_DBG(LOG_TAG, "pwlacc :%d", compose_haptics_info[size].pwl_acc[i]);
for (; j < strlen(data->data_buf); j++) {
if (data->data_buf[j] == ',') {
j = j + 1;
break;
}
}
}
}
}
if (data->hapticstag == TAG_ONESHOT_EFFECT) {
if (!strcmp(tag_name, "num_channels")) {
HapticsCnfg.num_channels = atoi(data->data_buf);
oneshot_haptics_info.push_back(HapticsCnfg);
} else if (!strcmp(tag_name, "channel_mask")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].channel_mask = atoi(data->data_buf);
} else if (!strcmp(tag_name, "wave_design_mode")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].wave_design_mode = atoi(data->data_buf);
} else if (!strcmp(tag_name, "auto_overdrive_brake_en")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].auto_overdrive_brake_en = atoi(data->data_buf);
} else if (!strcmp(tag_name, "f0_tracking_en")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].f0_tracking_en = atoi(data->data_buf);
} else if (!strcmp(tag_name, "f0_tracking_param_reset_flag")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].f0_tracking_param_reset_flag = atoi(data->data_buf);
} else if (!strcmp(tag_name, "override_flag")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].override_flag = atoi(data->data_buf);
} else if (!strcmp(tag_name, "wavegen_fstart_hz_q20")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].wavegen_fstart_hz_q20 = atoi(data->data_buf);
} else if (!strcmp(tag_name, "tracked_freq_warmup_time_ms")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].tracked_freq_warmup_time_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "settling_time_ms")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].settling_time_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "delay_time_ms")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].delay_time_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "repetition_count")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].repetition_count = atoi(data->data_buf);
} else if (!strcmp(tag_name, "repetition_period_ms")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].repetition_period_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "pilot_tone_en")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].pilot_tone_en = atoi(data->data_buf);
} else if (!strcmp(tag_name, "low_pulse_intensity")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].low_pulse_intensity = atoi(data->data_buf);
} else if (!strcmp(tag_name, "pulse_width_ms")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].pulse_width_ms = atoi(data->data_buf);
} else if (!strcmp(tag_name, "pulse_sharpness")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].pulse_sharpness = atoi(data->data_buf);
} else if (!strcmp(tag_name, "num_pwl")) {
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].num_pwl = atoi(data->data_buf);
} else if (!strcmp(tag_name, "pwl_time")) {
int j = 0;
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].pwl_time = (int32_t *) calloc(oneshot_haptics_info[size].num_pwl,
sizeof(int32_t));
for (int i=0; i < oneshot_haptics_info[size].num_pwl ;i++) {
oneshot_haptics_info[size].pwl_time[i] = atoi(&data->data_buf[j]);
PAL_DBG(LOG_TAG, "pwltime :%d", oneshot_haptics_info[size].pwl_time[i]);
for (; j<strlen(data->data_buf) ;j++) {
if (data->data_buf[j] == ',') {
j = j+1;
break;
}
}
}
} else if (!strcmp(tag_name, "pwl_acc")) {
int j = 0;
size = oneshot_haptics_info.size() - 1;
oneshot_haptics_info[size].pwl_acc = (int32_t *) calloc(oneshot_haptics_info[size].num_pwl,
sizeof(int32_t));
for (int i=0; i < oneshot_haptics_info[size].num_pwl ;i++) {
oneshot_haptics_info[size].pwl_acc[i] = atoi(&data->data_buf[j]);
PAL_DBG(LOG_TAG, "pwlacc :%d", oneshot_haptics_info[size].pwl_acc[i]);
for (; j<strlen(data->data_buf) ;j++) {
if (data->data_buf[j] == ',') {
j = j+1;
break;
}
}
}
}
}
if (data->hapticstag == TAG_RINGTONE_EFFECT) {
if (!strcmp(tag_name, "wave_design_mode")) {
ringtone_haptics_wave_design_mode = atoi(data->data_buf);
}
}
PAL_ERR(LOG_TAG, "%s \n", data->data_buf);
}
void AudioHapticsInterface::getTouchHapticsEffectConfiguration(int effect_id, bool isCompose, haptics_wave_designer_config_t **HConfig)
{
if (effect_id >= 0) {
if (*HConfig == NULL) {
if (isCompose) {
*HConfig = (haptics_wave_designer_config_t*)calloc(1, sizeof(compose_haptics_info[effect_id]));
if (*HConfig)
memcpy(*HConfig, &compose_haptics_info[effect_id],
sizeof(compose_haptics_info[effect_id]));
} else {
*HConfig = (haptics_wave_designer_config_t*)calloc(1, sizeof(predefined_haptics_info[effect_id]));
if (*HConfig)
memcpy(*HConfig, &predefined_haptics_info[effect_id],
sizeof(predefined_haptics_info[effect_id]));
}
}
} else {
if (*HConfig == NULL) {
*HConfig = (haptics_wave_designer_config_t *) calloc(1, sizeof(oneshot_haptics_info[0]));
if (*HConfig)
memcpy(*HConfig, &oneshot_haptics_info[0],
sizeof(oneshot_haptics_info[0]));
}
}
PAL_DBG(LOG_TAG, "getTouchHapticsEffectConfiguration exit\n");
}

View File

@@ -0,0 +1,490 @@
/*
* Copyright (C) 2015, 2021, The Linux Foundation. All rights reserved.
*
* Not a contribution.
*
* Copyright (C) 2011, 2017 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.
*
* Changes from Qualcomm Innovation Center are provided under the following
* license:
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the
* disclaimer below) 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 Qualcomm Innovation Center, Inc. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
* GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
*/
#include <unistd.h>
#include <mutex>
#include <thread>
#include <string>
#include <sys/stat.h>
#include <log/log.h>
#include <cutils/uevent.h>
#include "ChargerListener.h"
#define N_OF_EVNT_REG 2
#define MAX_BUFFER_LEN 16
#define UEVENT_MSG_LEN 2048
#define UEVENT_SOCKET_RCVBUF_SIZE 64 * 1024
#define SET_BOOST_CONCURRENT_BIT "1"
#define RESET_BOOST_CONCURRENT_BIT "0"
#define CHARGER_STATE_BUFF_MAX_LEN 2
#define CHARGING_STATUS_BUFF_MAX_LEN 16
#define CHARGER_PRESENCE_PATH "/sys/class/power_supply/usb/present"
#define CHARGING_STATUS_PATH "/sys/class/power_supply/battery/status"
#define BOOST_CONCURRENT_PATH "/sys/class/qcom-smb/boost_concurrent_mode"
int ChargerListenerImpl::readSysfsPath(const char *path, int flag, int length,
char *state)
{
int fd = -1, ret = -EINVAL;
ssize_t bytes;
if (!path || !state)
goto exit;
fd = ::open(path, flag);
if (fd == -1) {
ALOGE("%s %d, Failed to open fd in read mode: %s", __func__, __LINE__,
strerror(errno));
goto exit;
}
bytes = read(fd, state, length);
if (bytes <= 0) {
ALOGD("%s %d, Failed to get current state", __func__, __LINE__);
} else {
state[(bytes/(sizeof(char))) - 1] = '\0';
ret = 0;
}
exit:
if (ret && state)
state[0] = '\0';
if (fd != -1)
close(fd);
return ret;
}
int ChargerListenerImpl::getInitialStatus()
{
char state[MAX_BUFFER_LEN];
int status = 0;
int charger_state;
bool concurrent_state;
if (!info) {
return -EINVAL;
} else {
status = readSysfsPath(CHARGER_PRESENCE_PATH, O_RDONLY,
CHARGER_STATE_BUFF_MAX_LEN, state);
if (0 != status) {
ALOGE("%s %d, Failed to get Initial state for charger_presence %d",
__func__, __LINE__, status);
return status;
} else {
if (!strncmp(state, "0", strlen(state)))
charger_state = OFFLINE;
else
charger_state = ONLINE;
int status_bit = getConcurrentState();
concurrent_state = (status_bit == 1) ? true : false;
info->c_state = (charger_state_t)charger_state;
mcb(CHARGER_EVENT, charger_state, concurrent_state);
}
// No callback registered for battery_status for now
status = readSysfsPath(CHARGING_STATUS_PATH, O_RDONLY,
CHARGING_STATUS_BUFF_MAX_LEN, state);
if (0 != status)
ALOGE("%s %d, Failed to get Initial state for charging_status %d",
__func__, __LINE__, status);
// Not handling Error status for charging status.
status = 0;
}
return status;
}
void ChargerListenerImpl::getStateUpdate(int type)
{
char state[MAX_BUFFER_LEN];
bool concurrent_state;
int charger_state, status = 0;
switch (type) {
case CHARGER_EVENT:
status = readSysfsPath(CHARGER_PRESENCE_PATH, O_RDONLY,
CHARGER_STATE_BUFF_MAX_LEN, state);
if (0 == status) {
if (!strncmp(state, "0", strlen(state)))
charger_state = OFFLINE;
else
charger_state = ONLINE;
if (info->c_state != charger_state) {
ALOGD("%s %d, charger state change: %d from last state %d",
__func__, __LINE__, charger_state, info->c_state);
info->c_state = (charger_state_t)charger_state;
int status_bit = getConcurrentState();
concurrent_state = (status_bit == 1) ? true : false;
mcb(CHARGER_EVENT, charger_state, concurrent_state);
//TODO dispatcher_thread = std::thread (mcb, CHARGER_EVENT, charger_state, concurrent_state);
//TODO dispatcher_thread.detach();
}
}
break;
case BATTERY_EVENT:
readSysfsPath(CHARGING_STATUS_PATH, O_RDONLY,
CHARGING_STATUS_BUFF_MAX_LEN, state);
//Add cb to Process for battery event change.
break;
default :
ALOGI("%s %d, Unknown event", __func__, __LINE__);
break;
}
}
void ChargerListenerImpl::readEvent(void *context, struct charger_info *info)
{
/* Max size allowed for UEVENT_MSG_LEN is 2048 */
char msg_info [UEVENT_MSG_LEN];
int size_rcv;
int uevent_type;
size_rcv = uevent_kernel_multicast_recv(info->uevent_fd,
msg_info, sizeof(msg_info));
/* underflow and overflow condition*/
if (size_rcv <= 0 ||
size_rcv >= sizeof(msg_info)) {
ALOGE("%s %d, rcv size is not under size limit", __func__, __LINE__);
return;
}
msg_info[size_rcv] = '\0';
/* update specified uevent properties */
if (strstr(msg_info, "battery"))
uevent_type = BATTERY_EVENT;
else if (strstr(msg_info, "usb"))
uevent_type = CHARGER_EVENT;
else
uevent_type = UNKNOWN_EVENT;
/* Customize condition for other event*/
if (uevent_type == CHARGER_EVENT)
reinterpret_cast<ChargerListenerImpl*>(context)->getStateUpdate(uevent_type);
}
int ChargerListenerImpl::addEvent(func_ptr event_fun, int event_type, int fd)
{
int status = 0;
struct epoll_event reg_event;
ALOGD("%s %d, Enter :", __func__, __LINE__);
switch(event_type) {
case PIPE_EVENT:
reg_event.data.fd = fd;
reg_event.events = EPOLLIN | EPOLLWAKEUP;
if (epoll_ctl(info->epoll_fd, EPOLL_CTL_ADD, fd, &reg_event) == -1) {
ALOGE("%s %d, Failed to add non uevent :%s\n", __func__,
__LINE__, strerror(errno));
status = -errno;
} else {
info->event_count++;
}
break;
case U_EVENT:
reg_event.data.ptr = (void *)event_fun;
reg_event.events = EPOLLIN | EPOLLWAKEUP;
if (epoll_ctl(info->epoll_fd, EPOLL_CTL_ADD, fd, &reg_event) == -1) {
ALOGE("%s %d, Failed to add uevent :%s\n", __func__, __LINE__,
strerror(errno));
status = -errno;
} else {
info->event_count++;
}
break;
default :
ALOGI("%s %d, Unknown event", __func__, __LINE__);
break;
}
ALOGD("%s %d, Exit status %d", __func__, __LINE__, status);
return status;
}
int ChargerListenerImpl::initEvent()
{
int status = 0;
ALOGD("%s %d, Enter ", __func__, __LINE__);
pipe_status = pipe(intPipe);
if (pipe_status < 0) {
ALOGE("%s %d, Failed to open_pipe: %s", __func__, __LINE__,
strerror(errno));
status = -errno;
goto exit;
}
/* Adding pipe Event in Interested List to unblock epoll thread*/
fcntl(intPipe[0], F_SETFL, O_NONBLOCK);
status = addEvent(ChargerListenerImpl::readEvent, PIPE_EVENT, intPipe[0]);
if (status < 0) {
ALOGE("%s %d, Failed to add pipe event: %d", __func__, __LINE__, errno);
goto close_pipe;
}
info->uevent_fd = uevent_open_socket(UEVENT_SOCKET_RCVBUF_SIZE, true);
if (info->uevent_fd < 0) {
ALOGE("%s %d, Failed to open_uevent_socket: %s", __func__, __LINE__,
strerror(errno));
status = -errno;
goto close_pipe;
}
/* Adding U-Event Event in Interested List */
fcntl(info->uevent_fd, F_SETFL, O_NONBLOCK);
status = addEvent(ChargerListenerImpl::readEvent, U_EVENT, info->uevent_fd);
if (status < 0) {
ALOGE("%s %d, Failed to add U-Event: %d", __func__, __LINE__, errno);
goto close_uevent;
}
goto exit;
close_uevent:
if (info->uevent_fd) {
close(info->uevent_fd);
info->uevent_fd = 0;
}
close_pipe:
if (intPipe[0]) {
close(intPipe[0]);
intPipe[0] = 0;
}
exit:
ALOGD("%s %d, Exit status %d", __func__, __LINE__, status);
return status;
}
void ChargerListenerImpl::chargerMonitor()
{
func_ptr event_cb = NULL;
/**
*Initialise buf with "P" to continue poll unless set as "Q" to unblock
*charger monitor thread when rm deinit happen.
**/
char buf[2] = "P";
ALOGD("%s %d, Enter chargerMonitor", __func__, __LINE__);
while (1) {
int no_events = epoll_wait(info->epoll_fd, info->events,
info->event_count, -1);
if (no_events == -1) {
if (errno == EINTR)
continue;
ALOGE("%s %d, epoll_wait failed: %d", __func__,
__LINE__, errno);
break;
}
for (int i = 0; i < no_events; ++i) {
/* Unblock Polling Thread */
if (info->events[i].data.fd && info->events[i].data.fd == intPipe[0]) {
read(info->events[i].data.fd, buf, 1);
if (!strncmp(buf, "Q", strlen(buf)))
return;
} else {
event_cb = (func_ptr)info->events[i].data.ptr;
event_cb(this, info);
}
}
}
ALOGD("%s %d, Exit : ChargerMonitor is unblocked from poll", __func__, __LINE__);
}
void ChargerListenerImpl::CLImplInit()
{
/* Create poll fd */
info->epoll_fd = epoll_create(MAX_EVENTS);
if (info->epoll_fd == -1) {
ALOGE("%s %d, Failed to epoll_create: %s\n", __func__, __LINE__,
strerror(errno));
return;
}
/* Init for uevent */
if (initEvent() < 0) {
ALOGE("%s %d, Failed to init uevent: %s\n", __func__, __LINE__,
strerror(errno));
goto close_epoll_fd;
}
/* Initial state is setup for all event */
if (getInitialStatus() < 0) {
ALOGE("%s %d, Failed to determine init status: %s", __func__, __LINE__,
strerror(errno));
goto close_epoll_fd;
}
ALOGI("%s %d, Charger Listener Impl init is successful", __func__, __LINE__);
poll_thread = std::thread (&ChargerListenerImpl::chargerMonitor, this);
goto exit;
close_epoll_fd:
if (info->epoll_fd) {
close(info->epoll_fd);
info->epoll_fd = 0;
}
exit:
return;
}
int ChargerListenerImpl::getConcurrentState()
{
int status_bit = -EINVAL;
char state[22];
mlock.lock();
if (0 != readSysfsPath(BOOST_CONCURRENT_PATH, O_RDONLY, 2, state)) {
ALOGE("%s %d, read Concurrency bit failed %s", __func__, __LINE__,
strerror(errno));
} else {
sscanf(state, "%d", &status_bit);
}
mlock.unlock();
return status_bit;
}
int ChargerListenerImpl::setConcurrentState(bool is_boost_enable)
{
int intfd;
int status = 0;
int status_bit;
mlock.lock();
intfd = ::open(BOOST_CONCURRENT_PATH, O_WRONLY);
if (intfd == -1) {
ALOGE("%s %d, Failed to open sysnode: %s", __func__,
__LINE__, strerror(errno));
status = -errno;
} else {
if (is_boost_enable)
status_bit = write(intfd, SET_BOOST_CONCURRENT_BIT, 1);
else
status_bit = write(intfd, RESET_BOOST_CONCURRENT_BIT, 1);
if (status_bit == -1) {
ALOGE("%s %d, failed to Write concurrency bit: %s ", __func__,
__LINE__, strerror(errno));
status = -errno;
} else {
ALOGD("%s %d, Success on setting charger + boost concurr. bit %d", __func__,
__LINE__, is_boost_enable);
}
close(intfd);
}
mlock.unlock();
return status;
}
ChargerListenerImpl::ChargerListenerImpl(cb_fn_t cb) :
mcb(cb)
{
info = (struct charger_info *)calloc(sizeof(struct charger_info), 1);
if (!info) {
ALOGE("%s %d, Calloc failed for charger_info %s", __func__, __LINE__,
strerror(errno));
return;
}
CLImplInit();
}
ChargerListenerImpl *chargerListener = NULL;
ChargerListenerImpl::~ChargerListenerImpl()
{ /*TODO
if (dispatcher_thread.joinable())
dispatcher_thread.join();
*/
if (0 == pipe_status) {
write(intPipe[1], "Q", 1);
if (poll_thread.joinable()) {
poll_thread.join();
}
if (intPipe[0])
close(intPipe[0]);
if (intPipe[1])
close(intPipe[1]);
}
//Deallocating charger info
if (info) {
if (info->epoll_fd)
close(info->epoll_fd);
if (info->uevent_fd)
close(info->uevent_fd);
free(info);
info = NULL;
}
}
extern "C" {
void chargerPropertiesListenerInit(charger_status_change_fn_t fn)
{
chargerListener = new ChargerListenerImpl(fn);
}
void chargerPropertiesListenerDeinit()
{
delete chargerListener;
}
int chargerPropertiesListenerSetBoostState(bool is_boost_enable)
{
return(chargerListener->setConcurrentState(is_boost_enable));
}
} // extern C

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "MemLogBuilder.h"
#include "Device.h"
#include <hwbinder/IPCThreadState.h>
#define LOG_TAG "PAL: memLoggerBuilder"
int palStateQueueBuilder(pal_state_queue &que, Stream *s, pal_state_queue_state state, int32_t error)
{
PAL_DBG(LOG_TAG, "Entered PAL State Queue Builder");
int ret = 0;
std::vector <std::shared_ptr<Device>> aDevices;
struct pal_stream_attributes sAttr;
struct pal_device strDevAttr;
pal_stream_type_t type;
if (!memLoggerIsQueueInitialized())
{
PAL_ERR(LOG_TAG, "queues failed to initialize");
goto exit;
}
ret = s->getAssociatedDevices(aDevices);
if(ret != 0)
{
PAL_ERR(LOG_TAG, "getStreamType failed with status = %d", ret);
goto exit;
}
ret = s->getStreamType(&type);
if(ret != 0)
{
PAL_ERR(LOG_TAG, "getStreamType failed with status = %d", ret);
goto exit;
}
memset(&que, 0, sizeof(que));
s->getStreamAttributes(&sAttr);
que.stream_handle = (uint64_t) s; // array to store queue element
que.stream_type = type;
que.direction = sAttr.direction;
que.state = state;
que.error = error;
PAL_DBG(LOG_TAG, "Stream handle = " "%" PRId64 "\n", s);
memset(que.device_attr, 0, sizeof(que.device_attr));
for(int i=0; i<aDevices.size(); i++)
{
if(i < STATE_DEVICE_MAX_SIZE)
{
aDevices[i]->getDeviceAttributes(&strDevAttr, s);
que.device_attr[i].device = strDevAttr.id;
que.device_attr[i].sample_rate = strDevAttr.config.sample_rate;
que.device_attr[i].bit_width = strDevAttr.config.bit_width;
que.device_attr[i].channels = strDevAttr.config.ch_info.channels;
}
}
que.timestamp = memLoggerFetchTimestamp();
PAL_DBG(LOG_TAG, "TIME IS:" "%" PRId64 "\n", que.timestamp);
exit:
return ret;
}
int palStateEnqueue(Stream *s, pal_state_queue_state state, int32_t error)
{
int ret = 0;
struct pal_state_queue que;
ret = palStateQueueBuilder(que, s, state, error);
if (ret != 0)
{
PAL_ERR(LOG_TAG, "palStateQueueBuilder failed with status = %d", ret);
goto exit;
}
ret = memLoggerEnqueue(PAL_STATE_Q, (void*) &que);
if (ret != 0)
{
PAL_ERR(LOG_TAG, "memLoggerEnqueue failed with status = %d", ret);
}
exit:
return ret;
}
int palStateEnqueue(Stream *s, pal_state_queue_state state, int32_t error, pal_mlog_str_info str_info)
{
int ret = 0;
struct pal_state_queue que;
ret = palStateQueueBuilder(que, s, state, error);
if (ret != 0)
{
PAL_ERR(LOG_TAG, "palStateQueueBuilder failed with status = %d", ret);
goto exit;
}
memcpy(&(que.str_info), &str_info, sizeof(que.str_info));
ret = memLoggerEnqueue(PAL_STATE_Q, (void*) &que);
if (ret != 0)
{
PAL_ERR(LOG_TAG, "memLoggerEnqueue failed with status = %d", ret);
}
exit:
return ret;
}
void kpiEnqueue(const char name[], bool isEnter)
{
struct kpi_queue que;
strlcpy(que.func_name, name, sizeof(que.func_name));
que.pid = ::android::hardware::IPCThreadState::self()->getCallingPid();
que.timestamp = memLoggerFetchTimestamp();
que.type = isEnter;
memLoggerEnqueue(KPI_Q, (void*) &que);
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#define LOG_TAG "PAL: MetadataParser"
#include <string>
#include <log/log.h>
#include <unistd.h>
#include "PalDefs.h"
#include "MetadataParser.h"
int MetadataParser::parseMetadata(uint8_t* metadata, size_t metadataSize,
pal_clbk_buffer_info *bufferInfo) {
size_t mdBytesRead = 0;
if (!metadata || metadataSize < std::min(START_METADATA_SIZE(), END_METADATA_SIZE())) {
//TODO: may not work for multiple frames/buffer
ALOGE("%s: Metadata payload smaller than expected, bytes 0x%x, expected 0x%x",
__func__, mdBytesRead, std::min(START_METADATA_SIZE(), END_METADATA_SIZE()));
return -EINVAL;
}
while (mdBytesRead < metadataSize) {
metadata_header_t* metadataItem =
reinterpret_cast<metadata_header_t*>(metadata + mdBytesRead);
if (!metadataItem) {
return 0;
}
mdBytesRead += sizeof(metadata_header_t);
switch (metadataItem->metadata_id) {
//TODO: check if 2 start metadata/2 end metadata is present
case MODULE_CMN_MD_ID_BUFFER_START: {
size_t startMetadataPayloadSize = metadataItem->payload_size;
if (mdBytesRead + startMetadataPayloadSize > metadataSize) {
ALOGE("%s: Metadata item payload size larger than advertized metadata size"
" metadata id 0x%x, mdBytesRead = 0x%x, item payload size 0x%x,"
" metadata size = 0x%x ", __func__, metadataItem->metadata_id,
mdBytesRead, startMetadataPayloadSize, metadataSize);
return -EINVAL;
}
module_cmn_md_buffer_start_t* startMetadata =
reinterpret_cast<module_cmn_md_buffer_start_t*>(metadata + mdBytesRead);
if (!startMetadata) {
ALOGE("%s: Metadata start payload not found at offset 0x%x",
__func__, mdBytesRead);
return -EINVAL;
}
bufferInfo->frame_index = static_cast<uint64_t>((static_cast<uint64_t>(
startMetadata->buffer_index_msw) << 32) | startMetadata->buffer_index_lsw);
ALOGV("%s: startMetadata frame_index %llu", __func__, bufferInfo->frame_index);
mdBytesRead += sizeof(module_cmn_md_buffer_start_t);
break;
}
case MODULE_CMN_MD_ID_BUFFER_END: {
size_t endMetadataPayloadSize = metadataItem->payload_size;
if (mdBytesRead + endMetadataPayloadSize > metadataSize) {
ALOGE("%s: Metadata item payload size larger than advertized metadata size,"
" metadata id 0x%x, mdBytesRead = 0x%x, item payload size 0x%x,"
" metadata size = 0x%x ", __func__, metadataItem->metadata_id,
mdBytesRead, endMetadataPayloadSize, static_cast<uint32_t>(metadataSize));
return -EINVAL;
}
module_cmn_md_buffer_end_t* endMetadata =
reinterpret_cast<module_cmn_md_buffer_end_t*>(metadata + mdBytesRead);
if (!endMetadata) {
ALOGE("%s: Metadata end payload not found at offset 0x%x",
__func__, mdBytesRead);
return -EINVAL;
}
// TODO: compare previous input buffer index from start metadata,
// treat different values as error
bufferInfo->frame_index = static_cast<uint64_t>((static_cast<uint64_t>(
endMetadata->buffer_index_msw) << 32) | endMetadata->buffer_index_lsw);
if (endMetadata->flags) {
ALOGV("%s: End Metdata Flags=0x%x", __func__, endMetadata->flags);
if (((endMetadata->flags & MD_END_PAYLOAD_FLAGS_BIT_MASK_ERROR_RECOVERY_DONE)
>> MD_END_PAYLOAD_FLAGS_SHIFT_ERROR_RECOVERY_DONE)
== MD_END_RESULT_ERROR_RECOVERY_DONE ) {
ALOGI("%s: Error detected in input buffer and recovery attempted", __func__);
} else if ( ((endMetadata->flags & MD_END_PAYLOAD_FLAGS_BIT_MASK_ERROR_RESULT)
>> MD_END_PAYLOAD_FLAGS_SHIFT_ERROR_RESULT) == MD_END_RESULT_FAILED ) {
ALOGI("%s: Non-recoverable error detected in input buffer", __func__);
}
}
mdBytesRead += sizeof(module_cmn_md_buffer_end_t);
break;
}
case MODULE_CMN_MD_ID_MEDIA_FORMAT: {
size_t mfMetadataPayloadSize = metadataItem->payload_size;
if (mdBytesRead + mfMetadataPayloadSize > metadataSize){
ALOGE("%s: Metadata item payload size larger than advertized metadata size,"
" metadata id 0x%x, mdBytesRead = 0x%x, item payload size 0x%x,"
" metadata size = 0x%x ", __func__, metadataItem->metadata_id,
mdBytesRead, mfMetadataPayloadSize, metadataSize);
return -EINVAL;
}
media_format_t* mfPayload =
reinterpret_cast<media_format_t*>(metadata + mdBytesRead);
mdBytesRead += sizeof(media_format_t);
if (!mfPayload) {
ALOGE("%s: Media metadata payload not found at offset 0x%x",
__func__, mdBytesRead);
return -EINVAL;
}
if (mfPayload->fmt_id != MEDIA_FMT_ID_PCM) {
ALOGE("%s: Format ID within Media metadata payload not PCM,"
" fmt_id=x%x, offset=0x%x", __func__, mfPayload->fmt_id,
(uint32_t)offsetof(media_format_t, fmt_id));
return -EINVAL;
}
payload_media_fmt_pcm_t* pcmPayload =
reinterpret_cast<payload_media_fmt_pcm_t*>(metadata + mdBytesRead);
bufferInfo->sample_rate = pcmPayload->sample_rate;
bufferInfo->channel_count = pcmPayload->num_channels;
ALOGI("%s: sample_rate=%u, channel_count=%u", __func__,
bufferInfo->sample_rate, bufferInfo->channel_count);
mdBytesRead +=
ALIGN(sizeof(payload_media_fmt_pcm_t) +
pcmPayload->num_channels * sizeof(int8_t), 4);
break;
}
default: {
ALOGE("%s: Unknown Metadata marker found at offset 0x%x, Metadata ID=0x%x",
__func__, mdBytesRead, metadataItem->metadata_id);
// increment bytes read
mdBytesRead += metadataItem->payload_size;
break;
}
}
ALOGV("%s: mdBytesRead=%zu, metadataSize=%zu", __func__, mdBytesRead, metadataSize);
} // end while
return 0;
}
void MetadataParser::fillMetaData(uint8_t *metadata,
uint64_t frameIndex, size_t filledLength,
pal_media_config *streamMediaConfig) {
bool isEncode = false;
if (streamMediaConfig->aud_fmt_id == PAL_AUDIO_FMT_PCM_S8 ||
streamMediaConfig->aud_fmt_id == PAL_AUDIO_FMT_PCM_S16_LE ||
streamMediaConfig->aud_fmt_id == PAL_AUDIO_FMT_PCM_S24_LE ||
streamMediaConfig->aud_fmt_id == PAL_AUDIO_FMT_PCM_S24_3LE ||
streamMediaConfig->aud_fmt_id == PAL_AUDIO_FMT_PCM_S32_LE) {
isEncode = true;
}
auto getOffsetForEndMetadata = [&](uint32_t bufSize)
{
uint32_t sampleSizePerCh =
BYTES_PER_SAMPLE(streamMediaConfig->bit_width) *
streamMediaConfig->ch_info.channels;
return (isEncode) ? (bufSize / sampleSizePerCh) : bufSize;
};
// Fill start metadata
metadata_header_t* startMetadata = reinterpret_cast<metadata_header_t*>(metadata);
startMetadata->metadata_id = MODULE_CMN_MD_ID_BUFFER_START;
startMetadata->flags = static_cast<uint32_t>(MD_HEADER_FLAGS_BUFFER_ASSOCIATED << 4);
startMetadata->offset = 0;
startMetadata->payload_size = sizeof(module_cmn_md_buffer_start_t);
metadata += sizeof(metadata_header_t);
module_cmn_md_buffer_start_t startMetadataPayload = {GET_LSW(frameIndex),
GET_MSW(frameIndex)};
memcpy(reinterpret_cast<void*>(metadata),
reinterpret_cast<const void*>(&startMetadataPayload),
sizeof(module_cmn_md_buffer_start_t));
metadata += startMetadata->payload_size;
// Fill end metadata
metadata_header_t* endMetadata = reinterpret_cast<metadata_header_t*>(metadata);
endMetadata->metadata_id = MODULE_CMN_MD_ID_BUFFER_END;
endMetadata->flags = static_cast<uint32_t>(MD_HEADER_FLAGS_BUFFER_ASSOCIATED << 4);
endMetadata->offset = getOffsetForEndMetadata(filledLength);
endMetadata->payload_size = sizeof(module_cmn_md_buffer_end_t);
metadata += sizeof(metadata_header_t);
module_cmn_md_buffer_end_t endMetadataPayload = {GET_LSW(frameIndex),
GET_MSW(frameIndex),
0};
memcpy(reinterpret_cast<void*>(metadata),
reinterpret_cast<const void*>(&endMetadataPayload),
sizeof(module_cmn_md_buffer_end_t));
}

View File

@@ -0,0 +1,369 @@
/*
* 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 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: PalRingBuffer"
#ifdef LINUX_ENABLED
#include <algorithm>
#endif
#include "PalRingBuffer.h"
#include "PalCommon.h"
#include "StreamSoundTrigger.h"
int32_t PalRingBuffer::removeReader(PalRingBufferReader *reader)
{
auto iter = std::find(readers_.begin(), readers_.end(), reader);
if (iter != readers_.end())
readers_.erase(iter);
return 0;
}
size_t PalRingBuffer::read(std::shared_ptr<PalRingBufferReader>reader __unused,
void* readBuffer __unused, size_t readSize __unused)
{
return 0;
}
size_t PalRingBuffer::getFreeSize()
{
size_t freeSize = bufferEnd_;
std::vector<PalRingBufferReader*>::iterator it;
for (it = readers_.begin(); it != readers_.end(); it++) {
if ((*(it))->state_ == READER_ENABLED)
freeSize = std::min(freeSize, bufferEnd_ - (*(it))->unreadSize_);
}
return freeSize;
}
void PalRingBuffer::updateUnReadSize(size_t writtenSize)
{
int32_t i = 0;
std::vector<PalRingBufferReader*>::iterator it;
for (it = readers_.begin(); it != readers_.end(); it++, i++) {
(*(it))->unreadSize_ += writtenSize;
PAL_VERBOSE(LOG_TAG, "Reader (%d), unreadSize(%zu)", i, (*(it))->unreadSize_);
if ((*(it))->requestedSize_ > 0 &&
(*(it))->unreadSize_ >= (*(it))->requestedSize_) {
(*(it))->cv_.notify_one();
}
}
}
void PalRingBuffer::updateKwdConfig(Stream *s, uint32_t startIdx, uint32_t endIdx,
uint32_t preRoll)
{
uint32_t sz = 0;
struct kwdConfig kc;
std::vector<PalRingBufferReader *> readers = dynamic_cast<StreamSoundTrigger *>(s)->GetReaders();
std::lock_guard<std::mutex> lck(mutex_);
/*
* If the buffer is shared across concurrent detections, the first keyword
* offset is almost equal or close (depends on the max pre-roll in shared scenario)
* to the begining of the buffer. For the subsequent keyword, it can be
* far from the begining of the buffer relative to start of the keyword within
* the buffer. Since the unreadSize_ of subsequent detections is linearly
* increased from the first detection itself, adjust its starting from its
* pre-roll position in the buffer.
*/
sz = startIdx >= preRoll ? startIdx - preRoll : 0;
for (auto reader : readers) {
if (reader->unreadSize_ > sz) {
reader->unreadSize_ -= sz;
PAL_DBG(LOG_TAG, "adjusted unread size %zu", reader->unreadSize_);
}
reader->unreadSize_ %= bufferEnd_;
reader->readOffset_ = sz % bufferEnd_;
}
kc.startIdx = startIdx - sz;
kc.endIdx = endIdx - sz;
kc.ftrtSize = endIdx;
kwCfg_[s] = kc;
}
void PalRingBuffer::getIndices(Stream *s,
uint32_t *startIdx, uint32_t *endIdx, uint32_t *ftrtSize)
{
std::lock_guard<std::mutex> lck(mutex_);
*startIdx = kwCfg_[s].startIdx;
*endIdx = kwCfg_[s].endIdx;
*ftrtSize = kwCfg_[s].ftrtSize;
}
size_t PalRingBuffer::write(void* writeBuffer, size_t writeSize)
{
/* update the unread size for each reader*/
size_t freeSize = getFreeSize();
size_t writtenSize = 0;
size_t i = 0;
size_t sizeToCopy = 0;
std::lock_guard<std::mutex> lck(mutex_);
#ifndef SEC_AUDIO_ADD_FOR_DEBUG
PAL_DBG(LOG_TAG, "Enter. freeSize(%zu), writeOffset(%zu)", freeSize, writeOffset_);
#endif
if (writeSize <= freeSize)
sizeToCopy = writeSize;
else
sizeToCopy = freeSize;
if (sizeToCopy) {
//buffer wrapped around
if (writeOffset_ + sizeToCopy > bufferEnd_) {
i = bufferEnd_ - writeOffset_;
ar_mem_cpy(buffer_ + writeOffset_, i, writeBuffer, i);
writtenSize += i;
sizeToCopy -= writtenSize;
ar_mem_cpy(buffer_, sizeToCopy, (char*)writeBuffer + writtenSize,
sizeToCopy);
writtenSize += sizeToCopy;
writeOffset_ = sizeToCopy;
} else {
ar_mem_cpy(buffer_ + writeOffset_, sizeToCopy, writeBuffer,
sizeToCopy);
writeOffset_ += sizeToCopy;
writtenSize = sizeToCopy;
}
}
updateUnReadSize(writtenSize);
writeOffset_ = writeOffset_ % bufferEnd_;
#ifndef SEC_AUDIO_ADD_FOR_DEBUG
PAL_DBG(LOG_TAG, "Exit. writeOffset(%zu)", writeOffset_);
#endif
return writtenSize;
}
void PalRingBuffer::reset()
{
std::vector<PalRingBufferReader*>::iterator it;
mutex_.lock();
kwCfg_.clear();
writeOffset_ = 0;
mutex_.unlock();
/* Reset all the associated readers */
for (it = readers_.begin(); it != readers_.end(); it++)
(*(it))->reset();
}
void PalRingBuffer::resizeRingBuffer(size_t bufferSize)
{
if (buffer_) {
delete[] buffer_;
buffer_ = nullptr;
}
buffer_ = (char *)new char[bufferSize];
bufferEnd_ = bufferSize;
}
bool PalRingBufferReader::waitForBuffers(uint32_t buffer_size)
{
std::unique_lock<std::mutex> lck(mutex_);
if (state_ == READER_ENABLED) {
if (unreadSize_ >= buffer_size)
goto exit;
requestedSize_ = buffer_size;
cv_.wait_for(lck, std::chrono::milliseconds(3000));
}
exit:
requestedSize_ = 0;
return unreadSize_ >= buffer_size;
}
int32_t PalRingBufferReader::getKwData(Stream *s, uint8_t *data, uint32_t size)
{
size_t offset = 0;
std::lock_guard<std::mutex> lck(ringBuffer_->mutex_);
// assume that we always have enough data after 2nd stage done
if (readOffset_ + size > ringBuffer_->bufferEnd_) {
offset = ringBuffer_->bufferEnd_ - readOffset_;
ar_mem_cpy(data, offset,
ringBuffer_->buffer_ + readOffset_, offset);
ar_mem_cpy(data + offset, size - offset,
ringBuffer_->buffer_, size - offset);
} else {
ar_mem_cpy(data, size,
ringBuffer_->buffer_ + readOffset_, size);
}
return size;
}
int32_t PalRingBufferReader::read(void* readBuffer, size_t bufferSize)
{
int32_t readSize = 0;
if (state_ == READER_DISABLED) {
return -EINVAL;
} else if (state_ == READER_PREPARED) {
state_ = READER_ENABLED;
}
// Return 0 when no data can be read for current reader
if (unreadSize_ == 0)
return 0;
std::lock_guard<std::mutex> lck(ringBuffer_->mutex_);
// when writeOffset leads readOffset
if (ringBuffer_->writeOffset_ > readOffset_) {
unreadSize_ = ringBuffer_->writeOffset_ - readOffset_;
if (bufferSize >= unreadSize_) {
ar_mem_cpy(readBuffer, unreadSize_, ringBuffer_->buffer_ +
readOffset_, unreadSize_);
readOffset_ += unreadSize_;
readSize = unreadSize_;
unreadSize_ = 0;
} else {
ar_mem_cpy(readBuffer, unreadSize_, ringBuffer_->buffer_ +
readOffset_, bufferSize);
readOffset_ += bufferSize;
readSize = bufferSize;
unreadSize_ = ringBuffer_->writeOffset_ - readOffset_;
}
} else {
//When readOffset leads WriteOffset
int32_t freeClientSize = bufferSize;
int32_t i = ringBuffer_->bufferEnd_ - readOffset_;
if (bufferSize >= i) {
ar_mem_cpy(readBuffer, i, (char*)(ringBuffer_->buffer_ +
readOffset_), i);
readSize = i;
freeClientSize -= readSize;
unreadSize_ = ringBuffer_->writeOffset_;
readOffset_ = 0;
//copy remaining unread buffer
if (freeClientSize > unreadSize_) {
ar_mem_cpy((char *)readBuffer + readSize, unreadSize_,
ringBuffer_->buffer_, unreadSize_);
readSize += unreadSize_;
readOffset_ = unreadSize_;
unreadSize_ = 0;
} else {
//copy whatever we can
ar_mem_cpy((char *)readBuffer + readSize, freeClientSize,
ringBuffer_->buffer_, freeClientSize);
readSize += freeClientSize;
readOffset_ = freeClientSize;
unreadSize_ = ringBuffer_->writeOffset_ - readOffset_;
}
} else {
ar_mem_cpy(readBuffer, bufferSize, ringBuffer_->buffer_ +
readOffset_, bufferSize);
readSize = bufferSize;
readOffset_ += bufferSize;
unreadSize_ = ringBuffer_->bufferEnd_ - readOffset_ +
ringBuffer_->writeOffset_;
}
}
return readSize;
}
size_t PalRingBufferReader::advanceReadOffset(size_t advanceSize)
{
std::lock_guard<std::mutex> lock(ringBuffer_->mutex_);
readOffset_ = (readOffset_ + advanceSize) % ringBuffer_->bufferEnd_;
/*
* If the buffer is shared across concurrent detections, the second keyword
* can start anywhere in the buffer and possibly wrap around to the begining.
* For this case, advanceSize representing the start of keyword position in the
* buffer can be bigger than unReadSize_ which is aleady adjusted.
*/
if (unreadSize_ > advanceSize) {
unreadSize_ -= advanceSize;
} else {
PAL_DBG(LOG_TAG, "Warning: trying to advance read offset over write offset");
}
PAL_INFO(LOG_TAG, "offset %zu, advanced %zu, unread %zu", readOffset_, advanceSize, unreadSize_);
return advanceSize;
}
void PalRingBufferReader::updateState(pal_ring_buffer_reader_state state)
{
PAL_DBG(LOG_TAG, "update reader state to %d", state);
std::lock_guard<std::mutex> lock(ringBuffer_->mutex_);
state_ = state;
}
void PalRingBufferReader::getIndices(Stream *s,
uint32_t *startIdx, uint32_t *endIdx, uint32_t *ftrtSize)
{
ringBuffer_->getIndices(s, startIdx, endIdx, ftrtSize);
}
size_t PalRingBufferReader::getUnreadSize()
{
PAL_VERBOSE(LOG_TAG, "unread size %zu", unreadSize_);
return unreadSize_;
}
size_t PalRingBufferReader::getBufferSize()
{
return ringBuffer_->getBufferSize();
}
void PalRingBufferReader::reset()
{
std::lock_guard<std::mutex> lock(ringBuffer_->mutex_);
readOffset_ = 0;
unreadSize_ = 0;
state_ = READER_DISABLED;
requestedSize_ = 0;
cv_.notify_all();
}
PalRingBufferReader* PalRingBuffer::newReader()
{
PalRingBufferReader* reader =
new PalRingBufferReader(this);
readers_.push_back(reader);
return reader;
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#define NDEBUG 0
#define LOG_TAG "PAL: PerfLock"
#include <dlfcn.h>
#include "PalCommon.h"
#include "PerfLock.h"
#include <sstream>
PerfLock::PerfLock(const std::string &caller) : mCaller(caller) {
static bool isInit = init();
std::scoped_lock lock (sMutex);
acquire_l();
}
PerfLock::~PerfLock() {
std::scoped_lock lock (sMutex);
release_l();
}
void PerfLock::acquire_l() {
++sPerfLockCounter;
if (!sIsAcquired && sAcquirePerfLock != nullptr) {
sHandle = sAcquirePerfLock(0, 0, kPerfLockOpts.data(), kPerfLockOptsSize);
if (sHandle > 0) {
sIsAcquired = true;
PAL_VERBOSE(LOG_TAG, "succesful perf_lock_acq for %s", mCaller.c_str());
} else {
PAL_VERBOSE(LOG_TAG, "failed perf_lock_acq for %s", mCaller.c_str());
}
}
}
void PerfLock::release_l() {
--sPerfLockCounter;
if (sHandle > 0 && sReleasePerfLock != nullptr && (sPerfLockCounter == 0)) {
sReleasePerfLock(sHandle);
sIsAcquired = false;
PAL_VERBOSE(LOG_TAG, "succesful perf_lock_rel for %s", mCaller.c_str());
} else {
PAL_VERBOSE(LOG_TAG, "failed perf_lock_rel for %s", mCaller.c_str());
}
}
void PerfLock::setPerfLockOpt(const PerfLockConfig & config) {
if (config.usePerfLock) {
kPerfLockOptsSize = config.perfLockOpts.size();
kPerfLockOpts = config.perfLockOpts;
sLibraryName = config.libraryName;
}
}
// static
bool PerfLock::init() {
void* libHandle = dlopen(sLibraryName.c_str(), RTLD_LAZY);
if (libHandle == nullptr) {
const char* error = dlerror();
PAL_ERR(LOG_TAG, "Failed to dlopen %s error %s", sLibraryName.c_str(), error);
return false;
}
sAcquirePerfLock = reinterpret_cast<AcquirePerfLock>(dlsym(libHandle, "perf_lock_acq"));
if (sAcquirePerfLock == nullptr) {
PAL_ERR(LOG_TAG, "failed to find perf_lock_acq ");
dlclose(libHandle);
return false;
}
sReleasePerfLock = reinterpret_cast<ReleasePerfLock>(dlsym(libHandle, "perf_lock_rel"));
if (sReleasePerfLock == nullptr) {
PAL_ERR(LOG_TAG, "failed to find perf_lock_rel ");
dlclose(libHandle);
return false;
}
std::stringstream hexStream;
for (const auto i : kPerfLockOpts) {
hexStream << std::hex << i << " ";
}
PAL_INFO(LOG_TAG, "initialized perflock library %s size %d, locks %s", sLibraryName.c_str(),
kPerfLockOptsSize, hexStream.str().c_str());
return true;
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted (subject to the limitations in the
* disclaimer below) 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 Qualcomm Innovation Center, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
* GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
* HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER 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_NDEBUG 0
#define LOG_TAG "PAL: SignalHandler"
#include <unistd.h>
#include <log/log.h>
#include <chrono>
#include "SignalHandler.h"
#ifdef _ANDROID_
#include <utils/ProcessCallStack.h>
#include <cutils/android_filesystem_config.h>
#endif
std::mutex SignalHandler::sDefaultSigMapLock;
std::unordered_map<int, std::shared_ptr<struct sigaction>> SignalHandler::sDefaultSigMap;
std::function<void(int, pid_t, uid_t)> SignalHandler::sClientCb;
std::mutex SignalHandler::sAsyncRegisterLock;
std::future<void> SignalHandler::sAsyncHandle;
bool SignalHandler::sBuildDebuggable;
// static
void SignalHandler::asyncRegister(int signal) {
std::lock_guard<std::mutex> lock(sAsyncRegisterLock);
sigset_t pendingSigMask;
uint32_t tries = kDefaultSignalPendingTries;
// Delay registration to let default signal handler complete
do {
std::this_thread::sleep_for(
std::chrono::milliseconds(kDefaultRegistrationDelayMs));
sigpending(&pendingSigMask);
--tries;
} while (tries > 0 && sigismember(&pendingSigMask, signal) == 1);
// Register custom handler only if signal is not pending
if (!sigismember(&pendingSigMask, signal)) {
std::vector<int> signals({ signal });
getInstance()->registerSignalHandler(signals);
}
}
// static
void SignalHandler::setClientCallback(std::function<void(int, pid_t, uid_t)> cb) {
sClientCb = cb;
}
// static
std::shared_ptr<SignalHandler> SignalHandler::getInstance() {
static std::shared_ptr<SignalHandler> instance(new SignalHandler());
return instance;
}
// static
void SignalHandler::invokeDefaultHandler(std::shared_ptr<struct sigaction> sAct,
int code, struct siginfo *si, void *sc) {
ALOGE("%s: invoke default handler for signal %d", __func__, code);
// Remove custom handler so that default handler is invoked
sigaction(code, sAct.get(), NULL);
int status = 0;
if (si->si_code == SI_QUEUE) {
ALOGE("signal %d (%s), code -1 "
"(SI_QUEUE from pid %d, uid %d)",
code, sigToName.at(code).c_str(),
si->si_pid, si->si_uid);
status = sigqueue(getpid(), code, si->si_value);
#ifdef _ANDROID_
if(isBuildDebuggable() && si->si_uid == AID_AUDIOSERVER) {
std::string prefix = "audioserver_" + std::to_string(si->si_pid) + " ";
android::ProcessCallStack pcs;
pcs.update();
pcs.log(LOG_TAG, ANDROID_LOG_FATAL, prefix.c_str());
}
#endif
} else {
status = raise(code);
}
if (status < 0) {
ALOGW("%s: Sending signal %d failed with error %d",
__func__, code, errno);
}
// Register custom handler back asynchronously
sAsyncHandle = std::async(std::launch::async, SignalHandler::asyncRegister, code);
}
// static
void SignalHandler::customSignalHandler(
int code, struct siginfo *si, void *sc) {
ALOGV("%s: enter", __func__);
std::lock_guard<std::mutex> lock(sDefaultSigMapLock);
if (sClientCb) {
sClientCb(code, si->si_pid, si->si_uid);
}
// Invoke default handler
auto it = sDefaultSigMap.find(code);
if (it != sDefaultSigMap.end()) {
invokeDefaultHandler(it->second, code, si, sc);
}
}
// static
std::vector<int> SignalHandler::getRegisteredSignals() {
std::vector<int> registeredSignals;
std::lock_guard<std::mutex> lock(sDefaultSigMapLock);
for (const auto& element : sDefaultSigMap) {
registeredSignals.push_back(element.first);
}
return registeredSignals;
}
void SignalHandler::registerSignalHandler(std::vector<int> signalsToRegister) {
ALOGV("%s: enter", __func__);
struct sigaction regAction = {};
regAction.sa_sigaction = customSignalHandler;
regAction.sa_flags = SA_SIGINFO | SA_NODEFER;
std::lock_guard<std::mutex> lock(sDefaultSigMapLock);
for (int signal : signalsToRegister) {
ALOGV("%s: register signal %d", __func__, signal);
auto oldSigAction = std::make_shared<struct sigaction>();
if (sigaction(signal, &regAction, oldSigAction.get()) < 0) {
ALOGW("%s: Failed to register handler with error code %d for signal %d",
__func__, errno, signal);
}
sDefaultSigMap.emplace(signal, oldSigAction);
}
}

View File

@@ -0,0 +1,396 @@
/*
* 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) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "ACDPlatformInfo.h"
#include "VoiceUIPlatformInfo.h"
#include "ASRPlatformInfo.h"
#include "SoundTriggerPlatformInfo.h"
#include "PalCommon.h"
#define LOG_TAG "PAL: SoundTriggerPlatformInfo"
SoundTriggerUUID::SoundTriggerUUID() :
timeLow(0),
timeMid(0),
timeHiAndVersion(0),
clockSeq(0) {
}
bool SoundTriggerUUID::operator<(const SoundTriggerUUID& rhs) const {
if (timeLow > rhs.timeLow)
return false;
else if (timeLow < rhs.timeLow)
return true;
/* timeLow is equal */
if (timeMid > rhs.timeMid)
return false;
else if (timeMid < rhs.timeMid)
return true;
/* timeLow and timeMid are equal */
if (timeHiAndVersion > rhs.timeHiAndVersion)
return false;
else if (timeHiAndVersion < rhs.timeHiAndVersion)
return true;
/* timeLow, timeMid and timeHiAndVersion are equal */
if (clockSeq > rhs.clockSeq)
return false;
else if (clockSeq < rhs.clockSeq)
return true;
//check node
for (int i = 0; i < 6; i++) {
if (node[i] > rhs.node[i]) {
return false;
}
else if(node[i] < rhs.node[i]){
return true;
}
}
/* everything is equal */
return false;
}
SoundTriggerUUID& SoundTriggerUUID::operator = (SoundTriggerUUID& rhs) {
this->clockSeq = rhs.clockSeq;
this->timeLow = rhs.timeLow;
this->timeMid = rhs.timeMid;
this->timeHiAndVersion = rhs.timeHiAndVersion;
memcpy(node, rhs.node, sizeof(node));
return *this;
}
bool SoundTriggerUUID::CompareUUID(const struct st_uuid uuid) const {
if (uuid.timeLow != timeLow ||
uuid.timeMid != timeMid ||
uuid.timeHiAndVersion != timeHiAndVersion ||
uuid.clockSeq != clockSeq)
return false;
for (int i = 0; i < 6; i++) {
if (uuid.node[i] != node[i]) {
return false;
}
}
return true;
}
int SoundTriggerUUID::StringToUUID(const char* str,
SoundTriggerUUID& UUID) {
int tmp[10];
if (str == NULL) {
return -EINVAL;
}
if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
tmp, tmp + 1, tmp + 2, tmp + 3, tmp + 4, tmp + 5, tmp + 6,
tmp + 7, tmp + 8, tmp + 9) < 10) {
return -EINVAL;
}
UUID.timeLow = (uint32_t)tmp[0];
UUID.timeMid = (uint16_t)tmp[1];
UUID.timeHiAndVersion = (uint16_t)tmp[2];
UUID.clockSeq = (uint16_t)tmp[3];
UUID.node[0] = (uint8_t)tmp[4];
UUID.node[1] = (uint8_t)tmp[5];
UUID.node[2] = (uint8_t)tmp[6];
UUID.node[3] = (uint8_t)tmp[7];
UUID.node[4] = (uint8_t)tmp[8];
UUID.node[5] = (uint8_t)tmp[9];
return 0;
}
CaptureProfile::CaptureProfile(const std::string name) :
name_(name),
device_id_(PAL_DEVICE_IN_MIN),
sample_rate_(16000),
channels_(1),
bitwidth_(16),
device_pp_kv_(std::make_pair(0, 0)),
snd_name_("va-mic"),
is_ec_req_(false),
backend_("va_macro")
{
}
void CaptureProfile::HandleStartTag(const char* tag, const char** attribs)
{
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!strcmp(attribs[i], "device_id")) {
auto itr = deviceIdLUT.find(attribs[++i]);
if (itr == deviceIdLUT.end()) {
PAL_ERR(LOG_TAG, "could not find key %s in lookup table",
attribs[i]);
} else {
device_id_ = itr->second;
}
} else if (!strcmp(attribs[i], "sample_rate")) {
sample_rate_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "bit_width")) {
bitwidth_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "channels")) {
channels_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "snd_name")) {
snd_name_ = attribs[++i];
} else if (!strcmp(attribs[i], "ec_ref")) {
is_ec_req_ = !strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "backend")) {
backend_ = attribs[++i];
} else {
PAL_ERR(LOG_TAG, "Invalid attribute %s", attribs[i++]);
}
++i; /* move to next attribute */
}
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", (char *)tag);
}
}
/*
* Priority compare result indicated by return value as below:
* 1. CAPTURE_PROFILE_PRIORITY_HIGH
* current capture profile has higher priority than cap_prof
* 2. CAPTURE_PROFILE_PRIORITY_LOW
* current capture profile has lower priority than cap_prof
* 3. CAPTURE_PROFILE_PRIORITY_SAME
* current capture profile has same priority than cap_prof
*/
int32_t CaptureProfile::ComparePriority(std::shared_ptr<CaptureProfile> cap_prof)
{
int32_t priority_check = 0;
if (!cap_prof) {
priority_check = CAPTURE_PROFILE_PRIORITY_HIGH;
} else {
/* Comparing channel numbers, sample rate,
* and bitwidth together to check priority.
*/
if (backend_.compare(cap_prof->GetBackend()) != 0) {
PAL_DBG(LOG_TAG, "Skip priority comparison between %s and %s",
backend_.c_str(), cap_prof->GetBackend().c_str());
priority_check = -EINVAL;
goto exit;
}
if (channels_ != cap_prof->GetChannels()) {
channels_ > cap_prof->GetChannels() ? priority_check++ : priority_check--;
}
if (sample_rate_ != cap_prof->GetSampleRate()) {
sample_rate_ > cap_prof->GetSampleRate() ? priority_check++ : priority_check--;
}
if (bitwidth_ != cap_prof->GetBitWidth()) {
bitwidth_ > cap_prof->GetBitWidth() ? priority_check++ : priority_check--;
}
}
exit:
return priority_check;
}
std::shared_ptr<SoundTriggerPlatformInfo> SoundTriggerPlatformInfo::me_ = nullptr;
bool SoundTriggerPlatformInfo::lpi_enable_ = true;
bool SoundTriggerPlatformInfo::support_nlpi_switch_ = true;
bool SoundTriggerPlatformInfo::support_device_switch_ = false;
bool SoundTriggerPlatformInfo::enable_debug_dumps_ = false;
bool SoundTriggerPlatformInfo::concurrent_capture_ = false;
bool SoundTriggerPlatformInfo::concurrent_voice_call_ = false;
bool SoundTriggerPlatformInfo::concurrent_voip_call_ = false;
bool SoundTriggerPlatformInfo::low_latency_bargein_enable_ = false;
SoundTriggerPlatformInfo::SoundTriggerPlatformInfo() : curr_child_(nullptr)
{
}
std::shared_ptr<SoundTriggerPlatformInfo> SoundTriggerPlatformInfo::GetInstance()
{
if (!me_)
me_ = std::shared_ptr<SoundTriggerPlatformInfo>(new SoundTriggerPlatformInfo);
return me_;
}
void SoundTriggerPlatformInfo::ReadCapProfileNames(StOperatingModes mode,
const char** attribs,
st_op_modes_t& op_modes)
{
uint32_t i = 0;
while (attribs[i]) {
if (!strcmp(attribs[i], "capture_profile_handset")) {
op_modes[std::make_pair(mode, ST_INPUT_MODE_HANDSET)] =
capture_profile_map_.at(std::string(attribs[++i]));
} else if(!strcmp(attribs[i], "capture_profile_headset")) {
op_modes[std::make_pair(mode, ST_INPUT_MODE_HEADSET)] =
capture_profile_map_.at(std::string(attribs[++i]));
} else {
PAL_ERR(LOG_TAG, "Error:%d got unexpected attribute: %s",
-EINVAL, attribs[i]);
}
++i; /* move to next attribute */
}
}
void SoundTriggerPlatformInfo::HandleStartTag(const char* tag, const char** attribs)
{
/* Delegate to child element if currently active */
if (curr_child_) {
curr_child_->HandleStartTag(tag, attribs);
return;
}
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
if (!strcmp(tag, "vui_platform_info")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
VoiceUIPlatformInfo::GetInstance());
return;
}
if (!strcmp(tag, "acd_platform_info")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
ACDPlatformInfo::GetInstance());
return;
}
if (!strcmp(tag, "asr_platform_info")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
ASRPlatformInfo::GetInstance());
return;
}
if (!strcmp(tag, "capture_profile")) {
if (attribs[0] && !strcmp(attribs[0], "name")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
std::make_shared<CaptureProfile>(attribs[1]));
return;
} else {
PAL_ERR(LOG_TAG,"missing name attrib for tag %s", tag);
return;
}
}
if (!strcmp(tag, "common_config") || !strcmp(tag, "capture_profile_list")) {
PAL_VERBOSE(LOG_TAG, "tag:%s appeared, nothing to do", tag);
return;
}
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!attribs[i]) {
PAL_ERR(LOG_TAG,"missing attrib value for tag %s", tag);
} else if (!strcmp(attribs[i], "lpi_enable")) {
lpi_enable_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "support_nlpi_switch")) {
support_nlpi_switch_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "support_device_switch")) {
support_device_switch_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "enable_debug_dumps")) {
enable_debug_dumps_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "concurrent_capture")) {
concurrent_capture_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "concurrent_voice_call") &&
concurrent_capture_) {
concurrent_voice_call_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "concurrent_voip_call") &&
concurrent_capture_) {
concurrent_voip_call_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "low_latency_bargein_enable")) {
low_latency_bargein_enable_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else {
PAL_ERR(LOG_TAG, "Invalid attribute %s", attribs[i++]);
}
++i; /* move to next attribute */
}
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", tag);
}
}
void SoundTriggerPlatformInfo::HandleEndTag(struct xml_userdata *data, const char* tag)
{
PAL_DBG(LOG_TAG, "Got end tag %s", tag);
if (!strcmp(tag, "capture_profile")) {
std::shared_ptr<CaptureProfile> cap_prof(
std::static_pointer_cast<CaptureProfile>(curr_child_));
const auto res = capture_profile_map_.insert(
std::make_pair(cap_prof->GetName(), cap_prof));
if (!res.second)
PAL_ERR(LOG_TAG, "Failed to insert to map");
curr_child_ = nullptr;
} else if (!strcmp(tag, "acd_platform_info") ||
!strcmp(tag, "vui_platform_info") ||
!strcmp(tag, "asr_platform_info")) {
curr_child_ = nullptr;
}
if (curr_child_)
curr_child_->HandleEndTag(data, tag);
return;
}
std::shared_ptr<CaptureProfile> SoundTriggerPlatformInfo::GetCaptureProfileFromMap(std::string cap_prof_name)
{
st_cap_profile_map_t::iterator it;
it = capture_profile_map_.find(cap_prof_name);
if (it != capture_profile_map_.end())
return it->second;
else
return nullptr;
}

View File

@@ -0,0 +1,513 @@
/*
* 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 are provided under the following license:
* Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include "VoiceUIPlatformInfo.h"
#include "PalCommon.h"
#include "SoundTriggerUtils.h"
#define LOG_TAG "PAL: VoiceUIPlatformInfo"
static const struct st_uuid qcva_uuid =
{ 0x68ab2d40, 0xe860, 0x11e3, 0x95ef, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } };
VUISecondStageConfig::VUISecondStageConfig() :
detection_type_(ST_SM_TYPE_NONE),
sm_id_(0),
module_lib_(""),
sample_rate_(16000),
bit_width_(16),
channels_(1)
{
}
void VUISecondStageConfig::HandleStartTag(const char *tag, const char **attribs)
{
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!strcmp(attribs[i], "sm_detection_type")) {
i++;
if (!strcmp(attribs[i], "KEYWORD_DETECTION")) {
detection_type_ = ST_SM_TYPE_KEYWORD_DETECTION;
} else if (!strcmp(attribs[i], "USER_VERIFICATION")) {
detection_type_ = ST_SM_TYPE_USER_VERIFICATION;
} else if (!strcmp(attribs[i], "CUSTOM_DETECTION")) {
detection_type_ = ST_SM_TYPE_CUSTOM_DETECTION;
}
} else if (!strcmp(attribs[i], "sm_id")) {
sm_id_ = std::strtoul(attribs[++i], nullptr, 16);
} else if (!strcmp(attribs[i], "module_lib")) {
module_lib_ = attribs[++i];
} else if (!strcmp(attribs[i], "sample_rate")) {
sample_rate_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "bit_width")) {
bit_width_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "channel_count")) {
channels_ = std::stoi(attribs[++i]);
}
++i;
}
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", tag);
}
}
VUIFirstStageConfig::VUIFirstStageConfig() :
module_type_(ST_MODULE_TYPE_GMM),
module_name_("GMM"),
lpi_supported_(true)
{
for (int i = 0; i < MAX_PARAM_IDS; i++) {
module_tag_ids_[i] = 0;
param_ids_[i] = 0;
}
}
void VUIFirstStageConfig::HandleStartTag(const char *tag, const char **attribs)
{
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!strcmp(attribs[i], "module_type")) {
i++;
module_name_ = attribs[i];
if (!strcmp(attribs[i], "GMM")) {
module_type_ = ST_MODULE_TYPE_GMM;
} else if (!strcmp(attribs[i], "PDK")) {
module_type_ = ST_MODULE_TYPE_PDK;
} else if (!strcmp(attribs[i], "HOTWORD")) {
module_type_ = ST_MODULE_TYPE_HW;
} else if (!strcmp(attribs[i], "CUSTOM1")) {
module_type_ = ST_MODULE_TYPE_CUSTOM_1;
} else if (!strcmp(attribs[i], "CUSTOM2")) {
module_type_ = ST_MODULE_TYPE_CUSTOM_2;
} else if (!strcmp(attribs[i], "MMA")) {
module_type_ = ST_MODULE_TYPE_MMA;
}
PAL_DBG(LOG_TAG, "Module name:%s, type:%d",
module_name_.c_str(), module_type_);
} else if (!strcmp(attribs[i], "lpi_supported")) {
lpi_supported_ = !strcmp(attribs[++i], "true");
} else {
uint32_t index = 0;
if (!strcmp(attribs[i], "load_sound_model_ids")) {
index = LOAD_SOUND_MODEL;
} else if (!strcmp(attribs[i], "unload_sound_model_ids")) {
index = UNLOAD_SOUND_MODEL;
} else if (!strcmp(attribs[i], "wakeup_config_ids")) {
index = WAKEUP_CONFIG;
} else if (!strcmp(attribs[i], "buffering_config_ids")) {
index = BUFFERING_CONFIG;
} else if (!strcmp(attribs[i], "engine_reset_ids")) {
index = ENGINE_RESET;
} else if (!strcmp(attribs[i], "custom_config_ids")) {
index = CUSTOM_CONFIG;
} else if (!strcmp(attribs[i], "version_ids")) {
index = MODULE_VERSION;
} else if (!strcmp(attribs[i], "engine_per_model_reset_ids")) {
index = ENGINE_PER_MODEL_RESET;
}
sscanf(attribs[++i], "%x, %x", &module_tag_ids_[index],
&param_ids_[index]);
PAL_DBG(LOG_TAG, "index : %u, module_id : %x, param : %x",
index, module_tag_ids_[index], param_ids_[index]);
}
++i;
}
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", tag);
}
}
VUIStreamConfig::VUIStreamConfig() :
vui_intf_plugin_lib_name_(""),
is_qcva_uuid_(false),
merge_first_stage_sound_models_(false),
capture_keyword_(2000),
client_capture_read_delay_(2000),
pre_roll_duration_(0),
supported_first_stage_engine_count_(1),
enable_concurrent_event_capture_(false),
curr_child_(nullptr)
{
ext_det_prop_list_.clear();
}
/*
* Below functions GetVUIFirstStageConfig(), GetVUIModuleType(),
* and GetVUIModuleName() are to be used only for getting module
* info and module type/name for third party or custom sound model
* engines. It assumes only one module type per vendor UUID.
*/
std::shared_ptr<VUIFirstStageConfig> VUIStreamConfig::GetVUIFirstStageConfig()
{
auto smCfg = vui_uuid_1st_stage_cfg_list_.find(vendor_uuid_);
if(smCfg != vui_uuid_1st_stage_cfg_list_.end())
return smCfg->second;
else
return nullptr;
}
st_module_type_t VUIStreamConfig::GetVUIModuleType()
{
std::shared_ptr<VUIFirstStageConfig> sTModuleInfo = GetVUIFirstStageConfig();
if (sTModuleInfo != nullptr)
return sTModuleInfo->GetModuleType();
else
return ST_MODULE_TYPE_NONE;
}
std::string VUIStreamConfig::GetVUIModuleName()
{
std::shared_ptr<VUIFirstStageConfig> sTModuleInfo = GetVUIFirstStageConfig();
if (sTModuleInfo != nullptr)
return sTModuleInfo->GetModuleName();
else
return std::string();
}
std::shared_ptr<VUISecondStageConfig> VUIStreamConfig::GetVUISecondStageConfig(
const listen_model_indicator_enum& sm_type) const
{
uint32_t sm_id = static_cast<uint32_t>(sm_type);
auto ss_config = vui_2nd_stage_cfg_list_.find(sm_id);
if (ss_config != vui_2nd_stage_cfg_list_.end())
return ss_config->second;
else
return nullptr;
}
std::shared_ptr<VUIFirstStageConfig> VUIStreamConfig::GetVUIFirstStageConfig(const uint32_t type) const
{
uint32_t module_type = type;
PAL_DBG(LOG_TAG, "search module for model type %u", type);
if (IS_MODULE_TYPE_PDK(type)) {
PAL_DBG(LOG_TAG, "PDK module");
module_type = ST_MODULE_TYPE_PDK;
}
auto module_config = vui_1st_stage_cfg_list_.find(module_type);
if (module_config != vui_1st_stage_cfg_list_.end())
return module_config->second;
else
return nullptr;
}
void VUIStreamConfig::GetDetectionPropertyList(
std::vector<uint32_t> &list) {
for (int i = 0; i < ext_det_prop_list_.size(); i++)
list.push_back(ext_det_prop_list_[i]);
}
void VUIStreamConfig::ReadDetectionPropertyList(const char *prop_string)
{
int ret = 0;
char *token = nullptr;
char *delims = ",";
char *save = nullptr;
PAL_VERBOSE(LOG_TAG, "Detection property list %s", prop_string);
token = strtok_r(const_cast<char *>(prop_string), delims, &save);
while (token) {
ext_det_prop_list_.push_back(std::strtoul(token, nullptr, 16));
token = strtok_r(NULL, delims, &save);
}
for (int i = 0; i < ext_det_prop_list_.size(); i++) {
PAL_INFO(LOG_TAG, "Found extension detection property 0x%x",
ext_det_prop_list_[i]);
}
}
bool VUIStreamConfig::IsDetPropSupported(uint32_t prop) const {
auto iter =
std::find(ext_det_prop_list_.begin(), ext_det_prop_list_.end(), prop);
return iter != ext_det_prop_list_.end();
}
void VUIStreamConfig::HandleStartTag(const char* tag, const char** attribs)
{
/* Delegate to child element if currently active */
if (curr_child_) {
curr_child_->HandleStartTag(tag, attribs);
return;
}
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
if (!strcmp(tag, "first_stage_module_params")) {
auto st_module_info_ = std::make_shared<VUIFirstStageConfig>();
vui_uuid_1st_stage_cfg_list_.insert(std::make_pair(vendor_uuid_, st_module_info_));
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(st_module_info_);
return;
}
if (!strcmp(tag, "arm_ss_module_params")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
std::make_shared<VUISecondStageConfig>());
return;
}
if (!strcmp(tag, "operating_modes") || !strcmp(tag, "sound_model_info")
|| !strcmp(tag, "name")) {
PAL_DBG(LOG_TAG, "tag:%s appeared, nothing to do", tag);
return;
}
std::shared_ptr<SoundTriggerPlatformInfo> st_info = SoundTriggerPlatformInfo::GetInstance();
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!strcmp(attribs[i], "vendor_uuid")) {
UUID::StringToUUID(attribs[++i], vendor_uuid_);
if (vendor_uuid_.CompareUUID(qcva_uuid))
is_qcva_uuid_ = true;
} else if (!strcmp(attribs[i], "interface_plugin_lib")) {
vui_intf_plugin_lib_name_ = attribs[++i];
} else if (!strcmp(attribs[i], "get_module_version")) {
get_module_version_supported_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "merge_first_stage_sound_models")) {
merge_first_stage_sound_models_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "pdk_first_stage_max_engine_count")) {
supported_first_stage_engine_count_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "enable_concurrent_event_capture")) {
enable_concurrent_event_capture_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "capture_keyword")) {
capture_keyword_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "client_capture_read_delay")) {
client_capture_read_delay_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "pre_roll_duration")) {
pre_roll_duration_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "kw_start_tolerance")) {
kw_start_tolerance_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "kw_end_tolerance")) {
kw_end_tolerance_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "data_before_kw_start")) {
data_before_kw_start_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "data_after_kw_end")) {
data_after_kw_end_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "sample_rate")) {
sample_rate_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "bit_width")) {
bit_width_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "out_channels")) {
if (std::stoi(attribs[++i]) <= MAX_MODULE_CHANNELS)
out_channels_ = std::stoi(attribs[i]);
} else if (!strcmp(attribs[i], "detection_property_list")) {
ReadDetectionPropertyList(attribs[++i]);
} else {
PAL_ERR(LOG_TAG, "Invalid attribute %s", attribs[i++]);
}
++i; /* move to next attribute */
}
} else if (!strcmp(tag, "low_power")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_LOW_POWER, attribs, vui_op_modes_);
} else if (!strcmp(tag, "high_performance")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_HIGH_PERF, attribs, vui_op_modes_);
} else if (!strcmp(tag, "high_performance_and_charging")) {
st_info->ReadCapProfileNames(ST_OPERATING_MODE_HIGH_PERF_AND_CHARGING, attribs, vui_op_modes_);
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", (char *)tag);
}
}
void VUIStreamConfig::HandleEndTag(struct xml_userdata *data, const char* tag)
{
PAL_DBG(LOG_TAG, "Got end tag %s", tag);
if (!strcmp(tag, "first_stage_module_params")) {
std::shared_ptr<VUIFirstStageConfig> st_module_info(
std::static_pointer_cast<VUIFirstStageConfig>(curr_child_));
const auto res = vui_1st_stage_cfg_list_.insert(
std::make_pair(st_module_info->GetModuleType(), st_module_info));
if (!res.second)
PAL_ERR(LOG_TAG, "Failed to insert to map");
curr_child_ = nullptr;
} else if (!strcmp(tag, "arm_ss_module_params")) {
std::shared_ptr<VUISecondStageConfig> ss_cfg(
std::static_pointer_cast<VUISecondStageConfig>(curr_child_));
const auto res = vui_2nd_stage_cfg_list_.insert(
std::make_pair(ss_cfg->GetSoundModelID(), ss_cfg));
if (!res.second)
PAL_ERR(LOG_TAG, "Failed to insert to map");
curr_child_ = nullptr;
}
if (curr_child_)
curr_child_->HandleEndTag(data, tag);
return;
}
std::shared_ptr<VoiceUIPlatformInfo> VoiceUIPlatformInfo::me_ = nullptr;
VoiceUIPlatformInfo::VoiceUIPlatformInfo() :
enable_failure_detection_(false),
transit_to_non_lpi_on_charging_(false),
notify_second_stage_failure_(false),
mmap_enable_(false),
mmap_buffer_duration_(0),
mmap_frame_length_(0),
sound_model_lib_("liblistensoundmodel2vendor.so"),
curr_child_(nullptr)
{
}
std::shared_ptr<VUIStreamConfig> VoiceUIPlatformInfo::GetStreamConfig(const UUID& uuid) const
{
auto smCfg = stream_cfg_list_.find(uuid);
if (smCfg != stream_cfg_list_.end())
return smCfg->second;
else
return nullptr;
}
// We can assume only Hotword sm config supports version api
void VoiceUIPlatformInfo::GetStreamConfigForVersionQuery(
std::vector<std::shared_ptr<VUIStreamConfig>> &sm_cfg_list) const
{
std::shared_ptr<VUIStreamConfig> sm_cfg = nullptr;
for (auto iter = stream_cfg_list_.begin();
iter != stream_cfg_list_.end(); iter++) {
sm_cfg = iter->second;
if (sm_cfg && sm_cfg->GetModuleVersionSupported())
sm_cfg_list.push_back(sm_cfg);
}
}
std::shared_ptr<VoiceUIPlatformInfo> VoiceUIPlatformInfo::GetInstance()
{
if (!me_)
me_ = std::shared_ptr<VoiceUIPlatformInfo> (new VoiceUIPlatformInfo);
return me_;
}
void VoiceUIPlatformInfo::HandleStartTag(const char* tag, const char** attribs)
{
/* Delegate to child element if currently active */
if (curr_child_) {
curr_child_->HandleStartTag(tag, attribs);
return;
}
PAL_DBG(LOG_TAG, "Got start tag %s", tag);
if (!strcmp(tag, "stream_config")) {
curr_child_ = std::static_pointer_cast<SoundTriggerXml>(
std::make_shared<VUIStreamConfig>());
return;
}
if (!strcmp(tag, "config")) {
PAL_DBG(LOG_TAG, "tag:%s appeared, nothing to do", tag);
return;
}
if (!strcmp(tag, "param")) {
uint32_t i = 0;
while (attribs[i]) {
if (!attribs[i]) {
PAL_ERR(LOG_TAG,"missing attrib value for tag %s", tag);
} else if (!strcmp(attribs[i], "version")) {
vui_version_ = std::strtoul(attribs[++i], nullptr, 16);
} else if (!strcmp(attribs[i], "enable_failure_detection")) {
enable_failure_detection_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "transit_to_non_lpi_on_charging")) {
transit_to_non_lpi_on_charging_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "notify_second_stage_failure")) {
notify_second_stage_failure_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "mmap_enable")) {
mmap_enable_ =
!strncasecmp(attribs[++i], "true", 4) ? true : false;
} else if (!strcmp(attribs[i], "mmap_buffer_duration")) {
mmap_buffer_duration_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "mmap_frame_length")) {
mmap_frame_length_ = std::stoi(attribs[++i]);
} else if (!strcmp(attribs[i], "sound_model_lib")) {
sound_model_lib_ = std::string(attribs[++i]);
} else {
PAL_ERR(LOG_TAG, "Invalid attribute %s", attribs[i++]);
}
++i; /* move to next attribute */
}
} else {
PAL_ERR(LOG_TAG, "Invalid tag %s", tag);
}
}
void VoiceUIPlatformInfo::HandleEndTag(struct xml_userdata *data, const char* tag)
{
PAL_DBG(LOG_TAG, "Got end tag %s", tag);
if (!strcmp(tag, "stream_config")) {
std::shared_ptr<VUIStreamConfig> sm_cfg(
std::static_pointer_cast<VUIStreamConfig>(curr_child_));
const auto res = stream_cfg_list_.insert(
std::make_pair(sm_cfg->GetUUID(), sm_cfg));
if (!res.second)
PAL_ERR(LOG_TAG, "Failed to insert to map");
curr_child_ = nullptr;
}
if (curr_child_)
curr_child_->HandleEndTag(data, tag);
return;
}