Merge "st-hal: Add support for SVA sound models merging"
diff --git a/ListenSoundModelLib.h b/ListenSoundModelLib.h
new file mode 100644
index 0000000..888f79a
--- /dev/null
+++ b/ListenSoundModelLib.h
@@ -0,0 +1,919 @@
+/*
+ * ListenSoundModelLib.h
+ *
+ * This is the interface file of sound model library which provides
+ * the APIs to get sound model information and merge, delete functionality
+ * which will be used by STHAL.
+ *
+ * Copyright (c) 2019, 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.
+ */
+
+/*======================================================================
+DESCRIPTION : ListenSoundModelLibrary Version 3
+====================================================================*/
+
+#ifndef __LISTEN_SOUND_MODEL_LIB_V3_H__
+#define __LISTEN_SOUND_MODEL_LIB_V3_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#if defined(_SML_NO_DLL)
+#define DllFunc
+#define CDECLARE
+#elif defined(_MSC_VER) && defined(_EXPORT)
+#define DllFunc __declspec( dllexport )
+#define CDECLARE __cdecl
+#elif defined(_MSC_VER)
+#define DllFunc __declspec( dllimport )
+#define CDECLARE __cdecl
+#else // For other compiler like gcc
+#define DllFunc
+#define CDECLARE
+#endif
+
+#define LSMLIB_VERSION 2 // %%% some unique number that changes when API changes
+ // %%% could be == SoundModel version supported for SVA 2.0
+
+#define MAX_STRING_LEN (100 * 2) // maximum byte size of string representing Unicode character string
+// %%% NOTE: "MAX_STRING_LEN" replaces old constant "MAX_KEYWORD"
+
+
+// SVA 2.0
+// Keyword & User Identifier as zero terminated strings
+typedef char * keywordId_t;
+typedef char * userId_t;
+
+
+typedef struct {
+ //state machine parameters
+ float minSnrOnset; // The minimum snr of frame that speech segment starts
+ float minSnrLeave; // The minimum snr of frame that speech segment ends
+ float snrFloor; // The minimum snr value assumed in the end point detector
+ float snrThresholds; // The minimum snr value of speech to verify
+ float forgettingFactorNoise; // The forgetting factor used for noise estimation
+ int numFrameTransientFrame; // the number of frames in the beginning that are used for noise estimate(valid only for online mode)
+ float minEnergyFrameRatio; // the number of frame are used for noise estimation = minenergyFrameRatio * #frames of input(valid only for batch mode)
+
+ //post processing parameters
+ //Note:
+ int numMinFramesInPhrase; // the minimum nubmer of samples for a speech phrase (targetted speech)
+ int numMinFramesInSpeech; //the minimum number of samples for a speech intereval
+ int numMaxFrameInSpeechGap; //the maximum allowable number of samples for a speech gap
+ int numFramesInHead; //the speech head
+ int numFramesInTail; //the speech tail
+} listen_epd_params;
+
+typedef struct {
+ int16_t *data; /* Audio samples ( in Raw PCM format: 16kHz, 16bit, mono ) */
+ uint32_t n_samples; /* number of audio samples */
+} listen_user_recording;
+
+typedef struct {
+ uint8_t *data; /* block of memory containing Model data */
+ uint32_t size; /* size of memory allocated for Model data */
+} listen_language_model_type;
+
+typedef struct {
+ uint8_t *data; /* block of memory containing Model data */
+ uint32_t size; /* size of memory allocated for Model data */
+} listen_model_type;
+
+// kwihyuk - comments will update
+// %%% the numbering - names are up to you, as long as type + version is unique between SVA 1.0 and 2.0 SMs
+typedef enum {
+ kKeywordModel = 1, /* Keyword model */
+ kUserKeywordModel = 2, /* Userkeyword model */
+ kTargetSoundModel = 3,
+ kMultiUserKeywordModel = 4, /* Multiple Keyword models */
+ kKeywordModelWithVop = 5, //kwihyuk
+ kSecondStageKeywordModel = 6, //kwihyuk
+ kSecondStageKeywordModelWithVop = 7, //kwihyuk
+} listen_model_enum;
+
+typedef enum {
+ kSuccess = 0,
+ kFailure = 1
+} listen_detection_status_enum;
+
+typedef struct {
+ listen_model_enum type; /* model type: Keyword, User, TargetSound */
+ uint32_t version; /* model version */
+ uint32_t size; /* total size of the model: header + payload size */
+} listen_sound_model_info;
+
+
+typedef struct {
+ listen_detection_status_enum status; // SUCCESS or FAILURE
+ uint32_t size; // size in bytes of payload data
+ // just contains result confidence level values
+ uint8_t *data; // block of memory containing data payload
+} listen_event_payload;
+
+// SVA 2.0
+typedef struct {
+ uint16_t numKeywords; /* total number of keywords */
+ uint16_t numUsers; /* total number of users */
+ uint16_t numActiveUserKeywordPairs; /* total number of active user+keyword pairs in SM */
+ bool isStripped; /* if corresponding keyword is stripped or not */
+ uint16_t *langPerKw; /* Language code of each keyword */
+ /* number active Users per keyword - included as convenience */
+ uint16_t *numUsersSetPerKw;
+ bool *isUserDefinedKeyword;
+ /* Ordered 'truth' table of all possible pairs of users for each keyword.
+ * Active entries marked with 1, inactive 0.keywordPhrase
+ * 16-bit short (rather than boolean) is used to match SM model data size */
+ uint16_t **userKeywordPairFlags;
+ uint16_t model_indicator; /* for SM 3.0, indicate which models were combined */
+} listen_sound_model_header;
+
+
+
+
+// SVA 2.0
+// %%% this should match the 'sensitivity' data structure input in VoiceWakeupParamType
+typedef struct {
+ uint8_t size ; // number of keyword plus activePair confidence levels set d
+ uint8_t *pConfLevels; // level of each keyword and each active user+keyword pair
+} listen_confidence_levels ;
+
+// SVA 2.0
+typedef enum {
+ kSingleKWDetectionEvent = 1, /* SVA 1.0 model */
+ kMultiKWDetectionEvent = 2, /* SVA 2.0 model */
+} listen_detection_type_enum;
+
+
+// duplicates existing SVA1.0 typedef
+// Do not include listen_detection_entry_v1 in SVA 1.0 header if both headers included
+typedef struct {
+ char keyword[MAX_STRING_LEN];
+ uint16_t keywordConfidenceLevel;
+ uint16_t userConfidenceLevel;
+} listen_detection_event_v1;
+
+// denotes that a particular entry in confidence level array is not active
+static const uint8_t NO_CONF_LEVEL = 0;
+
+typedef struct {
+
+ char keywordPhrase[MAX_STRING_LEN]; /* string containing phrase string of keyword with highest confidence score */
+ char userName[MAX_STRING_LEN]; /* string containing name of user with highest confidence score */
+
+ uint8_t highestKeywordConfidenceLevel; // set to zero if detection status is Failed
+ uint8_t highestUserConfidenceLevel; // set to zero if detection status is Failed
+
+ listen_confidence_levels pairConfidenceLevels; // confidence levels of ALL pair (active or not)
+} listen_detection_event_v2;
+
+// modified for SVA 2.0 - this should override SVA 1.0 typedef
+typedef struct {
+ // %%% uint16_t version;
+ listen_detection_type_enum detection_data_type;
+ // data structure filled is based on detection_data_type
+ union {
+ listen_detection_event_v1 event_v1; // for SVA 1.0
+ listen_detection_event_v2 event_v2; // for SVA 2.0
+ } event;
+} listen_detection_event_type;
+
+typedef enum {
+ kSucess = 0,
+ kFailed = 1,
+ kBadParam,
+ kKeywordNotFound,
+ kUserNotFound,
+ kUserKwPairNotActive,
+ kSMVersionUnsupported,
+ kUserDataForKwAlreadyPresent,
+ kDuplicateKeyword,
+ kDuplicateUserKeywordPair,
+ kMaxKeywordsExceeded,
+ kMaxUsersExceeded,
+ kEventStructUnsupported, // payload contains event data that can not be processed, or mismatches SM version
+ kLastKeyword,
+ kNoSignal,
+ kLowSnr,
+ kRecordingTooShort,
+ kRecordingTooLong,
+ kNeedRetrain,
+ kUserUDKPairNotRemoved,
+ kCannotCreateUserUDK,
+ kOutputArrayTooSmall,
+ kTooManyAbnormalUserScores,
+ kWrongModel,
+ kWrongModelAndIndicator,
+ kDuplicateModel,
+} listen_status_enum;
+
+/*
+* Notes:
+* 1. The client code that calls getKeywordPhrases(), getUserNames() must allocate DstStr as [MAX_STRING_LEN]
+* 2. The client code that calls getUserKeywordModelSize(), createUserDefinedKeywordModel(),
+* createUserKeywordModel() should assign meaningful string for keywordId or userId, empty string is not recommended.
+* 3. verifyUserRecording() should be called before calling createUserKeywordModel(). If pConfidenceLevel returned
+* in verifyUserRecording() is below a CONFIDENCE_THRESHOLD value, the recording should be rejected and not used
+* to a create user model. The client code should decide the CONFIDENCE_THRESHOLD value, a recommended value range for
+* CONFIDENCE_THRESHOLD is 60~70.
+*
+*/
+
+ /*
+ * findKeywordEndPosition
+ *
+ * Returns the keyword end position of user recordings from the keyword model
+ * the keyword model finds the keyword end position by using keyword end finding algorithm inside SVA
+ *
+ * Param [in] pKeywordModel - pointer to keyword model data which will be used to find keyword end
+ * Param [in] keywordId - null terminated string contains keyword phrase string
+ * Param [in] pUserRecording - a single recording of user speaking keyword
+ other speech such as following command may follows
+ * Param [out] pKendPosition - returns keyword end position from the start of user recording in number of samples
+ *
+ * Return - status
+ * kBadParam - When any input pointer (except pEpdParameter) is NULL
+ * kKeywordNotFound - When keywordId not exist in the model
+ * kSMVersionUnsupported - When pKeywordModel is not 2.0 model
+ */
+DllFunc listen_status_enum CDECLARE findKeywordEndPosition(
+ listen_model_type *pKeywordModel,
+ keywordId_t keywordId,
+ listen_user_recording *pUserRecording,
+ uint32_t *pKendPosition);
+
+ /*
+ * verifyUserRecording
+ *
+ * Returns the confidence level ( 0 ~ 100 ) that user recording matches keyword
+ * User data is to be appended for a specific keyword in the model
+ * // will be updated or removed
+ * if input is SM 3.0 which combiend with GMM and other sound models,
+ * then parsing to GMM model and run same procedure.
+ *
+ * Param [in] pKeywordModel - pointer to user-independent keyword model data
+ * Param [in] keywordId - null terminated string contains keyword phrase string
+ * Param [in] listen_epd_params - epd parameter
+ if null is passing, default epd parameter will be used internally
+ * Param [in] pUserRecording - a single recording of user speaking keyword
+ * Param [out] pConfidenceLevel - returns confidence level returned by keyword detection
+ *
+ * Return - status
+ * kBadParam - When any input pointer (except pEpdParameter) is NULL
+ * kKeywordNotFound - When keywordId not exist in the model
+ * kSMVersionUnsupported - When pKeywordModel is not 2.0 (have to contain GMM) model
+ * kLowSnr - When user recording is too noisy
+ * kNoSignal - When user recording is non-speech
+ */
+DllFunc listen_status_enum CDECLARE verifyUserRecording(
+ listen_model_type *pKeywordModel,
+ keywordId_t keywordId, // add for SVA 2.0
+ listen_epd_params *pEpdParameter,
+ listen_user_recording *pUserRecording,
+ int16_t *pConfidenceLevel);
+
+ /*
+ * checkUserRecording
+ *
+ * Returns the status of user recordings that if user recording has problem with SNR(Signal Noise Ratio) and length
+ *
+ * Param [in] pLanguageModel - pointer to language model
+ * Param [in] pEpdParameter - pointer to EPD parameters
+ * Default parameter will be used if eEpdParameter is NULL
+ * Param [in] pUserRecording - User recording that is going to be tested
+ * Param [out] pOutSnr - SNR of user recording
+ * Param [in] maxPhonemeLength (optional parameter) - maximum phoneme length allowed for each user recording
+ * - It is optional parameter, whose default value is 0.
+ *
+ * Return - status
+ * kBadParam - When any input pointer (except pEpdParameter) is NULL
+ * kLowSnr - When user recording is too noisy
+ * kNoSignal - When user recording is non-speech
+ * kRecordingTooShort - When user recording is too short
+ */
+DllFunc listen_status_enum CDECLARE checkUserRecording(
+ listen_language_model_type *pLanguageModel,
+ listen_epd_params *pEpdParameter,
+ listen_user_recording *pUserRecording,
+ float *pOutSnr,
+ uint32_t maxPhonemeLength);
+
+ /*
+ * checkRecordingsQuality
+ *
+ * Returns the status of the last user recording in recording array that
+ * if user recording has problem with SNR(Signal Noise Ratio) and length
+ * Check the consistency of the input recordings if numUserRecording > 1
+ *
+ * Param [in] pLanguageModel - pointer to language model
+ * Param [in] pEpdParameter - pointer to EPD parameters
+ * Default parameter will be used if eEpdParameter is NULL
+ * Param [in] numUserRecording - number of input recordings
+ * Param [in] pUserRecordings - User recordings those are going to be tested
+ * Param [out] pOutSnr - SNR of user recording
+ *
+ * Return - status
+ * kBadParam - When any input pointer (except pEpdParameter) is NULL
+ * kLowSnr - When user recording is too noisy
+ * kNoSignal - When user recording is non-speech
+ * kRecordingTooShort - When user recording is too short
+ */
+
+DllFunc listen_status_enum CDECLARE checkRecordingsQuality(
+ listen_language_model_type *pLanguageModel,
+ listen_epd_params *pEpdParameter,
+ uint32_t numUserRecording,
+ listen_user_recording *pUserRecordings[],
+ float *pOutSnr);
+
+ /*
+ * tuneUserDefinedKeywordModelThreshold
+ *
+ * This function tunes threshold of user defined keyword.
+ *
+ * This function can be used when programmer want to make testing stage after training stage of user defined keyword
+ * even though threshold of user defined keyword is automatically tunned when create user defined keyword,
+ * this function can be useful when tune more threshold of user defined keyword
+ *
+ * Param [in] pUserDefinedKeyword - pointer to user defined keyword
+ * Param [in] keywordId - keyword spell
+ * Param [in] pUserRecording - user recording from testing stage
+ * Param [out] pOutputUserDefinedKeyword - tunned user defined keyword
+ *
+ * Return - listen_status_enum
+ * Return - status
+ * kBadParam - When any input pointer is NULL, or pUserDefinedKeyword is not UDK
+ * kKeywordNotFound - When keywordId not exist in the model
+ */
+DllFunc listen_status_enum CDECLARE tuneUserDefinedKeywordModelThreshold(
+ listen_model_type *pUserDefinedKeyword,
+ keywordId_t keywordId,
+ listen_user_recording *pUserRecording,
+ listen_model_type *pOutputUserDefinedKeyword);
+
+
+ /*
+ * getUserDefinedKeywordSize
+ *
+ * Get the size required to hold user defined keyword model that extends given keyword model
+ * with give user data
+ *
+ * Param [in] pUserDefinedKeyword - pointer to previous user defined keyword
+ if pUserDefinedKeyword is NULL, this will create new user defined keyword model
+ if pUserDefinedKeyword is not NULL, this will train incrementally ( not supported now )
+
+ * Param [in] keywordId - keyword spell of user defined keyword
+ * Param [in] userId - user spell of user defined keyword
+ * Param [in] pEpdParameter - epd parameter which is used for chopping user recording.
+ if eEpdParameter is NULL, default parameter will be used
+ * Param [in] numUserRecording - number of user recording
+ * Param [in] pUserRecordings[] - multiple recording of user speaking keyword
+ * Param [in] pLanguageModel - language model
+ * Param [out] pOutputSize - pointer to where output model size will be written
+ *
+ * Return - listen_status_enum
+ * Return - status
+ * kBadParam - When any input pointer (except pUserDefinedKeyword, pEpdParameter) is NULL, or pLanguageModel is fake
+ * kNoSignal - When user recording is non-speech
+ */
+DllFunc listen_status_enum CDECLARE getUserDefinedKeywordSize(
+ listen_model_type *pUserDefinedKeyword,
+ keywordId_t keywordId,
+ userId_t userId,
+ listen_epd_params *pEpdParameter,
+ uint32_t numUserRecording,
+ listen_user_recording *pUserRecordings[],
+ listen_language_model_type *pLanguageModel,
+ uint32_t *pOutputSize);
+
+ /*
+ * getUserDefinedKeywordApproxSize
+ *
+ * Get the size required to hold user-keyword model that extends given keyword model
+ * with give user data
+ *
+ * Param [in] keywordId - null terminated string containing keyword phrase string
+ * Param [in] userId - null terminated string containing user name string
+ * Param [in] pLanguageModel - pointer to language model data
+ * Param [out] pOutputSize - size of approximated output model
+ * Param [in] maxPhonemeLength (optional parameter) - maximum phoneme length allowed for each user recording
+ * - It is optional parameter, whose default value is 0.
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ */
+
+DllFunc listen_status_enum CDECLARE getUserDefinedKeywordApproxSize(
+ keywordId_t keywordId,
+ userId_t userId,
+ listen_language_model_type *pLanguageModel,
+ uint32_t *pOutputSize,
+ uint32_t maxPhonemeLength);
+
+ /*
+ * createUserDefinedKeywordModel
+ *
+ * Description : Create User Defined Keyword Model
+ *
+ * Param [in] pUserDefinedKeyword - pointer to previous user defined keyword
+ if pUserDefinedKeyword is NULL, this will create new user defined keyword model
+ if pUserDefinedKeyword is not NULL, this will train incrementally ( not supported now )
+
+ * Param [in] keywordId - keyword spell of user defined keyword
+ * Param [in] userId - user spell of user defined keyword
+ * Param [in] pEpdParameter - epd parameter which is used for chopping user recording.
+ if eEpdParameter is NULL, default parameter will be used
+ * Param [in] numUserRecording - number of user recording
+ * Param [in] pUserRecordings[] - multiple recording of user speaking keyword
+ * Param [in] pLanguageModel - language model
+ * Param [out] pOutputUserDefinedKeyword - pointer to where output model will be written
+ * Param [out] pMatchingScore - pointer to matching score
+ *
+ * Return - listen_status_enum
+ * Return - status
+ * kBadParam - When any input pointer (except pUserDefinedKeyword, pEpdParameter) is NULL, or pLanguageModel is fake
+ * kNoSignal - When user recording is non-speech
+ * kCannotCreateUserUDK - When creation process fails somewhere
+ * kOutputArrayTooSmall - When output size is smaller than actual udk model size
+ */
+DllFunc listen_status_enum CDECLARE createUserDefinedKeywordModel(
+ listen_model_type *pUserDefinedKeyword,
+ keywordId_t keywordId,
+ userId_t userId,
+ listen_epd_params *pEpdParameter,
+ uint32_t numUserRecording,
+ listen_user_recording *pUserRecordings[],
+ listen_language_model_type *pLanguageModel,
+ listen_model_type *pOutputUserDefinedKeyword,
+ int16_t *pMatchingScore);
+
+ /*
+ * getStrippedUserKeywordModelSize
+ *
+ * Return stripped model size
+ *
+ * Param[in] pModel - pointer to (user)keyword model data
+ * Param[out] nStrippedModelSize - return model size of stripped model
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kSMVersionUnsupported - When pModel is not 2.0 model
+ *
+ */
+DllFunc listen_status_enum CDECLARE getStrippedUserKeywordModelSize(
+ listen_model_type *pModel,
+ uint32_t *nStrippedModelSize);
+
+
+ /*
+ * stripUserKeywordModel
+ *
+ * Return stripped model
+ *
+ * Param[in] pModel - pointer to (user)keyword model data
+ * Param[out] pStrippedModel - pointer to stripped model data
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kSMVersionUnsupported - When pModel is not 2.0 model
+ *
+ */
+DllFunc listen_status_enum CDECLARE stripUserKeywordModel(
+ listen_model_type *pModel,
+ listen_model_type *pStrippedModel);
+
+ /*
+ * getUserKeywordModelSize
+ *
+ * Get the size required to hold user-keyword model that extends given keyword model
+ * with give user data
+ *
+ * Param [in] pKeywordModel - pointer to keyword model data
+ * Param [in] keywordId - null terminated string containing keyword phrase string
+ * Param [in] userId - null terminated string containing user name string
+ * Param [out] nUserKeywordModelSize - size of user keyword model
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kKeywordNotFound - When keywordId not exist in the model
+ * kSMVersionUnsupported - When pKeywordModel is not 2.0/3.0 model
+ */
+DllFunc listen_status_enum CDECLARE getUserKeywordModelSize(
+ listen_model_type *pKeywordModel,
+ keywordId_t keywordId, // add for SVA 2.0
+ userId_t userId, // add for SVA 2.0
+ uint32_t *nUserKeywordModelSize);
+
+ /*
+ * createUserKeywordModel
+ *
+ * Create a user keyword model
+ * Writes the user keyword model into given memory location
+ *
+ * Param [in] pKeywordModel - pointer to Keyword model or User keyword model data
+ if it is keyword model, create user-keyword model
+ if it is user keyword model, incrementally train user keyword model
+ * Param [in] keywordId - user data is to be appended for keyword in model with given identifier
+ * Param [in] userId - identifier of user data is created
+ * If identifier is already used, will replace existing user data with newly created data.
+ * The User Name is passed to this function so that if this is the first time user data is
+ * being added for a new user, the User's Name can be stored in the SM
+ * Param [in] pEpdParameter - end point detection parameter
+ * if eEpdParameter is NULL, default parameter will be used
+ * Param [in] numUserRecording - number of user recordings
+ * Param [in] pUserRecordings - multiple recording of user speaking keyword
+ * Param [out] pUserKeywordModel - pointer to where user keyword model data is to be written
+ * Param [out] pUserMatchingScore - pointer to user matching score
+ * Return - status
+ * kBadParam - When any input pointer (except pEpdParameter) is NULL
+ * kKeywordNotFound - When keywordId not exist in the model
+ * kSMVersionUnsupported - When pKeywordModel is not 2.0 or 3.0 model
+ * kLowSnr - When user recording is too noisy
+ * kNoSignal - When user recording is non-speech
+ * kCannotCreateUserUDK - When pKeywordModel is UDK model
+ */
+DllFunc listen_status_enum CDECLARE createUserKeywordModel(
+ listen_model_type *pKeywordModel,
+ keywordId_t keywordId, // add for SVA 2.0
+ userId_t userId, // add for SVA 2.0
+ listen_epd_params *pEpdParameter,
+ uint32_t numUserRecording,
+ listen_user_recording *pUserRecordings[],
+ listen_model_type *pUserKeywordModel,
+ int16_t *pUserMatchingScore);
+
+// Since size of new SM after removing data will be less than or equal to size of
+// input SM, this function could be optional and size of pInputModel could be used
+// to allocate memory for pResultModel when deleteFromModel() called.
+ /*
+ * getSizeAfterDeleting
+ *
+ * Return the size of sound model after removing data from a given SM for either
+ * a keyword, a user, or a specific user+keyword pair.
+ *
+ * Param [in] pInputModel - pointer to sound model
+ * Param [in] keywordId - data for this keyword in model with given identifier is removed
+ * If userId is 'null', then all keyword-only data and all user data associated
+ * with the given non-null keywordId is removed.
+ * If userId is also non-null, then only data associated with the userId+keywordId
+ * pair is removed.
+ * Param [in] userId - all data for this user in model with given identifier is removed
+ * If keywordId is 'null', then all all user data for the given non-null userId
+ * is removed.
+ * If keywordId is also non-null, then only data associated with the userId+keywordId
+ * pair is removed.
+ * Param [out] nOutputModelSize - outputs size of resulting soundmodel after removing data.
+ * Return - status
+ * kBadParam - When any input pointer (except keywordId, userId) is NULL
+ * kLastKeyword - When pInputModel has only one keyword
+ * kSMVersionUnsupported - When pInputModel is not 2.0 model
+ * kKeywordNotFound - When keywordId not exist in the model
+ * kUserNotFound - When userId not exist in the model
+ * kUserKWPairNotActive - When <keywordId, userId> pair not exist in the model
+ * kUserUDKPairNotRemoved - When <keywordId, userId> pair to delete is UDK
+ */
+DllFunc listen_status_enum CDECLARE getSizeAfterDeleting(
+ listen_model_type *pInputModel,
+ keywordId_t keywordId, // add for SVA 2.0
+ userId_t userId, // add for SVA 2.0
+ uint32_t *nOutputModelSize);
+
+// If getSizeAfterDeleting() supported, call it get size of new sound model after
+// removing desired data from given input sound model, and
+// allocate ResultModel with this size
+// Otherwise, use size of input SoundModel since size of ResultModel will be
+// less than or equal to size of input SoundModel.
+ /*
+ * deleteFromModel
+ *
+ * Return a new sound model after removing data from a given SM for a keyword, a user,
+ * or a user+keyword pair.
+ *
+ * Param [in] pInputModel - pointer to sound model
+ * Param [in] keywordId - data for this keyword in model with given identifier is removed
+ * If userId is 'null', then all keyword-only data and all user data associated
+ * with the given non-null keywordId is removed.
+ * If userId is also non-null, then only data associated with the userId+keywordId
+ * pair is removed.
+ * Param [in] userId - all data for this user in model with given identifier is removed
+ * If keywordId is 'null', then all all user data for the given non-null userId
+ * is removed.
+ * If keywordId is also non-null, then only data associated with the userId+keywordId
+ * pair is removed.
+ * Param [out] pResultModel - pointer to where user keyword model data is to be written
+ * Return - status
+ * kBadParam - When any input pointer (except keywordId, userId) is NULL
+ * kLastKeyword - When pInputModel has only one keyword
+ * kSMVersionUnsupported - When pInputModel is not 2.0 or 3.0 model
+ * kKeywordNotFound - When keywordId not exist in the model
+ * kUserNotFound - When userId not exist in the model
+ * kUserKWPairNotActive - When <keywordId, userId> pair not exist in the model
+ * kUserUDKPairNotRemoved - When <keywordId, userId> pair to delete is UDK
+ */
+DllFunc listen_status_enum CDECLARE deleteFromModel(
+ listen_model_type *pInputModel,
+ keywordId_t keywordId, // add for SVA 2.0
+ userId_t userId, // add for SVA 2.0
+ listen_model_type *pResultModel);
+
+
+ /*
+ * getMergedModelSize
+ *
+ * Return the size of sound model after merging required models
+ *
+ * Param [in] numModels - number of model files to be merged
+ * Param [in] pModels - array of pointers to Keyword or User keyword model data
+ * Param [out] nOutputModelSize - outputs size of resulting soundmodel after merging models
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kSMVersionUnsupported - When pInputModel is not 2.0 model
+ * kDuplicateKeyword - When same keywordId exists in more than 1 model
+ * kDuplicateUserKeywordPair
+ * kMaxKeywordsExceeded
+ * kMaxUsersExceeded,
+ */
+DllFunc listen_status_enum CDECLARE getMergedModelSize(
+ uint16_t numModels,
+ listen_model_type *pModels[],
+ uint32_t *nOutputModelSize);
+
+
+
+ /*
+ * mergeModels
+ *
+ * merges two or more Sound Models
+ *
+ * Writes the new merged model into given memory location
+ *
+ * Param [in] numModels - number of model files to be merged
+ * Param [in] pModels - array of pointers to Keyword or User keyword model data
+ * Param [out] pMergedModel - pointer to where merged model data is to be written
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kSMVersionUnsupported - When pInputModel is not 2.0 model
+ * kDuplicateKeyword - When same keywordId exists in more than 1 model
+ * kDuplicateUserKeywordPair - N/A to current version
+ * kMaxKeywordsExceeded - N/A to current version
+ * kMaxUsersExceeded - N/A to current version
+ */
+DllFunc listen_status_enum CDECLARE mergeModels(
+ uint16_t numModels,
+ listen_model_type *pModels[],
+ listen_model_type *pMergedModel);
+
+
+
+/* ParseFromBigSoundModel
+*
+* Parse the big 3.0 sound model to individual sub models
+*
+* Param [in] *pSM3p0Model – The pointer to the big 3.0 sound model
+* Param [out] p1stStageModel - pointer to parsed 1stStageModel
+* Param [out] p2ndStageKWModel - pointer to parsed 2nd stage KW Model
+* Param [out] p2stStageVoPModel - pointer to parsed 2nd stage VoP Model
+* Param [out] indicator – returned indicator, indicating what types of models parsed/returned
+* Return - status
+* kBadParam - When any input pointer is NULL
+* kSMVersionUnsupported - When pInputModel is not 3.0 model
+* kDuplicateKeyword - When same keywordId exists in more than 1 model
+* kWrongModel - when input is broken
+*/
+
+DllFunc listen_status_enum CDECLARE parseFromBigSoundModel(
+ listen_model_type *pSM3p0Model,
+ listen_model_type *p1stStageModel,
+ listen_model_type *p2ndStageKWModel,
+ listen_model_type *p2stStageVoPModel,
+ uint16_t *indicator );
+
+
+
+
+ /*
+ * parseDetectionEventData
+ *
+ * parse event payload into detection event.
+ *
+ * Version of input SM will detemine DetectionType created/returned
+ *
+ * Param [in] pUserKeywordModel - pointer to keyword or user keyword model data
+ * Param [in] pEventPayload - pointer to received event payload data
+ * Param [out] pDetectEvent - pointer to where detection event data is to be written
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kSMVersionUnsupported - When pUserKeywordModel is not 2.0 model
+ * kEventStructUnsupported - When pEventPayload->size != numKeywords + numActiveUsers
+ */
+
+DllFunc listen_status_enum CDECLARE parseDetectionEventData(
+ listen_model_type *pUserKeywordModel,
+ listen_event_payload *pEventPayload,
+ listen_detection_event_type *pDetectionEvent);
+
+
+// Declared in both SVA 1.0 and SVA 2.0 versions and SML 3.0 of ListenSoundModelMLib
+//
+ /*
+ * querySoundModel
+ *
+ * Returns the information about a sound model
+ * Sound model could be of any type: Keyword, UserKeyword, TargetSound,...
+ * Sound model could be any versions
+ *
+ * Param [in] pSoundModel - pointer to model data
+ * Param [out] pListenSoundModelInfo - returns information about the give sound model
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kFailed - When input model failed to be decoded
+ * kSMVersionUnsupported - When pSoundModel is fake model (invalid model other than 1.0 model, 2.0 model and 3.0 model)
+ */
+DllFunc listen_status_enum CDECLARE querySoundModel(
+ listen_model_type *pSoundModel,
+ listen_sound_model_info *pListenSoundModelInfo);
+
+
+ /*
+ * getSoundModelHeader
+ *
+ * Returns additional information about the sound model
+ * Sound model could be of any type: Keyword, UserKeyword, TargetSound,...
+ * Keyword
+ *
+ * Param [in] pSoundModel - pointer to model data
+ * Param [out] pListenSoundModelHeader - returns header field from sound model
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kSMVersionUnsupported - When pSoundModel is not 2.0 or 3.0 model
+ */
+
+DllFunc listen_status_enum CDECLARE getSoundModelHeader(
+ listen_model_type *pSoundModel,
+ listen_sound_model_header *pListenSoundModelHeader);
+
+
+ /*
+ * release sound model header
+ *
+ * deallocate sound model header
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ */
+DllFunc listen_status_enum CDECLARE releaseSoundModelHeader(
+ listen_sound_model_header *pListenSoundModelHeader);
+
+
+ /*
+ * getKeywordPhrases
+ *
+ * Get keyword phrase string for all Keywords defined in given SM 2.0 / 3.0
+ *
+ * App calling this function must allocate memory for all phrases
+ * by getting the number of keywords from querySoundModel() and allocating
+ * totalNumKeywords*MAX_STRING_LEN
+ * This function copies phrases into this allocated keywords array
+ *
+ * Param [in] pSoundModel - pointer to model data
+ * Param [in/out] numKeywords - [in] number of string entries allocated in keywords array
+ * [out] number of keyword phrase strings copied keyword array
+ * Param [out] keywords - array of keyword phrase null-terminated strings
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL, or numKeywords < real keywords number
+ * kSMVersionUnsupported - When pSoundModel is not 2.0 or 3.0 model
+ */
+DllFunc listen_status_enum CDECLARE getKeywordPhrases(
+ listen_model_type *pSoundModel,
+ uint16_t *numKeywords,
+ keywordId_t *keywords);
+
+
+ /*
+ * getUserNames
+ *
+ * Get user names for user data associated with a given SM 2.0 / 3.0
+ *
+ * App calling this function must allocate memory for all names
+ * by getting the number of users from querySoundModel() and allocating
+ * totalNumUsers*MAX_STRING_LEN
+ * This function copies names into this allocated keywords array
+ *
+ * Param [in] pSoundModel - pointer to model data
+ * Param [in/out] numUsers - [in] number of string entries allocated in users array
+ * [out] number of user name strings copied users array
+ * Param [out] users - array of user name null-terminated strings
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL, or numUsers < real users number, or pSoundModel is keyword-only model
+ * kSMVersionUnsupported - When pSoundModel is not 2.0 or 3.0 model
+ */
+DllFunc listen_status_enum CDECLARE getUserNames(
+ listen_model_type *pSoundModel,
+ uint16_t *numUsers,
+ userId_t *users);
+
+ /*
+ * loadConfParams
+ *
+ * Load configurable parameters to the sound model library
+ *
+ * Param [in] pConfData - pointer to param data
+ * Param [in] confDataSize - size of memory allocated for param data
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ */
+DllFunc listen_status_enum CDECLARE loadConfParams(
+ uint8_t *pConfData,
+ uint32_t confDataSize);
+ /*
+ * getBinaryModelSize
+ *
+ * Return binary model size
+ *
+ * Param[in] pListenModel - pointer to (user)keyword model data
+ * Param[out] nBinaryModelSize - return model size of binary model
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kSMVersionUnsupported - When pModel is not 2.0 or 3.0 model
+ *
+ */
+
+DllFunc listen_status_enum CDECLARE getBinaryModelSize(
+ listen_model_type *pListenModel,
+ uint32_t *nBinaryModelSize);
+
+ /*
+ * getSortedKeywordStatesUserKeywordModelSize
+ *
+ * Return sorted model size
+ *
+ * Param[in] pModel - pointer to (user)keyword model data
+ * Param[out] nSortedModelSize - return model size of sorted keyword states model
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ *
+ */
+
+DllFunc listen_status_enum CDECLARE getSortedKeywordStatesUserKeywordModelSize(
+ listen_model_type *pModel,
+ uint32_t *nSortedModelSize);
+
+ /*
+ * sortKeywordStatesOfUserKeywordModel
+ *
+ * Return sorted model
+ *
+ * Param[in] pInputModel - pointer to (user)keyword model data
+ * Param[out] pSortedModel - pointer to sorted keyword states model data
+ *
+ * Return - status
+ * kBadParam - When any input pointer is NULL
+ * kSMVersionUnsupported - when pModel is not 2.0 model
+ *
+ */
+
+DllFunc listen_status_enum CDECLARE sortKeywordStatesOfUserKeywordModel(
+ listen_model_type *pInputModel,
+ listen_model_type *pSortedModel);
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __LISTEN_SOUND_MODEL_LIB_V3_H__ */
+
diff --git a/sound_trigger_hw.c b/sound_trigger_hw.c
index ce879fc..2506887 100644
--- a/sound_trigger_hw.c
+++ b/sound_trigger_hw.c
@@ -121,6 +121,11 @@
free(st_session->rc_config);
st_session->rc_config = NULL;
}
+ if (st_session->st_conf_levels) {
+ free(st_session->st_conf_levels);
+ st_session->st_conf_levels = NULL;
+ }
+
pthread_mutex_unlock(&st_session->lock);
stdev_reconfig_backend_on_stop(st_session);
return status;
@@ -339,7 +344,7 @@
p_ses = node_to_item(node, st_session_t, list_node);
if (p_ses->exec_mode == ST_EXEC_MODE_CPE) {
/* check for sessions to keep on WDSP mode if requested by APP */
- if (ST_HW_SESS_DET_LOW_POWER_MODE == p_ses->hw_ses_current->client_req_det_mode) {
+ if (ST_DET_LOW_POWER_MODE == p_ses->client_req_det_mode) {
ALOGV("%s:[%d] session is requested on WDSP mode, skip",
__func__, p_ses->sm_handle);
continue;
@@ -348,9 +353,9 @@
if (cur_ses && (cur_ses != p_ses) &&
!platform_stdev_check_backends_match(stdev->platform,
cur_ses->exec_mode,
- cur_ses->hw_ses_current->st_device,
+ cur_ses->hw_proxy_ses->hw_ses_current->st_device,
p_ses->exec_mode,
- p_ses->hw_ses_current->st_device)) {
+ p_ses->hw_proxy_ses->hw_ses_current->st_device)) {
ALOGV("%s:[%d] session not sharing backend",
__func__, p_ses->sm_handle);
continue;
@@ -400,7 +405,7 @@
p_ses = node_to_item(node, st_session_t, transit_list_node);
if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
- update_available_phrase_info(p_ses, p_ses->sm_data, true);
+ update_available_phrase_info(p_ses, p_ses->phrase_sm, true);
ALOGD("%s:[%d] switch session to NONE", __func__, p_ses->sm_handle);
ret = st_session_set_exec_mode(p_ses, ST_EXEC_MODE_NONE);
@@ -432,7 +437,7 @@
}
if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
- update_available_phrase_info(p_ses, p_ses->sm_data, false);
+ update_available_phrase_info(p_ses, p_ses->phrase_sm, false);
}
ssr_exit:
@@ -502,7 +507,7 @@
p_ses = node_to_item(node, st_session_t, list_node);
if (p_ses->exec_mode == ST_EXEC_MODE_ADSP) {
/* check for sessions to keep on ADSP mode if requested by APP */
- if (ST_HW_SESS_DET_HIGH_PERF_MODE == p_ses->hw_ses_current->client_req_det_mode) {
+ if (ST_DET_HIGH_PERF_MODE == p_ses->client_req_det_mode) {
ALOGV("%s:[%d] session is requested on ADSP mode, skip",
__func__, p_ses->sm_handle);
continue;
@@ -511,9 +516,9 @@
if (cur_ses && (cur_ses != p_ses) &&
!platform_stdev_check_backends_match(stdev->platform,
cur_ses->exec_mode,
- cur_ses->hw_ses_current->st_device,
+ cur_ses->hw_proxy_ses->hw_ses_current->st_device,
p_ses->exec_mode,
- p_ses->hw_ses_current->st_device)) {
+ p_ses->hw_proxy_ses->hw_ses_current->st_device)) {
ALOGV("%s:[%d] session not sharing backend",
__func__, p_ses->sm_handle);
continue;
@@ -563,7 +568,7 @@
p_ses = node_to_item(node, st_session_t, transit_list_node);
if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
- update_available_phrase_info(p_ses, p_ses->sm_data, true);
+ update_available_phrase_info(p_ses, p_ses->phrase_sm, true);
ALOGD("%s:[%d] switch session to NONE", __func__, p_ses->sm_handle);
ret = st_session_set_exec_mode(p_ses, ST_EXEC_MODE_NONE);
@@ -595,7 +600,7 @@
}
if (p_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
- update_available_phrase_info(p_ses, p_ses->sm_data, false);
+ update_available_phrase_info(p_ses, p_ses->phrase_sm, false);
}
ssr_exit:
@@ -736,15 +741,16 @@
ALOGD("%s: Exit audio ec ref=%d", __func__, stdev->audio_ec_enabled);
}
-static void handle_audio_concurrency(audio_event_type_t event_type, audio_event_info_t* config)
+static void handle_audio_concurrency(audio_event_type_t event_type,
+ audio_event_info_t* config)
{
struct listnode *p_ses_node = NULL;
st_session_t *p_ses = NULL;
bool conc_allowed = false;
unsigned int num_sessions = 0;
- ALOGV_IF(config != NULL, "%s: Enter, event type = %d, audio device = %d", __func__,
- event_type, config->device_info.device);
+ ALOGV_IF(config != NULL, "%s: Enter, event type = %d, audio device = %d",
+ __func__, event_type, config->device_info.device);
/*
UC1:
@@ -859,6 +865,7 @@
*/
stdev->lpi_enable = st_hw_check_lpi_support(stdev, p_ses);
stdev->vad_enable = st_hw_check_vad_support(stdev, p_ses, stdev->lpi_enable);
+
if (stdev->lpi_enable != platform_get_lpi_mode(stdev->platform) &&
!is_any_session_buffering()) {
list_for_each(p_ses_node, &stdev->sound_model_list) {
@@ -1432,7 +1439,7 @@
struct sound_trigger_recognition_config *new_config
)
{
- unsigned int i, j;
+ unsigned int i = 0, j = 0;
/*
* Sometimes if the number of user confidence levels is 0, the
@@ -1581,7 +1588,8 @@
return status;
}
-static void deallocate_arm_second_stage_session(struct st_arm_second_stage *st_sec_stage)
+static void deallocate_arm_second_stage_session(
+ struct st_arm_second_stage *st_sec_stage)
{
if (st_sec_stage) {
if (st_sec_stage->ss_info) {
@@ -1650,8 +1658,6 @@
uint32_t i;
uint8_t *sound_model;
- list_init(&st_ses->second_stage_list);
-
for (i = 0; i < num_models; i++) {
big_sm = (SML_BigSoundModelTypeV3 *)(sm_payload + sizeof(SML_GlobalHeaderType) +
sizeof(SML_HeaderTypeV3) + (i * sizeof(SML_BigSoundModelTypeV3)));
@@ -1677,7 +1683,7 @@
memcpy(st_sec_stage->ss_session->sound_model, sound_model, big_sm->size);
memcpy((char *)st_sec_stage->ss_info, (char *)&ss_usecase.arm->common_params,
sizeof(struct st_second_stage_info));
-
+ st_sec_stage->stdev = st_ses->stdev;
list_add_tail(&st_ses->second_stage_list, &st_sec_stage->list_node);
ALOGD("%s: Added second stage session of type %d", __func__,
st_sec_stage->ss_info->sm_detection_type);
@@ -1704,7 +1710,8 @@
ss_cfg->params = ss_usecase.lsm;
ss_cfg->ss_info = &ss_usecase.lsm->common_params;
- list_add_tail(&st_ses->hw_ses_adsp->lsm_ss_cfg_list, &ss_cfg->list_node);
+ list_add_tail(&st_ses->hw_proxy_ses->hw_ses_adsp->lsm_ss_cfg_list,
+ &ss_cfg->list_node);
ALOGD("%s: Added second stage lsm usecase with sm id %d", __func__, big_sm->type);
} else if (ss_usecase.type == ST_SS_USECASE_TYPE_NONE) {
ALOGE("%s: No matching usecase in sound trigger platform for sm_id %d",
@@ -1714,8 +1721,6 @@
}
}
}
- if (!list_empty(&st_ses->second_stage_list))
- st_ses->enable_second_stage = true;
return 0;
@@ -1731,8 +1736,8 @@
static int get_gmm_model(struct sound_trigger_sound_model **common_sm,
uint8_t *sm_payload, uint32_t num_models)
{
- SML_BigSoundModelTypeV3 *big_sm;
- uint32_t i;
+ SML_BigSoundModelTypeV3 *big_sm = NULL;
+ uint32_t i = 0;
int status = 0;
for (i = 0; i < num_models; i++) {
@@ -1924,45 +1929,52 @@
*handle = android_atomic_inc(&stdev->session_id);
- ALOGD("%s: calling st_session_init with st_session ptr %p", __func__, st_session);
+ ALOGD("%s:[%d] calling st_session_init", __func__, *handle);
status = st_session_init(st_session, stdev, exec_mode, *handle);
if (status) {
- ALOGE("%s: failed to initialize st_session with error %d", __func__, status);
+ ALOGE("%s: failed to initialize st_session with error %d", __func__,
+ status);
goto exit_1;
}
- /* Parse second stage sound models and populate the second stage list for this session. */
- st_session->enable_second_stage = false;
+ /*
+ * Parse second stage sound models and populate the second stage list for
+ * this session.
+ */
+ list_init(&st_session->second_stage_list);
if (sm_version == SML_MODEL_V3) {
- status = check_and_configure_second_stage_models(st_session, sm_payload, num_models,
- phrase_sm->phrases[0].recognition_mode);
+ status = check_and_configure_second_stage_models(st_session, sm_payload,
+ num_models, phrase_sm->phrases[0].recognition_mode);
if (status) {
ALOGE("%s: Failed to set the second stage list", __func__);
goto exit_2;
}
}
- if (st_session->enable_second_stage) {
- ALOGD("%s: calling st_session_ss_init with st_session ptr %p", __func__, st_session);
+ if (!list_empty(&st_session->second_stage_list)) {
+ ALOGD("%s: calling st_session_ss_init ", __func__);
status = st_session_ss_init(st_session);
if (status) {
- ALOGE("%s: failed to initialize st_session second stage, error %d", __func__, status);
+ ALOGE("%s: failed to initialize st_session second stage,"
+ "error %d", __func__, status);
goto exit_2;
}
}
- /* Store the sound model information for handling SSR
- and interaction with smlib */
- st_session->sm_data = calloc(1, sm_size);
- if (!st_session->sm_data) {
+ /*
+ * Store the sound model information for handling SSR
+ * and interaction with smlib
+ */
+ st_session->phrase_sm = calloc(1, sm_size);
+ if (!st_session->phrase_sm) {
status = -ENOMEM;
goto exit_3;
}
if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
- memcpy(st_session->sm_data, (char *)phrase_sm, sizeof(*phrase_sm));
- st_session->sm_data->common.data_offset = sizeof(*phrase_sm);
- memcpy((char *)st_session->sm_data + sizeof(*phrase_sm),
+ memcpy(st_session->phrase_sm, (char *)phrase_sm, sizeof(*phrase_sm));
+ st_session->phrase_sm->common.data_offset = sizeof(*phrase_sm);
+ memcpy((char *)st_session->phrase_sm + sizeof(*phrase_sm),
(char *)phrase_sm + phrase_sm->common.data_offset,
phrase_sm->common.data_size);
/* TODO: SVA doesn't support per keyword recognition mode.
@@ -1971,16 +1983,18 @@
*/
st_session->recognition_mode = phrase_sm->phrases[0].recognition_mode;
ALOGD("%s: sm magic number 0x%x rm %d", __func__,
- ((int *)((char *)st_session->sm_data + phrase_sm->common.data_offset))[0],
+ ((int *)((char *)st_session->phrase_sm +
+ phrase_sm->common.data_offset))[0],
phrase_sm->phrases[0].recognition_mode);
} else {
st_session->recognition_mode = RECOGNITION_MODE_VOICE_TRIGGER;
- memcpy(st_session->sm_data, (char *)common_sm, sizeof(*common_sm));
- memcpy((char *)st_session->sm_data + common_sm->data_offset,
+ memcpy(st_session->phrase_sm, (char *)common_sm, sizeof(*common_sm));
+ memcpy((char *)st_session->phrase_sm + common_sm->data_offset,
(char *)common_sm + common_sm->data_offset,
common_sm->data_size);
ALOGD("%s: sm magic number 0x%x", __func__,
- ((int *)((char *)st_session->sm_data + common_sm->data_offset))[0]);
+ ((int *)((char *)st_session->phrase_sm +
+ common_sm->data_offset))[0]);
}
st_session->sm_type = sound_model->type;
@@ -2027,9 +2041,9 @@
return 0;
exit_3:
- if (st_session->sm_data != NULL)
- free(st_session->sm_data);
- if (st_session->enable_second_stage)
+ if (st_session->phrase_sm != NULL)
+ free(st_session->phrase_sm);
+ if (!list_empty(&st_session->second_stage_list))
st_session_ss_deinit(st_session);
exit_2:
@@ -2040,16 +2054,17 @@
exit:
if (st_session != NULL) {
- if (st_session->enable_second_stage) {
- list_for_each_safe(node, tmp_node, &st_session->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- list_remove(&st_sec_stage->list_node);
- deallocate_arm_second_stage_session(st_sec_stage);
- }
+ list_for_each_safe(node, tmp_node, &st_session->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
+ list_remove(&st_sec_stage->list_node);
+ deallocate_arm_second_stage_session(st_sec_stage);
}
- if (st_session->hw_ses_adsp) {
- list_for_each_safe(node, tmp_node, &st_session->hw_ses_adsp->lsm_ss_cfg_list) {
- st_lsm_ss_config_t *cfg = node_to_item(node, st_lsm_ss_config_t, list_node);
+ if (st_session->hw_proxy_ses &&
+ st_session->hw_proxy_ses->hw_ses_adsp) {
+ list_for_each_safe(node, tmp_node,
+ &st_session->hw_proxy_ses->hw_ses_adsp->lsm_ss_cfg_list) {
+ st_lsm_ss_config_t *cfg =
+ node_to_item(node, st_lsm_ss_config_t, list_node);
list_remove(&cfg->list_node);
deallocate_lsm_ss_config(cfg);
}
@@ -2081,12 +2096,12 @@
*/
st_session_t *best_ses = NULL;
st_session_t *ses = NULL;
- struct listnode *ses_node;
+ struct listnode *ses_node = NULL;
int ses_channel_count = 0;
int stopped_ses_channel_count = 0;
int best_channel_count = 0;
unsigned int stopped_ses_vad_preroll = 0;
- unsigned int best_vad_preroll = 0;
+ unsigned int best_vad_preroll = 0, preroll = 0;
bool stopped_ses_lpi_mode = false, is_stopped = false;
if (stopped_ses->exec_mode != ST_EXEC_MODE_ADSP &&
@@ -2110,17 +2125,13 @@
stopped_v_info);
if ((stopped_ses->exec_mode == ST_EXEC_MODE_ADSP) &&
- stopped_ses->hw_ses_adsp) {
- stopped_ses_lpi_mode = stopped_ses->hw_ses_adsp->lpi_enable;
- stopped_ses_vad_preroll = stopped_ses->hw_ses_current->client_req_preroll;
+ stopped_ses->hw_proxy_ses->hw_ses_adsp) {
+ stopped_ses_lpi_mode = stopped_ses->hw_proxy_ses->hw_ses_adsp->lpi_enable;
+ stopped_ses_vad_preroll = st_session_get_preroll(stopped_ses);
}
list_for_each(ses_node, &stdev->sound_model_list) {
ses = node_to_item(ses_node, st_session_t, list_node);
- ses_channel_count =
- platform_stdev_get_backend_channel_count(stdev->platform,
- ses->vendor_uuid_info);
- ALOGV("%s:[%d] check ses_v_info %p", __func__, ses->sm_handle, ses->vendor_uuid_info);
if (ses->exec_mode != ST_EXEC_MODE_ADSP &&
ses->exec_mode != ST_EXEC_MODE_ARM)
continue;
@@ -2137,9 +2148,17 @@
continue;
}
- if ((ses->exec_mode == ST_EXEC_MODE_ADSP) &&
- (ses->hw_ses_current->client_req_preroll > best_vad_preroll))
- best_vad_preroll = ses->hw_ses_current->client_req_preroll;
+ ses_channel_count =
+ platform_stdev_get_backend_channel_count(stdev->platform,
+ ses->vendor_uuid_info);
+ ALOGV("%s:[%d] check ses_v_info %p", __func__, ses->sm_handle,
+ ses->vendor_uuid_info);
+
+ if (ses->exec_mode == ST_EXEC_MODE_ADSP) {
+ preroll = st_session_get_preroll(ses);
+ if (preroll > best_vad_preroll)
+ best_vad_preroll = preroll;
+ }
if ((best_ses == NULL) || (ses_channel_count > best_channel_count)) {
best_ses = ses;
@@ -2184,18 +2203,16 @@
st_session_event_id_t event)
{
pthread_mutex_lock(&stdev->lock);
- st_session_t* st_sess = get_sound_trigger_session(stdev, handle);
+ st_session_t* st_ses = get_sound_trigger_session(stdev, handle);
- if (!st_sess)
+ if (!st_ses)
goto exit;
ALOGV("%s:[%d] event %d", __func__, handle, event);
switch (event) {
case ST_SES_EV_DEFERRED_STOP:
- if (st_sess->pending_stop) {
- stop_recognition_l(st_sess);
- st_sess->pending_stop = false;
- }
+ if (st_ses->pending_stop)
+ stop_recognition_l(st_ses);
break;
default:
break;
@@ -2252,17 +2269,17 @@
list_remove(&st_session->list_node);
if (st_session->sm_type == SOUND_MODEL_TYPE_KEYPHRASE)
- update_available_phrase_info(st_session, st_session->sm_data, true);
+ update_available_phrase_info(st_session, st_session->phrase_sm, true);
if (!get_num_sessions())
stdev->exec_mode = ST_EXEC_MODE_NONE;
pthread_mutex_lock(&st_session->lock);
- free(st_session->sm_data);
+ free(st_session->phrase_sm);
pthread_mutex_unlock(&st_session->lock);
run_keep_alive_session(stdev, st_session, ST_EVENT_STOP_KEEP_ALIVE);
- if (st_session->enable_second_stage) {
+ if (!list_empty(&st_session->second_stage_list)) {
st_session_ss_deinit(st_session);
list_for_each_safe(node, tmp_node, &st_session->second_stage_list) {
st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
@@ -2270,9 +2287,11 @@
deallocate_arm_second_stage_session(st_sec_stage);
}
}
- if (st_session && st_session->hw_ses_adsp) {
- list_for_each_safe(node, tmp_node, &st_session->hw_ses_adsp->lsm_ss_cfg_list) {
- st_lsm_ss_config_t *cfg = node_to_item(node, st_lsm_ss_config_t, list_node);
+ if (st_session && st_session->hw_proxy_ses->hw_ses_adsp) {
+ list_for_each_safe(node, tmp_node,
+ &st_session->hw_proxy_ses->hw_ses_adsp->lsm_ss_cfg_list) {
+ st_lsm_ss_config_t *cfg =
+ node_to_item(node, st_lsm_ss_config_t, list_node);
list_remove(&cfg->list_node);
deallocate_lsm_ss_config(cfg);
}
@@ -2323,25 +2342,12 @@
}
ALOGV("%s:[%d] About to take session lock", __func__, sound_model_handle);
- /* lock the session as we are about to change its
- stored parameters */
pthread_mutex_lock(&st_session->lock);
-
- /*
- * cancel pending stop notifications to avoid unnecessary
- * backend teardown and restart
- */
- ALOGV("%s cancel req with handle %d and ev ST_SES_EV_DEFERRED_STOP to cancel",
- __func__, st_session->sm_handle);
- hw_session_notifier_cancel(st_session->sm_handle, ST_SES_EV_DEFERRED_STOP);
- st_session->pending_stop = false;
-
if (!st_session->rc_config ||
!compare_recognition_config(config, st_session->rc_config)) {
config_updated = true;
- ALOGV("%s: received new params for session %d", __func__,
- st_session->sm_handle);
+ ALOGV("%s:[%d] received new params ", __func__, st_session->sm_handle);
/*
* Store the recogntion configuration for sending opaque data
@@ -2356,8 +2362,9 @@
*/
if ((config->data_size <= CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
st_session->vendor_uuid_info->is_qcva_uuid &&
- st_session->enable_second_stage) {
- ALOGE("%s: SVA 3.0 rc_config opaque data required, exiting", __func__);
+ !list_empty(&st_session->second_stage_list)) {
+ ALOGE("%s: SVA 3.0 rc_config opaque data required, exiting",
+ __func__);
status = -EINVAL;
goto cleanup;
}
@@ -2373,7 +2380,8 @@
memcpy((char *)st_session->rc_config + st_session->rc_config->data_offset,
(char *)config + config->data_offset, config->data_size);
- ALOGVV("%s: num_phrases=%d, id=%d", __func__, st_session->rc_config->num_phrases,
+ ALOGVV("%s: num_phrases=%d, id=%d", __func__,
+ st_session->rc_config->num_phrases,
st_session->rc_config->phrases[0].id);
st_session->callback = callback;
st_session->cookie = cookie;
@@ -2381,8 +2389,11 @@
st_session->capture_handle = config->capture_handle;
st_session->capture_requested = config->capture_requested;
- st_session->rc_config_update_counter++;
- status = st_hw_ses_update_config(st_session, st_session->hw_ses_current);
+ /*
+ * Must be called before lpi decision with updated config:
+ * preroll, client requested mode etc..
+ */
+ status = st_session_update_recongition_config(st_session);
if (status) {
ALOGE("%s: ERROR. updating rc_config, returned status %d",
__func__, status);
@@ -2393,8 +2404,9 @@
if (ST_EXEC_MODE_ADSP == st_session->exec_mode ||
ST_EXEC_MODE_ARM == st_session->exec_mode) {
stdev->lpi_enable = st_hw_check_lpi_support(stdev, st_session);
- stdev->vad_enable = st_hw_check_vad_support(stdev, st_session, stdev->lpi_enable);
- int vad_preroll = st_session->hw_ses_current->client_req_preroll;
+ stdev->vad_enable = st_hw_check_vad_support(stdev, st_session,
+ stdev->lpi_enable);
+ int vad_preroll = st_session_get_preroll(st_session);
status = platform_stdev_check_and_set_codec_backend_cfg(stdev->platform,
st_session->vendor_uuid_info, &backend_cfg_change,
@@ -2437,11 +2449,11 @@
}
/* Switch session to high performance/low power mode if requested by APP */
- if ((ST_EXEC_MODE_CPE == st_session->hw_ses_current->exec_mode) &&
- (ST_HW_SESS_DET_HIGH_PERF_MODE == st_session->hw_ses_current->client_req_det_mode))
+ if ((ST_EXEC_MODE_CPE == st_session->exec_mode) &&
+ (ST_DET_HIGH_PERF_MODE == st_session->client_req_det_mode))
check_and_transit_cpe_ses_to_ape(st_session);
- else if ((ST_EXEC_MODE_ADSP == st_session->hw_ses_current->exec_mode) &&
- (ST_HW_SESS_DET_LOW_POWER_MODE == st_session->hw_ses_current->client_req_det_mode))
+ else if ((ST_EXEC_MODE_ADSP == st_session->exec_mode) &&
+ (ST_DET_LOW_POWER_MODE == st_session->client_req_det_mode))
check_and_transit_ape_ses_to_cpe(st_session);
cleanup:
@@ -2513,10 +2525,10 @@
list_remove(node);
st_session_stop_lab(st_session);
st_session_stop(st_session);
- if (st_session->enable_second_stage)
+ if (!list_empty(&st_session->second_stage_list))
st_session_ss_deinit(st_session);
st_session_deinit(st_session);
- free(st_session->sm_data);
+ free(st_session->phrase_sm);
free(st_session->rc_config);
free(st_session);
}
@@ -2766,8 +2778,10 @@
return ret;
}
-/* Audio hal calls this callback for notifying Subsystem restart,
- lab stop and concurrency events */
+/*
+ * Audio hal calls this callback for notifying Subsystem restart,
+ * lab stop and concurrency events
+ */
int sound_trigger_hw_call_back(audio_event_type_t event,
audio_event_info_t* config)
{
diff --git a/sound_trigger_hw.h b/sound_trigger_hw.h
index c72f900..f241111 100644
--- a/sound_trigger_hw.h
+++ b/sound_trigger_hw.h
@@ -99,13 +99,71 @@
typedef int (*g722_init_decoder_t)(void *decoder_inp);
typedef int (*g722_dec_get_total_byte_size_t)(int *total_byte_size);
typedef int (*g722_dec_process_t)(short *in_buf, short *out_buf,
- int in_bytes, int *out_samples,
- void *decoder_inp);
+ int in_bytes, int *out_samples,
+ void *decoder_inp);
/* MULAW decoder APIs */
typedef int (*mulaw_dec_process_t)(short *out_buf, char *in_buf,
unsigned int in_bytes);
+/* Listen Sound Model Library APIs */
+#include "ListenSoundModelLib.h"
+
+typedef listen_status_enum (*smlib_getSoundModelHeader_t)
+(
+ listen_model_type *pSoundModel,
+ listen_sound_model_header *pListenSoundModelHeader
+);
+
+typedef listen_status_enum (*smlib_releaseSoundModelHeader_t)
+(
+ listen_sound_model_header *pListenSoundModelHeader
+);
+
+typedef listen_status_enum (*smlib_getKeywordPhrases_t)
+(
+ listen_model_type *pSoundModel,
+ uint16_t *numKeywords,
+ keywordId_t *keywords
+);
+
+typedef listen_status_enum (*smlib_getUserNames_t)
+(
+ listen_model_type *pSoundModel,
+ uint16_t *numUsers,
+ userId_t *users
+);
+
+typedef listen_status_enum (*smlib_getMergedModelSize_t)
+(
+ uint16_t numModels,
+ listen_model_type *pModels[],
+ uint32_t *nOutputModelSize
+);
+
+typedef listen_status_enum (*smlib_mergeModels_t)
+(
+ uint16_t numModels,
+ listen_model_type *pModels[],
+ listen_model_type *pMergedModel
+);
+
+typedef listen_status_enum (*getSizeAfterDeleting_t)
+(
+ listen_model_type *pInputModel,
+ keywordId_t keywordId,
+ userId_t userId,
+ uint32_t *nOutputModelSize
+);
+
+typedef listen_status_enum (*deleteFromModel_t)
+(
+ listen_model_type *pInputModel,
+ keywordId_t keywordId,
+ userId_t userId,
+ listen_model_type *pResultModel
+);
+
struct sound_trigger_device {
struct sound_trigger_hw_device device;
struct sound_trigger_properties *hw_properties;
@@ -176,14 +234,16 @@
bool is_gcs;
struct listnode vendor_uuid_list;
- void *smlib_handle;
- smlib_generate_sound_trigger_recognition_config_payload_t
- generate_st_recognition_config_payload;
- smlib_generate_sound_trigger_phrase_recognition_event_t
- generate_st_phrase_recognition_event;
- smlib_generate_sound_trigger_phrase_recognition_event_t
- generate_st_phrase_recognition_event_v2;
+ void *smlib_handle;
+ smlib_getSoundModelHeader_t smlib_getSoundModelHeader;
+ smlib_releaseSoundModelHeader_t smlib_releaseSoundModelHeader;
+ smlib_getKeywordPhrases_t smlib_getKeywordPhrases;
+ smlib_getUserNames_t smlib_getUserNames;
+ smlib_getMergedModelSize_t smlib_getMergedModelSize;
+ smlib_mergeModels_t smlib_mergeModels;
+ getSizeAfterDeleting_t smlib_getSizeAfterDeleting;
+ deleteFromModel_t smlib_deleteFromModel;
void *adpcm_dec_lib_handle;
g722_init_decoder_t adpcm_dec_init;
diff --git a/sound_trigger_platform.c b/sound_trigger_platform.c
index c7308cf..c048569 100644
--- a/sound_trigger_platform.c
+++ b/sound_trigger_platform.c
@@ -90,8 +90,8 @@
#define ST_PARAM_KEY_FIRMWARE_IMAGE "firmware_image"
#define ST_PARAM_KEY_SM_VENDOR_UUID "vendor_uuid"
+#define ST_PARAM_KEY_MERGE_FIRST_STAGE_SOUNDMODELS "merge_first_stage_sound_models"
#define ST_PARAM_KEY_APP_TYPE "app_type"
-#define ST_PARAM_KEY_LIBRARY "library"
#define ST_PARAM_KEY_MAX_CPE_PHRASES "max_cpe_phrases"
#define ST_PARAM_KEY_MAX_APE_USERS "max_ape_users"
#define ST_PARAM_KEY_MAX_APE_PHRASES "max_ape_phrases"
@@ -411,45 +411,62 @@
struct listnode acdb_meta_key_list;
};
-static int load_smlib(struct st_vendor_info *sm_info, const char *name)
+static int load_soundmodel_lib(sound_trigger_device_t *stdev)
{
int status = 0;
- sm_info->smlib_handle = dlopen(name, RTLD_NOW);
- if (!sm_info->smlib_handle) {
+ stdev->smlib_handle = dlopen(LIB_SVA_SOUNDMODEL, RTLD_NOW);
+ if (!stdev->smlib_handle) {
ALOGE("%s: ERROR. %s", __func__, dlerror());
return -ENODEV;
}
- DLSYM(sm_info->smlib_handle, sm_info->generate_st_phrase_recognition_event,
- generate_sound_trigger_phrase_recognition_event, status);
+ DLSYM(stdev->smlib_handle, stdev->smlib_getSoundModelHeader,
+ getSoundModelHeader, status);
if (status)
goto cleanup;
- DLSYM(sm_info->smlib_handle, sm_info->generate_st_phrase_recognition_event_v2,
- generate_sound_trigger_phrase_recognition_event_v2, status);
+
+ DLSYM(stdev->smlib_handle, stdev->smlib_releaseSoundModelHeader,
+ releaseSoundModelHeader, status);
if (status)
goto cleanup;
- DLSYM(sm_info->smlib_handle,
- sm_info->generate_st_recognition_config_payload,
- generate_sound_trigger_recognition_config_payload, status);
+
+ DLSYM(stdev->smlib_handle, stdev->smlib_getKeywordPhrases,
+ getKeywordPhrases, status);
if (status)
goto cleanup;
- DLSYM(sm_info->smlib_handle,
- sm_info->generate_st_recognition_config_payload_v2,
- generate_sound_trigger_recognition_config_payload_v2, status);
+
+ DLSYM(stdev->smlib_handle, stdev->smlib_getUserNames,
+ getUserNames, status);
if (status)
goto cleanup;
- DLSYM(sm_info->smlib_handle,
- sm_info->generate_st_phrase_recognition_event_v3,
- generate_sound_trigger_phrase_recognition_event_v3, status);
- /* Ignore error for this symbol */
+
+ DLSYM(stdev->smlib_handle, stdev->smlib_getMergedModelSize,
+ getMergedModelSize, status);
+ if (status)
+ goto cleanup;
+
+ DLSYM(stdev->smlib_handle, stdev->smlib_mergeModels,
+ mergeModels, status);
+ if (status)
+ goto cleanup;
+
+ DLSYM(stdev->smlib_handle, stdev->smlib_getSizeAfterDeleting,
+ getSizeAfterDeleting, status);
+ if (status)
+ goto cleanup;
+
+ DLSYM(stdev->smlib_handle, stdev->smlib_deleteFromModel,
+ deleteFromModel, status);
+ if (status)
+ goto cleanup;
return 0;
cleanup:
- if (sm_info->smlib_handle) {
- dlclose(sm_info->smlib_handle);
- sm_info->smlib_handle = NULL;
+ if (stdev->smlib_handle) {
+ dlclose(stdev->smlib_handle);
+ stdev->smlib_handle = NULL;
}
return status;
}
@@ -2326,16 +2343,6 @@
sm_info->app_type = strtoul(str_value, NULL, 16);
}
- err = str_parms_get_str(parms, ST_PARAM_KEY_LIBRARY,
- str_value, sizeof(str_value));
- if (err >= 0) {
- str_parms_del(parms, ST_PARAM_KEY_LIBRARY);
- /* if soundmodel library for ISV vendor uuid is mentioned, use it. If not
- ignore and continue sending the opaque data from HAL to DSP */
- if (strcmp(str_value, "none"))
- load_smlib(sm_info, str_value);
- }
-
err = str_parms_get_int(parms, ST_PARAM_KEY_MAX_CPE_PHRASES, &value);
if (err >= 0) {
str_parms_del(parms, ST_PARAM_KEY_MAX_CPE_PHRASES);
@@ -2512,6 +2519,14 @@
sm_info->lab_dam_cfg_payload.token_id = value;
}
+ err = str_parms_get_str(parms, ST_PARAM_KEY_MERGE_FIRST_STAGE_SOUNDMODELS,
+ str_value, sizeof(str_value));
+ if (err >= 0) {
+ str_parms_del(parms, ST_PARAM_KEY_MERGE_FIRST_STAGE_SOUNDMODELS);
+ sm_info->merge_fs_soundmodels =
+ !strncasecmp(str_value, "true", 4) ? true : false;
+ }
+
sm_info->avail_transit_ape_phrases = sm_info->avail_ape_phrases;
sm_info->avail_transit_ape_users = sm_info->avail_ape_users;
sm_info->avail_transit_cpe_phrases = sm_info->avail_cpe_phrases;
@@ -3612,9 +3627,18 @@
v_info = node_to_item(v_node, struct st_vendor_info, list_node);
if (!memcmp(&v_info->uuid, &qcva_uuid, sizeof(sound_trigger_uuid_t))) {
v_info->is_qcva_uuid = true;
+ if (!stdev->smlib_handle && v_info->merge_fs_soundmodels) {
+ ret = load_soundmodel_lib(stdev);
+ if (ret) {
+ v_info->merge_fs_soundmodels = false;
+ ret = 0;
+ }
+ }
} else if (!memcmp(&v_info->uuid, &qcmd_uuid, sizeof(sound_trigger_uuid_t))) {
v_info->is_qcmd_uuid = true;
+ v_info->merge_fs_soundmodels = false;
} else {
+ v_info->merge_fs_soundmodels = false;
ALOGV("%s: ISV uuid present", __func__);
}
if (!stdev->adpcm_dec_lib_handle &&
@@ -3684,8 +3708,6 @@
}
list_for_each_safe(v_node, temp_node, &stdev->vendor_uuid_list) {
v_info = node_to_item(v_node, struct st_vendor_info, list_node);
- if (v_info->smlib_handle)
- dlclose(v_info->smlib_handle);
list_remove(v_node);
free(v_info);
}
@@ -3741,8 +3763,6 @@
free(lsm_info);
}
- if (v_info->smlib_handle)
- dlclose(v_info->smlib_handle);
list_remove(v_node);
free(v_info);
}
diff --git a/sound_trigger_platform.h b/sound_trigger_platform.h
index 1520042..c6543d3 100644
--- a/sound_trigger_platform.h
+++ b/sound_trigger_platform.h
@@ -66,6 +66,8 @@
#define LIB_ACDB_LOADER "libacdbloader.so"
#define LIB_ADPCM_DECODER "libadpcmdec.so"
#define LIB_MULAW_DECODER "libmulawdec.so"
+#define LIB_SVA_SOUNDMODEL "liblistensoundmodel2.so"
+
#define BUF_SIZE 1024
#define MAX_SND_CARD 8
@@ -274,34 +276,6 @@
ST_SHARED_BUF_RAW,
} st_shared_buf_fmt_t;
-/* soundmodel library wrapper functions */
-typedef int (*smlib_generate_sound_trigger_phrase_recognition_event_t)
-(
- const struct sound_trigger_phrase_sound_model *sm,
- const struct sound_trigger_recognition_config *config,
- const void *payload,
- unsigned int payload_size,
- struct sound_trigger_phrase_recognition_event **r_event
-);
-
-typedef int (*smlib_generate_sound_trigger_recognition_config_payload_t)
-(
- const struct sound_trigger_phrase_sound_model *sm,
- const struct sound_trigger_recognition_config *config,
- unsigned char **out_payload,
- unsigned int *out_payload_size
-);
-
-typedef int (*smlib_generate_sound_trigger_phrase_recognition_event_v3_t)
-(
- const struct sound_trigger_phrase_sound_model *sm,
- const struct sound_trigger_recognition_config *config,
- const void *payload,
- unsigned int payload_size,
- qsthw_recognition_event_type_t event_type,
- void **r_event
-);
-
struct st_lsm_params {
struct listnode list_node;
st_exec_mode_t exec_mode;
@@ -368,6 +342,7 @@
int app_type;
bool is_qcva_uuid;
bool is_qcmd_uuid;
+ bool merge_fs_soundmodels;
unsigned int fwk_mode;
int sample_rate;
int format;
@@ -404,19 +379,6 @@
struct listnode lsm_usecase_list;
struct listnode arm_ss_usecase_list;
struct listnode lsm_ss_usecase_list;
-
- void *smlib_handle;
- smlib_generate_sound_trigger_recognition_config_payload_t
- generate_st_recognition_config_payload;
- smlib_generate_sound_trigger_recognition_config_payload_t
- generate_st_recognition_config_payload_v2;
-
- smlib_generate_sound_trigger_phrase_recognition_event_t
- generate_st_phrase_recognition_event;
- smlib_generate_sound_trigger_phrase_recognition_event_t
- generate_st_phrase_recognition_event_v2;
- smlib_generate_sound_trigger_phrase_recognition_event_v3_t
- generate_st_phrase_recognition_event_v3;
};
typedef struct st_codec_backend_cfg {
diff --git a/st_extn/st_hw_extn.c b/st_extn/st_hw_extn.c
index 2fb2496..d6351ca 100644
--- a/st_extn/st_hw_extn.c
+++ b/st_extn/st_hw_extn.c
@@ -49,6 +49,78 @@
#include "st_session.h"
#include "st_hw_defs.h"
+static int generate_sound_trigger_phrase_recognition_event_v3
+(
+ const struct sound_trigger_phrase_sound_model *phrase_sm,
+ const struct sound_trigger_recognition_config *rc_config,
+ const void *payload,
+ unsigned int payload_size,
+ qsthw_recognition_event_type_t event_type,
+ void **out_rc_event
+)
+{
+ unsigned int i = 0, j = 0, user_id = 0;
+ int rc = 0;
+
+ ALOGD("%s: Enter payload_size %d", __func__, payload_size);
+
+ if (!payload || !phrase_sm || !rc_config || !out_rc_event) {
+ ALOGE("%s: Null params", __func__);
+ return -EINVAL;
+ }
+
+ *out_rc_event = NULL;
+
+ switch (event_type) {
+ case QSTHW_RC_EVENT_TYPE_TIMESTAMP: {
+ struct qsthw_phrase_recognition_event *event;
+ struct sound_trigger_phrase_recognition_event *phrase_event;
+ event = calloc(1, sizeof(*event) + payload_size);
+ if (!event) {
+ ALOGE("%s: event allocation failed size %d",
+ __func__, payload_size);
+ rc = -ENODEV;
+ break;
+ }
+
+ phrase_event = &event->phrase_event;
+
+ phrase_event->num_phrases = rc_config->num_phrases;
+ phrase_event->common.data_offset = sizeof(*event);
+ phrase_event->common.data_size = payload_size;
+
+ /* fill confidence levels */
+ for (i = 0; i < rc_config->num_phrases; i++) {
+ phrase_event->phrase_extras[i].id = rc_config->phrases[i].id;
+ phrase_event->phrase_extras[i].recognition_modes =
+ phrase_sm->phrases[0].recognition_mode;
+ phrase_event->phrase_extras[i].confidence_level =
+ ((char *)payload)[i];
+ phrase_event->phrase_extras[i].num_levels =
+ rc_config->phrases[i].num_levels;
+ for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
+ user_id = rc_config->phrases[i].levels[j].user_id;
+ phrase_event->phrase_extras[i].levels[j].user_id = user_id;
+ phrase_event->phrase_extras[i].levels[j].level =
+ ((char *)payload)[user_id];
+ }
+ }
+
+ /* Copy payload to event using offset generated above */
+ memcpy((char *)event + phrase_event->common.data_offset,
+ payload, payload_size);
+
+ *out_rc_event = (struct qsthw_phrase_recognition_event *)event;
+ break;
+ }
+ default:
+ ALOGE("%s: Invalid event type passed %d", __func__, event_type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
bool sthw_extn_check_process_det_ev_support()
{
return true;
@@ -56,21 +128,20 @@
/* recognition event with timestamp */
int sthw_extn_process_detection_event_keyphrase(
- st_session_t *st_ses, uint64_t timestamp, int detect_status,
+ st_proxy_session_t *st_ses, uint64_t timestamp, int detect_status,
void *payload, size_t payload_size,
struct sound_trigger_phrase_recognition_event **event)
{
- st_hw_session_t *st_hw_ses = NULL;
+ st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
+ st_session_t *stc_ses = st_ses->det_stc_ses;
struct qsthw_phrase_recognition_event *local_event = NULL;
struct st_vendor_info *v_info = st_ses->vendor_uuid_info;
- struct sound_trigger_phrase_sound_model *phrase_sm= st_ses->sm_data;
+ struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
int status = 0;
unsigned int i, j;
qsthw_recognition_event_type_t event_type = QSTHW_RC_EVENT_TYPE_TIMESTAMP;
- st_hw_ses = st_ses->hw_ses_current;
-
if (st_hw_ses->is_generic_event) {
/*
* For generic event, reusing the st_session v2 event generation.
@@ -104,19 +175,15 @@
free(generic_phrase_event);
*event = &local_event->phrase_event;
goto exit;
- } else if (v_info && v_info->smlib_handle) {
+ } else if (v_info->is_qcva_uuid) {
/* if smlib is present, get the event from it, else send the
* DSP received payload as it is to App
*/
- status = v_info->generate_st_phrase_recognition_event_v3(
- phrase_sm,
- st_ses->rc_config,
- payload,
- payload_size,
- event_type,
- (void *)&local_event);
+ status = generate_sound_trigger_phrase_recognition_event_v3(
+ phrase_sm, stc_ses->rc_config, payload, payload_size,
+ event_type, (void *)&local_event);
- if (status) {
+ if (status || !local_event) {
ALOGW("%s: smlib fill recognition event failed, status %d",
__func__, status);
goto exit;
@@ -130,11 +197,12 @@
goto exit;
}
- memcpy(local_event->phrase_event.phrase_extras, st_ses->rc_config->phrases,
- st_ses->rc_config->num_phrases *
- sizeof(struct sound_trigger_phrase_recognition_extra));
+ memcpy(local_event->phrase_event.phrase_extras,
+ stc_ses->rc_config->phrases,
+ stc_ses->rc_config->num_phrases *
+ sizeof(struct sound_trigger_phrase_recognition_extra));
- local_event->phrase_event.num_phrases = st_ses->rc_config->num_phrases;
+ local_event->phrase_event.num_phrases = stc_ses->rc_config->num_phrases;
local_event->phrase_event.common.data_offset = sizeof(*local_event);
local_event->phrase_event.common.data_size = payload_size;
memcpy((char *)local_event + local_event->phrase_event.common.data_offset,
@@ -147,9 +215,9 @@
local_event->timestamp = timestamp;
local_event->phrase_event.common.status = detect_status;
- local_event->phrase_event.common.type = st_ses->sm_data->common.type;;
- local_event->phrase_event.common.model = st_ses->sm_handle;
- local_event->phrase_event.common.capture_available = st_ses->capture_requested;
+ local_event->phrase_event.common.type = phrase_sm->common.type;;
+ local_event->phrase_event.common.model = stc_ses->sm_handle;
+ local_event->phrase_event.common.capture_available = stc_ses->capture_requested;
local_event->phrase_event.common.capture_delay_ms = 0;
local_event->phrase_event.common.capture_preamble_ms = 0;
local_event->phrase_event.common.audio_config.sample_rate =
@@ -170,11 +238,11 @@
}
}
- ALOGI("%s:[%d] send keyphrase recognition event %d", __func__,
- st_ses->sm_handle, detect_status);
- ALOGV("%s:[%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
+ ALOGI("%s:[c%d] send keyphrase recognition event %d", __func__,
+ stc_ses->sm_handle, detect_status);
+ ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
"num_phrases=%d, id=%d, timestamp = %" PRIu64,
- __func__, st_ses->sm_handle, local_event->phrase_event.common.status,
+ __func__, stc_ses->sm_handle, local_event->phrase_event.common.status,
local_event->phrase_event.common.type, local_event->phrase_event.common.model,
local_event->phrase_event.common.capture_available, local_event->phrase_event.num_phrases,
local_event->phrase_event.phrase_extras[0].id, local_event->timestamp);
@@ -182,4 +250,4 @@
*event = &local_event->phrase_event;
exit:
return status;
-}
+}
\ No newline at end of file
diff --git a/st_extn/st_hw_extn.h b/st_extn/st_hw_extn.h
index 82cc324..c5b3efb 100644
--- a/st_extn/st_hw_extn.h
+++ b/st_extn/st_hw_extn.h
@@ -37,7 +37,7 @@
#define sthw_extn_check_process_det_ev_support() (false)
#else
int sthw_extn_process_detection_event_keyphrase(
- st_session_t *st_ses, uint64_t timestamp, int detect_status,
+ st_proxy_session_t *st_ses, uint64_t timestamp, int detect_status,
void *payload, size_t payload_size,
struct sound_trigger_phrase_recognition_event **event);
bool sthw_extn_check_process_det_ev_support();
diff --git a/st_hw_common.c b/st_hw_common.c
index b550fd7..4e55daa 100644
--- a/st_hw_common.c
+++ b/st_hw_common.c
@@ -80,21 +80,29 @@
* Second stage is only supported on an adsp session,
* and when multi-stage support is available in lsm drivers.
*/
- if (!st_ses || !st_ses->hw_ses_adsp || !st_hw_check_multi_stage_lsm_support())
+ if (!st_ses || st_ses->hw_proxy_ses ||
+ !st_ses->hw_proxy_ses->hw_ses_adsp ||
+ !st_hw_check_multi_stage_lsm_support()) {
return false;
+ }
stdev = st_ses->stdev;
list_for_each(node, &stdev->sound_model_list) {
p_ses = node_to_item(node, st_session_t, list_node);
- if (p_ses == NULL || p_ses == st_ses || p_ses->exec_mode != ST_EXEC_MODE_ADSP)
+ if (p_ses == NULL || p_ses == st_ses ||
+ p_ses->exec_mode != ST_EXEC_MODE_ADSP)
continue;
- if (p_ses->hw_ses_adsp && !list_empty(&p_ses->hw_ses_adsp->lsm_ss_cfg_list))
+ pthread_mutex_lock(&p_ses->hw_proxy_ses->lock);
+ if (p_ses->hw_proxy_ses->hw_ses_adsp &&
+ !list_empty(&p_ses->hw_proxy_ses->hw_ses_adsp->lsm_ss_cfg_list))
lsm_ss_uc_count++;
if (lsm_ss_uc_count >= max_lsm_ss_uc_count) {
- ALOGD("%s: max supported ss usecase count(%d) already active, not allowing further",
- __func__, max_lsm_ss_uc_count);
+ ALOGD("%s: max supported ss usecase count(%d) already active,"
+ "not allowing further", __func__, max_lsm_ss_uc_count);
+ pthread_mutex_unlock(&p_ses->hw_proxy_ses->lock);
return false;
}
+ pthread_mutex_unlock(&p_ses->hw_proxy_ses->lock);
}
ALOGD("%s: ss usecase allowed", __func__);
return true;
@@ -209,8 +217,7 @@
list_for_each(ses_node, &stdev->sound_model_list) {
ses = node_to_item(ses_node, st_session_t, list_node);
- if (ses->hw_ses_current->client_req_det_mode ==
- ST_HW_SESS_DET_HIGH_PERF_MODE) {
+ if (ses->client_req_det_mode == ST_DET_HIGH_PERF_MODE) {
ALOGD("%s:[%d] lpi NOT supported due to high perf mode", __func__,
ses->sm_handle);
return false;
@@ -271,332 +278,30 @@
return vad_enable;
}
-void st_hw_check_and_set_lpi_mode(st_session_t *st_ses)
+void st_hw_check_and_set_lpi_mode(st_session_t *stc_ses)
{
- if (st_ses && st_ses->hw_ses_adsp) {
+ st_proxy_session_t *st_ses = NULL;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return;
+
+ st_ses = stc_ses->hw_proxy_ses;
+
+ pthread_mutex_lock(&st_ses->lock);
+ if (st_ses->hw_ses_adsp) {
if (st_ses->stdev->platform_lpi_enable == ST_PLATFORM_LPI_NONE) {
st_ses->hw_ses_adsp->lpi_enable =
(st_ses->vendor_uuid_info->lpi_enable &&
- is_projected_lpi_budget_available(st_ses->stdev, st_ses));
+ is_projected_lpi_budget_available(st_ses->stdev, stc_ses));
} else {
st_ses->hw_ses_adsp->lpi_enable =
(st_ses->stdev->platform_lpi_enable ==
ST_PLATFORM_LPI_ENABLE) ? true: false;
}
}
+ pthread_mutex_unlock(&st_ses->lock);
}
-static int parse_config_key_conf_levels
-(
- st_session_t *st_ses,
- st_hw_session_t* st_hw_ses,
- void *opaque_conf_levels
-)
-{
- struct st_confidence_levels_info *conf_levels = NULL;
- struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
- struct st_sound_model_conf_levels *sm_levels = NULL;
- struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
- struct listnode *node = NULL, *tmp_node = NULL;
- st_lsm_ss_config_t *ss_cfg = NULL;
- st_arm_second_stage_t *st_sec_stage = NULL;
- int status = 0;
- uint32_t i = 0;
- bool gmm_conf_found = false;
- uint8_t confidence_level = 0;
- int32_t confidence_level_v2 = 0;
- bool arm_second_stage = st_hw_ses->enable_second_stage;
- bool adsp_second_stage = (st_hw_ses == st_ses->hw_ses_adsp &&
- !list_empty(&st_hw_ses->lsm_ss_cfg_list));
-
- if (arm_second_stage || adsp_second_stage) {
- if (st_ses->rc_config->num_phrases > 1) {
- ALOGE("%s: Multi keyword is unsupported with 2nd stage detection",
- __func__);
- return -EINVAL;
- }
-
- if (st_ses->rc_config->phrases[0].num_levels > 1) {
- ALOGE("%s: Multi user is unsupported with 2nd stage detection",
- __func__);
- return -EINVAL;
- }
- }
-
- if (st_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
- conf_levels = (struct st_confidence_levels_info *)
- ((char *)opaque_conf_levels + sizeof(struct st_param_header));
- st_hw_ses->conf_levels_info =
- calloc(1, sizeof(struct st_confidence_levels_info));
- if (!st_hw_ses->conf_levels_info) {
- ALOGE("%s: failed to alloc conf_levels_info", __func__);
- return -ENOMEM;
- }
- memcpy(st_hw_ses->conf_levels_info, (char *)conf_levels,
- sizeof(struct st_confidence_levels_info));
-
- for (i = 0; i < conf_levels->num_sound_models; i++) {
- sm_levels = (struct st_sound_model_conf_levels *)
- &conf_levels->conf_levels[i];
- if (sm_levels->sm_id == ST_SM_ID_SVA_GMM) {
- if ((st_ses->stdev->is_gcs) && (st_hw_ses == st_ses->hw_ses_cpe))
- status =
- generate_sound_trigger_recognition_config_payload_v2(
- (void *)sm_levels, &st_hw_ses->conf_levels,
- &st_hw_ses->num_conf_levels,
- st_ses->conf_levels_intf_version);
- else
- status =
- generate_sound_trigger_recognition_config_payload(
- (void *)sm_levels, &st_hw_ses->conf_levels,
- &st_hw_ses->num_conf_levels,
- st_ses->conf_levels_intf_version);
- gmm_conf_found = true;
- } else if ((sm_levels->sm_id == ST_SM_ID_SVA_CNN) ||
- (sm_levels->sm_id == ST_SM_ID_SVA_VOP)) {
- confidence_level = (sm_levels->sm_id == ST_SM_ID_SVA_CNN) ?
- sm_levels->kw_levels[0].kw_level:
- sm_levels->kw_levels[0].user_levels[0].level;
- if (arm_second_stage) {
- list_for_each_safe(node, tmp_node,
- st_hw_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t,
- list_node);
- if (st_sec_stage->ss_info->sm_id == sm_levels->sm_id)
- st_sec_stage->ss_session->confidence_threshold =
- confidence_level;
- }
- } else if (adsp_second_stage) {
- list_for_each_safe(node, tmp_node,
- &st_hw_ses->lsm_ss_cfg_list) {
- ss_cfg = node_to_item(node, st_lsm_ss_config_t,
- list_node);
- if (ss_cfg->ss_info->sm_id == sm_levels->sm_id)
- ss_cfg->confidence_threshold = confidence_level;
- }
- }
- } else {
- ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
- sm_levels->sm_id);
- status = -EINVAL;
- break;
- }
- }
- } else {
- conf_levels_v2 = (struct st_confidence_levels_info_v2 *)
- ((char *)opaque_conf_levels + sizeof(struct st_param_header));
- st_hw_ses->conf_levels_info =
- calloc(1, sizeof(struct st_confidence_levels_info_v2));
- if (!st_hw_ses->conf_levels_info) {
- ALOGE("%s: failed to alloc conf_levels_info", __func__);
- return -ENOMEM;
- }
- memcpy(st_hw_ses->conf_levels_info, (char *)conf_levels_v2,
- sizeof(struct st_confidence_levels_info_v2));
-
- for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
- sm_levels_v2 = (struct st_sound_model_conf_levels_v2 *)
- &conf_levels_v2->conf_levels[i];
- if (sm_levels_v2->sm_id == ST_SM_ID_SVA_GMM) {
- if ((st_ses->stdev->is_gcs) &&
- (st_hw_ses == st_ses->hw_ses_cpe))
- status =
- generate_sound_trigger_recognition_config_payload_v2(
- (void *)sm_levels_v2, &st_hw_ses->conf_levels,
- &st_hw_ses->num_conf_levels,
- st_ses->conf_levels_intf_version);
- else
- status =
- generate_sound_trigger_recognition_config_payload(
- (void *)sm_levels_v2, &st_hw_ses->conf_levels,
- &st_hw_ses->num_conf_levels,
- st_ses->conf_levels_intf_version);
- gmm_conf_found = true;
- } else if ((sm_levels_v2->sm_id == ST_SM_ID_SVA_CNN) ||
- (sm_levels_v2->sm_id == ST_SM_ID_SVA_VOP)) {
- confidence_level_v2 =
- (sm_levels_v2->sm_id == ST_SM_ID_SVA_CNN) ?
- sm_levels_v2->kw_levels[0].kw_level:
- sm_levels_v2->kw_levels[0].user_levels[0].level;
- if (arm_second_stage) {
- list_for_each_safe(node, tmp_node,
- st_hw_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t,
- list_node);
- if (st_sec_stage->ss_info->sm_id ==
- sm_levels_v2->sm_id)
- st_sec_stage->ss_session->confidence_threshold =
- confidence_level_v2;
- }
- } else if (adsp_second_stage) {
- list_for_each_safe(node, tmp_node,
- &st_hw_ses->lsm_ss_cfg_list) {
- ss_cfg = node_to_item(node, st_lsm_ss_config_t,
- list_node);
- if (ss_cfg->ss_info->sm_id == sm_levels_v2->sm_id)
- ss_cfg->confidence_threshold = confidence_level_v2;
- }
- }
- } else {
- ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
- sm_levels_v2->sm_id);
- status = -EINVAL;
- break;
- }
- }
- }
-
- if (!gmm_conf_found) {
- ALOGE("%s: Did not receive GMM confidence threshold, error!", __func__);
- status = -EINVAL;
- }
-
- if (status && st_hw_ses->conf_levels_info) {
- free(st_hw_ses->conf_levels_info);
- st_hw_ses->conf_levels_info = NULL;
- }
-
- return status;
-}
-
-int st_hw_ses_update_config(st_session_t *st_ses, st_hw_session_t* st_hw_ses)
-{
- int status = 0;
- uint8_t *opaque_ptr = NULL;
- unsigned int opaque_size = 0, conf_levels_payload_size = 0;
- struct st_param_header *param_hdr = NULL;
- struct st_hist_buffer_info *hist_buf = NULL;
- struct st_det_perf_mode_info *det_perf_mode = NULL;
- struct sound_trigger_recognition_config *rc_config = st_ses->rc_config;
-
- ST_DBG_DECLARE(FILE *rc_opaque_fd = NULL; static int rc_opaque_cnt = 0);
- ST_DBG_FILE_OPEN_WR(rc_opaque_fd, ST_DEBUG_DUMP_LOCATION,
- "rc_config_opaque_data", "bin", rc_opaque_cnt++);
- ST_DBG_FILE_WRITE(rc_opaque_fd, (uint8_t *)rc_config + rc_config->data_offset,
- rc_config->data_size);
- ST_DBG_FILE_CLOSE(rc_opaque_fd);
-
- /* First release memory and reset allocation from previous rc_config update */
- if (st_hw_ses->conf_levels_info) {
- free(st_hw_ses->conf_levels_info);
- st_hw_ses->conf_levels_info = NULL;
- }
- if (st_hw_ses->conf_levels) {
- free(st_hw_ses->conf_levels);
- st_hw_ses->conf_levels = NULL;
- }
- st_hw_ses->client_req_hist_buf = 0;
- st_hw_ses->client_req_preroll = 0;
- st_hw_ses->client_req_det_mode = ST_HW_SESS_DET_UNKNOWN_MODE;
-
- if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
- st_hw_ses->vendor_uuid_info->is_qcva_uuid) {
- opaque_ptr = (uint8_t *)rc_config + rc_config->data_offset;
- while (opaque_size < rc_config->data_size) {
- param_hdr = (struct st_param_header *)opaque_ptr;
- ALOGV("%s: key %d, payload size %d", __func__,
- param_hdr->key_id, param_hdr->payload_size);
-
- switch(param_hdr->key_id) {
- case ST_PARAM_KEY_CONFIDENCE_LEVELS:
- memcpy((char *)&st_ses->conf_levels_intf_version,
- (char *)(opaque_ptr + sizeof(struct st_param_header)),
- sizeof(uint32_t));
- if (st_ses->conf_levels_intf_version !=
- CONF_LEVELS_INTF_VERSION_0002) {
- conf_levels_payload_size =
- sizeof(struct st_confidence_levels_info);
- } else {
- conf_levels_payload_size =
- sizeof(struct st_confidence_levels_info_v2);
- }
- if (param_hdr->payload_size != conf_levels_payload_size) {
- ALOGE("%s: Conf level format error, exiting", __func__);
- return -EINVAL;
- }
- status = parse_config_key_conf_levels(st_ses, st_hw_ses,
- opaque_ptr);
- opaque_size += sizeof(struct st_param_header) +
- conf_levels_payload_size;
- opaque_ptr += sizeof(struct st_param_header) +
- conf_levels_payload_size;
- if (status) {
- ALOGE("%s: parsing conf levels failed(status=%d)",
- __func__, status);
- return -EINVAL;
- }
- break;
- case ST_PARAM_KEY_HISTORY_BUFFER_CONFIG:
- if (param_hdr->payload_size != sizeof(struct st_hist_buffer_info)) {
- ALOGE("%s: History buffer config format error, exiting", __func__);
- return -EINVAL;
- }
- hist_buf = (struct st_hist_buffer_info *)(opaque_ptr +
- sizeof(struct st_param_header));
- st_hw_ses->client_req_hist_buf = hist_buf->hist_buffer_duration_msec;
- st_hw_ses->client_req_preroll = hist_buf->pre_roll_duration_msec;
- ALOGV("%s: recognition config history buf len = %d, preroll len = %d, minor version = %d",
- __func__, hist_buf->hist_buffer_duration_msec,
- hist_buf->pre_roll_duration_msec, hist_buf->version);
- opaque_size += sizeof(struct st_param_header) + sizeof(struct st_hist_buffer_info);
- opaque_ptr += sizeof(struct st_param_header) + sizeof(struct st_hist_buffer_info);
- break;
- case ST_PARAM_KEY_DETECTION_PERF_MODE:
- if (param_hdr->payload_size != sizeof(struct st_det_perf_mode_info)) {
- ALOGE("%s: Opaque data format error, exiting", __func__);
- return -EINVAL;
- }
- det_perf_mode = (struct st_det_perf_mode_info *)(opaque_ptr +
- sizeof(struct st_param_header));
- ALOGV("set perf mode to %d", det_perf_mode->mode);
- st_hw_ses->client_req_det_mode = det_perf_mode->mode;
- opaque_size += sizeof(struct st_param_header) +
- sizeof(struct st_det_perf_mode_info);
- opaque_ptr += sizeof(struct st_param_header) +
- sizeof(struct st_det_perf_mode_info);
- break;
- default:
- ALOGE("%s: Unsupported opaque data key id, exiting", __func__);
- return -EINVAL;
- }
- }
- } else if (st_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
- struct sound_trigger_phrase_sound_model *phrase_sm = st_ses->sm_data;
- struct st_vendor_info *v_info = st_hw_ses->vendor_uuid_info;
-
- ALOGV("%s: num_phrases=%d, id=%d", __func__,
- rc_config->num_phrases, rc_config->phrases[0].id);
-
- /*
- * Can be QC SVA or ISV vendor. Get from corresponding smlib defined
- * in platform file. if soundmodel library for ISV vendor uuid is
- * mentioned, use it. If not ignore, in this case opaque data would be
- * send from HAL to DSP.
- */
- if (v_info && v_info->smlib_handle) {
- if (st_ses->stdev->is_gcs && st_hw_ses == st_ses->hw_ses_cpe)
- status = v_info->generate_st_recognition_config_payload_v2(
- phrase_sm, rc_config,
- &st_hw_ses->conf_levels,
- &st_hw_ses->num_conf_levels);
- else
- status = v_info->generate_st_recognition_config_payload(
- phrase_sm, rc_config,
- &st_hw_ses->conf_levels,
- &st_hw_ses->num_conf_levels);
- if (status || !st_hw_ses->conf_levels)
- ALOGE("%s: failed to get conf levels from lib handle", __func__);
- } else {
- ALOGD("%s: No smlib, opaque data would be sent as is", __func__);
- }
- }
-
- st_hw_ses->rc_config = st_ses->rc_config;
- st_hw_ses->rc_config_update_counter = st_ses->rc_config_update_counter;
- return status;
-}
-
-
int stop_other_sessions(struct sound_trigger_device *stdev,
st_session_t *cur_ses)
{
@@ -671,6 +376,58 @@
return NULL;
}
+/*
+ * This function is used to prepare the detection engine custom config payload for
+ * sound trigger sessions that have second stage sessions. If history buffering is not
+ * requested by the client, add it into the payload here. Second stage sessions require
+ * the keyword to be buffered.
+ */
+int st_hw_ses_get_hist_buff_payload
+(
+ st_hw_session_t *p_ses,
+ uint8_t *payload_buf,
+ size_t buff_size
+)
+{
+ struct st_hist_buffer_info *hist_buf = NULL;
+
+ if (!payload_buf || buff_size < sizeof(*hist_buf)) {
+ ALOGE("%s: buffer size(%zd) too small to fill payload(%zd)",
+ __func__, buff_size, sizeof(*hist_buf));
+ return -EINVAL;
+ }
+
+ hist_buf = (struct st_hist_buffer_info *) payload_buf;
+ hist_buf->version = DEFAULT_CUSTOM_CONFIG_MINOR_VERSION;
+
+ if (p_ses->sthw_cfg.client_req_hist_buf > 0) {
+ hist_buf->hist_buffer_duration_msec =
+ p_ses->sthw_cfg.client_req_hist_buf;
+ hist_buf->pre_roll_duration_msec = p_ses->sthw_cfg.client_req_preroll;
+
+ if (p_ses->is_generic_event) {
+ if (p_ses->sthw_cfg.client_req_hist_buf <=
+ (p_ses->sthw_cfg.client_req_preroll + KW_LEN_WARNING))
+ ALOGW("%s: Client hist buf and preroll lens leave only"
+ "%dms for keyword", __func__,
+ (p_ses->sthw_cfg.client_req_hist_buf -
+ p_ses->sthw_cfg.client_req_preroll));
+
+ if (p_ses->sthw_cfg.client_req_preroll < PREROLL_LEN_WARNING)
+ ALOGW("%s: Client requested small preroll length %dms",
+ __func__, p_ses->sthw_cfg.client_req_preroll);
+ }
+ } else {
+ hist_buf->hist_buffer_duration_msec =
+ p_ses->vendor_uuid_info->kw_duration;
+ hist_buf->pre_roll_duration_msec = 0;
+ }
+ ALOGD("%s: history buf duration %d, preroll %d", __func__,
+ hist_buf->hist_buffer_duration_msec,
+ hist_buf->pre_roll_duration_msec);
+ return 0;
+}
+
/* ---------------- hw session notify thread --------------- */
#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof((arr)[0]))
@@ -909,379 +666,3 @@
}
enable_gcov();
}
-
-/*
- * This function is used to prepare the detection engine custom config payload for
- * sound trigger sessions that have second stage sessions. If history buffering is not
- * requested by the client, add it into the payload here. Second stage sessions require
- * the keyword to be buffered.
- */
-int st_hw_ses_get_hist_buff_payload
-(
- st_hw_session_t *p_ses,
- uint8_t *payload_buff,
- size_t buff_size
-)
-{
- struct st_hist_buffer_info *hist_buf = NULL;
-
- if (!payload_buff || buff_size < sizeof(*hist_buf)) {
- ALOGE("%s: buffer size(%zd) too small to fill payload(%zd)",
- __func__, buff_size, sizeof(*hist_buf));
- return -EINVAL;
- }
-
- hist_buf = (struct st_hist_buffer_info *) payload_buff;
- hist_buf->version = DEFAULT_CUSTOM_CONFIG_MINOR_VERSION;
-
- if (p_ses->client_req_hist_buf > 0) {
- hist_buf->hist_buffer_duration_msec = p_ses->client_req_hist_buf;
- hist_buf->pre_roll_duration_msec = p_ses->client_req_preroll;
-
- if (p_ses->is_generic_event) {
- if (p_ses->client_req_hist_buf <= p_ses->client_req_preroll + KW_LEN_WARNING)
- ALOGW("%s: Warning: Client hist buf and preroll lens leave only %dms for keyword",
- __func__, (p_ses->client_req_hist_buf - p_ses->client_req_preroll));
-
- if (p_ses->client_req_preroll < PREROLL_LEN_WARNING)
- ALOGW("%s: Warning: Client requested small preroll length %dms",
- __func__, p_ses->client_req_preroll);
- }
-
- } else {
- hist_buf->hist_buffer_duration_msec = p_ses->vendor_uuid_info->kw_duration;
- hist_buf->pre_roll_duration_msec = 0;
- }
-
- return 0;
-}
-
-static int fill_sound_trigger_recognition_config_payload
-(
- const void *sm_levels_generic,
- unsigned char *conf_levels,
- unsigned int num_conf_levels,
- unsigned int total_num_users,
- uint32_t version
-)
-{
- int status = 0;
- unsigned int user_level, user_id;
- unsigned int i, j;
- unsigned char *user_id_tracker;
- struct st_sound_model_conf_levels *sm_levels = NULL;
- struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
-
- /* Example: Say the recognition structure has 3 keywords with users
- * |kid|
- * [0] k1 |uid|
- * [0] u1 - 1st trainer
- * [1] u2 - 4th trainer
- * [3] u3 - 3rd trainer
- * [1] k2
- * [2] u2 - 2nd trainer
- * [4] u3 - 5th trainer
- * [2] k3
- * [5] u4 - 6th trainer
- *
- * Output confidence level array will be
- * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
- */
-
- if (version != CONF_LEVELS_INTF_VERSION_0002) {
- sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
- if (!sm_levels || !conf_levels || !num_conf_levels) {
- ALOGE("%s: ERROR. Invalid inputs", __func__);
- return -EINVAL;
- }
- user_id_tracker = calloc(1, num_conf_levels);
- if (!user_id_tracker) {
- ALOGE("%s: failed to allocate user_id_tracker", __func__);
- return -ENOMEM;
- }
-
- for (i = 0; i < sm_levels->num_kw_levels; i++) {
- ALOGV("%s: [%d] kw level %d", __func__, i,
- sm_levels->kw_levels[i].kw_level);
- for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
- ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
- sm_levels->kw_levels[i].user_levels[j].user_id,
- sm_levels->kw_levels[i].user_levels[j].level);
- }
- }
-
- for (i = 0; i < sm_levels->num_kw_levels; i++) {
- conf_levels[i] = sm_levels->kw_levels[i].kw_level;
- for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
- user_level = sm_levels->kw_levels[i].user_levels[j].level;
- user_id = sm_levels->kw_levels[i].user_levels[j].user_id;
- if ((user_id < sm_levels->num_kw_levels) ||
- (user_id >= num_conf_levels)) {
- ALOGE("%s: ERROR. Invalid params user id %d>%d",
- __func__, user_id, total_num_users);
- status = -EINVAL;
- goto exit;
- } else {
- if (user_id_tracker[user_id] == 1) {
- ALOGE("%s: ERROR. Duplicate user id %d",
- __func__, user_id);
- status = -EINVAL;
- goto exit;
- }
- conf_levels[user_id] = (user_level < 100) ?
- user_level: 100;
- user_id_tracker[user_id] = 1;
- ALOGV("%s: user_conf_levels[%d] = %d", __func__,
- user_id, conf_levels[user_id]);
- }
- }
- }
- } else {
- sm_levels_v2 =
- (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
- if (!sm_levels_v2 || !conf_levels || !num_conf_levels) {
- ALOGE("%s: ERROR. Invalid inputs", __func__);
- return -EINVAL;
- }
- user_id_tracker = calloc(1, num_conf_levels);
- if (!user_id_tracker) {
- ALOGE("%s: failed to allocate user_id_tracker", __func__);
- return -ENOMEM;
- }
-
- for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
- ALOGV("%s: [%d] kw level %d", __func__, i,
- sm_levels_v2->kw_levels[i].kw_level);
- for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
- ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
- sm_levels_v2->kw_levels[i].user_levels[j].user_id,
- sm_levels_v2->kw_levels[i].user_levels[j].level);
- }
- }
-
- for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
- conf_levels[i] = sm_levels_v2->kw_levels[i].kw_level;
- for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
- user_level = sm_levels_v2->kw_levels[i].user_levels[j].level;
- user_id = sm_levels_v2->kw_levels[i].user_levels[j].user_id;
- if ((user_id < sm_levels_v2->num_kw_levels) ||
- (user_id >= num_conf_levels)) {
- ALOGE("%s: ERROR. Invalid params user id %d>%d",
- __func__, user_id, total_num_users);
- status = -EINVAL;
- goto exit;
- } else {
- if (user_id_tracker[user_id] == 1) {
- ALOGE("%s: ERROR. Duplicate user id %d",
- __func__, user_id);
- status = -EINVAL;
- goto exit;
- }
- conf_levels[user_id] = (user_level < 100) ?
- user_level: 100;
- user_id_tracker[user_id] = 1;
- ALOGV("%s: user_conf_levels[%d] = %d", __func__,
- user_id, conf_levels[user_id]);
- }
- }
- }
- }
-
-exit:
- free(user_id_tracker);
- return status;
-}
-
-int generate_sound_trigger_recognition_config_payload
-(
- const void *sm_levels_generic,
- unsigned char **out_payload,
- unsigned int *out_payload_size,
- uint32_t version
-)
-{
- int status = 0;
- unsigned int total_num_users = 0, num_conf_levels = 0;
- unsigned char *conf_levels = NULL;
- unsigned int i = 0, j = 0;
- struct st_sound_model_conf_levels *sm_levels = NULL;
- struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
-
- ALOGV("%s: Enter...", __func__);
-
- if (version != CONF_LEVELS_INTF_VERSION_0002) {
- sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
- if (!sm_levels || !out_payload || !out_payload_size) {
- ALOGE("%s: ERROR. Invalid inputs", __func__);
- status = -EINVAL;
- goto exit;
- }
- *out_payload = NULL;
- *out_payload_size = 0;
-
- if (sm_levels->num_kw_levels == 0) {
- ALOGE("%s: ERROR. No confidence levels present", __func__);
- status = -EINVAL;
- goto exit;
- }
- for (i = 0; i < sm_levels->num_kw_levels; i++) {
- for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
- total_num_users++;
- }
-
- num_conf_levels = total_num_users + sm_levels->num_kw_levels;
- conf_levels = calloc(1, num_conf_levels);
- if (!conf_levels) {
- ALOGE("%s: ERROR. conf levels alloc failed", __func__);
- status = -ENOMEM;
- goto exit;
- }
- } else {
- sm_levels_v2 =
- (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
- if (!sm_levels_v2 || !out_payload || !out_payload_size) {
- ALOGE("%s: ERROR. Invalid inputs", __func__);
- status = -EINVAL;
- goto exit;
- }
- *out_payload = NULL;
- *out_payload_size = 0;
-
- if (sm_levels_v2->num_kw_levels == 0) {
- ALOGE("%s: ERROR. No confidence levels present", __func__);
- status = -EINVAL;
- goto exit;
- }
- for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
- for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
- total_num_users++;
- }
-
- num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
- conf_levels = calloc(1, num_conf_levels);
- if (!conf_levels) {
- ALOGE("%s: ERROR. conf levels alloc failed", __func__);
- status = -ENOMEM;
- goto exit;
- }
- }
-
- status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
- conf_levels, num_conf_levels, total_num_users, version);
- if (status) {
- ALOGE("%s: fill config payload failed, error %d", __func__, status);
- goto exit;
- }
-
- *out_payload = conf_levels;
- *out_payload_size = num_conf_levels;
-
- return status;
-
-exit:
- if (conf_levels)
- free(conf_levels);
-
- return status;
-}
-
-int generate_sound_trigger_recognition_config_payload_v2
-(
- const void *sm_levels_generic,
- unsigned char **out_payload,
- unsigned int *out_payload_size,
- uint32_t version
-)
-{
- int status = 0;
- unsigned int total_num_users = 0, num_conf_levels = 0;
- unsigned char *conf_levels = NULL;
- unsigned int i = 0, j = 0;
- struct st_sound_model_conf_levels *sm_levels = NULL;
- struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
-
- ALOGV("%s: Enter...", __func__);
-
- if (version != CONF_LEVELS_INTF_VERSION_0002) {
- sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
- if (!sm_levels || !out_payload || !out_payload_size) {
- ALOGE("%s: ERROR. Invalid inputs", __func__);
- status = -EINVAL;
- goto exit;
- }
- *out_payload = NULL;
- *out_payload_size = 0;
-
- if (sm_levels->num_kw_levels == 0) {
- ALOGE("%s: ERROR. No confidence levels present", __func__);
- status = -EINVAL;
- goto exit;
- }
- for (i = 0; i < sm_levels->num_kw_levels; i++) {
- for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
- total_num_users++;
- }
-
- num_conf_levels = total_num_users + sm_levels->num_kw_levels;
- } else {
- sm_levels_v2 =
- (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
- if (!sm_levels_v2 || !out_payload || !out_payload_size) {
- ALOGE("%s: ERROR. Invalid inputs", __func__);
- status = -EINVAL;
- goto exit;
- }
- *out_payload = NULL;
- *out_payload_size = 0;
-
- if (sm_levels_v2->num_kw_levels == 0) {
- ALOGE("%s: ERROR. No confidence levels present", __func__);
- status = -EINVAL;
- goto exit;
- }
- for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
- for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
- total_num_users++;
- }
-
- num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
- }
-
- /*
- * allocate dsp payload w/additional 2 bytes for minor_version and
- * num_active_models and additional num_conf_levels for KW enable
- * fields
- */
- conf_levels = calloc(1, 2 + 2 * num_conf_levels);
- if (!conf_levels) {
- ALOGE("%s: ERROR. conf levels alloc failed", __func__);
- status = -ENOMEM;
- goto exit;
- }
-
- conf_levels[0] = 1; /* minor version */
- conf_levels[1] = num_conf_levels; /* num_active_models */
- status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
- conf_levels + 2, num_conf_levels, total_num_users, version);
- if (status) {
- ALOGE("%s: fill config payload failed, error %d", __func__, status);
- goto exit;
- }
-
- /* set KW enable fields to 1 for now
- * TODO set appropriately based on what client is passing in rc_config
- */
- memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
- ALOGV("%s: here", __func__);
- *out_payload = conf_levels;
- /* add size of minor version and num_active_models */
- *out_payload_size = 2 + 2 * num_conf_levels;
-
- return status;
-
-exit:
- if (conf_levels)
- free(conf_levels);
-
- return status;
-}
diff --git a/st_hw_common.h b/st_hw_common.h
index 5b2529a..6fb9548 100644
--- a/st_hw_common.h
+++ b/st_hw_common.h
@@ -61,12 +61,6 @@
/* 2nd stage detection */
int st_hw_ses_get_hist_buff_payload(st_hw_session_t *p_ses,
uint8_t *payload_buff, size_t buff_size);
-int generate_sound_trigger_recognition_config_payload(
- const void *sm_levels_generic, unsigned char **out_payload,
- unsigned int *out_payload_size, uint32_t version);
-int generate_sound_trigger_recognition_config_payload_v2(
- const void *sm_levels_generic, unsigned char **out_payload,
- unsigned int *out_payload_size, uint32_t version);
static inline uint64_t get_current_time_ns()
{
diff --git a/st_hw_session.h b/st_hw_session.h
index 1ea0fd2..6c61bee 100644
--- a/st_hw_session.h
+++ b/st_hw_session.h
@@ -53,12 +53,6 @@
ST_HW_SESS_EVENT_MAX
} st_hw_sess_event_id_t;
-typedef enum {
- ST_HW_SESS_DET_LOW_POWER_MODE,
- ST_HW_SESS_DET_HIGH_PERF_MODE,
- ST_HW_SESS_DET_UNKNOWN_MODE = 0xFF,
-} st_hw_sess_det_mode_t;
-
typedef struct st_hw_sess_detected_ev {
uint64_t timestamp;
int detect_status;
@@ -75,6 +69,15 @@
typedef void (*hw_ses_event_callback_t)(st_hw_sess_event_t *event, void *cookie);
+struct st_hw_ses_config {
+ unsigned int client_req_hist_buf;
+ unsigned int client_req_preroll;
+ unsigned char *conf_levels;
+ unsigned int num_conf_levels;
+ char *custom_data;
+ unsigned int custom_data_size;
+};
+
struct st_hw_session {
struct st_session_fptrs *fptrs;
@@ -84,37 +87,34 @@
struct pcm_config config;
struct st_vendor_info *vendor_uuid_info;
- unsigned int num_conf_levels;
- unsigned char *conf_levels;
-
hw_ses_event_callback_t callback_to_st_session;
void *cookie;
st_exec_mode_t exec_mode;
enum sound_trigger_states state;
- sound_model_handle_t sm_handle; /* used when logging debug info */
+ sound_model_handle_t sm_handle; /* used when logging */
struct sound_trigger_device *stdev;
st_device_t st_device;
char *st_device_name;
- unsigned int client_req_hist_buf;
- unsigned int client_req_preroll;
struct listnode *second_stage_list;
uint32_t kw_start_idx;
uint32_t kw_end_idx;
int32_t user_level;
bool enable_second_stage;
- void *conf_levels_info;
bool is_generic_event;
struct listnode lsm_ss_cfg_list;
bool lpi_enable;
- st_hw_sess_det_mode_t client_req_det_mode;
- struct sound_trigger_recognition_config *rc_config;
+ bool lab_enabled;
+
int rc_config_update_counter;
uint64_t first_stage_det_event_time;
uint64_t second_stage_det_event_time;
st_buffer_t *buffer;
+
+ struct st_hw_ses_config sthw_cfg;
+ bool sthw_cfg_updated;
};
typedef struct st_hw_session st_hw_session_t;
@@ -122,22 +122,20 @@
/* Function pointers to routing layers */
typedef void (*sound_trigger_init_session_t)(st_hw_session_t *);
typedef int (*sound_trigger_reg_sm_t)(st_hw_session_t *,
- void*, sound_trigger_sound_model_type_t sm_type);
+ void*, unsigned int, sound_trigger_sound_model_type_t sm_type);
typedef int (*sound_trigger_reg_sm_params_t)(st_hw_session_t *,
unsigned int recognition_mode, bool capture_requested,
struct sound_trigger_recognition_config *rc_config,
sound_trigger_sound_model_type_t sm_type, void * sm_data);
-typedef int (*sound_trigger_dereg_sm_t)(st_hw_session_t *,
- bool capture_requested);
+typedef int (*sound_trigger_dereg_sm_t)(st_hw_session_t *);
typedef int (*sound_trigger_dereg_sm_params_t)(st_hw_session_t *);
typedef int (*sound_trigger_start_t)(st_hw_session_t *);
-typedef int (*sound_trigger_restart_t)(st_hw_session_t *, unsigned int, bool,
+typedef int (*sound_trigger_restart_t)(st_hw_session_t *, unsigned int,
struct sound_trigger_recognition_config *,
sound_trigger_sound_model_type_t, void *);
typedef int (*sound_trigger_stop_t)(st_hw_session_t *);
-typedef int (*sound_trigger_stop_buffering_t)(st_hw_session_t *,
- bool capture_requested);
+typedef int (*sound_trigger_stop_buffering_t)(st_hw_session_t *);
typedef int (*sound_trigger_set_device_t)(st_hw_session_t *, bool);
typedef int (*sound_trigger_read_pcm_t)(st_hw_session_t *,
unsigned char *, unsigned int );
diff --git a/st_hw_session_gcs.c b/st_hw_session_gcs.c
index e5a2980..83c84ff 100644
--- a/st_hw_session_gcs.c
+++ b/st_hw_session_gcs.c
@@ -56,7 +56,7 @@
#define WDSP_SYSFS_NAME "/dev/wcd_dsp0_control"
static int reg_sm(st_hw_session_t *p_ses,
- void *sm_data,
+ void *sm_data, unsigned int sm_size,
sound_trigger_sound_model_type_t sm_type);
static int reg_sm_params(st_hw_session_t *p_ses,
unsigned int recognition_mode,
@@ -68,15 +68,15 @@
unsigned char *buf,
unsigned int bytes);
static void process_lab_capture(st_hw_session_t *p_ses);
-static int dereg_sm(st_hw_session_t *p_ses, bool capture_requested);
+static int dereg_sm(st_hw_session_t *p_ses);
static int dereg_sm_params(st_hw_session_t *p_ses);
static int start(st_hw_session_t *p_ses);
static int restart(st_hw_session_t *p_ses,
- unsigned int recognition_mode, bool capture_requested,
+ unsigned int recognition_mode,
struct sound_trigger_recognition_config *rc_config __unused,
sound_trigger_sound_model_type_t sm_type, void *sm_data);
static int stop(st_hw_session_t *p_ses);
-static int stop_buffering(st_hw_session_t *p_ses, bool capture_requested);
+static int stop_buffering(st_hw_session_t *p_ses);
static int set_device(st_hw_session_t *p_ses,
bool enable);
static int disable_device(st_hw_session_t *p_ses, bool setting_device);
@@ -504,22 +504,15 @@
return NULL;
}
-static int reg_sm(st_hw_session_t *p_ses,
- void *sm_data,
- sound_trigger_sound_model_type_t sm_type)
+static int reg_sm(st_hw_session_t *p_ses, void *sm_data,
+ unsigned int sm_size, sound_trigger_sound_model_type_t sm_type __unused)
{
int status = 0;
uint8_t *load_sm_msg = NULL;
struct graphite_cal_header *sm_msg_hdr = NULL;
- size_t load_sm_msg_sz = 0;
+ unsigned int load_sm_msg_sz = 0;
struct st_vendor_info *v_info = p_ses->vendor_uuid_info;
struct gcs_module_param_info gcs_module_info; /* used to register for ev*/
- struct sound_trigger_phrase_sound_model *phrase_sm =
- (struct sound_trigger_phrase_sound_model *)sm_data;
- struct sound_trigger_sound_model *common_sm =
- (struct sound_trigger_sound_model *)sm_data;
- size_t sm_data_size = 0;
- uint32_t sm_data_offset = 0;
st_hw_session_gcs_t *p_gcs_ses = (st_hw_session_gcs_t *)p_ses;
int st_device = 0, device_acdb_id = 0;
int capture_device;
@@ -575,22 +568,14 @@
goto cleanup1;
}
- if (sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
- sm_data_size = phrase_sm->common.data_size;
- sm_data_offset = phrase_sm->common.data_offset;
- } else {
- sm_data_size = common_sm->data_size;
- sm_data_offset = common_sm->data_offset;
- }
-
/* calculate size of load sm msg */
load_sm_msg_sz = sizeof(struct graphite_cal_header); /* param header for sound model param */
- load_sm_msg_sz += sm_data_size; /* SM opaque data size from upper layers */
+ load_sm_msg_sz += sm_size; /* SM opaque data size from upper layers */
load_sm_msg_sz = ALIGN(load_sm_msg_sz, 4);
load_sm_msg = calloc(load_sm_msg_sz, sizeof(uint8_t));
if (!load_sm_msg) {
- ALOGE("%s: failed to allocate memory for sm msg, size = %zu", __func__,
+ ALOGE("%s: failed to allocate memory for sm msg, size = %u", __func__,
load_sm_msg_sz);
status = -ENOMEM;
goto cleanup1;
@@ -602,15 +587,15 @@
params[LOAD_SOUND_MODEL].instance_id;
sm_msg_hdr->param_id = p_gcs_ses->gcs_usecase->
params[LOAD_SOUND_MODEL].param_id;
- sm_msg_hdr->size = sm_data_size;
+ sm_msg_hdr->size = sm_size;
- ALOGV("%s: sm cal header MID %x, IID %x, PID %x \n sm data %p, sm size %zu,"
- " alloc size %zu", __func__, sm_msg_hdr->module_id,
+ ALOGV("%s: sm cal header MID %x, IID %x, PID %x \n sm data %p, sm size %u,"
+ " alloc size %u", __func__, sm_msg_hdr->module_id,
sm_msg_hdr->instance_id, sm_msg_hdr->param_id, sm_data,
- sm_data_size, load_sm_msg_sz);
+ sm_size, load_sm_msg_sz);
memcpy(load_sm_msg + sizeof(struct graphite_cal_header),
- (uint8_t *)sm_data + sm_data_offset, sm_data_size);
+ (uint8_t *)sm_data, sm_size);
ST_DBG_DECLARE(FILE *load_fd = NULL; static int load_fd_cnt = 0);
@@ -619,11 +604,11 @@
ST_DBG_FILE_CLOSE(load_fd);
ALOGD("%s:[%d] calling gcs_load_data with graph_handle %d, load_sm_msg %p, "
- "load_sm_msg_sz %zu", __func__, p_ses->sm_handle, p_gcs_ses->graph_handle,
+ "load_sm_msg_sz %d", __func__, p_ses->sm_handle, p_gcs_ses->graph_handle,
load_sm_msg, load_sm_msg_sz);
ATRACE_BEGIN("sthal:gcs: gcs_load_data");
status = gcs_load_data_fn(p_gcs_ses->graph_handle, load_sm_msg,
- (uint32_t)load_sm_msg_sz, &p_gcs_ses->loaded_sm_handle);
+ load_sm_msg_sz, &p_gcs_ses->loaded_sm_handle);
ATRACE_END();
if (status) {
ALOGE("%s: gcs_load_data failed with status %d", __func__, status);
@@ -729,12 +714,12 @@
*/
if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
- p_ses->vendor_uuid_info->is_qcva_uuid) {
+ v_info->is_qcva_uuid) {
if (!capture_requested)
disable_custom_config = true;
det_config_size = sizeof(struct gcs_det_engine_config_param) +
- p_ses->num_conf_levels;
+ p_ses->sthw_cfg.num_conf_levels;
det_config_size = ALIGN(det_config_size, 4);
p_hw_ses->nonpersistent_cal_size += det_config_size;
@@ -758,9 +743,9 @@
p_hw_ses->nonpersistent_cal_size += custom_config_size;
}
- if (v_info->smlib_handle) {
+ if (v_info->is_qcva_uuid || v_info->is_qcmd_uuid) {
det_config_size = sizeof(struct gcs_det_engine_config_param) +
- p_ses->num_conf_levels;
+ p_ses->sthw_cfg.num_conf_levels;
/* If not using custom config param, send opaque data as part of
* DETECTION_ENGINE_CONFIG. Opaque data will be put after confidence
* level payload data.
@@ -780,7 +765,7 @@
* Just set this flag to handle generic detection event coming from DSP
*/
p_ses->is_generic_event = true;
- if (p_ses->vendor_uuid_info->is_qcva_uuid) {
+ if (v_info->is_qcva_uuid) {
det_event_type_size +=
sizeof(struct gcs_det_event_type_custom_config);
det_event_type_size = ALIGN(det_event_type_size, 4);
@@ -841,19 +826,20 @@
}
msg_offset += sizeof(struct gcs_det_engine_config_param);
- if (p_ses->conf_levels) {
- memcpy(msg_offset, (uint8_t *)p_ses->conf_levels, p_ses->num_conf_levels);
- msg_offset += p_ses->num_conf_levels;
- p_msg->custom_payload_sz = p_ses->num_conf_levels;
+ if (p_ses->sthw_cfg.conf_levels) {
+ memcpy(msg_offset, (uint8_t *)p_ses->sthw_cfg.conf_levels,
+ p_ses->sthw_cfg.num_conf_levels);
+ msg_offset += p_ses->sthw_cfg.num_conf_levels;
+ p_msg->custom_payload_sz = p_ses->sthw_cfg.num_conf_levels;
/*
* The detection_engine_config struct has 2 bytes for minor
* version and num_active_models before the confidence levels.
* There is also 1 byte added for each confidence level as an
* enable/disable flag.
*/
- for (i = 0; i < (p_ses->num_conf_levels - 2) / 2; i++) {
+ for (i = 0; i < (p_ses->sthw_cfg.num_conf_levels - 2) / 2; i++) {
ALOGD("%s: First stage conf_levels[%d] = %d",
- __func__, i, *(p_ses->conf_levels + 2 + i));
+ __func__, i, *(p_ses->sthw_cfg.conf_levels + 2 + i));
}
}
}
@@ -878,7 +864,7 @@
cc_msg->cal_hdr.param_id);
if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
- p_ses->vendor_uuid_info->is_qcva_uuid) {
+ v_info->is_qcva_uuid) {
/* Custom config for updated opaque data structure for SVA 3.0. */
cc_msg->cal_hdr.size = sizeof(struct st_hist_buffer_info);
msg_offset += sizeof(struct gcs_det_engine_custom_config_param);
@@ -1002,7 +988,7 @@
return status;
}
-static int dereg_sm(st_hw_session_t *p_ses, bool capture_requested __unused)
+static int dereg_sm(st_hw_session_t *p_ses)
{
int status = 0, rc = 0;
st_hw_session_gcs_t *p_gcs_ses = (st_hw_session_gcs_t *)p_ses;
@@ -1039,19 +1025,6 @@
if (status)
rc = status;
}
-
- if (p_ses->conf_levels_info) {
- free(p_ses->conf_levels_info);
- p_ses->conf_levels_info = NULL;
- }
-
- if (p_ses->conf_levels) {
- free(p_ses->conf_levels);
- p_ses->conf_levels = NULL;
- }
-
- p_ses->rc_config = NULL;
-
return rc;
}
@@ -1116,7 +1089,6 @@
static int restart(st_hw_session_t *p_ses,
unsigned int recognition_mode __unused,
- bool capture_requested __unused,
struct sound_trigger_recognition_config *rc_config,
sound_trigger_sound_model_type_t sm_type, void *sm_data)
{
@@ -1159,7 +1131,7 @@
goto exit;
}
- status = reg_sm_params(p_ses, recognition_mode, capture_requested,
+ status = reg_sm_params(p_ses, recognition_mode, p_ses->lab_enabled,
rc_config, sm_type, sm_data);
if (status) {
ALOGE("%s: failed to reg_sm_params err %d", __func__, status);
@@ -1220,8 +1192,7 @@
return status;
}
-static int stop_buffering(st_hw_session_t *p_ses,
- bool capture_requested)
+static int stop_buffering(st_hw_session_t *p_ses)
{
int status = 0;
st_hw_session_gcs_t *p_hw_ses = (st_hw_session_gcs_t *)p_ses;
@@ -1240,7 +1211,7 @@
}
}
- if (capture_requested) {
+ if (p_ses->lab_enabled) {
/* signal stop of bufferinng */
ALOGV("%s: acquirung lock", __func__);
pthread_mutex_lock(&p_hw_ses->lock);
@@ -1539,9 +1510,9 @@
prepend_bytes =
convert_ms_to_bytes(p_ses->vendor_uuid_info->kw_start_tolerance,
&p_ses->config);
- if (p_ses->client_req_hist_buf) {
+ if (p_ses->sthw_cfg.client_req_hist_buf) {
kw_duration_bytes =
- convert_ms_to_bytes(p_ses->client_req_hist_buf, &p_ses->config);
+ convert_ms_to_bytes(p_ses->sthw_cfg.client_req_hist_buf, &p_ses->config);
} else {
kw_duration_bytes =
convert_ms_to_bytes(p_ses->vendor_uuid_info->kw_duration,
@@ -1610,7 +1581,7 @@
pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
}
- if (p_ses->enable_second_stage && !p_ses->client_req_hist_buf)
+ if (p_ses->enable_second_stage && !p_ses->sthw_cfg.client_req_hist_buf)
p_hw_ses->move_client_ptr = true;
else
p_hw_ses->move_client_ptr = false;
@@ -1855,7 +1826,6 @@
p_ses->fptrs = &fptrs_gcs;
p_ses->stdev = stdev;
p_ses->is_generic_event = false;
- p_ses->client_req_det_mode = ST_HW_SESS_DET_UNKNOWN_MODE;
p_hw_ses->nonpersistent_cal = NULL;
p_hw_ses->detect_payload_size = 0;
p_hw_ses->detection_signaled = false;
diff --git a/st_hw_session_lsm.c b/st_hw_session_lsm.c
index 1e9867a..a2c41c4 100644
--- a/st_hw_session_lsm.c
+++ b/st_hw_session_lsm.c
@@ -63,46 +63,45 @@
#define DOA_POLAR_ACTIVITY_INDICATORS 360
static int ape_reg_sm(st_hw_session_t* p_ses, void *sm_data,
- sound_trigger_sound_model_type_t sm_type);
+ unsigned int sm_size, sound_trigger_sound_model_type_t sm_type);
static int ape_reg_sm_params(st_hw_session_t* p_ses, unsigned int recognition_mode,
bool capture_requested, struct sound_trigger_recognition_config *rc_config,
sound_trigger_sound_model_type_t sm_type, void *sm_data);
-static int ape_dereg_sm(st_hw_session_t* p_ses, bool capture_requested);
+static int ape_dereg_sm(st_hw_session_t* p_ses);
static int ape_dereg_sm_params(st_hw_session_t* p_ses);
static int ape_start(st_hw_session_t* p_ses);
static int ape_stop(st_hw_session_t* p_ses);
static int ape_stop_buffering(st_hw_session_t* p_ses);
-static int cpe_reg_sm(st_hw_session_t* p_ses,void *sm_data, sound_trigger_sound_model_type_t sm_type);
+static int cpe_reg_sm(st_hw_session_t* p_ses,void *sm_data, unsigned int sm_size, sound_trigger_sound_model_type_t sm_type);
static int cpe_reg_sm_params(st_hw_session_t* p_ses, unsigned int recognition_mode,
bool capture_requested, struct sound_trigger_recognition_config *rc_config,
sound_trigger_sound_model_type_t sm_type, void *sm_data);
-static int cpe_dereg_sm(st_hw_session_t* p_ses, bool capture_requested);
+static int cpe_dereg_sm(st_hw_session_t* p_ses);
static int cpe_dereg_sm_params(st_hw_session_t* p_ses);
static int cpe_start(st_hw_session_t* p_ses);
static int cpe_stop(st_hw_session_t* p_ses);
-static int cpe_stop_buffering(st_hw_session_t *p_ses, bool capture_requested);
+static int cpe_stop_buffering(st_hw_session_t *p_ses);
/* Routing layer functions to route to either ADSP or CPE */
static int route_reg_sm_ape(st_hw_session_t *p_ses,
- void *sm_data, sound_trigger_sound_model_type_t sm_type);
+ void *sm_data, unsigned int sm_size, sound_trigger_sound_model_type_t sm_type);
static int route_reg_sm_params_ape(st_hw_session_t* p_ses,
unsigned int recognition_mode, bool capture_requested,
struct sound_trigger_recognition_config *rc_config,
sound_trigger_sound_model_type_t sm_type, void *sm_data);
-static int route_dereg_sm_ape(st_hw_session_t* p_ses, bool capture_requested);
+static int route_dereg_sm_ape(st_hw_session_t* p_ses);
static int route_dereg_sm_params_ape(st_hw_session_t* p_ses);
static int route_restart_ape(st_hw_session_t* p_ses,
unsigned int recognition_mode,
- bool capture_requested,
struct sound_trigger_recognition_config *rc_config,
sound_trigger_sound_model_type_t sm_type,
void *sm_data);
static int route_start_ape(st_hw_session_t* p_ses);
static int route_stop_ape(st_hw_session_t* p_ses);
-static int route_stop_buffering_ape(st_hw_session_t* p_ses, bool capture_requested);
+static int route_stop_buffering_ape(st_hw_session_t* p_ses);
static int route_set_device_ape(st_hw_session_t* p_ses,
bool enable);
static int route_read_pcm_ape(st_hw_session_t *p_ses,
@@ -112,19 +111,19 @@
static int route_send_custom_chmix_coeff_ape(st_hw_session_t *p_ses, char *str);
static int route_reg_sm_cpe(st_hw_session_t *p_ses,
- void *sm_data, sound_trigger_sound_model_type_t sm_type);
+ void *sm_data, unsigned int sm_size, sound_trigger_sound_model_type_t sm_type);
static int route_reg_sm_params_cpe(st_hw_session_t* p_ses,
unsigned int recognition_mode, bool capture_requested,
struct sound_trigger_recognition_config *rc_config,
sound_trigger_sound_model_type_t sm_type, void *sm_data);
-static int route_dereg_sm_cpe(st_hw_session_t* p_ses, bool capture_requested);
+static int route_dereg_sm_cpe(st_hw_session_t* p_ses);
static int route_dereg_sm_params_cpe(st_hw_session_t* p_ses);
static int route_start_cpe(st_hw_session_t* p_ses);
static int route_restart(st_hw_session_t* p_ses, unsigned int recognition_mode,
- bool capture_requested, struct sound_trigger_recognition_config *rc_config __unused,
+ struct sound_trigger_recognition_config *rc_config __unused,
sound_trigger_sound_model_type_t sm_type, void *sm_data);
static int route_stop_cpe(st_hw_session_t* p_ses);
-static int route_stop_buffering_cpe(st_hw_session_t* p_ses, bool capture_requested);
+static int route_stop_buffering_cpe(st_hw_session_t* p_ses);
static int route_set_device_cpe(st_hw_session_t* p_ses,
bool enable);
static int route_read_pcm_cpe(st_hw_session_t *p_ses,
@@ -1013,13 +1012,15 @@
convert_ms_to_bytes(
p_lsm_ses->common.vendor_uuid_info->kw_start_tolerance,
&p_lsm_ses->common.config);
- if (p_lsm_ses->common.client_req_hist_buf) {
+ if (p_lsm_ses->common.sthw_cfg.client_req_hist_buf) {
kw_duration_bytes =
- convert_ms_to_bytes(p_lsm_ses->common.client_req_hist_buf,
+ convert_ms_to_bytes(
+ p_lsm_ses->common.sthw_cfg.client_req_hist_buf,
&p_lsm_ses->common.config);
} else {
kw_duration_bytes =
- convert_ms_to_bytes(p_lsm_ses->common.vendor_uuid_info->kw_duration,
+ convert_ms_to_bytes(
+ p_lsm_ses->common.vendor_uuid_info->kw_duration,
&p_lsm_ses->common.config);
}
@@ -1086,7 +1087,7 @@
}
if (p_lsm_ses->common.enable_second_stage &&
- !p_lsm_ses->common.client_req_hist_buf)
+ !p_lsm_ses->common.sthw_cfg.client_req_hist_buf)
p_lsm_ses->move_client_ptr = true;
else
p_lsm_ses->move_client_ptr = false;
@@ -1115,7 +1116,7 @@
ALOGE("%s: pcm read failed status %d - %s", __func__, status,
pcm_get_error(p_lsm_ses->pcm));
p_lsm_ses->exit_lab_processing = true;
- p_lsm_ses->common.fptrs->stop_buffering(&p_lsm_ses->common, true);
+ p_lsm_ses->common.fptrs->stop_buffering(&p_lsm_ses->common);
pcm_stop(p_lsm_ses->pcm);
pcm_start(p_lsm_ses->pcm);
break;
@@ -1359,7 +1360,7 @@
exit:
if (!p_ses->exit_lab_processing) {
p_ses->exit_lab_processing = true;
- p_ses->common.fptrs->stop_buffering(&p_ses->common, true);
+ p_ses->common.fptrs->stop_buffering(&p_ses->common);
}
ST_DBG_FILE_CLOSE(fptr_drv);
@@ -1396,13 +1397,15 @@
convert_ms_to_bytes(
p_lsm_ses->common.vendor_uuid_info->kw_start_tolerance,
&p_lsm_ses->common.config);
- if (p_lsm_ses->common.client_req_hist_buf) {
+ if (p_lsm_ses->common.sthw_cfg.client_req_hist_buf) {
kw_duration_bytes =
- convert_ms_to_bytes(p_lsm_ses->common.client_req_hist_buf,
+ convert_ms_to_bytes(
+ p_lsm_ses->common.sthw_cfg.client_req_hist_buf,
&p_lsm_ses->common.config);
} else {
kw_duration_bytes =
- convert_ms_to_bytes(p_lsm_ses->common.vendor_uuid_info->kw_duration,
+ convert_ms_to_bytes(
+ p_lsm_ses->common.vendor_uuid_info->kw_duration,
&p_lsm_ses->common.config);
}
@@ -1472,7 +1475,7 @@
}
if (p_lsm_ses->common.enable_second_stage &&
- !p_lsm_ses->common.client_req_hist_buf)
+ !p_lsm_ses->common.sthw_cfg.client_req_hist_buf)
p_lsm_ses->move_client_ptr = true;
else
p_lsm_ses->move_client_ptr = false;
@@ -1524,6 +1527,7 @@
}
ape_stop_buffering(&p_lsm_ses->common);
+ p_lsm_ses->lab_on_detection = false;
p_lsm_ses->lab_processing_active = false;
pthread_cond_broadcast(&p_lsm_ses->cond);
pthread_mutex_unlock(&p_lsm_ses->lock);
@@ -1648,6 +1652,9 @@
hw_sess_event.payload.detected.payload_size = params->payload_size;
}
+ if (p_lsm_ses->common.lab_enabled)
+ p_lsm_ses->lab_on_detection = true;
+
ST_DBG_DECLARE(FILE *detect_fd = NULL; static int detect_fd_cnt = 0);
ST_DBG_FILE_OPEN_WR(detect_fd, ST_DEBUG_DUMP_LOCATION,
"lsm_detection_event", "bin", detect_fd_cnt++);
@@ -1854,8 +1861,9 @@
unsigned int rt_bytes_one_sec;
p_lsm_ses->lab_drv_buf_size = pcm_frames_to_bytes(p_lsm_ses->pcm,
- p_lsm_ses->common.config.period_size);
- p_lsm_ses->lab_drv_buf = (unsigned char *)calloc(1, p_lsm_ses->lab_drv_buf_size);
+ p_lsm_ses->common.config.period_size);
+ p_lsm_ses->lab_drv_buf = (unsigned char *)calloc(1,
+ p_lsm_ses->lab_drv_buf_size);
if (!p_lsm_ses->lab_drv_buf) {
ALOGE("%s: ERROR. Can not allocate lab buffer size %d", __func__,
p_lsm_ses->lab_drv_buf_size);
@@ -1866,13 +1874,13 @@
__func__, p_lsm_ses->lab_drv_buf_size);
rt_bytes_one_sec = (p_lsm_ses->common.config.rate *
- p_lsm_ses->common.config.channels *
- (pcm_format_to_bits(p_lsm_ses->common.config.format) >> 3));
+ p_lsm_ses->common.config.channels *
+ (pcm_format_to_bits(p_lsm_ses->common.config.format) >> 3));
- if ((p_lsm_ses->common.client_req_hist_buf +
- p_lsm_ses->common.client_req_preroll) > v_info->kw_duration) {
- circ_buff_sz = ((p_lsm_ses->common.client_req_hist_buf +
- p_lsm_ses->common.client_req_preroll +
+ if ((p_lsm_ses->common.sthw_cfg.client_req_hist_buf +
+ p_lsm_ses->common.sthw_cfg.client_req_preroll) > v_info->kw_duration) {
+ circ_buff_sz = ((p_lsm_ses->common.sthw_cfg.client_req_hist_buf +
+ p_lsm_ses->common.sthw_cfg.client_req_preroll +
v_info->client_capture_read_delay) * rt_bytes_one_sec) / 1000;
} else {
circ_buff_sz = ((v_info->kw_duration +
@@ -1918,12 +1926,10 @@
profile_type = get_profile_type(p_ses);
if (enable) {
status = platform_stdev_check_and_set_codec_backend_cfg(
- p_ses->stdev->platform,
- v_info,
- &backend_cfg_change,
- p_ses->stdev->lpi_enable,
- p_ses->stdev->vad_enable,
- p_ses->client_req_preroll);
+ p_ses->stdev->platform, v_info, &backend_cfg_change,
+ p_ses->stdev->lpi_enable, p_ses->stdev->vad_enable,
+ p_ses->sthw_cfg.client_req_preroll);
+
if (status) {
ALOGE("%s: ERROR. codec backend config update failed, status=%d",
__func__, status);
@@ -2032,15 +2038,11 @@
}
static int ape_reg_sm(st_hw_session_t *p_ses, void *sm_data,
- sound_trigger_sound_model_type_t sm_type)
+ unsigned int sm_size, sound_trigger_sound_model_type_t sm_type __unused)
{
int status = 0, param_count = 0, stage_idx = 0;
st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t*)p_ses;
struct st_vendor_info *v_info = p_ses->vendor_uuid_info;
- struct sound_trigger_phrase_sound_model *phrase_sm =
- (struct sound_trigger_phrase_sound_model*)sm_data;
- struct sound_trigger_sound_model *common_sm=
- (struct sound_trigger_sound_model*)sm_data;
struct snd_lsm_session_data ses_data;
struct snd_lsm_module_params lsm_params;
lsm_param_info_t param_info[LSM_MAX_STAGES_PER_SESSION];
@@ -2051,7 +2053,7 @@
struct st_module_param_info *mparams = NULL;
audio_devices_t capture_device = 0;
- ALOGD("%s:[%d] Enter vinfo %p", __func__, p_ses->sm_handle, v_info);
+ ALOGD("%s:[%d] Enter", __func__, p_ses->sm_handle);
p_lsm_ses->pcm_id = platform_ape_get_pcm_device_id(p_ses->stdev->platform,
&p_ses->use_case_idx);
@@ -2172,16 +2174,9 @@
stage_idx = LSM_STAGE_INDEX_FIRST;
lsm_params.params = (unsigned char*)¶m_info[0];
mparams = p_lsm_ses->lsm_usecase->params;
+ param_info[param_count].param_data = sm_data;
+ param_info[param_count].param_size = sm_size;
- if (sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
- param_info[param_count].param_size = phrase_sm->common.data_size;
- param_info[param_count].param_data =
- (unsigned char*)phrase_sm + phrase_sm->common.data_offset;
- } else {
- param_info[param_count].param_size = common_sm->data_size;
- param_info[param_count].param_data =
- (unsigned char*)common_sm + common_sm->data_offset;
- }
lsm_fill_param_info(LSM_REG_SND_MODEL, ¶m_info[param_count++],
&mparams[LOAD_SOUND_MODEL], stage_idx);
@@ -2258,7 +2253,7 @@
return status;
}
-static int ape_dereg_sm(st_hw_session_t *p_ses, bool capture_requested)
+static int ape_dereg_sm(st_hw_session_t *p_ses)
{
int status = 0, buf_en = 0;
struct snd_lsm_module_params lsm_params;
@@ -2271,18 +2266,6 @@
ALOGD("%s:[%d] Enter", __func__, p_lsm_ses->common.sm_handle);
- if (p_ses->conf_levels_info) {
- free(p_ses->conf_levels_info);
- p_ses->conf_levels_info = NULL;
- }
-
- if (p_ses->conf_levels) {
- free(p_ses->conf_levels);
- p_ses->conf_levels = NULL;
- }
-
- p_ses->rc_config = NULL;
-
if (!p_lsm_ses->pcm) {
ALOGV("%s: pcm NULL", __func__);
return status;
@@ -2303,7 +2286,7 @@
mparams = p_lsm_ses->lsm_usecase->params;
/* reset last stage only if lab capture was set */
- if ((stage_idx == p_lsm_ses->num_stages - 1) && capture_requested &&
+ if ((stage_idx == p_lsm_ses->num_stages - 1) && p_ses->lab_enabled &&
(p_lsm_ses->lsm_usecase->param_tag_tracker & PARAM_LAB_CONTROL_BIT)) {
param_info[param_count].param_size = sizeof(buf_en);
param_info[param_count].param_data = (unsigned char *)&buf_en;
@@ -2316,7 +2299,7 @@
ss_cfg = node_to_item(node, st_lsm_ss_config_t, list_node);
mparams = ss_cfg->params->params;
/* reset last stage only if lab capture was set */
- if ((stage_idx == p_lsm_ses->num_stages) && (!capture_requested))
+ if ((stage_idx == p_lsm_ses->num_stages) && (!p_ses->lab_enabled))
break;
param_info[param_count].param_size = sizeof(buf_en);
@@ -2335,7 +2318,7 @@
__func__, status);
}
- if (capture_requested) {
+ if (p_ses->lab_enabled) {
/*
* Check and reset lab if ses was non-multi-stage,
* and lab control param bit was not set.
@@ -2395,8 +2378,9 @@
return status;
}
-static int ape_reg_sm_params(st_hw_session_t* p_ses, unsigned int recognition_mode,
- bool capture_requested, struct sound_trigger_recognition_config *rc_config,
+static int ape_reg_sm_params(st_hw_session_t* p_ses,
+ unsigned int recognition_mode, bool capture_requested,
+ struct sound_trigger_recognition_config *rc_config __unused,
sound_trigger_sound_model_type_t sm_type __unused, void *sm_data __unused)
{
int status = 0, buf_en = 1, retry_num = 0, offset = 0;
@@ -2460,8 +2444,8 @@
if (status)
goto error_exit;
- if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
- p_ses->vendor_uuid_info->is_qcva_uuid && !capture_requested)
+ if ((p_ses->sthw_cfg.custom_data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
+ v_info->is_qcva_uuid && !capture_requested)
disable_custom_config = true;
ATRACE_BEGIN("sthal:lsm: pcm_start");
@@ -2490,6 +2474,8 @@
ALOGE("%s: Unknown recognition mode %d", __func__, recognition_mode);
goto error_exit_1;
}
+ ALOGV("%s: st recogntion_mode %d, dsp det_mode %d", __func__,
+ recognition_mode, det_mode.mode);
stage_idx = LSM_STAGE_INDEX_FIRST;
param_count = 0;
@@ -2498,18 +2484,18 @@
mparams = p_lsm_ses->lsm_usecase->params;
/*
- * If smlib is not present, pass only the opaque data as custom params and
+ * For other than QTI VA, pass only the opaque data as custom params and
* ignore sending all other params
*/
- if (v_info->smlib_handle) {
+ if (v_info->is_qcva_uuid || v_info->is_qcmd_uuid) {
det_mode.detect_failure = p_ses->stdev->detect_failure;
ALOGV("%s: dm %d df %d lab %d", __func__,
det_mode.mode, det_mode.detect_failure, capture_requested);
if (param_tag_tracker & PARAM_CONFIDENCE_LEVELS_BIT) {
/* fill confidence level params */
cfl_params = ¶m_info[param_count++];
- cfl_params->param_size = p_ses->num_conf_levels;
- cfl_params->param_data = p_ses->conf_levels;
+ cfl_params->param_size = p_ses->sthw_cfg.num_conf_levels;
+ cfl_params->param_data = p_ses->sthw_cfg.conf_levels;
lsm_fill_param_info(LSM_MIN_CONFIDENCE_LEVELS, cfl_params,
&mparams[CONFIDENCE_LEVELS], stage_idx);
{
@@ -2541,7 +2527,7 @@
* Custom config is mandatory for adsp multi-stage session,
* Default config would be sent if not explicitly set from client applicaiton.
*/
- if ((rc_config->data_size && !disable_custom_config) ||
+ if ((p_ses->sthw_cfg.custom_data_size && !disable_custom_config) ||
!list_empty(&p_ses->lsm_ss_cfg_list)) {
/* fill opaque data as custom params */
cus_params = ¶m_info[param_count++];
@@ -2600,29 +2586,34 @@
}
/* copy opaque data from recognition config to payload */
- if (((rc_config->data_size == 0) ||
- (rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE)) &&
- p_ses->vendor_uuid_info->is_qcva_uuid) {
- st_hw_ses_get_hist_buff_payload(p_ses, (uint8_t *)custom_payload + offset,
- custom_payload_size - offset);
+ if (v_info->is_qcva_uuid &&
+ ((p_ses->sthw_cfg.custom_data_size == 0) ||
+ (p_ses->sthw_cfg.custom_data_size >
+ CUSTOM_CONFIG_OPAQUE_DATA_SIZE))) {
+ st_hw_ses_get_hist_buff_payload(p_ses,
+ (uint8_t *)custom_payload + offset,
+ custom_payload_size - offset);
} else {
/* copy opaque data from recognition config to payload */
memcpy((char *)custom_payload + offset,
- (char *)rc_config + rc_config->data_offset, rc_config->data_size);
+ p_ses->sthw_cfg.custom_data,
+ p_ses->sthw_cfg.custom_data_size);
}
} else {
/*
* Send opaque data as it is,
- * Using legacy custom param where app needs to form appropriate payload.
+ * Using legacy custom param where app needs to form appropriate
+ * payload.
*/
- custom_payload_size = rc_config->data_size;
- custom_payload = (unsigned char *)calloc(1, custom_payload_size);
+ custom_payload_size = p_ses->sthw_cfg.custom_data_size;
+ custom_payload = calloc(1, custom_payload_size);
if (!custom_payload) {
- ALOGE("%s: ERROR. Cannot allocate memory for custom_payload", __func__);
+ ALOGE("%s: ERROR. Cannot allocate memory for custom_payload",
+ __func__);
goto error_exit_1;
}
- memcpy(custom_payload, (char *)rc_config + rc_config->data_offset,
- rc_config->data_size);
+ memcpy(custom_payload, p_ses->sthw_cfg.custom_data,
+ p_ses->sthw_cfg.custom_data_size);
}
cus_params->param_size = custom_payload_size;
cus_params->param_data = (unsigned char *)custom_payload;
@@ -2844,7 +2835,7 @@
goto error_exit_1;
}
}
-
+ p_ses->lab_enabled = capture_requested;
return status;
error_exit_1:
@@ -2971,12 +2962,11 @@
return status;
}
-static int cpe_reg_sm(st_hw_session_t *p_ses, void* sm_data,
- sound_trigger_sound_model_type_t sm_type)
+static int cpe_reg_sm(st_hw_session_t *p_ses,
+ void* sm_data, unsigned int sm_size,
+ sound_trigger_sound_model_type_t sm_type __unused)
{
int status = 0, fd;
- struct sound_trigger_phrase_sound_model *phrase_sm = sm_data;
- struct sound_trigger_sound_model *common_sm= sm_data;
struct snd_lsm_module_params lsm_params;
struct lsm_params_info param_info;
struct st_vendor_info *v_info = p_ses->vendor_uuid_info;
@@ -3080,16 +3070,8 @@
param_info.param_type = LSM_REG_SND_MODEL;
param_info.module_id = mparams[LOAD_SOUND_MODEL].module_id;
param_info.param_id = mparams[LOAD_SOUND_MODEL].param_id;
-
- if (sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
- param_info.param_size = phrase_sm->common.data_size;
- param_info.param_data =
- (unsigned char*)phrase_sm + phrase_sm->common.data_offset;
- } else {
- param_info.param_size = common_sm->data_size;
- param_info.param_data =
- (unsigned char*)common_sm + common_sm->data_offset;
- }
+ param_info.param_data = sm_data;
+ param_info.param_size = sm_size;
lsm_params.num_params = 1;
lsm_params.params = (unsigned char*)¶m_info;
@@ -3131,7 +3113,7 @@
return status;
}
-static int cpe_dereg_sm(st_hw_session_t *p_ses, bool capture_requested)
+static int cpe_dereg_sm(st_hw_session_t *p_ses)
{
int status = 0, buf_en;
struct snd_lsm_module_params lsm_params;
@@ -3141,18 +3123,6 @@
ALOGD("%s:[%d] Enter", __func__, p_lsm_ses->common.sm_handle);
- if (p_ses->conf_levels_info) {
- free(p_ses->conf_levels_info);
- p_ses->conf_levels_info = NULL;
- }
-
- if (p_ses->conf_levels) {
- free(p_ses->conf_levels);
- p_ses->conf_levels = NULL;
- }
-
- p_ses->rc_config = NULL;
-
if (!p_lsm_ses->pcm) {
ALOGV("%s: pcm NULL", __func__);
return status;
@@ -3164,7 +3134,7 @@
/* note see note in ape_dereg_sm */
pthread_join(p_lsm_ses->callback_thread, (void **) NULL);
- if (capture_requested) {
+ if (p_ses->lab_enabled) {
buf_en = 0;
ATRACE_BEGIN("sthal:lsm: pcm_ioctl sndrv_lsm_lab_control");
status = pcm_ioctl(p_lsm_ses->pcm, SNDRV_LSM_LAB_CONTROL, &buf_en);
@@ -3209,8 +3179,9 @@
return status;
}
-static int cpe_reg_sm_params(st_hw_session_t* p_ses, unsigned int recognition_mode,
- bool capture_requested, struct sound_trigger_recognition_config *rc_config,
+static int cpe_reg_sm_params(st_hw_session_t* p_ses,
+ unsigned int recognition_mode, bool capture_requested,
+ struct sound_trigger_recognition_config *rc_config __unused,
sound_trigger_sound_model_type_t sm_type, void *sm_data __unused)
{
int status = 0, idx = 0;
@@ -3248,8 +3219,8 @@
return status;
}
- if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
- p_ses->vendor_uuid_info->is_qcva_uuid && !capture_requested)
+ if (!capture_requested && v_info->is_qcva_uuid &&
+ (p_ses->sthw_cfg.custom_data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE))
disable_custom_config = true;
ATRACE_BEGIN("sthal:lsm: pcm_start");
@@ -3287,24 +3258,24 @@
param_tag_tracker = p_lsm_ses->lsm_usecase->param_tag_tracker;
/*
- * If this is generic sound model or smlib is not present, pass only the
+ * If this is generic sound model or other than QTI VA, pass only the
* opaque data as custom params and ignore sending all other params.
*/
- if (v_info->smlib_handle &&
+ if ((v_info->is_qcva_uuid || v_info->is_qcmd_uuid) &&
(sm_type == SOUND_MODEL_TYPE_KEYPHRASE)) {
det_mode.detect_failure = p_ses->stdev->detect_failure;
ALOGV("%s: dm %d df %d lab %d", __func__,
det_mode.mode, det_mode.detect_failure, capture_requested);
if ((param_tag_tracker & PARAM_CONFIDENCE_LEVELS_BIT) &&
- p_ses->conf_levels) {
+ p_ses->sthw_cfg.conf_levels) {
/* fill confidence level params if present */
cfl_params = ¶m_info[idx++];
cfl_params->param_type = LSM_MIN_CONFIDENCE_LEVELS;
cfl_params->module_id = mparams[CONFIDENCE_LEVELS].module_id;
cfl_params->param_id = mparams[CONFIDENCE_LEVELS].param_id;
- cfl_params->param_size = p_ses->num_conf_levels;
- cfl_params->param_data = p_ses->conf_levels;
+ cfl_params->param_size = p_ses->sthw_cfg.num_conf_levels;
+ cfl_params->param_data = p_ses->sthw_cfg.conf_levels;
lsm_params.num_params++;
{
unsigned int i;
@@ -3327,7 +3298,7 @@
}
}
- if (rc_config->data_size && !disable_custom_config) {
+ if (p_ses->sthw_cfg.custom_data_size && !disable_custom_config) {
/* fill opaque data as custom params */
cus_params = ¶m_info[idx++];
if (param_tag_tracker & PARAM_CUSTOM_CONFIG_BIT) {
@@ -3348,29 +3319,31 @@
memcpy(custom_payload, &custom_conf_params, sizeof(struct lsm_param_payload));
offset += sizeof(struct lsm_param_payload);
/* copy opaque data from recognition config to payload */
- if (((rc_config->data_size == 0) ||
- (rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE)) &&
- p_ses->vendor_uuid_info->is_qcva_uuid) {
- st_hw_ses_get_hist_buff_payload(p_ses, (uint8_t *)custom_payload + offset,
- custom_payload_size - offset);
+ if (v_info->is_qcva_uuid &&
+ ((p_ses->sthw_cfg.custom_data_size == 0) ||
+ (p_ses->sthw_cfg.custom_data_size >
+ CUSTOM_CONFIG_OPAQUE_DATA_SIZE))) {
+ st_hw_ses_get_hist_buff_payload(p_ses,
+ (uint8_t *)custom_payload + offset,
+ custom_payload_size - offset);
} else {
/* copy opaque data from recognition config to payload */
memcpy((char *)custom_payload + offset,
- (char *)rc_config + rc_config->data_offset, rc_config->data_size);
+ p_ses->sthw_cfg.custom_data, p_ses->sthw_cfg.custom_data_size);
}
} else {
- /*
+ /*
* Send opaque data as it is,
* Using legacy custom param where app needs to form appropriate payload.
*/
- custom_payload_size = rc_config->data_size;
- custom_payload = (unsigned char *)calloc(1, custom_payload_size);
- if (!custom_payload) {
- ALOGE("%s: ERROR. Cannot allocate memory for custom_payload", __func__);
- goto error_exit;
- }
- memcpy(custom_payload, (char *)rc_config + rc_config->data_offset,
- rc_config->data_size);
+ custom_payload_size = p_ses->sthw_cfg.custom_data_size;
+ custom_payload = calloc(1, custom_payload_size);
+ if (!custom_payload) {
+ ALOGE("%s: ERROR. Cannot allocate memory for custom_payload", __func__);
+ goto error_exit;
+ }
+ memcpy(custom_payload, p_ses->sthw_cfg.custom_data,
+ p_ses->sthw_cfg.custom_data_size);
}
cus_params->param_type = LSM_CUSTOM_PARAMS;
cus_params->param_size = custom_payload_size;
@@ -3406,7 +3379,7 @@
if (status)
goto err_exit_1;
}
-
+ p_ses->lab_enabled = capture_requested;
ALOGD("%s:[%d] Exit, status=%d", __func__, p_lsm_ses->common.sm_handle, status);
return 0;
error_exit:
@@ -3489,7 +3462,7 @@
return status;
}
-static int cpe_stop_buffering(st_hw_session_t* p_ses, bool capture_requested)
+static int cpe_stop_buffering(st_hw_session_t* p_ses)
{
int status = 0;
st_hw_session_lsm_t *p_lsm_ses =
@@ -3516,7 +3489,7 @@
ALOGE("%s: ERROR. SNDRV_PCM_IOCTL_RESET failed status %d",
__func__, status);
}
- if (capture_requested) {
+ if (p_ses->lab_enabled) {
pthread_mutex_lock(&p_lsm_ses->lock);
pthread_cond_broadcast(&p_lsm_ses->cond);
pthread_mutex_unlock(&p_lsm_ses->lock);
@@ -3527,9 +3500,9 @@
}
static int route_reg_sm_ape(st_hw_session_t *p_ses,void *sm_data,
- sound_trigger_sound_model_type_t sm_type)
+ unsigned int sm_size, sound_trigger_sound_model_type_t sm_type)
{
- return ape_reg_sm(p_ses, sm_data, sm_type);
+ return ape_reg_sm(p_ses, sm_data, sm_size, sm_type);
}
static int route_reg_sm_params_ape(st_hw_session_t* p_ses,
@@ -3546,12 +3519,11 @@
return ape_dereg_sm_params(p_ses);
}
-static int route_dereg_sm_ape(st_hw_session_t* p_ses,
- bool capture_requested)
+static int route_dereg_sm_ape(st_hw_session_t* p_ses)
{
int status = 0;
- status = ape_dereg_sm(p_ses, capture_requested);
+ status = ape_dereg_sm(p_ses);
return status;
}
@@ -3564,7 +3536,6 @@
static int route_restart_ape(st_hw_session_t* p_ses,
unsigned int recognition_mode __unused,
- bool capture_requested __unused,
struct sound_trigger_recognition_config *rc_config __unused,
sound_trigger_sound_model_type_t sm_type __unused,
void *sm_data __unused)
@@ -3582,7 +3553,7 @@
return ape_stop(p_ses);
}
-static int route_stop_buffering_ape(st_hw_session_t* p_ses, bool capture_requested __unused)
+static int route_stop_buffering_ape(st_hw_session_t* p_ses)
{
int status = 0;
st_hw_session_lsm_t *p_lsm_ses = (st_hw_session_lsm_t *)p_ses;
@@ -3630,6 +3601,11 @@
break;
}
}
+ if (p_lsm_ses->lab_on_detection) {
+ ape_stop_buffering(&p_lsm_ses->common);
+ p_lsm_ses->lab_on_detection = false;
+ }
+
pthread_mutex_unlock(&p_lsm_ses->lock);
return status;
@@ -3675,9 +3651,9 @@
}
static int route_reg_sm_cpe(st_hw_session_t *p_ses, void* sm_data,
- sound_trigger_sound_model_type_t sm_type)
+ unsigned int sm_size, sound_trigger_sound_model_type_t sm_type)
{
- return cpe_reg_sm(p_ses, sm_data, sm_type);
+ return cpe_reg_sm(p_ses, sm_data, sm_size, sm_type);
}
static int route_reg_sm_params_cpe(st_hw_session_t* p_ses,
@@ -3694,9 +3670,9 @@
return cpe_dereg_sm_params(p_ses);
}
-static int route_dereg_sm_cpe(st_hw_session_t* p_ses, bool capture_requested)
+static int route_dereg_sm_cpe(st_hw_session_t* p_ses)
{
- return cpe_dereg_sm(p_ses, capture_requested);
+ return cpe_dereg_sm(p_ses);
}
static int route_start_cpe(st_hw_session_t* p_ses)
@@ -3705,7 +3681,7 @@
}
static int route_restart(st_hw_session_t* p_ses __unused, unsigned int recognition_mode __unused,
- bool capture_requested __unused, struct sound_trigger_recognition_config *rc_config __unused,
+ struct sound_trigger_recognition_config *rc_config __unused,
sound_trigger_sound_model_type_t sm_type __unused, void *sm_data __unused)
{
/*
@@ -3720,8 +3696,7 @@
return cpe_stop(p_ses);
}
-static int route_stop_buffering_cpe(st_hw_session_t* p_ses,
- bool capture_requested)
+static int route_stop_buffering_cpe(st_hw_session_t* p_ses)
{
int status = 0;
st_arm_second_stage_t *st_sec_stage;
@@ -3742,7 +3717,7 @@
}
check_and_exit_lab(p_ses);
- status = cpe_stop_buffering(p_ses, capture_requested);
+ status = cpe_stop_buffering(p_ses);
CLEAR_STATE(p_ses->state, SES_BUFFERING);
return status;
@@ -4147,7 +4122,6 @@
p_ses->sm_handle = sm_handle;
p_ses->stdev = stdev;
p_ses->is_generic_event = false;
- p_ses->client_req_det_mode = ST_HW_SESS_DET_UNKNOWN_MODE;
p_lsm_ses->exit_lab_processing = false;
p_lsm_ses->lab_processing_active = false;
diff --git a/st_hw_session_lsm.h b/st_hw_session_lsm.h
index 69fab9a..bbb6b63 100644
--- a/st_hw_session_lsm.h
+++ b/st_hw_session_lsm.h
@@ -185,6 +185,7 @@
pthread_mutex_t callback_thread_lock;
bool lab_buffers_allocated;
+ bool lab_on_detection;
void *adpcm_dec_state;
diff --git a/st_hw_session_pcm.c b/st_hw_session_pcm.c
index 8ec3e3c..a8592e8 100644
--- a/st_hw_session_pcm.c
+++ b/st_hw_session_pcm.c
@@ -73,23 +73,23 @@
} st_get_param_payload_t;
static int reg_sm(st_hw_session_t* p_ses, void *sm_data,
- sound_trigger_sound_model_type_t sm_type);
+ unsigned int sm_size,
+ sound_trigger_sound_model_type_t sm_type);
static int reg_sm_params(st_hw_session_t* p_ses, unsigned int recognition_mode,
bool capture_requested, struct sound_trigger_recognition_config *rc_config,
sound_trigger_sound_model_type_t sm_type, void *sm_data);
-static int dereg_sm(st_hw_session_t* p_ses, bool capture_requested);
+static int dereg_sm(st_hw_session_t* p_ses);
static int dereg_sm_params(st_hw_session_t* p_ses);
static int start(st_hw_session_t* p_ses);
static int stop(st_hw_session_t* p_ses);
-static int stop_buffering(st_hw_session_t* p_ses, bool capture_requested);
+static int stop_buffering(st_hw_session_t* p_ses);
static int set_device(st_hw_session_t *p_ses,
bool enable);
static int disable_device(st_hw_session_t *p_ses, bool setting_device);
static int enable_device(st_hw_session_t *p_ses, bool setting_device);
static void process_lab_capture(st_hw_session_t *p_ses);
static int restart(st_hw_session_t* p_ses, unsigned int recognition_mode,
- bool capture_requested,
struct sound_trigger_recognition_config *rc_config __unused,
sound_trigger_sound_model_type_t sm_type, void *sm_data __unused);
static int read_pcm(st_hw_session_t *p_ses,
@@ -1214,7 +1214,7 @@
}
static int reg_sm(st_hw_session_t *p_ses, void *sm_data,
- sound_trigger_sound_model_type_t sm_type __unused)
+ unsigned int sm_size, sound_trigger_sound_model_type_t sm_type __unused)
{
int status = 0;
st_hw_session_pcm_t *p_pcm_ses =
@@ -1225,10 +1225,6 @@
int frame_len;
int sample_rate;
const char *config_file_path = ST_FFV_CONFIG_FILE_PATH;
- struct sound_trigger_phrase_sound_model *phrase_sm =
- (struct sound_trigger_phrase_sound_model*)sm_data;
- char* sm_buffer = (char *)((unsigned char*)phrase_sm + phrase_sm->common.data_offset);
- uint32_t sm_size = phrase_sm->common.data_size;
FfvStatusType status_type;
EspStatusType esp_status_type;
int total_mem_size;
@@ -1334,7 +1330,7 @@
ALOGD("%s: LICENSE[%s] key[%d]", __func__, product_license, product_id);
status_type = ffv_init_fn(&p_pcm_ses->handle, num_tx_in_ch, num_out_ch, num_ec_ref_ch,
- frame_len, sample_rate, config_file_path, sm_buffer, sm_size,
+ frame_len, sample_rate, config_file_path, (char *)sm_data, sm_size,
&total_mem_size, product_id, product_license);
if (status_type) {
ALOGE("%s: ERROR. ffv_init returned %d", __func__, status_type);
@@ -1400,7 +1396,7 @@
return status;
}
-static int dereg_sm(st_hw_session_t *p_ses, bool capture_requested)
+static int dereg_sm(st_hw_session_t *p_ses)
{
int status = 0;
st_hw_session_pcm_t *p_pcm_ses =
@@ -1444,7 +1440,7 @@
false);
/* Deallocate buffers allocated during start_recognition */
- if (capture_requested) {
+ if (p_ses->lab_enabled) {
if (p_pcm_ses->lab_buffers_allocated) {
deallocate_lab_buffers(p_pcm_ses);
}
@@ -1478,6 +1474,7 @@
if (!p_pcm_ses->lab_buffers_allocated)
status = allocate_lab_buffers(p_pcm_ses);
}
+ p_ses->lab_enabled = capture_requested;
error:
ALOGD("%s:[%d] Exit, status=%d", __func__,
@@ -1645,7 +1642,7 @@
return status;
}
-static int pcm_stop_buffering(st_hw_session_t* p_ses, bool capture_requested)
+static int pcm_stop_buffering(st_hw_session_t* p_ses)
{
int status = 0;
st_hw_session_pcm_t *p_pcm_ses =
@@ -1654,7 +1651,7 @@
ALOGD("%s:[%d] Enter pcm %p", __func__, p_pcm_ses->common.sm_handle,
p_pcm_ses->pcm);
- if (capture_requested) {
+ if (p_ses->lab_enabled) {
pthread_mutex_lock(&p_pcm_ses->lab_out_buf_lock);
pthread_cond_broadcast(&p_pcm_ses->lab_out_buf_cond);
pthread_mutex_unlock(&p_pcm_ses->lab_out_buf_lock);
@@ -1679,7 +1676,7 @@
}
}
-static int stop_buffering(st_hw_session_t* p_ses, bool capture_requested)
+static int stop_buffering(st_hw_session_t* p_ses)
{
st_hw_session_pcm_t *p_pcm_ses =
(st_hw_session_pcm_t *)p_ses;
@@ -1693,14 +1690,13 @@
}
check_and_exit_lab(p_ses);
- status = pcm_stop_buffering(p_ses, capture_requested);
+ status = pcm_stop_buffering(p_ses);
CLEAR_STATE(p_ses->state, SES_BUFFERING);
return status;
}
static int restart(st_hw_session_t* p_ses, unsigned int recognition_mode __unused,
- bool capture_requested __unused,
struct sound_trigger_recognition_config *rc_config __unused,
sound_trigger_sound_model_type_t sm_type __unused, void *sm_data __unused)
{
diff --git a/st_second_stage.c b/st_second_stage.c
index 1090513..e153e39 100644
--- a/st_second_stage.c
+++ b/st_second_stage.c
@@ -33,7 +33,7 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define LOG_TAG "sound_trigger_hw"
+#define LOG_TAG "sound_trigger_hw:ss"
#define ATRACE_TAG (ATRACE_TAG_HAL)
/* #define LOG_NDEBUG 0 */
#define LOG_NDDEBUG 0
@@ -227,7 +227,8 @@
kw_start_ms, kw_end_ms);
} else {
ss_session->det_status = KEYWORD_DETECTION_REJECT;
- ALOGD("%s: Detection reject", __func__);
+ ALOGD("%s: Detection reject, confidence level = %d", __func__,
+ ss_session->confidence_score);
}
/* Signal aggregator thread with detection result */
pthread_cond_signal(&ss_session->st_ses->ss_detections_cond);
@@ -362,8 +363,8 @@
capi_uv_ptr.actual_data_len = sizeof(voiceprint2_sva_uv_score_t);
capi_uv_ptr.max_data_len = sizeof(voiceprint2_sva_uv_score_t);
- ALOGV("%s: Issuing capi_set_param for param %d", __func__,
- VOICEPRINT2_ID_SVA_UV_SCORE);
+ ALOGV("%s: Issuing capi_set_param for param %d, uv_conf_score %f", __func__,
+ VOICEPRINT2_ID_SVA_UV_SCORE, uv_cfg_ptr->sva_uv_confidence_score);
rc = ss_session->capi_handle->vtbl_ptr->set_param(ss_session->capi_handle,
VOICEPRINT2_ID_SVA_UV_SCORE, NULL, &capi_uv_ptr);
if (CAPI_V2_EOK != rc) {
@@ -429,7 +430,8 @@
ss_session->confidence_score);
} else {
ss_session->det_status = USER_VERIFICATION_REJECT;
- ALOGD("%s: Detection reject", __func__);
+ ALOGD("%s: Detection reject, confidence level = %d", __func__,
+ ss_session->confidence_score);
}
/* Signal aggregator thread with detection result */
pthread_cond_signal(&ss_session->st_ses->ss_detections_cond);
@@ -721,8 +723,10 @@
{
if (st_sec_stage) {
if (st_sec_stage->ss_session) {
- dlclose(st_sec_stage->ss_session->capi_lib_handle);
- st_sec_stage->ss_session->capi_lib_handle = NULL;
+ if (st_sec_stage->ss_session->capi_lib_handle) {
+ dlclose(st_sec_stage->ss_session->capi_lib_handle);
+ st_sec_stage->ss_session->capi_lib_handle = NULL;
+ }
if (st_sec_stage->ss_session->capi_handle) {
st_sec_stage->ss_session->capi_handle->vtbl_ptr = NULL;
free(st_sec_stage->ss_session->capi_handle);
@@ -762,7 +766,7 @@
if ((st_sec_stage->ss_info->sm_detection_type ==
ST_SM_TYPE_USER_VERIFICATION) &&
- !st_sec_stage->ss_session->st_ses->stdev->ssr_offline_received) {
+ !st_sec_stage->stdev->ssr_offline_received) {
ALOGV("%s: Issuing capi_end", __func__);
rc = st_sec_stage->ss_session->capi_handle->vtbl_ptr->end(
st_sec_stage->ss_session->capi_handle);
diff --git a/st_second_stage.h b/st_second_stage.h
index 6107775..64662d8 100644
--- a/st_second_stage.h
+++ b/st_second_stage.h
@@ -88,6 +88,7 @@
struct st_second_stage_info *ss_info;
struct listnode list_node;
struct st_arm_ss_session *ss_session;
+ struct sound_trigger_device *stdev;
FILE *dump_fp;
}st_arm_second_stage_t;
@@ -97,7 +98,7 @@
pthread_mutex_t lock;
pthread_cond_t cond;
bool exit_thread;
- struct st_session *st_ses;
+ struct st_proxy_session *st_ses;
/* For CNN to overwrite 1st stage indices */
uint32_t kw_start_idx;
diff --git a/st_session.c b/st_session.c
index f5b362a..aaac3df 100644
--- a/st_session.c
+++ b/st_session.c
@@ -54,8 +54,10 @@
#ifdef LINUX_ENABLED
#define ST_SES_DEFERRED_STOP_DELAY_MS 0
+#define ST_SES_DEFERRED_STOP_SS_DELAY_MS 0
#else
#define ST_SES_DEFERRED_STOP_DELAY_MS 1000
+#define ST_SES_DEFERRED_STOP_SS_DELAY_MS 250
#endif
#define IS_SS_DETECTION_PENDING(det)\
@@ -63,6 +65,26 @@
#define IS_SS_DETECTION_SUCCESS(det)\
!(det & (KEYWORD_DETECTION_REJECT | USER_VERIFICATION_REJECT))
+#define STATE_TRANSITION(st_session, new_state_fn)\
+do {\
+ if (st_session->current_state != new_state_fn) {\
+ st_session->current_state = new_state_fn;\
+ ALOGD("session[%d]: %s ---> %s", st_session->sm_handle, __func__, \
+ #new_state_fn);\
+ }\
+} while(0)
+
+#define DISPATCH_EVENT(st_session, event, status)\
+do {\
+ status = st_session->current_state(st_session, &event);\
+} while (0)
+
+#define REG_SM_RETRY_CNT 5
+#define REG_SM_WAIT_TIME_MS 100
+
+#define MAX_CONF_LEVEL_VALUE (100)
+#define MAX_KW_USERS_NAME_LEN (2 * MAX_STRING_LEN)
+
/* below enum used in cleanup in error scenarios */
enum hw_session_err_mask {
HW_SES_ERR_MASK_DEVICE_SET = 0x1,
@@ -72,58 +94,8 @@
HW_SES_ERR_MASK_BUFFERING = 0x10,
};
-#define STATE_TRANSITION(st_session, new_state_fn)\
-do {\
- st_session->current_state = new_state_fn;\
- ALOGD("session[%d]: %s ---> %s %s", st_session->sm_handle, __func__, \
- #new_state_fn, st_session->paused ? "(paused)" : "");\
-} while(0)
-
-#define DISPATCH_EVENT(ST_SESSION, EVENT, STATUS)\
-do {\
- STATUS = ST_SESSION->current_state(ST_SESSION, &EVENT);\
-} while (0)
-
-#define REG_SM_RETRY_CNT 5
-#define REG_SM_WAIT_TIME_MS 100
-
-static inline int process_detection_event
-(
- st_session_t *st_ses, uint64_t timestamp, int detect_status,
- void *payload, size_t payload_size,
- struct sound_trigger_recognition_event **event
-);
-
-static inline void enable_second_stage_processing
-(
- st_session_t *st_ses,
- st_hw_session_t *hw_ses
-)
-{
- hw_ses->enable_second_stage = st_ses->enable_second_stage;
- st_ses->lab_enabled =
- (st_ses->capture_requested || st_ses->enable_second_stage);
-}
-
-static inline void disable_second_stage_processing
-(
- st_session_t *st_ses,
- st_hw_session_t *hw_ses
-)
-{
- hw_ses->enable_second_stage = false;
- st_ses->lab_enabled = st_ses->capture_requested;
-}
-
-static int idle_state_fn(st_session_t *st_ses, st_session_ev_t *ev);
-static int loaded_state_fn(st_session_t *st_ses, st_session_ev_t *ev);
-static int active_state_fn(st_session_t *st_ses, st_session_ev_t *ev);
-static int detected_state_fn(st_session_t *st_ses, st_session_ev_t *ev);
-static int buffering_state_fn(st_session_t *st_ses, st_session_ev_t *ev);
-static int ssr_state_fn(st_session_t *st_ses, st_session_ev_t *ev);
-
typedef struct st_session_loadsm_payload {
- struct sound_trigger_phrase_sound_model *sm_data;
+ struct sound_trigger_phrase_sound_model *phrase_sm;
} st_session_loadsm_payload_t;
typedef struct st_session_start_payload {
@@ -159,13 +131,28 @@
bool enable;
st_session_getparam_payload_t getparam;
} payload;
+ st_session_t *stc_ses;
};
+static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
+static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
+static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
+static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
+static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
+static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev);
+
+static inline int process_detection_event
+(
+ st_proxy_session_t *st_ses, uint64_t timestamp, int detect_status,
+ void *payload, size_t payload_size,
+ struct sound_trigger_recognition_event **event
+);
+
ST_DBG_DECLARE(static int file_cnt = 0);
void hw_sess_cb(st_hw_sess_event_t *hw_event, void *cookie)
{
- st_session_t *st_ses = (st_session_t *)cookie;
+ st_proxy_session_t *st_ses = (st_proxy_session_t *)cookie;
int status = 0;
int lock_status = 0;
@@ -176,17 +163,27 @@
switch (hw_event->event_id) {
case ST_HW_SESS_EVENT_DETECTED:
- {
- st_session_ev_t ev;
- ev.ev_id = ST_SES_EV_DETECTED;
- ev.payload.detected = hw_event->payload.detected;
+ {
+ st_session_ev_t ev;
+ ev.ev_id = ST_SES_EV_DETECTED;
+ ev.payload.detected = hw_event->payload.detected;
- do {
- lock_status = pthread_mutex_trylock(&st_ses->lock);
- } while (lock_status && !st_ses->device_disabled &&
- (st_ses->exec_mode != ST_EXEC_MODE_NONE) &&
- (st_ses->current_state != ssr_state_fn));
+ do {
+ lock_status = pthread_mutex_trylock(&st_ses->lock);
+ } while (lock_status && !st_ses->device_disabled &&
+ (st_ses->exec_mode != ST_EXEC_MODE_NONE) &&
+ (st_ses->current_state != ssr_state_fn));
+ if (st_ses->device_disabled) {
+ ALOGV("%s:[%d] device switch in progress, ignore event",
+ __func__, st_ses->sm_handle);
+ } else if (st_ses->exec_mode == ST_EXEC_MODE_NONE) {
+ ALOGV("%s:[%d] transition in progress, ignore event",
+ __func__, st_ses->sm_handle);
+ } else if (st_ses->current_state == ssr_state_fn) {
+ ALOGV("%s:[%d] SSR handling in progress, ignore event",
+ __func__, st_ses->sm_handle);
+ } else if (!lock_status) {
/*
* TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
* the SoundTrigger API header.
@@ -194,24 +191,14 @@
if (st_ses->detection_requested)
ev.payload.detected.detect_status = 3;
- if (st_ses->device_disabled) {
- ALOGV("%s:[%d] device switch in progress, ignore event",
- __func__, st_ses->sm_handle);
- } else if (st_ses->exec_mode == ST_EXEC_MODE_NONE) {
- ALOGV("%s:[%d] transition in progress, ignore event",
- __func__, st_ses->sm_handle);
- } else if (st_ses->current_state == ssr_state_fn) {
- ALOGV("%s:[%d] SSR handling in progress, ignore event",
- __func__, st_ses->sm_handle);
- } else if (!lock_status) {
- DISPATCH_EVENT(st_ses, ev, status);
- }
-
- if (!lock_status)
- pthread_mutex_unlock(&st_ses->lock);
- break;
+ DISPATCH_EVENT(st_ses, ev, status);
}
+ if (!lock_status)
+ pthread_mutex_unlock(&st_ses->lock);
+ break;
+ }
+
default:
ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
break;
@@ -219,11 +206,2133 @@
}
-static void do_hw_sess_cleanup(st_session_t *st_ses, st_hw_session_t *hw_ses,
- enum hw_session_err_mask err)
+static inline void free_array_ptrs(char **arr, unsigned int arr_len)
+{
+ int i = 0;
+
+ if (!arr)
+ return;
+
+ for (i = 0; i < arr_len; i++) {
+ if (arr[i]) {
+ free(arr[i]);
+ arr[i] = NULL;
+ }
+ }
+ free(arr);
+ arr = NULL;
+}
+
+static inline void alloc_array_ptrs(char ***arr, unsigned int arr_len,
+ unsigned int elem_len)
+{
+ char **str_arr = NULL;
+ int i = 0;
+
+ str_arr = (char **) calloc(arr_len, sizeof(char *));
+
+ if (!str_arr) {
+ *arr = NULL;
+ return;
+ }
+
+ for (i = 0; i < arr_len; i++) {
+ str_arr[i] = (char *) calloc(elem_len, sizeof(char));
+ if (str_arr[i] == NULL) {
+ free_array_ptrs(str_arr, i);
+ *arr = NULL;
+ return;
+ }
+ }
+ *arr = str_arr;
+ ALOGV("%s: string array %p", __func__, *arr);
+ for (i = 0; i < arr_len; i++)
+ ALOGV("%s: string array[%d] %p", __func__, i, (*arr)[i]);
+}
+
+
+static int merge_sound_models(struct sound_trigger_device *stdev,
+ unsigned int num_models, listen_model_type *in_models[],
+ listen_model_type *out_model)
+{
+ listen_status_enum sm_ret = 0;
+ int status = 0;
+
+ ALOGV("%s: num_models to merge %d", __func__, num_models);
+
+ if (!stdev->smlib_handle) {
+ ALOGE("%s: NULL sound model lib handle", __func__);
+ return -ENOSYS;
+ }
+
+ sm_ret = stdev->smlib_getMergedModelSize(num_models, in_models,
+ &out_model->size);
+ if ((sm_ret != kSucess) || !out_model->size) {
+ ALOGE("%s: smlib_getMergedModelSize failed, err %d, size %d", __func__,
+ sm_ret, out_model->size);
+ return -EINVAL;
+ }
+ ALOGD("%s: merge sound model size %d", __func__, out_model->size);
+
+ out_model->data = calloc(1, out_model->size * sizeof(char));
+ if (!out_model->data) {
+ ALOGE("%s: Merged sound model allocation failed", __func__);
+ return -ENOMEM;
+ }
+
+ sm_ret = stdev->smlib_mergeModels(num_models, in_models, out_model);
+ if (sm_ret != kSucess) {
+ ALOGE("%s: smlib_mergeModels failed, err %d", __func__, sm_ret);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ if (!out_model->data || !out_model->size) {
+ ALOGE("%s: MergeModels returned NULL data or size %d", __func__,
+ out_model->size);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ ALOGV("%s: Exit", __func__);
+ return 0;
+
+cleanup:
+ if (out_model->data) {
+ free(out_model->data);
+ out_model->data = NULL;
+ out_model->size = 0;
+ }
+ return status;
+}
+
+static int delete_from_merged_sound_model(struct sound_trigger_device *stdev,
+ char **keyphrases, unsigned int num_keyphrases,
+ listen_model_type *in_model, listen_model_type *out_model)
+{
+ listen_model_type merge_model = {0};
+ listen_status_enum sm_ret = 0;
+ unsigned int out_model_sz = 0;
+ int status = 0, i = 0;
+
+ out_model->data = NULL;
+ out_model->size = 0;
+ merge_model.data = in_model->data;
+ merge_model.size = in_model->size;
+
+ for (i = 0; i < num_keyphrases; i++) {
+ sm_ret = stdev->smlib_getSizeAfterDeleting(&merge_model, keyphrases[i],
+ NULL, &out_model_sz);
+ if (sm_ret != kSucess) {
+ ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ if (out_model_sz >= in_model->size) {
+ ALOGE("%s: unexpected, smlib_getSizeAfterDeleting returned size %d"
+ "not less than merged model size %d", __func__,
+ out_model_sz, in_model->size);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ ALOGV("%s: Size after deleting kw[%d] = %d", __func__, i, out_model_sz);
+ if (!out_model->data) {
+ /* Valid if deleting multiple keyphrases one after other */
+ free (out_model->data);
+ out_model->size = 0;
+ }
+ out_model->data = calloc(1, out_model_sz * sizeof(char));
+ if (!out_model->data) {
+ ALOGE("%s: Merge sound model allocation failed, size %d ", __func__,
+ out_model_sz);
+ status = -ENOMEM;
+ goto cleanup;
+ }
+ out_model->size = out_model_sz;
+
+ sm_ret = stdev->smlib_deleteFromModel(&merge_model, keyphrases[i],
+ NULL, out_model);
+ if (sm_ret != kSucess) {
+ ALOGE("%s: smlib_getSizeAfterDeleting failed %d", __func__, sm_ret);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ if (out_model->size != out_model_sz) {
+ ALOGE("%s: unexpected, out_model size %d != expected size %d",
+ __func__, out_model->size, out_model_sz);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ /* Used if deleting multiple keyphrases one after other */
+ merge_model.data = out_model->data;
+ merge_model.size = out_model->size;
+ }
+ return 0;
+
+cleanup:
+ if (out_model->data) {
+ free(out_model->data);
+ out_model->data = NULL;
+ }
+ return status;
+}
+
+static void release_sound_model_info(struct sound_model_info *sm_info)
+{
+ ALOGV("%s", __func__);
+
+ if (sm_info->cf_levels) {
+ free(sm_info->cf_levels);
+ sm_info->cf_levels = NULL;
+ sm_info->det_cf_levels = NULL;
+ }
+ free_array_ptrs(sm_info->keyphrases, sm_info->num_keyphrases);
+ sm_info->keyphrases = NULL;
+
+ free_array_ptrs(sm_info->users, sm_info->num_users);
+ sm_info->users = NULL;
+
+ free_array_ptrs(sm_info->cf_levels_kw_users, sm_info->cf_levels_size);
+ sm_info->cf_levels_kw_users = NULL;
+}
+
+static inline void stdbg_print_sound_model_header(
+ listen_sound_model_header *smh)
+{
+ int i = 0, j = 0;
+
+ ALOGV("%s", __func__);
+ ALOGV("numKeywords = %d", smh->numKeywords);
+ ALOGV("numUsers = %d", smh->numUsers);
+ ALOGV("numActiveUserKeywordPairs = %d", smh->numActiveUserKeywordPairs);
+ ALOGV("isStripped = %d", smh->isStripped);
+ ALOGV("model_indicator = %d", smh->model_indicator);
+
+ for (i = 0; i < smh->numKeywords; i++) {
+ ALOGV("kw-%d langPerKw = %d", i, smh->langPerKw[i]);
+ ALOGV("kw-%d numUsersSetPerKw = %d", i, smh->numUsersSetPerKw[i]);
+ ALOGV("kw-%d isUserDefinedKeyword = %d", i,
+ smh->isUserDefinedKeyword[i]);
+ }
+ if (smh->userKeywordPairFlags) {
+ for (i = 0; i < smh->numUsers; i++) {
+ for (j = 0; j < smh->numKeywords; j++)
+ ALOGV("userKeywordPairFlags[%d][%d] = %d", i, j,
+ smh->userKeywordPairFlags[i][j]);
+ }
+ }
+}
+
+static int query_sound_model(struct sound_trigger_device *stdev,
+ struct sound_model_info *sm_info, unsigned char *sm_data,
+ unsigned int sm_size)
+{
+ listen_sound_model_header sm_header = {0};
+ listen_model_type model = {0};
+ listen_status_enum sm_ret = 0;
+ int status = 0, i = 0, j = 0, k = 0;
+ uint16_t tmp = 0;
+
+ ALOGV("%s: enter sm_size %d", __func__, sm_size);
+
+ if (!stdev->smlib_handle) {
+ ALOGE("%s: NULL sound model lib handle", __func__);
+ return -ENOSYS;
+ }
+
+ model.data = sm_data;
+ model.size = sm_size;
+
+ sm_ret = stdev->smlib_getSoundModelHeader(&model, &sm_header);
+ if (sm_ret != kSucess) {
+ ALOGE("%s: smlib_getSoundModelHeader failed, err %d ", __func__, sm_ret);
+ return -EINVAL;
+ }
+ if (sm_header.numKeywords == 0) {
+ ALOGE("%s: num keywords zero!!", __func__);
+ return -EINVAL;
+ }
+ if (sm_header.numActiveUserKeywordPairs < sm_header.numUsers) {
+ ALOGE("%s: smlib activeUserKwPairs(%d) < total users (%d)", __func__,
+ sm_header.numActiveUserKeywordPairs, sm_header.numUsers);
+ goto cleanup;
+ }
+ if (sm_header.numUsers && !sm_header.userKeywordPairFlags) {
+ ALOGE("%s: userKeywordPairFlags is NULL, numUsers (%d)", __func__,
+ sm_header.numUsers);
+ goto cleanup;
+ }
+ stdbg_print_sound_model_header(&sm_header);
+
+ /* MAX_STRING_LEN is part of listen sound model header file */
+ alloc_array_ptrs(&sm_info->keyphrases, sm_header.numKeywords,
+ MAX_STRING_LEN);
+ if (!sm_info->keyphrases) {
+ ALOGE("%s: keyphrases allocation failed", __func__);
+ status = -ENOMEM;
+ goto cleanup;
+ }
+ sm_info->num_keyphrases = sm_header.numKeywords;
+ sm_info->num_users = sm_header.numUsers;
+
+ tmp = sm_header.numKeywords;
+ ALOGV("%s: stdb: model.data %p, model.size %d", __func__, model.data,
+ model.size);
+ sm_ret = stdev->smlib_getKeywordPhrases(&model, &tmp, sm_info->keyphrases);
+ if (sm_ret) {
+ ALOGE("%s: smlib_getKeywordPhrases failed, err %d ", __func__, sm_ret);
+ goto cleanup;
+ }
+ if (tmp != sm_header.numKeywords) {
+ ALOGE("%s: smlib_getkeywordPhrases(%d) != sml header (%d)", __func__,
+ tmp, sm_header.numKeywords);
+ goto cleanup;
+ }
+ for (i = 0; i < sm_header.numKeywords; i++)
+ ALOGV("%s: keyphrases names = %s", __func__, sm_info->keyphrases[i]);
+
+ if (sm_header.numUsers) {
+ alloc_array_ptrs(&sm_info->users, sm_header.numUsers, MAX_STRING_LEN);
+ if (!sm_info->users) {
+ ALOGE("%s: users allocation failed", __func__);
+ status = -ENOMEM;
+ goto cleanup;
+ }
+
+ tmp = sm_header.numUsers;
+ sm_ret = stdev->smlib_getUserNames(&model, &tmp, sm_info->users);
+ if (sm_ret) {
+ ALOGE("%s: smlib_getUserNames failed, err %d ", __func__, sm_ret);
+ goto cleanup;
+ }
+ if (tmp != sm_header.numUsers) {
+ ALOGE("%s: smlib_getUserNames(%d) != sml header (%d)", __func__,
+ tmp, sm_header.numUsers);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ for (i = 0; i < sm_header.numUsers; i++)
+ ALOGV("%s: users names = %s", __func__, sm_info->users[i]);
+ }
+
+ sm_info->cf_levels_size = sm_header.numKeywords +
+ sm_header.numActiveUserKeywordPairs;
+ alloc_array_ptrs(&sm_info->cf_levels_kw_users, sm_info->cf_levels_size,
+ MAX_KW_USERS_NAME_LEN);
+ if (!sm_info->cf_levels_kw_users) {
+ ALOGE("%s: cf_levels_kw_users allocation failed", __func__);
+ status = -ENOMEM;
+ goto cleanup;
+ }
+
+ /* Used later for mapping client to/from merged DSP confidence levels */
+ sm_info->cf_levels = calloc(1, 2 * sm_info->cf_levels_size);
+ if (!sm_info->cf_levels) {
+ ALOGE("%s: cf_levels allocation failed", __func__);
+ status = -ENOMEM;
+ goto cleanup;
+ }
+ /*
+ * Used for updating detection confidence level values from DSP merged
+ * detection conf levels
+ */
+ sm_info->det_cf_levels = sm_info->cf_levels + sm_info->cf_levels_size;
+
+ /*
+ * Used for conf level setting to DSP. Reset the conf value to max value,
+ * so that the keyword of a loaded and in-active model in a merged model
+ * doesn't detect.
+ */
+ memset(sm_info->cf_levels, MAX_CONF_LEVEL_VALUE, sm_info->cf_levels_size);
+
+ /*
+ * Derive the confidence level payload for keyword and user pairs.
+ * Store the user-keyword pair names in an array that will be used for
+ * mapping the DSP detection and confidence levels to the client.
+ */
+ char **kw_names = sm_info->cf_levels_kw_users;
+ char **ukw_names = &sm_info->cf_levels_kw_users[sm_header.numKeywords];
+ int ukw_idx = 0;
+
+ for (i = 0; i < sm_header.numKeywords; i++) {
+ strlcpy(kw_names[i], sm_info->keyphrases[i], MAX_KW_USERS_NAME_LEN);
+ if (!sm_header.numUsersSetPerKw)
+ continue;
+ for (j = 0, k = 0; j < sm_header.numUsers; j++) {
+ if (k >= sm_header.numUsersSetPerKw[i])
+ break;
+ if (sm_header.userKeywordPairFlags[j][i]) {
+ strlcpy(ukw_names[ukw_idx], sm_info->users[j],
+ MAX_KW_USERS_NAME_LEN);
+ strlcat(ukw_names[ukw_idx], sm_info->keyphrases[i],
+ MAX_KW_USERS_NAME_LEN);
+ ukw_idx++;
+ k++;
+ }
+ }
+ }
+ for (i = 0; i < sm_info->cf_levels_size; i++)
+ ALOGV("%s: cf_levels_kw_users = %s", __func__,
+ sm_info->cf_levels_kw_users[i]);
+
+ sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
+ if (sm_ret != kSucess) {
+ ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
+ sm_ret);
+ status = -EINVAL;
+ goto cleanup_1;
+ }
+ ALOGV("%s: exit", __func__);
+ return 0;
+
+cleanup:
+ sm_ret = stdev->smlib_releaseSoundModelHeader(&sm_header);
+ if (sm_ret != kSucess)
+ ALOGE("%s: smlib_releaseSoundModelHeader failed, err %d ", __func__,
+ sm_ret);
+
+cleanup_1:
+ release_sound_model_info(sm_info);
+
+ return status;
+}
+
+static int add_sound_model(st_session_t *stc_ses, unsigned char *sm_data,
+ unsigned int sm_size)
+{
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+ listen_model_type **in_models = NULL;
+ listen_model_type out_model = {0};
+ struct sound_model_info sm_info = {0};
+ int status = 0, num_models = 0;
+
+ ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
+ if (stc_ses->sm_info.sm_data) {
+ ALOGD("%s:[c%d] Already added", __func__, stc_ses->sm_handle);
+ return 0;
+ }
+ if (!st_ses->vendor_uuid_info->merge_fs_soundmodels) {
+ stc_ses->sm_info.sm_data = sm_data;
+ stc_ses->sm_info.sm_size = sm_size;
+ st_ses->sm_info.sm_data = sm_data;
+ st_ses->sm_info.sm_size = sm_size;
+ st_ses->sm_info.sm_type = stc_ses->sm_type;
+ ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
+ return 0;
+ }
+ /* get sound model header information for client model */
+ status = query_sound_model(st_ses->stdev, &stc_ses->sm_info,
+ sm_data, sm_size);
+ if (status)
+ return status;
+
+ stc_ses->sm_info.sm_data = sm_data;
+ stc_ses->sm_info.sm_size = sm_size;
+ ALOGV("%s: stc_ses %p - sm_data %p, sm_size %d", __func__,
+ stc_ses, stc_ses->sm_info.sm_data,
+ stc_ses->sm_info.sm_size);
+
+ /* Check for remaining client sound models to merge */
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if ((c_ses != stc_ses) && c_ses->sm_info.sm_data)
+ num_models++;
+ }
+ if (!num_models) {
+ if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
+ free(st_ses->sm_info.sm_data);
+ }
+ /* Only one current client model, just re-use it */
+ st_ses->recognition_mode = stc_ses->recognition_mode;
+ stc_ses->sm_info.sm_type = stc_ses->sm_type;
+ st_ses->sm_info = stc_ses->sm_info;
+ st_ses->sm_info.sm_merged = false;
+ ALOGD("%s: re-use single client c%d model, size %d", __func__,
+ stc_ses->sm_handle, stc_ses->sm_info.sm_size);
+ return 0;
+ }
+ ALOGV("%s: num existing models %d", __func__, num_models);
+ /*
+ * Merge this client model with already existing merged model due to other
+ * clients models.
+ */
+ if (!st_ses->sm_info.sm_data) {
+ if (num_models == 1) {
+ /*
+ * Its not a merged model yet, but proxy ses sm_data is valid and
+ * must be pointing to client sm_data
+ */
+ ALOGE("%s: Unexpected, sm_info.sm_data NULL, num current"
+ "models %d", __func__, num_models);
+ status = -EINVAL;
+ goto cleanup;
+ } else if (!st_ses->sm_info.sm_merged) {
+ ALOGE("%s: Unexpected, no pre-existing merged model, num current"
+ "models %d", __func__, num_models);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ }
+
+ /* Merge this client model with remaining clients models */
+ num_models = 2;/* re-use */
+ alloc_array_ptrs((char***)&in_models, num_models, sizeof(listen_model_type));
+ if (!in_models) {
+ ALOGE("%s: in_models allocation failed", __func__);
+ status = -ENOMEM;
+ goto cleanup;
+ }
+ /* Add existing model */
+ in_models[0]->data = st_ses->sm_info.sm_data;
+ in_models[0]->size = st_ses->sm_info.sm_size;
+ /* Add this client model */
+ in_models[1]->data = sm_data;
+ in_models[1]->size = sm_size;
+
+ status = merge_sound_models(st_ses->stdev, 2, in_models, &out_model);
+ if (status)
+ goto cleanup;
+
+ sm_info.sm_data = out_model.data;
+ sm_info.sm_size = out_model.size;
+ sm_info.sm_merged = true;
+
+ status = query_sound_model(st_ses->stdev, &sm_info,
+ out_model.data, out_model.size);
+ if (status)
+ goto cleanup;
+
+ if (out_model.size < st_ses->sm_info.sm_size) {
+ ALOGE("%s: Unexpected, merged model sz %d < current sz %d",
+ __func__, out_model.size, st_ses->sm_info.sm_size);
+ release_sound_model_info(&sm_info);
+ status = -EINVAL;
+ goto cleanup;
+ }
+ free_array_ptrs((char **)in_models, num_models);
+ in_models = NULL;
+
+ /* Update the new merged model */
+ if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
+ release_sound_model_info(&st_ses->sm_info);
+ free(st_ses->sm_info.sm_data);
+ }
+ ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
+ st_ses->sm_info.sm_size, out_model.size);
+ st_ses->sm_info = sm_info;
+
+ /*
+ * If any of the clients has user identificaiton enabled, underlying
+ * hw session has to operate with user identification enabled.
+ */
+ if (stc_ses->recognition_mode & RECOGNITION_MODE_USER_IDENTIFICATION)
+ st_ses->recognition_mode |= stc_ses->recognition_mode;
+
+ return 0;
+
+cleanup:
+ release_sound_model_info(&stc_ses->sm_info);
+ stc_ses->sm_info.sm_data = NULL;
+
+ if (out_model.data)
+ free(out_model.data);
+
+ if (in_models)
+ free_array_ptrs((char **)in_models, num_models);
+
+ return status;
+}
+
+static int delete_sound_model(st_session_t *stc_ses)
+{
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL, *c_ses_rem = NULL;
+ listen_model_type in_model = {0};
+ listen_model_type out_model = {0};
+ struct sound_model_info sm_info = {0};
+ int status = 0, num_models = 0;
+ unsigned int rec_mode = RECOGNITION_MODE_VOICE_TRIGGER;
+
+ ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
+ if (!stc_ses->sm_info.sm_data) {
+ ALOGD("%s:[c%d] Already deleted", __func__, stc_ses->sm_handle);
+ return 0;
+ }
+ if (!st_ses->vendor_uuid_info->merge_fs_soundmodels) {
+ /*
+ * As it directly points to client model, just set as NULL
+ * without freeing
+ */
+ st_ses->sm_info.sm_data = NULL;
+ stc_ses->sm_info.sm_data = NULL;
+ ALOGD("%s:[c%d] no merge", __func__, stc_ses->sm_handle);
+ return 0;
+ }
+
+ ALOGV("%s: stc_ses %p - sm_data %p, sm_size %d", __func__,
+ stc_ses, stc_ses->sm_info.sm_data,
+ stc_ses->sm_info.sm_size);
+
+ /* Check for remaining clients sound models to merge */
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
+ c_ses_rem = c_ses;
+ num_models++;
+ }
+ }
+ if (num_models == 0) {
+ ALOGD("%s: No remaining models", __func__);
+ /* Delete current client model */
+ release_sound_model_info(&stc_ses->sm_info);
+ stc_ses->sm_info.sm_data = NULL;
+ return 0;
+ }
+
+ if (num_models == 1) {
+ ALOGD("%s: reuse only remaining client model, size %d", __func__,
+ c_ses_rem->sm_info.sm_size);
+ /* If only one remaining client model exists, re-use it */
+ if (st_ses->sm_info.sm_merged) {
+ release_sound_model_info(&st_ses->sm_info);
+ if (st_ses->sm_info.sm_data)
+ free(st_ses->sm_info.sm_data);
+ }
+ st_ses->sm_info = c_ses_rem->sm_info;
+ st_ses->sm_info.sm_merged = false;
+ st_ses->hw_ses_current->sthw_cfg.conf_levels =
+ st_ses->sm_info.cf_levels;
+ st_ses->hw_ses_current->sthw_cfg.num_conf_levels =
+ st_ses->sm_info.cf_levels_size;
+ /* Delete current client model */
+ release_sound_model_info(&stc_ses->sm_info);
+ stc_ses->sm_info.sm_data = NULL;
+ return 0;
+ }
+ /* Update overall recogniton mode from remaining clients */
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if ((c_ses != stc_ses) && c_ses->sm_info.sm_data) {
+ if (c_ses->recognition_mode == RECOGNITION_MODE_USER_IDENTIFICATION)
+ rec_mode |= RECOGNITION_MODE_USER_IDENTIFICATION;
+ }
+ }
+
+ /*
+ * Delete this client model with already existing merged model due to other
+ * clients models.
+ */
+ if (!st_ses->sm_info.sm_merged || !st_ses->sm_info.sm_data) {
+ ALOGE("%s: Unexpected, no pre-existing merged model to delete from,"
+ "num current models %d", __func__, num_models);
+ goto cleanup;
+ }
+
+ /* Existing merged model from which the current client model to be deleted */
+ in_model.data = st_ses->sm_info.sm_data;
+ in_model.size = st_ses->sm_info.sm_size;
+
+ status = delete_from_merged_sound_model(st_ses->stdev,
+ stc_ses->sm_info.keyphrases, stc_ses->sm_info.num_keyphrases,
+ &in_model, &out_model);
+
+ if (status)
+ goto cleanup;
+
+ sm_info.sm_data = out_model.data;
+ sm_info.sm_size = out_model.size;
+ sm_info.sm_merged = true;
+
+ /* Update existing merged model info with new merged model */
+ status = query_sound_model(st_ses->stdev, &sm_info, out_model.data,
+ out_model.size);
+ if (status)
+ goto cleanup;
+
+ if (out_model.size > st_ses->sm_info.sm_size) {
+ ALOGE("%s: Unexpected, merged model sz %d > current sz %d",
+ __func__, out_model.size, st_ses->sm_info.sm_size);
+ release_sound_model_info(&sm_info);
+ status = -EINVAL;
+ goto cleanup;
+ }
+
+ if (st_ses->sm_info.sm_merged && st_ses->sm_info.sm_data) {
+ release_sound_model_info(&st_ses->sm_info);
+ free(st_ses->sm_info.sm_data);
+ }
+
+ ALOGD("%s: Updated sound model: current size %d, new size %d", __func__,
+ st_ses->sm_info.sm_size, out_model.size);
+ st_ses->sm_info = sm_info;
+ /*
+ * If any of the remaining clients has user identificaiton enabled,
+ * underlying hw session has to operate with user identificaiton enabled.
+ */
+ st_ses->recognition_mode = rec_mode;
+
+ /* Release current client model */
+ release_sound_model_info(&stc_ses->sm_info);
+ stc_ses->sm_info.sm_data = NULL;
+
+ return 0;
+
+cleanup:
+ release_sound_model_info(&stc_ses->sm_info);
+ stc_ses->sm_info.sm_data = NULL;
+
+ if (out_model.data)
+ free(out_model.data);
+
+ return status;
+}
+
+static int update_sound_model(st_session_t *stc_ses, bool add)
+{
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
+ struct sound_trigger_sound_model *common_sm =
+ (struct sound_trigger_sound_model*)stc_ses->phrase_sm;
+ unsigned char *sm_data = NULL;
+ unsigned int sm_size = 0;
+ int status = 0;
+
+ ALOGV("%s: Enter", __func__);
+
+ if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ sm_data = (unsigned char*)phrase_sm + phrase_sm->common.data_offset;
+ sm_size = phrase_sm->common.data_size;
+ } else {
+ sm_data = (unsigned char*)common_sm + common_sm->data_offset;
+ sm_size = common_sm->data_size;
+ }
+
+ pthread_mutex_lock(&st_ses->lock);
+ if (add)
+ status = add_sound_model(stc_ses, sm_data, sm_size);
+ else
+ status = delete_sound_model(stc_ses);
+ pthread_mutex_unlock(&st_ses->lock);
+
+ ALOGV("%s: Exit", __func__);
+ return status;
+}
+
+static int update_merge_conf_levels_payload(st_proxy_session_t *st_ses,
+ struct sound_model_info *src_sm_info, unsigned char *src,
+ unsigned int src_size, bool set)
+{
+ int i = 0, j = 0;
+
+ if (!st_ses || !src) {
+ ALOGE("%s: NULL pointer", __func__);
+ return -EINVAL;
+ }
+
+ if (!st_ses->sm_info.sm_merged)
+ return 0;
+
+ if (src_size > st_ses->sm_info.cf_levels_size) {
+ ALOGE("%s:[%d] Unexpected, client conf levels %d > "
+ "merged conf levels %d", __func__, st_ses->sm_handle,
+ src_size, st_ses->sm_info.cf_levels_size);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < src_size; i++)
+ ALOGV("%s: src cf_levels[%d]=%d", __func__, i, src[i]);
+
+ /* Populate DSP merged sound model conf levels */
+ for (i = 0; i < src_size; i++) {
+ for (j = 0; j < st_ses->sm_info.cf_levels_size; j++) {
+ if (!strcmp(st_ses->sm_info.cf_levels_kw_users[j],
+ src_sm_info->cf_levels_kw_users[i])) {
+ if (set) {
+ st_ses->sm_info.cf_levels[j] = src[i];
+ ALOGV("%s: set: sm_info.cf_levels[%d]=%d", __func__,
+ j, st_ses->sm_info.cf_levels[j]);
+ } else {
+ st_ses->sm_info.cf_levels[j] = MAX_CONF_LEVEL_VALUE;
+ ALOGV("%s: reset: sm_info.cf_levels[%d]=%d", __func__,
+ j, st_ses->sm_info.cf_levels[j]);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int update_merge_conf_levels_payload_with_active_clients(
+ st_proxy_session_t *st_ses)
+{
+ int status = 0;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if (c_ses->state == ST_STATE_ACTIVE) {
+ ALOGV("%s: update merge conf levels with other active"
+ "client %d ", __func__, c_ses->sm_handle);
+ status = update_merge_conf_levels_payload(st_ses,
+ &c_ses->sm_info, c_ses->sm_info.cf_levels,
+ c_ses->sm_info.cf_levels_size, true);
+ if (status)
+ return status;
+ }
+ }
+ return status;
+}
+
+static void check_and_extract_det_conf_levels_payload(
+ st_proxy_session_t *st_ses,
+ unsigned char *src, unsigned int src_size,
+ unsigned char **dst, unsigned int *dst_size)
+{
+ st_session_t *stc_ses = st_ses->det_stc_ses;
+ int i = 0, j = 0;
+
+ *dst = src;
+ *dst_size = src_size;
+
+ if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
+ !st_ses->sm_info.sm_merged) {
+ ALOGV("%s:[%d] not merged", __func__, st_ses->sm_handle);
+ return;
+ }
+
+ if (src_size < st_ses->sm_info.cf_levels_size) {
+ ALOGE("%s:[%d] Unexpected, detection conf payload size %d < %d",
+ __func__, st_ses->sm_handle, src_size,
+ st_ses->sm_info.cf_levels_size);
+ return;
+ }
+
+ /* Reset any cached previous detection values */
+ memset(stc_ses->sm_info.det_cf_levels, 0, stc_ses->sm_info.cf_levels_size);
+
+ /* Extract the client conf level values from DSP payload */
+ for(i = 0; i < st_ses->sm_info.cf_levels_size; i++) {
+ if (!src[i])
+ continue;
+ for(j = 0; j < stc_ses->sm_info.cf_levels_size; j++) {
+ if (!strcmp(stc_ses->sm_info.cf_levels_kw_users[j],
+ st_ses->sm_info.cf_levels_kw_users[i])) {
+ stc_ses->sm_info.det_cf_levels[j] = src[i];
+ }
+ }
+ }
+ for (i = 0; i < stc_ses->sm_info.cf_levels_size; i++)
+ ALOGD("%s: c%d det_cf_levels[%d]=%d", __func__, stc_ses->sm_handle, i,
+ stc_ses->sm_info.det_cf_levels[i]);
+
+ *dst = stc_ses->sm_info.det_cf_levels;
+ *dst_size = stc_ses->sm_info.cf_levels_size;
+}
+
+static inline bool check_for_multi_clients(st_proxy_session_t *st_ses)
+{
+ struct listnode *node = NULL;
+ int cnt = 0;
+
+ list_for_each(node, &st_ses->clients_list) {
+ if (++cnt > 1)
+ return true;
+ }
+ return false;
+}
+
+static inline bool is_other_client_attached(st_proxy_session_t *st_ses,
+ st_session_t *stc_ses)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if (c_ses != stc_ses)
+ return true;
+ }
+ return false;
+}
+
+static inline void reset_clients_pending_load(st_proxy_session_t *st_ses)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->pending_load = false;
+ }
+}
+
+static inline int is_any_client_not_pending_load(st_proxy_session_t *st_ses)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if (!c_ses->pending_load)
+ return true;
+ }
+ return false;
+}
+
+static inline int is_any_client_not_pending_set_device(
+ st_proxy_session_t *st_ses)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if (!c_ses->pending_set_device)
+ return true;
+ }
+ return false;
+}
+
+static inline void reset_clients_pending_set_device(st_proxy_session_t *st_ses)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->pending_set_device = false;
+ }
+}
+
+static bool check_and_get_other_active_client(st_proxy_session_t *st_ses,
+ st_session_t *stc_ses)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if ((c_ses != stc_ses) && (c_ses->state == ST_STATE_ACTIVE))
+ return c_ses;
+ }
+ return NULL;
+}
+
+static inline bool is_any_client_paused(st_proxy_session_t *st_ses)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if (c_ses->paused)
+ return true;
+ }
+ return false;
+}
+
+static inline bool is_any_client_in_state(st_proxy_session_t *st_ses,
+ enum client_states_t state)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if (c_ses->state == state)
+ return true;
+ }
+ return false;
+}
+
+static void update_hw_config_on_restart(st_proxy_session_t *st_ses,
+ st_session_t *stc_ses)
+{
+ st_hw_session_t *hw_ses = st_ses->hw_ses_current;
+ struct st_hw_ses_config *sthw_cfg = &hw_ses->sthw_cfg;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+ int hb_sz = 0, pr_sz = 0;
+ bool enable_lab = false;
+
+ if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
+ !st_ses->sm_info.sm_merged)
+ return;
+
+ /*
+ * Adjust history buffer and preroll durations to highest of
+ * all clients, including current restarting client.
+ * If any of the clients requested capture or enabled the
+ * second stage, the underlying hw session buffering needs to be
+ * enabled.
+ */
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if ((c_ses == stc_ses) || (c_ses->state == ST_STATE_ACTIVE)) {
+ if (hb_sz < c_ses->hist_buf_duration)
+ hb_sz = c_ses->hist_buf_duration;
+ if (pr_sz < c_ses->preroll_duration)
+ pr_sz = c_ses->preroll_duration;
+ if (!enable_lab)
+ enable_lab = (c_ses->rc_config &&
+ c_ses->rc_config->capture_requested) ||
+ !list_empty(&c_ses->second_stage_list);
+ }
+ }
+
+ sthw_cfg->client_req_hist_buf = hb_sz;
+ sthw_cfg->client_req_preroll = pr_sz;
+ st_ses->lab_enabled = enable_lab;
+
+ update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
+ stc_ses->sm_info.cf_levels,
+ stc_ses->sm_info.cf_levels_size,
+ true);
+ hw_ses->sthw_cfg_updated = true;
+
+ ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
+ st_ses->sm_handle, st_ses->lab_enabled,
+ sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
+}
+
+static bool update_hw_config_on_stop(st_proxy_session_t *st_ses,
+ st_session_t *stc_ses)
+{
+ st_hw_session_t *hw_ses = st_ses->hw_ses_current;
+ struct st_hw_ses_config *sthw_cfg = &hw_ses->sthw_cfg;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+ int hb_sz = 0, pr_sz = 0;
+ bool active = false, enable_lab = false;
+
+ if (!st_ses->vendor_uuid_info->merge_fs_soundmodels ||
+ !st_ses->sm_info.sm_merged) {
+ if (sthw_cfg->conf_levels) {
+ ALOGV("%s: free hw conf_levels", __func__);
+ free(sthw_cfg->conf_levels);
+ sthw_cfg->conf_levels = NULL;
+ }
+ return false;
+ }
+ /*
+ * Adjust history buffer and preroll durations to highest of
+ * remaining clients.
+ * If any of the remaining clients requested capture or enabled the
+ * second stage, the underlying hw session buffering needs to be
+ * enabled.
+ */
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if ((c_ses != stc_ses) && (c_ses->state == ST_STATE_ACTIVE)) {
+ active = true;
+ if (hb_sz < c_ses->hist_buf_duration)
+ hb_sz = c_ses->hist_buf_duration;
+ if (pr_sz < c_ses->preroll_duration)
+ pr_sz = c_ses->preroll_duration;
+ if (!enable_lab)
+ enable_lab = c_ses->rc_config->capture_requested ||
+ !list_empty(&c_ses->second_stage_list);
+ }
+ }
+ if (!active) {
+ sthw_cfg->client_req_hist_buf = 0;
+ sthw_cfg->client_req_preroll = 0;
+ st_ses->lab_enabled = 0;
+ sthw_cfg->custom_data = NULL;
+ sthw_cfg->custom_data_size = 0;
+ hw_ses->sthw_cfg_updated = true;
+ ALOGV("%s:[%d] no active client hw cfg is reset", __func__,
+ st_ses->sm_handle);
+ return false;
+ }
+
+ sthw_cfg->client_req_hist_buf = hb_sz;
+ sthw_cfg->client_req_preroll = pr_sz;
+ st_ses->lab_enabled = enable_lab;
+
+ update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
+ stc_ses->sm_info.cf_levels,
+ stc_ses->sm_info.cf_levels_size,
+ false);
+ hw_ses->sthw_cfg_updated = true;
+
+ ALOGV("%s:[%d] lab_enabled %d, hb_sz %d, pr_sz %d", __func__,
+ st_ses->sm_handle, st_ses->lab_enabled,
+ sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
+
+ return active;
+}
+
+static void get_conf_levels_from_dsp_payload(st_proxy_session_t *st_ses,
+ unsigned char *payload, unsigned int payload_size,
+ unsigned char **conf_levels, unsigned int *conf_levels_size)
+{
+ st_hw_session_t *hw_ses = st_ses->hw_ses_current;
+ uint32_t key_id = 0, key_payload_size = 0;
+ unsigned int i = 0;
+
+ if (hw_ses->is_generic_event) {
+ while (i < payload_size) {
+ key_id = *(uint32_t *)payload;
+ key_payload_size = *((uint32_t *)payload + 1);
+
+ if (key_id == KEY_ID_CONFIDENCE_LEVELS) {
+ *conf_levels = payload + (4 * sizeof(uint32_t));
+ *conf_levels_size = *((uint32_t *)payload + 3);;
+ ALOGV("%s: generic_event: DSP num conf levels %d", __func__,
+ *conf_levels_size);
+ break;
+ }
+ i += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
+ payload += i;
+ }
+ } else {
+ if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
+ *conf_levels = payload + 2;
+ *conf_levels_size = payload_size - 2;
+ } else {
+ *conf_levels = payload;
+ *conf_levels_size = payload_size;
+ }
+ }
+}
+
+st_session_t* get_detected_client(st_proxy_session_t *st_ses,
+ unsigned char *payload, unsigned int payload_size)
+{
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
+ unsigned char *conf_levels = NULL;
+ unsigned int conf_levels_size = 0;
+ int i = 0, j = 0;
+
+ if (list_empty(&st_ses->clients_list)) {
+ ALOGE("%s:[%d] no clients attached!!", __func__, st_ses->sm_handle);
+ return NULL;
+ }
+ /*
+ * If only single client exist, this detection is not for merged
+ * sound model, hence return this as only available client
+ */
+ if (!check_for_multi_clients(st_ses)) {
+ ALOGV("%s:[%d] single client detection", __func__, st_ses->sm_handle);
+ node = list_head(&st_ses->clients_list);
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if (c_ses->state == ST_STATE_ACTIVE) {
+ ALOGD("%s: detected c%d", __func__, c_ses->sm_handle);
+ return c_ses;
+ } else {
+ ALOGE("%s: detected c%d is not active", __func__, c_ses->sm_handle);
+ return NULL;
+ }
+ }
+
+ get_conf_levels_from_dsp_payload(st_ses, payload, payload_size,
+ &conf_levels, &conf_levels_size);
+ if (!conf_levels) {
+ ALOGE("%s:[%d] no conf levels payload found!!", __func__,
+ st_ses->sm_handle);
+ return NULL;
+ }
+ if (conf_levels_size < st_ses->sm_info.num_keyphrases) {
+ ALOGE("%s:[%d] detection conf levels size %d < num of keywords %d",
+ __func__, st_ses->sm_handle, conf_levels_size,
+ st_ses->sm_info.num_keyphrases);
+ return NULL;
+ }
+
+ /*
+ * The DSP payload contains the keyword conf levels from the beginning.
+ * Only one keyword conf level is expected to be non-zero from keyword
+ * detection. Find non-zero conf level up to number of keyphrases and if
+ * one is found, match it to the corresponding keyphrase from list of
+ * clients to obtain the detected client.
+ */
+ for (i = 0; i < st_ses->sm_info.num_keyphrases; i++) {
+ if (!conf_levels[i])
+ continue;
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ for (j = 0; j < c_ses->sm_info.num_keyphrases; j++) {
+ if (!strcmp(st_ses->sm_info.keyphrases[i],
+ c_ses->sm_info.keyphrases[j])) {
+ if (c_ses->state == ST_STATE_ACTIVE) {
+ ALOGV("%s: detected c%d", __func__, c_ses->sm_handle);
+ return c_ses;
+ } else {
+ ALOGE("%s: detected c%d is not active", __func__,
+ c_ses->sm_handle);
+ return NULL;
+ }
+ }
+ }
+ }
+ }
+ return c_ses;
+}
+
+static int fill_conf_levels_payload_from_rc_config
+(
+ const struct sound_trigger_phrase_sound_model *phrase_sm,
+ const struct sound_trigger_recognition_config *rc_config,
+ unsigned char *conf_levels,
+ unsigned int num_conf_levels,
+ unsigned int total_num_users
+)
+{
+ int status = 0;
+ unsigned int user_level, user_id;
+ unsigned int i = 0, j = 0;
+ unsigned char *user_id_tracker;
+
+ if (!phrase_sm || !rc_config || !conf_levels || !num_conf_levels) {
+ ALOGE("%s: ERROR. Invalid inputs",__func__);
+ return -EINVAL;
+ }
+
+ /* Example: Say the recognition structure has 3 keywords with users
+ * |kid|
+ * [0] k1 |uid|
+ * [3] u1 - 1st trainer
+ * [4] u2 - 4th trainer
+ * [6] u3 - 3rd trainer
+ * [1] k2
+ * [5] u2 - 2nd trainer
+ * [7] u3 - 5th trainer
+ * [2] k3
+ * [8] u4 - 6th trainer
+ *
+ * Output confidence level array will be
+ * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
+ */
+
+ user_id_tracker = calloc(1, num_conf_levels);
+ if (!user_id_tracker) {
+ ALOGE("%s: failed to allocate user_id_tracker", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < rc_config->num_phrases; i++) {
+ ALOGV("%s: [%d] kw level %d", __func__, i,
+ rc_config->phrases[i].confidence_level);
+ for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
+ ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
+ rc_config->phrases[i].levels[j].user_id,
+ rc_config->phrases[i].levels[j].level);
+ }
+ }
+
+ for (i = 0; i < rc_config->num_phrases; i++) {
+ conf_levels[i] = rc_config->phrases[i].confidence_level;
+ for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
+ user_level = rc_config->phrases[i].levels[j].level;
+ user_id = rc_config->phrases[i].levels[j].user_id;
+ if ((user_id < rc_config->num_phrases) ||
+ (user_id >= num_conf_levels)) {
+ ALOGE("%s: ERROR. Invalid params user id %d>%d",
+ __func__, user_id, total_num_users);
+ status = -EINVAL;
+ goto exit;
+ } else {
+ if (user_id_tracker[user_id] == 1) {
+ ALOGE("%s: ERROR. Duplicate user id %d",
+ __func__, user_id);
+ status = -EINVAL;
+ goto exit;
+ }
+ conf_levels[user_id] = (user_level < 100) ? user_level: 100;
+ user_id_tracker[user_id] = 1;
+ ALOGV("%s: user_conf_levels[%d] = %d", __func__,
+ user_id, conf_levels[user_id]);
+ }
+ }
+ }
+
+exit:
+ free(user_id_tracker);
+ return status;
+}
+
+int generate_conf_levels_payload_from_rc_config
+(
+ const struct sound_trigger_phrase_sound_model *phrase_sm,
+ const struct sound_trigger_recognition_config *rc_config,
+ unsigned char **out_payload,
+ unsigned int *out_payload_size
+)
+{
+ int status = 0;
+ unsigned int total_num_users = 0, num_conf_levels = 0;
+ unsigned int i = 0, j = 0;
+ unsigned char *conf_levels = NULL;
+
+ if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
+ ALOGE("%s: ERROR. Invalid inputs",__func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ *out_payload = NULL;
+ *out_payload_size = 0;
+
+ if((rc_config->num_phrases == 0) ||
+ (rc_config->num_phrases > phrase_sm->num_phrases)) {
+ ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
+ rc_config->num_phrases, phrase_sm->num_phrases);
+ status = -EINVAL;
+ goto exit;
+ }
+ for (i = 0; i < rc_config->num_phrases; i++) {
+ for (j = 0; j < rc_config->phrases[i].num_levels; j++)
+ total_num_users++;
+ }
+
+ num_conf_levels = total_num_users + rc_config->num_phrases;
+ conf_levels = calloc(1, num_conf_levels);
+ if (!conf_levels) {
+ ALOGE("%s: ERROR. conf levels alloc failed",__func__);
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
+ conf_levels, num_conf_levels, total_num_users);
+ if (status) {
+ ALOGE("%s: fill config payload failed, error %d", __func__, status);
+ goto exit;
+ }
+
+ *out_payload = conf_levels;
+ *out_payload_size = num_conf_levels;
+
+ return status;
+
+exit:
+ if (conf_levels)
+ free(conf_levels);
+ return status;
+}
+
+int generate_conf_levels_payload_from_rc_config_v2
+(
+ const struct sound_trigger_phrase_sound_model *phrase_sm,
+ const struct sound_trigger_recognition_config *rc_config,
+ unsigned char **out_payload,
+ unsigned int *out_payload_size
+)
+{
+ int status = 0;
+ unsigned int total_num_users = 0, num_conf_levels = 0;
+ unsigned char *conf_levels = NULL;
+ unsigned int i = 0, j = 0;
+
+ ALOGV("%s: Enter...", __func__);
+
+ if (!phrase_sm || !rc_config || !out_payload || !out_payload_size) {
+ ALOGE("%s: ERROR. Invalid inputs",__func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ *out_payload = NULL;
+ *out_payload_size = 0;
+
+ if((rc_config->num_phrases == 0) ||
+ (rc_config->num_phrases > phrase_sm->num_phrases)) {
+ ALOGE("%s: ERROR. Invalid phrases %d!=%d",__func__,
+ rc_config->num_phrases, phrase_sm->num_phrases);
+ status = -EINVAL;
+ goto exit;
+ }
+ for (i = 0; i < rc_config->num_phrases; i++) {
+ for (j = 0; j < rc_config->phrases[i].num_levels; j++)
+ total_num_users++;
+ }
+
+ num_conf_levels = total_num_users + rc_config->num_phrases;
+ /*
+ * allocate dsp payload w/additional 2 bytes for minor_version and
+ * num_active_models and additional num_conf_levels for KW enable
+ * fields
+ */
+ conf_levels = calloc(1, 2 + 2 * num_conf_levels);
+ if (!conf_levels) {
+ ALOGE("%s: ERROR. conf levels alloc failed",__func__);
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ conf_levels[0] = 1; /* minor version */
+ conf_levels[1] = num_conf_levels; /* num_active_models */
+ status = fill_conf_levels_payload_from_rc_config(phrase_sm, rc_config,
+ conf_levels + 2, num_conf_levels, total_num_users);
+ if (status) {
+ ALOGE("%s: fill config payload failed, error %d", __func__, status);
+ goto exit;
+ }
+
+ /*
+ * set KW enable fields to 1 for now
+ * TODO: set appropriately based on what client is passing in rc_config
+ */
+ memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
+ ALOGV("%s: here", __func__);
+ *out_payload = conf_levels;
+ /* add size of minor version and num_active_models */
+ *out_payload_size = 2 + 2 * num_conf_levels;
+ return status;
+
+exit:
+ if (conf_levels)
+ free(conf_levels);
+ return status;
+}
+
+static int fill_sound_trigger_recognition_config_payload
+(
+ const void *sm_levels_generic,
+ unsigned char *conf_levels,
+ unsigned int num_conf_levels,
+ unsigned int total_num_users,
+ uint32_t version
+)
+{
+ int status = 0;
+ unsigned int user_level = 0, user_id = 0;
+ unsigned int i = 0, j = 0;
+ unsigned char *user_id_tracker = NULL;
+ struct st_sound_model_conf_levels *sm_levels = NULL;
+ struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
+
+ /* Example: Say the recognition structure has 3 keywords with users
+ * |kid|
+ * [0] k1 |uid|
+ * [3] u1 - 1st trainer
+ * [4] u2 - 4th trainer
+ * [6] u3 - 3rd trainer
+ * [1] k2
+ * [5] u2 - 2nd trainer
+ * [7] u3 - 5th trainer
+ * [2] k3
+ * [8] u4 - 6th trainer
+ *
+ * Output confidence level array will be
+ * [k1, k2, k3, u1k1, u2k1, u2k2, u3k1, u3k2, u4k3]
+ */
+
+ if (version != CONF_LEVELS_INTF_VERSION_0002) {
+ sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
+ if (!sm_levels || !conf_levels || !num_conf_levels) {
+ ALOGE("%s: ERROR. Invalid inputs", __func__);
+ return -EINVAL;
+ }
+ user_id_tracker = calloc(1, num_conf_levels);
+ if (!user_id_tracker) {
+ ALOGE("%s: failed to allocate user_id_tracker", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < sm_levels->num_kw_levels; i++) {
+ ALOGV("%s: [%d] kw level %d", __func__, i,
+ sm_levels->kw_levels[i].kw_level);
+ for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
+ ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
+ sm_levels->kw_levels[i].user_levels[j].user_id,
+ sm_levels->kw_levels[i].user_levels[j].level);
+ }
+ }
+
+ for (i = 0; i < sm_levels->num_kw_levels; i++) {
+ conf_levels[i] = sm_levels->kw_levels[i].kw_level;
+ for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++) {
+ user_level = sm_levels->kw_levels[i].user_levels[j].level;
+ user_id = sm_levels->kw_levels[i].user_levels[j].user_id;
+ if ((user_id < sm_levels->num_kw_levels) ||
+ (user_id >= num_conf_levels)) {
+ ALOGE("%s: ERROR. Invalid params user id %d>%d",
+ __func__, user_id, total_num_users);
+ status = -EINVAL;
+ goto exit;
+ } else {
+ if (user_id_tracker[user_id] == 1) {
+ ALOGE("%s: ERROR. Duplicate user id %d",
+ __func__, user_id);
+ status = -EINVAL;
+ goto exit;
+ }
+ conf_levels[user_id] = (user_level < 100) ?
+ user_level: 100;
+ user_id_tracker[user_id] = 1;
+ ALOGV("%s: user_conf_levels[%d] = %d", __func__,
+ user_id, conf_levels[user_id]);
+ }
+ }
+ }
+ } else {
+ sm_levels_v2 =
+ (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
+ if (!sm_levels_v2 || !conf_levels || !num_conf_levels) {
+ ALOGE("%s: ERROR. Invalid inputs", __func__);
+ return -EINVAL;
+ }
+ user_id_tracker = calloc(1, num_conf_levels);
+ if (!user_id_tracker) {
+ ALOGE("%s: failed to allocate user_id_tracker", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
+ ALOGV("%s: [%d] kw level %d", __func__, i,
+ sm_levels_v2->kw_levels[i].kw_level);
+ for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
+ ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
+ sm_levels_v2->kw_levels[i].user_levels[j].user_id,
+ sm_levels_v2->kw_levels[i].user_levels[j].level);
+ }
+ }
+
+ for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
+ conf_levels[i] = sm_levels_v2->kw_levels[i].kw_level;
+ for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++) {
+ user_level = sm_levels_v2->kw_levels[i].user_levels[j].level;
+ user_id = sm_levels_v2->kw_levels[i].user_levels[j].user_id;
+ if ((user_id < sm_levels_v2->num_kw_levels) ||
+ (user_id >= num_conf_levels)) {
+ ALOGE("%s: ERROR. Invalid params user id %d>%d",
+ __func__, user_id, total_num_users);
+ status = -EINVAL;
+ goto exit;
+ } else {
+ if (user_id_tracker[user_id] == 1) {
+ ALOGE("%s: ERROR. Duplicate user id %d",
+ __func__, user_id);
+ status = -EINVAL;
+ goto exit;
+ }
+ conf_levels[user_id] = (user_level < 100) ?
+ user_level: 100;
+ user_id_tracker[user_id] = 1;
+ ALOGV("%s: user_conf_levels[%d] = %d", __func__,
+ user_id, conf_levels[user_id]);
+ }
+ }
+ }
+ }
+
+exit:
+ free(user_id_tracker);
+ return status;
+}
+
+static int generate_sound_trigger_recognition_config_payload
+(
+ const void *sm_levels_generic,
+ unsigned char **out_payload,
+ unsigned int *out_payload_size,
+ uint32_t version
+)
+{
+ int status = 0;
+ unsigned int total_num_users = 0, num_conf_levels = 0;
+ unsigned char *conf_levels = NULL;
+ unsigned int i = 0, j = 0;
+ struct st_sound_model_conf_levels *sm_levels = NULL;
+ struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
+
+ ALOGV("%s: Enter...", __func__);
+
+ if (version != CONF_LEVELS_INTF_VERSION_0002) {
+ sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
+ if (!sm_levels || !out_payload || !out_payload_size) {
+ ALOGE("%s: ERROR. Invalid inputs", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ *out_payload = NULL;
+ *out_payload_size = 0;
+
+ if (sm_levels->num_kw_levels == 0) {
+ ALOGE("%s: ERROR. No confidence levels present", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ for (i = 0; i < sm_levels->num_kw_levels; i++) {
+ for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
+ total_num_users++;
+ }
+
+ num_conf_levels = total_num_users + sm_levels->num_kw_levels;
+ conf_levels = calloc(1, num_conf_levels);
+ if (!conf_levels) {
+ ALOGE("%s: ERROR. conf levels alloc failed", __func__);
+ status = -ENOMEM;
+ goto exit;
+ }
+ } else {
+ sm_levels_v2 =
+ (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
+ if (!sm_levels_v2 || !out_payload || !out_payload_size) {
+ ALOGE("%s: ERROR. Invalid inputs", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ *out_payload = NULL;
+ *out_payload_size = 0;
+
+ if (sm_levels_v2->num_kw_levels == 0) {
+ ALOGE("%s: ERROR. No confidence levels present", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
+ for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
+ total_num_users++;
+ }
+
+ num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
+ conf_levels = calloc(1, num_conf_levels);
+ if (!conf_levels) {
+ ALOGE("%s: ERROR. conf levels alloc failed", __func__);
+ status = -ENOMEM;
+ goto exit;
+ }
+ }
+
+ status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
+ conf_levels, num_conf_levels, total_num_users, version);
+ if (status) {
+ ALOGE("%s: fill config payload failed, error %d", __func__, status);
+ goto exit;
+ }
+
+ *out_payload = conf_levels;
+ *out_payload_size = num_conf_levels;
+
+ return status;
+
+exit:
+ if (conf_levels)
+ free(conf_levels);
+
+ return status;
+}
+
+static int generate_sound_trigger_recognition_config_payload_v2
+(
+ const void *sm_levels_generic,
+ unsigned char **out_payload,
+ unsigned int *out_payload_size,
+ uint32_t version
+)
+{
+ int status = 0;
+ unsigned int total_num_users = 0, num_conf_levels = 0;
+ unsigned char *conf_levels = NULL;
+ unsigned int i = 0, j = 0;
+ struct st_sound_model_conf_levels *sm_levels = NULL;
+ struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
+
+ ALOGV("%s: Enter...", __func__);
+
+ if (version != CONF_LEVELS_INTF_VERSION_0002) {
+ sm_levels = (struct st_sound_model_conf_levels *)sm_levels_generic;
+ if (!sm_levels || !out_payload || !out_payload_size) {
+ ALOGE("%s: ERROR. Invalid inputs", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ *out_payload = NULL;
+ *out_payload_size = 0;
+
+ if (sm_levels->num_kw_levels == 0) {
+ ALOGE("%s: ERROR. No confidence levels present", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ for (i = 0; i < sm_levels->num_kw_levels; i++) {
+ for (j = 0; j < sm_levels->kw_levels[i].num_user_levels; j++)
+ total_num_users++;
+ }
+
+ num_conf_levels = total_num_users + sm_levels->num_kw_levels;
+ } else {
+ sm_levels_v2 =
+ (struct st_sound_model_conf_levels_v2 *)sm_levels_generic;
+ if (!sm_levels_v2 || !out_payload || !out_payload_size) {
+ ALOGE("%s: ERROR. Invalid inputs", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ *out_payload = NULL;
+ *out_payload_size = 0;
+
+ if (sm_levels_v2->num_kw_levels == 0) {
+ ALOGE("%s: ERROR. No confidence levels present", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ for (i = 0; i < sm_levels_v2->num_kw_levels; i++) {
+ for (j = 0; j < sm_levels_v2->kw_levels[i].num_user_levels; j++)
+ total_num_users++;
+ }
+ num_conf_levels = total_num_users + sm_levels_v2->num_kw_levels;
+ }
+
+ /*
+ * allocate dsp payload w/additional 2 bytes for minor_version and
+ * num_active_models and additional num_conf_levels for KW enable
+ * fields
+ */
+ conf_levels = calloc(1, 2 + 2 * num_conf_levels);
+ if (!conf_levels) {
+ ALOGE("%s: ERROR. conf levels alloc failed", __func__);
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ conf_levels[0] = 1; /* minor version */
+ conf_levels[1] = num_conf_levels; /* num_active_models */
+ status = fill_sound_trigger_recognition_config_payload(sm_levels_generic,
+ conf_levels + 2, num_conf_levels, total_num_users, version);
+ if (status) {
+ ALOGE("%s: fill config payload failed, error %d", __func__, status);
+ goto exit;
+ }
+
+ /* set KW enable fields to 1 for now
+ * TODO set appropriately based on what client is passing in rc_config
+ */
+ memset(&conf_levels[num_conf_levels + 2], 0x1, num_conf_levels);
+ ALOGV("%s: here", __func__);
+ *out_payload = conf_levels;
+ /* add size of minor version and num_active_models */
+ *out_payload_size = 2 + 2 * num_conf_levels;
+
+ return status;
+
+exit:
+ if (conf_levels)
+ free(conf_levels);
+
+ return status;
+}
+
+static int parse_rc_config_key_conf_levels
+(
+ st_session_t *stc_ses,
+ st_hw_session_t *st_hw_ses,
+ void *opaque_conf_levels,
+ unsigned char **out_conf_levels,
+ unsigned int *out_num_conf_levels
+)
+{
+ struct st_confidence_levels_info *conf_levels = NULL;
+ struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
+ struct st_sound_model_conf_levels *sm_levels = NULL;
+ struct st_sound_model_conf_levels_v2 *sm_levels_v2 = NULL;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ struct listnode *node = NULL;
+ st_lsm_ss_config_t *ss_cfg = NULL;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ int status = 0;
+ uint32_t i = 0;
+ bool gmm_conf_found = false;
+ uint8_t confidence_level = 0;
+ int32_t confidence_level_v2 = 0;
+ bool arm_second_stage = !list_empty(&stc_ses->second_stage_list);
+ bool adsp_second_stage = (st_hw_ses == st_ses->hw_ses_adsp &&
+ !list_empty(&st_hw_ses->lsm_ss_cfg_list));
+
+ if (arm_second_stage || adsp_second_stage) {
+ if (stc_ses->rc_config->num_phrases > 1) {
+ ALOGE("%s: Multi keyword is unsupported with 2nd stage detection",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (stc_ses->rc_config->phrases[0].num_levels > 1) {
+ ALOGE("%s: Multi user is unsupported with 2nd stage detection",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ if (stc_ses->st_conf_levels) {
+ free(stc_ses->st_conf_levels);
+ stc_ses->st_conf_levels = NULL;
+ }
+
+ if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
+ conf_levels = (struct st_confidence_levels_info *)
+ ((char *)opaque_conf_levels + sizeof(struct st_param_header));
+
+ stc_ses->st_conf_levels =
+ calloc(1, sizeof(struct st_confidence_levels_info));
+ if (!stc_ses->st_conf_levels) {
+ ALOGE("%s: failed to alloc st_conf_levels", __func__);
+ return -ENOMEM;
+ }
+ /* Cache to use during detection event processing */
+ memcpy(stc_ses->st_conf_levels, (char *)conf_levels,
+ sizeof(struct st_confidence_levels_info));
+
+ for (i = 0; i < conf_levels->num_sound_models; i++) {
+ sm_levels = &conf_levels->conf_levels[i];
+ if (sm_levels->sm_id == ST_SM_ID_SVA_GMM) {
+ if ((st_ses->stdev->is_gcs) && (st_hw_ses == st_ses->hw_ses_cpe))
+ status =
+ generate_sound_trigger_recognition_config_payload_v2(
+ (void *)sm_levels, out_conf_levels, out_num_conf_levels,
+ stc_ses->conf_levels_intf_version);
+ else
+ status =
+ generate_sound_trigger_recognition_config_payload(
+ (void *)sm_levels, out_conf_levels, out_num_conf_levels,
+ stc_ses->conf_levels_intf_version);
+ gmm_conf_found = true;
+ } else if ((sm_levels->sm_id == ST_SM_ID_SVA_CNN) ||
+ (sm_levels->sm_id == ST_SM_ID_SVA_VOP)) {
+ confidence_level = (sm_levels->sm_id == ST_SM_ID_SVA_CNN) ?
+ sm_levels->kw_levels[0].kw_level:
+ sm_levels->kw_levels[0].user_levels[0].level;
+ if (arm_second_stage) {
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t,
+ list_node);
+ if (st_sec_stage->ss_info->sm_id == sm_levels->sm_id)
+ st_sec_stage->ss_session->confidence_threshold =
+ confidence_level;
+ }
+ } else if (adsp_second_stage) {
+ list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
+ ss_cfg = node_to_item(node, st_lsm_ss_config_t,
+ list_node);
+ if (ss_cfg->ss_info->sm_id == sm_levels->sm_id)
+ ss_cfg->confidence_threshold = confidence_level;
+ }
+ }
+ } else {
+ ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
+ sm_levels->sm_id);
+ status = -EINVAL;
+ break;
+ }
+ }
+ } else {
+ conf_levels_v2 = (struct st_confidence_levels_info_v2 *)
+ ((char *)opaque_conf_levels + sizeof(struct st_param_header));
+
+ stc_ses->st_conf_levels =
+ calloc(1, sizeof(struct st_confidence_levels_info_v2));
+ if (!stc_ses->st_conf_levels) {
+ ALOGE("%s: failed to alloc st_conf_levels", __func__);
+ return -ENOMEM;
+ }
+ /* Cache to use during detection event processing */
+ memcpy(stc_ses->st_conf_levels, (char *)conf_levels_v2,
+ sizeof(struct st_confidence_levels_info_v2));
+
+ for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
+ sm_levels_v2 = &conf_levels_v2->conf_levels[i];
+ if (sm_levels_v2->sm_id == ST_SM_ID_SVA_GMM) {
+ if ((st_ses->stdev->is_gcs) &&
+ (st_hw_ses == st_ses->hw_ses_cpe))
+ status =
+ generate_sound_trigger_recognition_config_payload_v2(
+ (void *)sm_levels_v2, out_conf_levels, out_num_conf_levels,
+ stc_ses->conf_levels_intf_version);
+ else
+ status =
+ generate_sound_trigger_recognition_config_payload(
+ (void *)sm_levels_v2, out_conf_levels,
+ out_num_conf_levels, stc_ses->conf_levels_intf_version);
+ gmm_conf_found = true;
+ } else if ((sm_levels_v2->sm_id == ST_SM_ID_SVA_CNN) ||
+ (sm_levels_v2->sm_id == ST_SM_ID_SVA_VOP)) {
+ confidence_level_v2 =
+ (sm_levels_v2->sm_id == ST_SM_ID_SVA_CNN) ?
+ sm_levels_v2->kw_levels[0].kw_level:
+ sm_levels_v2->kw_levels[0].user_levels[0].level;
+ if (arm_second_stage) {
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t,
+ list_node);
+ if (st_sec_stage->ss_info->sm_id ==
+ sm_levels_v2->sm_id)
+ st_sec_stage->ss_session->confidence_threshold =
+ confidence_level_v2;
+ }
+ } else if (adsp_second_stage) {
+ list_for_each(node, &st_hw_ses->lsm_ss_cfg_list) {
+ ss_cfg = node_to_item(node, st_lsm_ss_config_t,
+ list_node);
+ if (ss_cfg->ss_info->sm_id == sm_levels_v2->sm_id)
+ ss_cfg->confidence_threshold = confidence_level_v2;
+ }
+ }
+ } else {
+ ALOGE("%s: Unsupported sm id (%d), exiting", __func__,
+ sm_levels_v2->sm_id);
+ status = -EINVAL;
+ break;
+ }
+ }
+ }
+
+ if (!gmm_conf_found) {
+ ALOGE("%s: Did not receive GMM confidence threshold, error!", __func__);
+ status = -EINVAL;
+ }
+
+ if (status && stc_ses->st_conf_levels) {
+ free(stc_ses->st_conf_levels);
+ stc_ses->st_conf_levels = NULL;
+ }
+ return status;
+}
+
+static int update_hw_config_on_start(st_session_t *stc_ses,
+ st_hw_session_t *st_hw_ses)
+{
+ struct st_param_header *param_hdr = NULL;
+ struct st_hist_buffer_info *hist_buf = NULL;
+ struct st_det_perf_mode_info *det_perf_mode = NULL;
+ struct sound_trigger_recognition_config *rc_config = stc_ses->rc_config;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ struct st_vendor_info *v_info = NULL;
+ struct st_hw_ses_config *sthw_cfg = NULL;
+ unsigned char *conf_levels = NULL;
+ unsigned int num_conf_levels = 0;
+ uint8_t *opaque_ptr = NULL;
+ unsigned int opaque_size = 0, conf_levels_payload_size = 0;
+ int status = 0;
+ bool enable_lab = false;
+
+
+ ST_DBG_DECLARE(FILE *rc_opaque_fd = NULL; static int rc_opaque_cnt = 0);
+ ST_DBG_FILE_OPEN_WR(rc_opaque_fd, ST_DEBUG_DUMP_LOCATION,
+ "rc_config_opaque_data", "bin", rc_opaque_cnt++);
+ ST_DBG_FILE_WRITE(rc_opaque_fd,
+ (uint8_t *)rc_config + rc_config->data_offset,
+ rc_config->data_size);
+ ST_DBG_FILE_CLOSE(rc_opaque_fd);
+
+ if (!st_hw_ses) {
+ ALOGE("%s: NULL hw session !!!", __func__);
+ return -EINVAL;
+ }
+
+ v_info = st_hw_ses->vendor_uuid_info;
+
+ if ((rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
+ v_info->is_qcva_uuid) {
+ stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
+
+ opaque_ptr = (uint8_t *)rc_config + rc_config->data_offset;
+ while (opaque_size < rc_config->data_size) {
+ param_hdr = (struct st_param_header *)opaque_ptr;
+ ALOGV("%s: key %d, payload size %d", __func__,
+ param_hdr->key_id, param_hdr->payload_size);
+
+ switch(param_hdr->key_id) {
+ case ST_PARAM_KEY_CONFIDENCE_LEVELS:
+ stc_ses->conf_levels_intf_version =
+ *(uint32_t *)(opaque_ptr + sizeof(struct st_param_header));
+
+ if (stc_ses->conf_levels_intf_version !=
+ CONF_LEVELS_INTF_VERSION_0002) {
+ conf_levels_payload_size =
+ sizeof(struct st_confidence_levels_info);
+ } else {
+ conf_levels_payload_size =
+ sizeof(struct st_confidence_levels_info_v2);
+ }
+ if (param_hdr->payload_size != conf_levels_payload_size) {
+ ALOGE("%s: Conf level format error, exiting", __func__);
+ return -EINVAL;
+ }
+ status = parse_rc_config_key_conf_levels(stc_ses, st_hw_ses,
+ opaque_ptr, &conf_levels, &num_conf_levels);
+ opaque_size += sizeof(struct st_param_header) +
+ conf_levels_payload_size;
+ opaque_ptr += sizeof(struct st_param_header) +
+ conf_levels_payload_size;
+ if (status) {
+ ALOGE("%s: parsing conf levels failed(status=%d)",
+ __func__, status);
+ return -EINVAL;
+ }
+ break;
+ case ST_PARAM_KEY_HISTORY_BUFFER_CONFIG:
+ if (param_hdr->payload_size !=
+ sizeof(struct st_hist_buffer_info)) {
+ ALOGE("%s: History buffer config format error, exiting",
+ __func__);
+ return -EINVAL;
+ }
+ hist_buf = (struct st_hist_buffer_info *)(opaque_ptr +
+ sizeof(struct st_param_header));
+ stc_ses->hist_buf_duration =
+ hist_buf->hist_buffer_duration_msec;
+ stc_ses->preroll_duration = hist_buf->pre_roll_duration_msec;
+ ALOGV("%s: recognition config history buf len = %d, "
+ "preroll len = %d, minor version = %d",
+ __func__, hist_buf->hist_buffer_duration_msec,
+ hist_buf->pre_roll_duration_msec, hist_buf->version);
+ opaque_size += sizeof(struct st_param_header) +
+ sizeof(struct st_hist_buffer_info);
+ opaque_ptr += sizeof(struct st_param_header) +
+ sizeof(struct st_hist_buffer_info);
+ break;
+ case ST_PARAM_KEY_DETECTION_PERF_MODE:
+ if (param_hdr->payload_size !=
+ sizeof(struct st_det_perf_mode_info)) {
+ ALOGE("%s: Opaque data format error, exiting", __func__);
+ return -EINVAL;
+ }
+ det_perf_mode = (struct st_det_perf_mode_info *)(opaque_ptr +
+ sizeof(struct st_param_header));
+ ALOGV("set perf mode to %d", det_perf_mode->mode);
+ stc_ses->client_req_det_mode = det_perf_mode->mode;
+ opaque_size += sizeof(struct st_param_header) +
+ sizeof(struct st_det_perf_mode_info);
+ opaque_ptr += sizeof(struct st_param_header) +
+ sizeof(struct st_det_perf_mode_info);
+ break;
+ default:
+ ALOGE("%s: Unsupported opaque data key id, exiting", __func__);
+ return -EINVAL;
+ }
+ }
+ } else if (stc_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ struct sound_trigger_phrase_sound_model *phrase_sm = stc_ses->phrase_sm;
+
+ ALOGV("%s: num_phrases=%d, id=%d", __func__,
+ rc_config->num_phrases, rc_config->phrases[0].id);
+
+ if (st_ses->vendor_uuid_info->is_qcva_uuid ||
+ st_ses->vendor_uuid_info->is_qcmd_uuid) {
+ if (st_ses->stdev->is_gcs && st_hw_ses == st_ses->hw_ses_cpe)
+ status = generate_conf_levels_payload_from_rc_config_v2(
+ phrase_sm, rc_config, &conf_levels, &num_conf_levels);
+ else
+ status = generate_conf_levels_payload_from_rc_config(
+ phrase_sm, rc_config, &conf_levels, &num_conf_levels);
+ if (status || !conf_levels) {
+ ALOGE("%s: failed to get conf levels from lib handle",
+ __func__);
+ return status;
+ }
+ } else {
+ ALOGD("%s: No smlib, opaque data would be sent as is", __func__);
+ }
+ }
+
+ sthw_cfg = &st_hw_ses->sthw_cfg;
+ enable_lab = stc_ses->rc_config->capture_requested ||
+ !list_empty(&stc_ses->second_stage_list);
+
+ if (v_info->merge_fs_soundmodels) {
+ /* merge_fs_soundmodels is true only for QC SVA UUID */
+
+ /*
+ * Note:
+ * For ADSP case, the generated conf levles size must be equal to
+ * SML queried conf levels.
+ * For WDSP gcs case, there is additional payload for KW enable
+ * fields in generated conf_levels. If merge sound model is supported
+ * on WDSP case, update logic here accordingly.
+ */
+ if (num_conf_levels != stc_ses->sm_info.cf_levels_size) {
+ ALOGE("%s: Unexpected, client cf levels %d != sm_info cf levels %d",
+ __func__, num_conf_levels, stc_ses->sm_info.cf_levels_size);
+ return -EINVAL;
+ }
+
+ /*
+ * If any of the active clients requested capture or enabled the
+ * second stage, the underlying hw session buffering needs to
+ * be enabled. Ignore if it is already enabled.
+ */
+ if (!st_ses->lab_enabled && enable_lab)
+ st_ses->lab_enabled = true;
+
+ /* Aggregate DSP configuration for highest client configuration */
+
+ /* SVA2.0 sound models */
+ if (!stc_ses->hist_buf_duration &&
+ stc_ses->rc_config->capture_requested &&
+ (stc_ses->rc_config->data_size > 0)) {
+ stc_ses->hist_buf_duration = st_ses->vendor_uuid_info->kw_duration;
+ stc_ses->preroll_duration = 0;
+ }
+
+ if (stc_ses->hist_buf_duration > sthw_cfg->client_req_hist_buf)
+ sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
+ if (stc_ses->preroll_duration > sthw_cfg->client_req_preroll)
+ sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
+
+ ALOGV("%s: client hb_sz %d pr_sz %d, sthw lab %d hb_sz %d "
+ "pr_sz %d", __func__, stc_ses->hist_buf_duration,
+ stc_ses->preroll_duration, st_ses->lab_enabled,
+ sthw_cfg->client_req_hist_buf, sthw_cfg->client_req_preroll);
+
+ /* Cache it to use when client restarts without config update or
+ * during only one remaining client model as there won't be a
+ * merged model yet.
+ */
+ memcpy(stc_ses->sm_info.cf_levels, conf_levels,
+ stc_ses->sm_info.cf_levels_size);
+
+ status = update_merge_conf_levels_payload(st_ses, &stc_ses->sm_info,
+ conf_levels, num_conf_levels, true);
+ free(conf_levels); /* Merged model conf levels will be used further */
+ if (status)
+ return status;
+
+ sthw_cfg->conf_levels = st_ses->sm_info.cf_levels;
+ sthw_cfg->num_conf_levels = st_ses->sm_info.cf_levels_size;
+ st_hw_ses->sthw_cfg_updated = true;
+
+ /*
+ * Merging further unknown custom data is not needed, as
+ * SVA doesn't support unkown custom data. if required in future,
+ * handle here.
+ * For now just copy the the current client data which is same
+ * across SVA engines.
+ */
+ if (!sthw_cfg->custom_data) {
+ sthw_cfg->custom_data = (char *)rc_config + rc_config->data_offset;
+ if (rc_config->data_size)
+ sthw_cfg->custom_data_size = rc_config->data_size;
+ }
+
+ } else {
+ st_ses->recognition_mode = stc_ses->recognition_mode;
+ st_ses->lab_enabled = enable_lab;
+
+ sthw_cfg->client_req_hist_buf = stc_ses->hist_buf_duration;
+ sthw_cfg->client_req_preroll = stc_ses->preroll_duration;
+
+ if (sthw_cfg->conf_levels)
+ free(sthw_cfg->conf_levels);
+ sthw_cfg->conf_levels = conf_levels;
+ sthw_cfg->num_conf_levels = num_conf_levels;
+
+ sthw_cfg->custom_data = (char *)rc_config + rc_config->data_offset;
+ sthw_cfg->custom_data_size = rc_config->data_size;
+ }
+ ALOGD("%s:[%d] lab enabled %d", __func__, st_ses->sm_handle,
+ st_ses->lab_enabled);
+
+ return status;
+}
+
+static void do_hw_sess_cleanup(st_proxy_session_t *st_ses,
+ st_hw_session_t *hw_ses, enum hw_session_err_mask err)
{
if (err & HW_SES_ERR_MASK_BUFFERING)
- hw_ses->fptrs->stop_buffering(hw_ses, st_ses->lab_enabled);
+ hw_ses->fptrs->stop_buffering(hw_ses);
if (err & HW_SES_ERR_MASK_STARTED) {
hw_ses->fptrs->stop(hw_ses);
@@ -237,43 +2346,49 @@
hw_ses->fptrs->set_device(hw_ses, false);
if (err & HW_SES_ERR_MASK_REG_SM)
- hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
+ hw_ses->fptrs->dereg_sm(hw_ses);
}
-static void reg_hal_event_session(st_session_t *p_ses, st_hw_session_t *hw_ses)
+static void reg_hal_event_session(st_session_t *stc_ses,
+ st_hw_session_t *hw_ses)
{
struct sound_trigger_event_info event_info;
/* Pass the pcm information to audio hal for capturing LAB */
- if (p_ses->lab_enabled && p_ses->stdev->audio_hal_cb) {
- ALOGD("%s: ST_EVENT_SESSION_REGISTER capture_handle %d p_ses %p",
- __func__, p_ses->capture_handle, (void *)p_ses);
- event_info.st_ses.p_ses = (void *)p_ses;
+ if ((stc_ses->rc_config &&
+ stc_ses->rc_config->capture_requested) &&
+ stc_ses->stdev->audio_hal_cb) {
+ ALOGD("%s:[c%d] ST_EVENT_SESSION_REGISTER capture_handle %d",
+ __func__, stc_ses->sm_handle, stc_ses->capture_handle);
+ event_info.st_ses.p_ses = (void *)stc_ses;
event_info.st_ses.config = hw_ses->config;
- event_info.st_ses.capture_handle = p_ses->capture_handle;
+ event_info.st_ses.capture_handle = stc_ses->capture_handle;
/*
* set pcm to NULL as this version of st_hal doesn't pass pcm to
* audio HAL
*/
event_info.st_ses.pcm = NULL;
- p_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_REGISTER, &event_info);
+ stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_REGISTER, &event_info);
}
}
-static void dereg_hal_event_session(st_session_t *p_ses)
+static void dereg_hal_event_session(st_session_t *stc_ses)
{
struct sound_trigger_event_info event_info;
- /* Indicate to audio hal that buffering is stopped to stop reading LAB data */
- if (p_ses->lab_enabled && p_ses->stdev->audio_hal_cb) {
- ALOGD("%s: ST_EVENT_SESSION_DEREGISTER capture_handle %d p_ses %p",
- __func__, p_ses->capture_handle, p_ses);
- event_info.st_ses.p_ses = (void *)p_ses;
- event_info.st_ses.capture_handle = p_ses->capture_handle;
+ /* Indicate to audio hal that to stop reading LAB data */
+ if ((stc_ses->rc_config &&
+ stc_ses->rc_config->capture_requested) &&
+ stc_ses->stdev->audio_hal_cb) {
+ ALOGD("%s:[c%d] ST_EVENT_SESSION_DEREGISTER capture_handle %d",
+ __func__, stc_ses->sm_handle, stc_ses->capture_handle);
+ event_info.st_ses.p_ses = (void *)stc_ses;
+ event_info.st_ses.capture_handle = stc_ses->capture_handle;
event_info.st_ses.pcm = NULL;
- p_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_DEREGISTER, &event_info);
+ stc_ses->stdev->audio_hal_cb(ST_EVENT_SESSION_DEREGISTER, &event_info);
}
}
-static int start_hw_session(st_session_t *st_ses, st_hw_session_t *hw_ses, bool load_sm)
+static int start_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
+ bool load_sm)
{
int status = 0, err = 0;
@@ -287,7 +2402,7 @@
hw_ses->lpi_enable = hw_ses->stdev->lpi_enable;
if (!load_sm) {
load_sm = true;
- status = hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
+ status = hw_ses->fptrs->dereg_sm(hw_ses);
if (status)
ALOGW("%s:[%d] failed to dereg_sm err %d", __func__,
st_ses->sm_handle, status);
@@ -295,8 +2410,8 @@
}
if (load_sm) {
- status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_data,
- st_ses->sm_type);
+ status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
+ st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
if (status) {
ALOGE("%s:[%d] failed to reg_sm err %d", __func__,
st_ses->sm_handle, status);
@@ -313,24 +2428,9 @@
}
err |= HW_SES_ERR_MASK_DEVICE_SET;
- /*
- * Check for rc_config update before reg_sm_param,
- * as hw session can change from transitions,
- * and hence related config might also need to be updated.
- */
- if (hw_ses->rc_config != st_ses->rc_config ||
- hw_ses->rc_config_update_counter != st_ses->rc_config_update_counter) {
- status = st_hw_ses_update_config(st_ses, hw_ses);
- if (status) {
- ALOGE("%s: ERROR. updating rc_config, returned status %d",
- __func__, status);
- goto cleanup;
- }
- }
-
- status = hw_ses->fptrs->reg_sm_params(hw_ses,
- st_ses->recognition_mode, st_ses->lab_enabled,
- st_ses->rc_config, st_ses->sm_type, st_ses->sm_data);
+ status = hw_ses->fptrs->reg_sm_params(hw_ses, st_ses->recognition_mode,
+ st_ses->lab_enabled, st_ses->rc_config, st_ses->sm_info.sm_type,
+ st_ses->sm_info.sm_data);
if (status) {
ALOGE("%s:[%d] failed to reg_sm_params err %d", __func__,
st_ses->sm_handle, status);
@@ -354,7 +2454,8 @@
return status;
}
-static int stop_hw_session(st_session_t *st_ses, st_hw_session_t *hw_ses, bool unload_sm)
+static int stop_hw_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
+ bool unload_sm)
{
int status = 0;
int rc = 0;
@@ -380,7 +2481,7 @@
rc = status;
}
if (unload_sm) {
- status = hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
+ status = hw_ses->fptrs->dereg_sm(hw_ses);
if (status) {
ALOGE("%s:[%d] failed to dereg_sm, err %d", __func__,
st_ses->sm_handle, status);
@@ -395,79 +2496,75 @@
return rc;
}
-static int start_session(st_session_t *st_ses, st_hw_session_t *hw_ses, bool load_sm)
+static int start_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses,
+ bool load_sm)
{
int status = 0;
+
if (st_ses->hw_session_started) {
ALOGE("%s:[%d] already started", __func__, st_ses->sm_handle);
return -1;
}
- /*
- * The reg_hal_event_session call must be after start_hw_session. This is
- * important for when load_sm is true, because reg_sm sets the correct pcm
- * config for the current hw session. That pcm config is then sent to audio hal.
- */
+
status = start_hw_session(st_ses, hw_ses, load_sm);
- if (!status)
- reg_hal_event_session(st_ses, hw_ses);
+ hw_ses->sthw_cfg_updated = false;
+
return status;
}
-static int restart_session(st_session_t *st_ses, st_hw_session_t *hw_ses)
+static int restart_session(st_proxy_session_t *st_ses, st_hw_session_t *hw_ses)
{
- int status = hw_ses->fptrs->restart(hw_ses, st_ses->recognition_mode,
- st_ses->lab_enabled, st_ses->rc_config,
- st_ses->sm_type, st_ses->sm_data);
+ int status = 0;
+
+ status = hw_ses->fptrs->restart(hw_ses, st_ses->recognition_mode,
+ st_ses->rc_config, st_ses->sm_info.sm_type,
+ st_ses->sm_info.sm_data);
if (status == 0) {
st_ses->hw_session_started = true;
} else {
- ALOGE("%s:[%d] failed to restart, stop session", __func__, st_ses->sm_handle);
- /*
- * lower layers like gcs/lsm need to handle double stop calls properly
- * to avoid possible crash, as some of the clean ups are already issued
- * during fptrs->restart() when it's failed.
- */
- stop_hw_session(st_ses, hw_ses, true);
+ ALOGE("%s:[%d] failed to restart", __func__, st_ses->sm_handle);
+ st_ses->hw_session_started = false;
}
+
return status;
}
-static int stop_session(st_session_t *st_ses, st_hw_session_t *hw_ses, bool unload_sm)
+static int stop_session(st_proxy_session_t *st_ses,
+ st_hw_session_t *hw_ses, bool unload_sm)
{
if (!st_ses->hw_session_started) {
ALOGV("%s:[%d] already stopped", __func__, st_ses->sm_handle);
return 0;
}
- dereg_hal_event_session(st_ses);
- if (st_ses->detection_requested) {
- st_ses->detection_requested = false;
- enable_second_stage_processing(st_ses, hw_ses);
- }
+ st_ses->detection_requested = false;
return stop_hw_session(st_ses, hw_ses, unload_sm);
}
/*
- * This function gets the first stage detection keyword indices, which are needed
- * by the second stage sessions. If the legacy DSP is used, which does not provide
- * keyword indices, set the indices to include the entire keyword duration. This
- * function also gets the user confidence level if there is an active voiceprint
- * session.
+ * This function gets the first stage detection keyword indices, which are
+ * needed by the second stage sessions. If the legacy DSP is used, which does
+ * not provide keyword indices, set the indices to include the entire keyword
+ * duration. This function also gets the user confidence level if there is an
+ * active voiceprint session.
*/
-static int get_first_stage_detection_params(st_session_t *st_ses, void *payload,
- size_t payload_size)
+static int get_first_stage_detection_params(st_proxy_session_t *st_ses,
+ void *payload, size_t payload_size)
{
size_t count_size = 0;
uint8_t *payload_ptr = (uint8_t *)payload;
- uint32_t key_id = 0, key_payload_size = 0;
+ uint8_t *cf_levels = NULL;
+ uint32_t key_id = 0, key_payload_size = 0, cf_levels_size = 0;
uint32_t kw_start_ms = 0, kw_end_ms = 0;
st_hw_session_t *hw_ses = st_ses->hw_ses_current;
- struct listnode *node = NULL, *tmp_node = NULL;
+ struct listnode *node = NULL;
st_arm_second_stage_t *st_sec_stage = NULL;
+ st_session_t *stc_ses = st_ses->det_stc_ses;
bool is_active_vop_session = false;
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
+ list_for_each(node, &stc_ses->second_stage_list) {
st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- if (st_sec_stage->ss_info->sm_detection_type == ST_SM_TYPE_USER_VERIFICATION) {
+ if (st_sec_stage->ss_info->sm_detection_type ==
+ ST_SM_TYPE_USER_VERIFICATION) {
is_active_vop_session = true;
break;
}
@@ -486,8 +2583,25 @@
switch (key_id) {
case KEY_ID_CONFIDENCE_LEVELS:
if (is_active_vop_session) {
- hw_ses->user_level = (int32_t)(*(payload_ptr +
- GENERIC_DET_EVENT_USER_LEVEL_OFFSET));
+ /*
+ * It is expected that VoP is supported with single KW/user
+ * SVA3.0 model, hence get it directly with hard offset.
+ */
+ if (!st_ses->sm_info.sm_merged) {
+ hw_ses->user_level = (int32_t)(*(payload_ptr +
+ GENERIC_DET_EVENT_USER_LEVEL_OFFSET));
+ } else {
+ /* Extract from first stage merged conf levels */
+ check_and_extract_det_conf_levels_payload(st_ses,
+ payload_ptr + (4 * sizeof(uint32_t)),
+ *((uint32_t *)payload_ptr + 3),
+ &cf_levels, &cf_levels_size);
+ if (!cf_levels || !cf_levels_size)
+ break;
+ hw_ses->user_level = cf_levels[1];
+ ALOGV("%s:hw_ses->user_level %d at cf_levels[1]",
+ __func__, hw_ses->user_level);
+ }
}
break;
@@ -515,9 +2629,9 @@
* duration from platform xml will be used.
*/
hw_ses->kw_start_idx = 0;
- if (hw_ses->client_req_hist_buf) {
+ if (hw_ses->sthw_cfg.client_req_hist_buf) {
hw_ses->kw_end_idx =
- convert_ms_to_bytes(hw_ses->client_req_hist_buf,
+ convert_ms_to_bytes(hw_ses->sthw_cfg.client_req_hist_buf,
&hw_ses->config);
} else {
hw_ses->kw_end_idx =
@@ -531,7 +2645,7 @@
hw_ses->user_level = (int32_t)(*(payload_ptr +
GCS_NON_GENERIC_USER_LEVEL_OFFSET));
} else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) ||
- !st_ses->stdev->is_gcs) {
+ !st_ses->stdev->is_gcs) {
hw_ses->user_level = (int32_t)(*(payload_ptr +
LSM_NON_GENERIC_USER_LEVEL_OFFSET));
}
@@ -540,64 +2654,1372 @@
kw_start_ms = convert_bytes_to_ms(hw_ses->kw_start_idx, &hw_ses->config);
kw_end_ms = convert_bytes_to_ms(hw_ses->kw_end_idx, &hw_ses->config);
- ALOGD("%s:[%d] 1st stage kw_start = %dms, kw_end = %dms, is_generic_event %d",
- __func__, st_ses->sm_handle, kw_start_ms, kw_end_ms,
- hw_ses->is_generic_event);
+ ALOGD("%s:[%d] 1st stage kw_start = %dms, kw_end = %dms,"
+ "is_generic_event %d", __func__, st_ses->sm_handle,
+ kw_start_ms, kw_end_ms, hw_ses->is_generic_event);
return 0;
}
-static inline void stop_second_stage_session(st_session_t *st_ses)
+static inline int prepapre_second_stage_for_client(st_session_t *stc_ses)
{
- struct listnode *node = NULL, *tmp_node = NULL;
+ struct listnode *node = NULL;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ int status = 0;
+
+ ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
+
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
+ status = st_second_stage_prepare_session(st_sec_stage);
+ }
+ return status;
+}
+
+static inline int start_second_stage_for_client(st_session_t *stc_ses)
+{
+ struct listnode *node = NULL;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ int status = 0;
+
+ ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
+
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
+ status = st_second_stage_start_session(st_sec_stage);
+ }
+ return status;
+}
+
+static inline void stop_second_stage_for_client(st_session_t *stc_ses)
+{
+ struct listnode *node = NULL;
st_arm_second_stage_t *st_sec_stage = NULL;
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
+ ALOGV("%s:[c%d]", __func__, stc_ses->sm_handle);
+
+ list_for_each(node, &stc_ses->second_stage_list) {
st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
st_second_stage_stop_session(st_sec_stage);
}
}
-static int idle_state_fn(st_session_t *st_ses, st_session_ev_t *ev)
+static int generate_legacy_st_phrase_recognition_event
+(
+ const struct sound_trigger_phrase_sound_model *phrase_sm,
+ const struct sound_trigger_recognition_config *rc_config,
+ const void *payload,
+ unsigned int payload_size,
+ struct sound_trigger_phrase_recognition_event **out_rc_event
+)
+{
+ struct sound_trigger_phrase_recognition_event *event;
+ unsigned int i = 0, j = 0, user_id = 0;
+
+ ALOGD("%s: Enter payload_size %d", __func__, payload_size);
+
+ if(!payload || !phrase_sm || !rc_config || !out_rc_event) {
+ ALOGE("%s: Null params", __func__);
+ return -EINVAL;
+ }
+
+ *out_rc_event = NULL;
+ event = calloc(1, sizeof(*event) + payload_size);
+ if (!event) {
+ ALOGE("%s: event allocation failed size %d", __func__, payload_size);
+ return -ENODEV;
+ }
+
+ event->num_phrases = rc_config->num_phrases;
+ event->common.data_offset = sizeof(*event);
+ event->common.data_size = payload_size;
+ memcpy((char *)event + event->common.data_offset, payload, payload_size);
+
+ /* fill confidence levels */
+ for (i = 0; i < rc_config->num_phrases; i++) {
+ event->phrase_extras[i].id = rc_config->phrases[i].id;
+ event->phrase_extras[i].recognition_modes =
+ phrase_sm->phrases[0].recognition_mode;
+ event->phrase_extras[i].confidence_level = ((char *)payload)[i];
+ event->phrase_extras[i].num_levels = rc_config->phrases[i].num_levels;
+ for (j = 0; j < rc_config->phrases[i].num_levels; j++) {
+ user_id = rc_config->phrases[i].levels[j].user_id;
+ event->phrase_extras[i].levels[j].user_id = user_id;
+ event->phrase_extras[i].levels[j].level =
+ ((char *)payload)[user_id];
+ }
+ }
+
+ *out_rc_event = event;
+ return 0;
+}
+
+/*
+ * This function sets the opaque data size for the DSP's generic detection
+ * events. This opaque data can now have varying size based on the requested
+ * params.
+ */
+static size_t set_opaque_data_size(char *payload, size_t payload_size,
+ uint32_t version)
+{
+ size_t count_size = 0, opaque_size = 0;
+ uint32_t key_id = 0, key_payload_size = 0;
+
+ while (count_size < payload_size) {
+ key_id = *(uint32_t *)payload;
+ key_payload_size = *((uint32_t *)payload + 1);
+
+ switch (key_id) {
+ case KEY_ID_CONFIDENCE_LEVELS:
+ opaque_size += sizeof(struct st_param_header);
+ if (version != CONF_LEVELS_INTF_VERSION_0002) {
+ opaque_size +=
+ sizeof(struct st_confidence_levels_info);
+ } else {
+ opaque_size +=
+ sizeof(struct st_confidence_levels_info_v2);
+ }
+ count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
+ payload += count_size;
+ break;
+
+ case KEY_ID_KEYWORD_POSITION_STATS:
+ opaque_size += sizeof(struct st_param_header) +
+ sizeof(struct st_keyword_indices_info);
+ count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
+ payload += count_size;
+ break;
+
+ default:
+ ALOGE("%s: Unsupported generic detection event key id", __func__);
+ }
+ }
+
+ opaque_size += sizeof(struct st_param_header) +
+ sizeof(struct st_timestamp_info);
+
+ return opaque_size;
+}
+
+/*
+ * This function packs the updated opaque data confidence levels which are
+ * passed to the client via callback.
+ */
+static int pack_opaque_data_conf_levels(
+ st_proxy_session_t *st_ses, void *opaque_data,
+ uint8_t *payload,
+ unsigned int payload_size)
+{
+ uint8_t *payload_ptr = payload;
+ unsigned int i = 0, j = 0, k = 0, user_id = 0;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ struct listnode *node = NULL;
+ struct st_confidence_levels_info *conf_levels = NULL;
+ struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
+ st_session_t *stc_ses = st_ses->det_stc_ses;
+ int32_t kw_level = 0, user_level = 0;
+
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
+ if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
+ kw_level = st_sec_stage->ss_session->confidence_score;
+ } else if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_VOP) {
+ user_level = st_sec_stage->ss_session->confidence_score;
+ }
+ }
+
+ if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
+ conf_levels = (struct st_confidence_levels_info *)opaque_data;
+ for (i = 0; i < conf_levels->num_sound_models; i++) {
+ if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
+ for (j = 0;
+ j < conf_levels->conf_levels[i].num_kw_levels; j++) {
+ if (j <= payload_size)
+ conf_levels->conf_levels[i].kw_levels[j].kw_level =
+ payload_ptr[j];
+ else
+ ALOGE("%s: unexpected conf size %d < %d", __func__,
+ payload_size, j);
+ for (k = 0;
+ k < conf_levels->conf_levels[i].kw_levels[j].num_user_levels;
+ k++) {
+ user_id =
+ conf_levels->conf_levels[i].kw_levels[j].
+ user_levels[k].user_id;
+ if (user_id <= payload_size)
+ conf_levels->conf_levels[i].kw_levels[j].
+ user_levels[k].level = payload_ptr[user_id];
+ else
+ ALOGE("%s: Unexpected conf size %d < %d", __func__,
+ payload_size, user_id);
+ }
+ }
+ } else if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_CNN) {
+ conf_levels->conf_levels[i].kw_levels[0].kw_level = kw_level;
+ } else if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_VOP) {
+ /*
+ * Fill both the keyword and user confidence level with the
+ * confidence score returned from the voiceprint algorithm.
+ */
+ conf_levels->conf_levels[i].kw_levels[0].kw_level =
+ (uint8_t)user_level;
+ conf_levels->conf_levels[i].kw_levels[0].user_levels[0].level =
+ (uint8_t)user_level;
+ }
+ }
+ } else {
+ conf_levels_v2 = (struct st_confidence_levels_info_v2 *)opaque_data;
+ for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
+ if (conf_levels_v2->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
+ for (j = 0;
+ j < conf_levels_v2->conf_levels[i].num_kw_levels; j++) {
+ if (j <= payload_size)
+ conf_levels_v2->conf_levels[i].kw_levels[j].kw_level =
+ payload_ptr[j];
+ else
+ ALOGE("%s: unexpected conf size %d < %d", __func__,
+ payload_size, j);
+
+ for (k = 0;
+ k < conf_levels_v2->conf_levels[i].kw_levels[j].num_user_levels;
+ k++) {
+ user_id =
+ conf_levels_v2->conf_levels[i].kw_levels[j].
+ user_levels[k].user_id;
+ if (user_id <= payload_size)
+ conf_levels_v2->conf_levels[i].kw_levels[j].
+ user_levels[k].level = payload_ptr[user_id];
+ else
+ ALOGE("%s: Unexpected conf size %d < %d", __func__,
+ payload_size, user_id);
+ }
+ }
+ } else if (conf_levels_v2->conf_levels[i].sm_id ==
+ ST_SM_ID_SVA_CNN) {
+ conf_levels_v2->conf_levels[i].kw_levels[0].kw_level = kw_level;
+ } else if (conf_levels_v2->conf_levels[i].sm_id ==
+ ST_SM_ID_SVA_VOP) {
+ /*
+ * Fill both the keyword and user confidence level with the
+ * confidence score returned from the voiceprint algorithm.
+ */
+ conf_levels_v2->conf_levels[i].kw_levels[0].kw_level =
+ user_level;
+ conf_levels_v2->conf_levels[i].kw_levels[0].user_levels[0].level =
+ user_level;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* This function packs the sound trigger API confidence levels */
+static int pack_recognition_event_conf_levels(
+ st_proxy_session_t *st_ses, uint8_t *payload,
+ unsigned int payload_size,
+ struct sound_trigger_phrase_recognition_event *local_event)
+{
+ unsigned int j = 0, k = 0, user_id = 0;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ struct listnode *node = NULL;
+ st_session_t *stc_ses = st_ses->det_stc_ses;
+ struct sound_trigger_phrase_sound_model *phrase_sm =
+ (struct sound_trigger_phrase_sound_model *)stc_ses->phrase_sm;
+
+ /*
+ * Fill in the GMM confidence levels to the sound trigger recognition event
+ * APIs first. If any second stage session is enabled, overwrite the APIs
+ * with the second stage confidence levels.
+ */
+ for (j = 0; j < stc_ses->rc_config->num_phrases; j++) {
+ local_event->phrase_extras[j].id = stc_ses->rc_config->phrases[j].id;
+ local_event->phrase_extras[j].recognition_modes =
+ phrase_sm->phrases[j].recognition_mode;
+ local_event->phrase_extras[j].num_levels =
+ stc_ses->rc_config->phrases[j].num_levels;
+ if (j <= payload_size)
+ local_event->phrase_extras[j].confidence_level = payload[j];
+ else
+ ALOGE("%s: unexpected conf size %d < %d", __func__,
+ payload_size, j);
+
+ for (k = 0; k < stc_ses->rc_config->phrases[j].num_levels; k++) {
+ user_id = stc_ses->rc_config->phrases[j].levels[k].user_id;
+ if (user_id <= payload_size) {
+ local_event->phrase_extras[j].levels[k].user_id = user_id;
+ local_event->phrase_extras[j].levels[k].level =
+ payload[user_id];
+ } else {
+ ALOGE("%s: Unexpected conf size %d < %d", __func__,
+ payload_size, user_id);
+ }
+ }
+ }
+
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
+ if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
+ local_event->phrase_extras[0].confidence_level =
+ (uint8_t)st_sec_stage->ss_session->confidence_score;
+ } else if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_VOP) {
+ local_event->phrase_extras[0].levels[0].level =
+ (uint8_t)st_sec_stage->ss_session->confidence_score;
+ }
+ }
+ return 0;
+}
+
+static int parse_generic_event_and_pack_opaque_data(
+ st_proxy_session_t *st_ses, uint8_t *opaque_data,
+ uint8_t *payload, size_t payload_size,
+ struct sound_trigger_phrase_recognition_event *local_event)
+{
+ uint32_t key_id = 0, key_payload_size = 0;
+ struct st_param_header *param_hdr = NULL;
+ struct st_keyword_indices_info *kw_indices = NULL;
+ struct st_timestamp_info *timestamps = NULL;
+ size_t count_size = 0;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ struct listnode *node = NULL;
+ st_session_t *stc_ses = st_ses->det_stc_ses;
+ int status = 0;
+ unsigned char *cf_levels = NULL;
+ unsigned int cf_levels_size = 0;
+
+ while (count_size < payload_size) {
+ key_id = *(uint32_t *)payload;
+ key_payload_size = *((uint32_t *)payload + 1);
+
+ switch (key_id) {
+ case KEY_ID_CONFIDENCE_LEVELS:
+ /* Pack the opaque data confidence levels structure */
+ param_hdr = (struct st_param_header *)(opaque_data);
+ param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
+ opaque_data += sizeof(struct st_param_header);
+ if (stc_ses->conf_levels_intf_version !=
+ CONF_LEVELS_INTF_VERSION_0002) {
+ param_hdr->payload_size =
+ sizeof(struct st_confidence_levels_info);
+ } else {
+ param_hdr->payload_size =
+ sizeof(struct st_confidence_levels_info_v2);
+ }
+ check_and_extract_det_conf_levels_payload(st_ses,
+ payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
+ &cf_levels, &cf_levels_size);
+ if (!cf_levels || !cf_levels_size) {
+ status = -EINVAL;
+ goto exit;
+ }
+ memcpy(opaque_data, stc_ses->st_conf_levels,
+ param_hdr->payload_size);
+ pack_opaque_data_conf_levels(st_ses, opaque_data,
+ cf_levels, cf_levels_size);
+ pack_recognition_event_conf_levels(st_ses, cf_levels,
+ cf_levels_size, local_event);
+ opaque_data += param_hdr->payload_size;
+ break;
+
+ case KEY_ID_KEYWORD_POSITION_STATS:
+ /* Pack the opaque data keyword indices structure */
+ param_hdr = (struct st_param_header *)(opaque_data);
+ param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
+ param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
+ opaque_data += sizeof(struct st_param_header);
+ kw_indices = (struct st_keyword_indices_info *)(opaque_data);
+ kw_indices->version = 0x1;
+ kw_indices->start_index = *((uint32_t *)payload + 3);
+ kw_indices->end_index = *((uint32_t *)payload + 4);
+
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t,
+ list_node);
+ if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
+ kw_indices->start_index =
+ st_sec_stage->ss_session->kw_start_idx;
+ kw_indices->end_index =
+ st_sec_stage->ss_session->kw_end_idx;
+ }
+ }
+ opaque_data += sizeof(struct st_keyword_indices_info);
+ break;
+
+ default:
+ ALOGE("%s: Unsupported generic detection event key id", __func__);
+ status = -EINVAL;
+ goto exit;
+ }
+ count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
+ payload += count_size;
+ }
+
+ /* Pack the opaque data detection timestamp structure */
+ param_hdr = (struct st_param_header *)(opaque_data);
+ param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
+ param_hdr->payload_size = sizeof(struct st_timestamp_info);
+ opaque_data += sizeof(struct st_param_header);
+ timestamps = (struct st_timestamp_info *)(opaque_data);
+ timestamps->version = 0x1;
+ timestamps->first_stage_det_event_time =
+ st_ses->hw_ses_current->first_stage_det_event_time;
+ if (!list_empty(&stc_ses->second_stage_list))
+ timestamps->second_stage_det_event_time =
+ st_ses->hw_ses_current->second_stage_det_event_time;
+ opaque_data += sizeof(struct st_timestamp_info);
+
+exit:
+ return status;
+}
+
+static int parse_generic_event_without_opaque_data(
+ st_proxy_session_t *st_ses, uint8_t *payload, size_t payload_size,
+ struct sound_trigger_phrase_recognition_event *local_event)
+{
+ uint32_t key_id = 0, key_payload_size = 0;
+ size_t count_size = 0;
+ int status = 0;
+ unsigned char *cf_levels = NULL;
+ unsigned int cf_levels_size = 0;;
+
+ while (count_size < payload_size) {
+ key_id = *(uint32_t *)payload;
+ key_payload_size = *((uint32_t *)payload + 1);
+
+ switch (key_id) {
+ case KEY_ID_CONFIDENCE_LEVELS:
+ check_and_extract_det_conf_levels_payload(st_ses,
+ payload + (4 * sizeof(uint32_t)), *((uint32_t *)payload + 3),
+ &cf_levels, &cf_levels_size);
+ if (!cf_levels || !cf_levels_size) {
+ status = -EINVAL;
+ return status;
+ }
+ pack_recognition_event_conf_levels(st_ses, cf_levels,
+ cf_levels_size, local_event);
+ return status;
+
+ case KEY_ID_KEYWORD_POSITION_STATS:
+ count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
+ payload += count_size;
+ break;
+
+ default:
+ ALOGE("%s: Unsupported generic detection event key id", __func__);
+ status = -EINVAL;
+ return status;
+ }
+ }
+ return status;
+}
+
+/*
+ * This function handles detection payloads in the format of the DSP's
+ * generic detection event.
+ */
+int process_detection_event_keyphrase_v2(
+ st_proxy_session_t *st_ses, int detect_status,
+ void *payload, size_t payload_size,
+ struct sound_trigger_phrase_recognition_event **event)
+{
+ st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
+ st_session_t *stc_ses = st_ses->det_stc_ses;
+ unsigned int i = 0, j = 0;
+ int status = 0;
+ uint8_t *opaque_data = NULL;
+ size_t opaque_size = 0;
+ struct sound_trigger_phrase_recognition_event *local_event = NULL;
+
+ if (st_ses->vendor_uuid_info->is_qcva_uuid)
+ opaque_size = set_opaque_data_size(payload, payload_size,
+ stc_ses->conf_levels_intf_version);
+ else
+ opaque_size = payload_size;
+
+ local_event = calloc(1,
+ sizeof(struct sound_trigger_phrase_recognition_event) + opaque_size);
+ if (!local_event) {
+ ALOGE("%s: local_event allocation failed, opaque data size = %d",
+ __func__, (unsigned int)opaque_size);
+ return -ENOMEM;
+ }
+
+ local_event->num_phrases = stc_ses->rc_config->num_phrases;
+ local_event->common.data_offset =
+ sizeof(struct sound_trigger_phrase_recognition_event);
+ local_event->common.data_size = opaque_size;
+ opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
+
+ if (st_ses->vendor_uuid_info->is_qcva_uuid) {
+ if (stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) {
+ status = parse_generic_event_and_pack_opaque_data(st_ses,
+ opaque_data, payload, payload_size, local_event);
+ if (status) {
+ ALOGE("%s: Failed to parse generic detection event with opaque"
+ "data %d", __func__, status);
+ goto exit;
+ }
+
+ ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
+ ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
+ "detection_opaque_data", "bin", opaque_cnt++);
+ ST_DBG_FILE_WRITE(opaque_fd, opaque_data, opaque_size);
+ ST_DBG_FILE_CLOSE(opaque_fd);
+ } else {
+ status = parse_generic_event_without_opaque_data(st_ses, payload,
+ payload_size, local_event);
+ if (status) {
+ ALOGE("%s: Failed to parse generic detection event without"
+ "opaque data %d", __func__, status);
+ goto exit;
+ }
+ }
+ } else {
+ local_event = calloc(1, sizeof(*local_event) + payload_size);
+ if (!local_event) {
+ ALOGE("%s: event allocation failed, size %zd", __func__,
+ payload_size);
+ status = -ENOMEM;
+ goto exit;
+ }
+ memcpy(local_event->phrase_extras,
+ stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
+ sizeof(struct sound_trigger_phrase_recognition_extra));
+ local_event->num_phrases = stc_ses->rc_config->num_phrases;
+ local_event->common.data_offset = sizeof(*local_event);
+ local_event->common.data_size = opaque_size;
+ memcpy(opaque_data, payload, opaque_size);
+ opaque_data += opaque_size;
+ }
+
+ /*
+ * fill the remaining recognition event parameters not specific
+ * to soundmodel lib
+ */
+ local_event->common.status = detect_status;
+ local_event->common.type = stc_ses->phrase_sm->common.type;
+ local_event->common.model = stc_ses->sm_handle;
+ local_event->common.capture_available =
+ stc_ses->rc_config->capture_requested;
+ local_event->common.capture_delay_ms = 0;
+ local_event->common.capture_preamble_ms = 0;
+ local_event->common.audio_config.sample_rate =
+ SOUND_TRIGGER_SAMPLING_RATE_16000;
+ local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
+ local_event->common.audio_config.channel_mask =
+ audio_channel_in_mask_from_count(st_hw_ses->config.channels);
+
+ for (i = 0; i < local_event->num_phrases; ++i) {
+ ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
+ local_event->phrase_extras[i].id,
+ local_event->phrase_extras[i].confidence_level);
+ for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
+ ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
+ local_event->phrase_extras[i].levels[j].user_id,
+ local_event->phrase_extras[i].levels[j].level);
+ }
+ }
+
+ ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
+
+ ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
+ "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
+ local_event->common.status, local_event->common.type,
+ local_event->common.model, local_event->common.capture_available,
+ local_event->num_phrases, local_event->phrase_extras[0].id);
+
+ *event = local_event;
+ return 0;
+
+exit:
+ if (local_event)
+ free(local_event);
+ return status;
+}
+
+/*
+ * This function handles detection payloads in the format of the DSP's
+ * legacy (non-generic) detection event.
+ * TODO: Deprecate this when DSP for all shared targets of this component
+ * move to generic event.
+ */
+static int process_detection_event_keyphrase(
+ st_proxy_session_t *st_ses, int detect_status,
+ void *payload, size_t payload_size,
+ struct sound_trigger_phrase_recognition_event **event)
+{
+ st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
+ st_session_t *stc_ses = st_ses->det_stc_ses;
+ unsigned int i = 0, j = 0;
+ int status = 0;
+ struct sound_trigger_phrase_recognition_event *local_event = NULL;
+ size_t opaque_size = 0;
+ uint8_t *opaque_data = NULL, *payload_ptr = NULL;
+ struct st_param_header *param_hdr = NULL;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ struct listnode *node = NULL;
+ struct st_keyword_indices_info *kw_indices = NULL;
+ struct st_timestamp_info *timestamps = NULL;
+ bool enable_kw_indices = false;
+ unsigned char *cf_levels = NULL;
+ unsigned int cf_levels_size = 0;
+
+ if ((stc_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
+ st_ses->vendor_uuid_info->is_qcva_uuid) {
+ /*
+ * This logic is for the updated opaque data format. Sound trigger
+ * recognition event APIs are filled along with the opaque data's
+ * confidence levels, keyword indices, and timestamp parameters.
+ */
+ opaque_size = (2 * sizeof(struct st_param_header)) +
+ sizeof(struct st_timestamp_info);
+ if (stc_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002)
+ opaque_size += sizeof(struct st_confidence_levels_info);
+ else
+ opaque_size += sizeof(struct st_confidence_levels_info_v2);
+
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
+ if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
+ enable_kw_indices = true;
+ opaque_size += sizeof(struct st_param_header) +
+ sizeof(struct st_keyword_indices_info);
+ break;
+ }
+ }
+
+ local_event = calloc(1,
+ sizeof(struct sound_trigger_phrase_recognition_event) +
+ opaque_size);
+ if (!local_event) {
+ ALOGE("%s: local_event allocation failed, opaque data size = %d",
+ __func__, (unsigned int)opaque_size);
+ return -ENOMEM;
+ }
+
+ local_event->num_phrases = stc_ses->rc_config->num_phrases;
+ local_event->common.data_offset =
+ sizeof(struct sound_trigger_phrase_recognition_event);
+ local_event->common.data_size = opaque_size;
+ opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
+ if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
+ payload_ptr = (uint8_t *)payload + 2;
+ payload_size -= 2; /* Re-use */
+ } else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) ||
+ !st_ses->stdev->is_gcs) {
+ payload_ptr = (uint8_t *)payload;
+ } else {
+ ALOGE("%s: Invalid execution mode, exiting", __func__);
+ status = -EINVAL;
+ goto err_exit;
+ }
+
+ /* Pack the opaque data confidence levels structure */
+ param_hdr = (struct st_param_header *)opaque_data;
+ param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
+ opaque_data += sizeof(struct st_param_header);
+ if (stc_ses->conf_levels_intf_version !=
+ CONF_LEVELS_INTF_VERSION_0002) {
+ param_hdr->payload_size =
+ sizeof(struct st_confidence_levels_info);
+ } else {
+ param_hdr->payload_size =
+ sizeof(struct st_confidence_levels_info_v2);
+ }
+ check_and_extract_det_conf_levels_payload(st_ses, payload_ptr,
+ payload_size, &cf_levels, &cf_levels_size);
+ if (!cf_levels || !cf_levels_size) {
+ status = -EINVAL;
+ goto err_exit;
+ }
+ memcpy(opaque_data, stc_ses->st_conf_levels, param_hdr->payload_size);
+ pack_opaque_data_conf_levels(st_ses, opaque_data, cf_levels,
+ cf_levels_size);
+ pack_recognition_event_conf_levels(st_ses, cf_levels, cf_levels_size,
+ local_event);
+ opaque_data += param_hdr->payload_size;
+
+ /* Pack the opaque data keyword indices structure */
+ if (enable_kw_indices) {
+ param_hdr = (struct st_param_header *)opaque_data;
+ param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
+ param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
+ opaque_data += sizeof(struct st_param_header);
+ kw_indices = (struct st_keyword_indices_info *)opaque_data;
+ kw_indices->version = 0x1;
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t,
+ list_node);
+ if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
+ kw_indices->start_index =
+ st_sec_stage->ss_session->kw_start_idx;
+ kw_indices->end_index =
+ st_sec_stage->ss_session->kw_end_idx;
+ }
+ }
+ opaque_data += sizeof(struct st_keyword_indices_info);
+ }
+
+ /* Pack the opaque data detection timestamp structure */
+ param_hdr = (struct st_param_header *)opaque_data;
+ param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
+ param_hdr->payload_size = sizeof(struct st_timestamp_info);
+ opaque_data += sizeof(struct st_param_header);
+ timestamps = (struct st_timestamp_info *)opaque_data;
+ timestamps->version = 0x1;
+ timestamps->first_stage_det_event_time =
+ st_hw_ses->first_stage_det_event_time;
+ if (!list_empty(&stc_ses->second_stage_list))
+ timestamps->second_stage_det_event_time =
+ st_hw_ses->second_stage_det_event_time;
+ opaque_data += sizeof(struct st_timestamp_info);
+
+ ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
+ ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
+ "detection_opaque_data", "bin", opaque_cnt++);
+ ST_DBG_FILE_WRITE(opaque_fd, (opaque_data - opaque_size), opaque_size);
+ ST_DBG_FILE_CLOSE(opaque_fd);
+
+ } else {
+ if (st_ses->vendor_uuid_info->is_qcva_uuid ||
+ st_ses->vendor_uuid_info->is_qcmd_uuid) {
+ if (st_ses->stdev->is_gcs &&
+ ST_EXEC_MODE_CPE == st_ses->exec_mode &&
+ !st_hw_ses->is_generic_event) {
+ payload_ptr = payload;
+ payload_ptr += 2; /* Skip minor_version and num_active_models */
+ payload_size -= 2;
+ } else {
+ payload_ptr = payload;
+ }
+ status = generate_legacy_st_phrase_recognition_event(
+ stc_ses->phrase_sm, stc_ses->rc_config, payload_ptr,
+ payload_size, &local_event);
+
+ if (status)
+ goto exit;
+ } else {
+ ALOGD("%s: Send detection payload as is", __func__);
+
+ local_event = calloc(1, sizeof(*local_event) + payload_size);
+ if (!local_event) {
+ ALOGE("%s: event allocation failed, size %zd", __func__,
+ payload_size);
+ status = -ENOMEM;
+ goto exit;
+ }
+ memcpy(local_event->phrase_extras,
+ stc_ses->rc_config->phrases, stc_ses->rc_config->num_phrases *
+ sizeof(struct sound_trigger_phrase_recognition_extra));
+ local_event->num_phrases = stc_ses->rc_config->num_phrases;
+ local_event->common.data_offset = sizeof(*local_event);
+ local_event->common.data_size = payload_size;
+ memcpy((char *)local_event + local_event->common.data_offset,
+ payload, payload_size);
+ }
+ }
+
+ /* fill the remaining recognition event parameters not specific
+ to soundmodel lib */
+ local_event->common.status = detect_status;
+ local_event->common.type = stc_ses->phrase_sm->common.type;
+ local_event->common.model = stc_ses->sm_handle;
+ local_event->common.capture_available =
+ stc_ses->rc_config->capture_requested;
+ local_event->common.capture_delay_ms = 0;
+ local_event->common.capture_preamble_ms = 0;
+ local_event->common.audio_config.sample_rate =
+ SOUND_TRIGGER_SAMPLING_RATE_16000;
+ local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
+ local_event->common.audio_config.channel_mask =
+ audio_channel_in_mask_from_count(st_hw_ses->config.channels);
+
+ for (i = 0; i < local_event->num_phrases; ++i) {
+ ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
+ local_event->phrase_extras[i].id,
+ local_event->phrase_extras[i].confidence_level);
+ for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
+ ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
+ local_event->phrase_extras[i].levels[j].user_id,
+ local_event->phrase_extras[i].levels[j].level);
+ }
+ }
+
+ ALOGI("%s:[c%d]", __func__, stc_ses->sm_handle);
+
+ ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
+ "num_phrases=%d id=%d", __func__, stc_ses->sm_handle,
+ local_event->common.status, local_event->common.type,
+ local_event->common.model, local_event->common.capture_available,
+ local_event->num_phrases, local_event->phrase_extras[0].id);
+
+ *event = local_event;
+ return 0;
+
+err_exit:
+ if (local_event)
+ free(local_event);
+
+exit:
+ return status;
+}
+
+static int process_detection_event_generic(st_proxy_session_t *st_ses,
+ int detect_status,
+ void *payload, size_t payload_size,
+ struct sound_trigger_recognition_event **event)
+{
+ st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
+ st_session_t *stc_ses = st_ses->det_stc_ses;
+ struct st_vendor_info *v_info = st_ses->vendor_uuid_info;
+ int status = 0;
+ struct sound_trigger_recognition_event *local_event = NULL;
+
+ local_event = calloc(1, sizeof(*local_event) + payload_size);
+ if (!local_event) {
+ ALOGE("%s: event allocation failed, size %zd", __func__,
+ payload_size);
+ status = -ENOMEM;
+ goto exit;
+ }
+
+ local_event->status = detect_status;
+ local_event->type = stc_ses->sm_type;
+ local_event->model = stc_ses->sm_handle;
+ local_event->capture_available = stc_ses->rc_config->capture_requested;
+ local_event->capture_delay_ms = 0;
+ local_event->capture_preamble_ms = 0;
+ local_event->audio_config.sample_rate = v_info ?
+ v_info->sample_rate : SOUND_TRIGGER_SAMPLING_RATE_16000;
+ local_event->audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
+ local_event->audio_config.channel_mask =
+ audio_channel_in_mask_from_count(st_hw_ses->config.channels);
+
+ local_event->data_offset = sizeof(*local_event);
+ local_event->data_size = payload_size;
+ memcpy((char *)local_event + local_event->data_offset,
+ payload, payload_size);
+
+ ALOGI("%s:[%d]", __func__, stc_ses->sm_handle);
+ ALOGV("%s:[c%d] status=%d, type=%d, model=%d, capture_avaiable=%d",
+ __func__, stc_ses->sm_handle, local_event->status,
+ local_event->type, local_event->model,
+ local_event->capture_available);
+
+ *event = local_event;
+
+exit:
+ return status;
+}
+
+static inline int process_detection_event(st_proxy_session_t *st_ses,
+ uint64_t timestamp __unused,
+ int detect_status,
+ void *payload, size_t payload_size,
+ struct sound_trigger_recognition_event **event)
+{
+ int ret;
+ struct sound_trigger_phrase_recognition_event *phrase_event = NULL;
+
+ *event = NULL;
+ if (st_ses->sm_info.sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ if (sthw_extn_check_process_det_ev_support())
+ ret = sthw_extn_process_detection_event_keyphrase(st_ses,
+ timestamp, detect_status, payload, payload_size, &phrase_event);
+ else if (st_ses->hw_ses_current->is_generic_event &&
+ !st_ses->vendor_uuid_info->is_qcmd_uuid)
+ ret = process_detection_event_keyphrase_v2(st_ses, detect_status,
+ payload, payload_size, &phrase_event);
+ else
+ ret = process_detection_event_keyphrase(st_ses, detect_status,
+ payload, payload_size, &phrase_event);
+ if (phrase_event)
+ *event = &phrase_event->common;
+ } else {
+ ret = process_detection_event_generic(st_ses, detect_status, payload,
+ payload_size, event);
+ }
+ return ret;
+}
+
+
+/*
+ * If the keyword detection session detects before the user verification
+ * session, signal to process user verification. If the keyword detection
+ * session rejects before the user verification session, signal to stop
+ * processing user verification.
+ */
+static void handle_vop_pending_detection(st_arm_ss_session_t *ss_session,
+ unsigned int det_status, unsigned int kw_det_buff_sz)
+{
+ if (det_status & KEYWORD_DETECTION_SUCCESS) {
+ if (kw_det_buff_sz > ss_session->unread_bytes)
+ ss_session->buff_sz = kw_det_buff_sz;
+ else
+ ss_session->buff_sz = ss_session->unread_bytes;
+
+ /*
+ * It is possible that VOP started processing by already consuming
+ * data from unread_bytes while CNN detects. In this case, it does
+ * not need to be signaled.
+ */
+ if (ss_session->unread_bytes >= ss_session->buff_sz) {
+ ALOGD("%s: Processing UV due to KW detection success", __func__);
+ pthread_cond_signal(&ss_session->cond);
+ }
+ } else if (det_status & KEYWORD_DETECTION_REJECT) {
+ ss_session->exit_buffering = true;
+ ALOGD("%s: Exiting from UV due to KW detection rejection", __func__);
+ pthread_cond_signal(&ss_session->cond);
+ }
+}
+
+/*
+ * If the user verification session rejects before the keyword detection
+ * session, signal to stop processing keyword detection.
+ */
+static void handle_cnn_pending_detection(st_arm_ss_session_t *ss_session,
+ unsigned int det_status)
+{
+ if (det_status & USER_VERIFICATION_REJECT) {
+ ss_session->exit_buffering = true;
+ ALOGD("%s: Exiting from KW detection due to UV rejection", __func__);
+ pthread_cond_signal(&ss_session->cond);
+ }
+}
+
+/*
+ * This thread handles detection events from the second stage sessions
+ * and aggregates them into 1 final decision. It will call the client callback
+ * or restart the first stage session based on this decision.
+ */
+static void *aggregator_thread_loop(void *st_session)
+{
+ st_proxy_session_t *st_ses = (st_proxy_session_t *)st_session;
+ st_session_t *stc_ses = NULL;
+ recognition_callback_t callback = NULL;
+ void *cookie = NULL;
+ struct listnode *node = NULL;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ int status = 0, lock_status = 0;
+ unsigned int kw_det_buff_sz = 0, det_status = 0;
+ struct timespec tspec = {0};
+ struct sound_trigger_recognition_event *event = NULL;
+ bool capture_requested = false;
+
+ ALOGV("%s: Enter", __func__);
+
+ /*
+ * For multi-clients it is expected only one of the clients detection
+ * happens at a time. Continue processing on a run time detected client
+ */
+ pthread_mutex_lock(&st_ses->ss_detections_lock);
+ while (!st_ses->exit_aggregator_loop) {
+ det_status = 0;
+ lock_status = 0;
+ ALOGV("%s: waiting on cond", __func__);
+ pthread_cond_wait(&st_ses->ss_detections_cond,
+ &st_ses->ss_detections_lock);
+ ALOGV("%s: done waiting on cond", __func__);
+ if (st_ses->exit_aggregator_loop) {
+ ALOGV("%s: exit", __func__);
+ pthread_mutex_unlock(&st_ses->ss_detections_lock);
+ return NULL;
+ }
+ if (!st_ses->det_stc_ses)
+ continue;
+ stc_ses = st_ses->det_stc_ses;
+
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t,
+ list_node);
+
+ pthread_mutex_lock(&st_sec_stage->ss_session->lock);
+ det_status |= st_sec_stage->ss_session->det_status;
+ if (st_sec_stage->ss_session->det_status ==
+ KEYWORD_DETECTION_SUCCESS)
+ kw_det_buff_sz = st_sec_stage->ss_session->bytes_processed;
+ pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
+ }
+
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t,
+ list_node);
+
+ pthread_mutex_lock(&st_sec_stage->ss_session->lock);
+ if ((st_sec_stage->ss_info->sm_detection_type ==
+ ST_SM_TYPE_USER_VERIFICATION) &&
+ (det_status & USER_VERIFICATION_PENDING)) {
+ handle_vop_pending_detection(st_sec_stage->ss_session,
+ det_status, kw_det_buff_sz);
+ } else if ((st_sec_stage->ss_info->sm_detection_type ==
+ ST_SM_TYPE_KEYWORD_DETECTION) &&
+ (det_status & KEYWORD_DETECTION_PENDING)) {
+ handle_cnn_pending_detection(st_sec_stage->ss_session,
+ det_status);
+ }
+ pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
+ }
+
+ if (!IS_SS_DETECTION_PENDING(det_status)) {
+ pthread_mutex_lock(&st_ses->lock);
+ /*
+ * If the client stops before 2nd stage finishes processing, or a
+ * transition is in progress, the detection event should not be
+ * handled.
+ */
+ if ((st_ses->current_state != buffering_state_fn) ||
+ (st_ses->exec_mode == ST_EXEC_MODE_NONE)) {
+ ALOGW("%s: First stage is not in a valid state, continuing",
+ __func__);
+ pthread_mutex_unlock(&st_ses->lock);
+ continue;
+ }
+ if (IS_SS_DETECTION_SUCCESS(det_status)) {
+ clock_gettime(CLOCK_MONOTONIC, &tspec);
+ st_ses->hw_ses_current->second_stage_det_event_time =
+ get_current_time_ns();
+ ATRACE_ASYNC_END("sthal: detection success",
+ st_ses->sm_handle);
+
+ status = process_detection_event(st_ses,
+ st_ses->det_session_ev->payload.detected.timestamp,
+ st_ses->det_session_ev->payload.detected.detect_status,
+ st_ses->det_session_ev->payload.detected.detect_payload,
+ st_ses->det_session_ev->payload.detected.payload_size,
+ &event);
+ if (status || !event) {
+ ALOGE("%s:[%d] process_detection_event failed err %d",
+ __func__, st_ses->sm_handle, status);
+ /*
+ * Stop buffering if this is not a successful detection and
+ * LAB is triggered in hw automatically
+ */
+ st_ses->hw_ses_current->fptrs->stop_buffering(
+ st_ses->hw_ses_current);
+
+ pthread_mutex_unlock(&st_ses->lock);
+ if (event) {
+ free(event);
+ event = NULL;
+ }
+ goto exit;
+ }
+ callback = stc_ses->callback;
+ capture_requested = stc_ses->rc_config->capture_requested;
+ cookie = stc_ses->cookie;
+ ALOGD("%s:[c%d] Second stage detected successfully, "
+ "calling client callback", __func__, stc_ses->sm_handle);
+ pthread_mutex_unlock(&st_ses->lock);
+ ATRACE_BEGIN("sthal: client detection callback");
+ callback(event, cookie);
+ free(event);
+ ATRACE_END();
+
+ /*
+ * The client could unload the sound model during the callback,
+ * which would join this thread and wait for this thread exit
+ * as part of st_session_deinit() with st_session_lock held. By
+ * this time, the state is also moved to idle. To avoid
+ * deadlock, upon return from client callback, try acquiring
+ * lock only if not in idle state, else exit right away.
+ */
+ do {
+ lock_status = pthread_mutex_trylock(&st_ses->lock);
+ } while (lock_status && (st_ses->current_state !=
+ idle_state_fn));
+
+ if (st_ses->current_state == idle_state_fn) {
+ ALOGV("%s:[%d] client unloaded after callback"
+ ", lock status %d", __func__, st_ses->sm_handle,
+ lock_status);
+ if (!lock_status)
+ pthread_mutex_unlock(&st_ses->lock);
+ goto exit;
+ }
+ /*
+ * If client has not requested capture data,
+ * stop hw session buffering here to resume next
+ * detection
+ */
+ if (!capture_requested)
+ st_ses->hw_ses_current->fptrs->stop_buffering(
+ st_ses->hw_ses_current);
+ } else {
+ ATRACE_ASYNC_END("sthal: detection reject",
+ st_ses->sm_handle);
+ ALOGD("%s: Second stage did NOT detect, restarting st_session",
+ __func__);
+ st_ses->hw_ses_current->fptrs->stop_buffering(
+ st_ses->hw_ses_current);
+ start_second_stage_for_client(stc_ses);
+ st_session_ev_t ev = {.ev_id = ST_SES_EV_RESTART,
+ .stc_ses = stc_ses};
+ DISPATCH_EVENT(st_ses, ev, status);
+ }
+ pthread_mutex_unlock(&st_ses->lock);
+ } else {
+ ALOGV("%s: There is a second stage session pending, continuing",
+ __func__);
+ }
+ }
+exit:
+ pthread_mutex_unlock(&st_ses->ss_detections_lock);
+ ALOGV("%s: Exit", __func__);
+ return NULL;
+}
+
+static void init_det_event_aggregator(st_proxy_session_t *st_ses)
+{
+ int status = 0;
+ pthread_condattr_t attr;
+
+ ALOGV("%s", __func__);
+
+ st_ses->exit_aggregator_loop = false;
+ pthread_mutex_init(&st_ses->ss_detections_lock, NULL);
+ pthread_condattr_init(&attr);
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ pthread_cond_init(&st_ses->ss_detections_cond, &attr);
+ pthread_condattr_destroy(&attr);
+ status = pthread_create(&st_ses->aggregator_thread, NULL,
+ aggregator_thread_loop, st_ses);
+ if (status) {
+ ALOGE("%s: Error creating aggregator thread. status = %d",
+ __func__, status);
+ } else {
+ st_ses->aggregator_thread_created = true;
+ }
+}
+
+static void destroy_det_event_aggregator(st_proxy_session_t *st_ses)
+{
+ int status = 0;
+
+ ALOGV("%s", __func__);
+
+ st_ses->exit_aggregator_loop = true;
+ pthread_mutex_lock(&st_ses->ss_detections_lock);
+ pthread_cond_signal(&st_ses->ss_detections_cond);
+ pthread_mutex_unlock(&st_ses->ss_detections_lock);
+ status = pthread_join(st_ses->aggregator_thread, NULL);
+ if (status)
+ ALOGE("%s: Error joining aggregator thread. status = %d",
+ __func__, status);
+ pthread_cond_destroy(&st_ses->ss_detections_cond);
+ pthread_mutex_destroy(&st_ses->ss_detections_lock);
+ st_ses->aggregator_thread_created = false;
+}
+
+/* This function is called for multi-client */
+static int handle_load_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
+{
+ st_hw_session_t *hw_ses = st_ses->hw_ses_current;
+ int status = 0;
+
+ ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
+ if (!stc_ses->phrase_sm) {
+ ALOGE("%s:[c%d] sound model data is not initialzed", __func__,
+ stc_ses->sm_handle);
+ return -EINVAL;
+ }
+
+ if (!is_other_client_attached(st_ses, stc_ses)) {
+ ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
+ stc_ses->sm_handle);
+ return -EINVAL;
+ }
+
+ if (st_ses->current_state == buffering_state_fn)
+ hw_ses->fptrs->stop_buffering(hw_ses);
+
+ if (st_ses->current_state == active_state_fn ||
+ st_ses->current_state == detected_state_fn ||
+ st_ses->current_state == buffering_state_fn) {
+ status = stop_session(st_ses, hw_ses, false);
+ if (status)
+ ALOGE("%s:[%d] stop_session failed %d", __func__, st_ses->sm_handle,
+ status);
+ }
+
+ status = hw_ses->fptrs->dereg_sm(hw_ses);
+ if (status) {
+ ALOGE("%s:[%d] dereg_sm failed %d", __func__,
+ st_ses->sm_handle, status);
+ }
+ /* Continue updating sound model resulting in merged model */
+ status = update_sound_model(stc_ses, true);
+ if (status) {
+ ALOGE("%s:[c%d] update_sound_model add failed %d", __func__,
+ stc_ses->sm_handle, status);
+ goto exit;
+ }
+ hw_ses->sthw_cfg.conf_levels = st_ses->sm_info.cf_levels;
+ hw_ses->sthw_cfg.num_conf_levels = st_ses->sm_info.cf_levels_size;
+ hw_ses->sthw_cfg_updated = true;
+ /*
+ * Sound model merge would have changed the order of merge conf levels,
+ * which need to be re-updated for all current active clients, if any.
+ */
+ status = update_merge_conf_levels_payload_with_active_clients(st_ses);
+ if (status)
+ goto exit_1;
+
+ /* Load merged sound model */
+ status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
+ st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
+ if (status) {
+ ALOGE("%s:[%d] reg_sm failed %d", __func__,
+ st_ses->sm_handle, status);
+ goto exit_1;
+ }
+
+ if (st_ses->current_state == active_state_fn ||
+ st_ses->current_state == detected_state_fn ||
+ st_ses->current_state == buffering_state_fn) {
+
+ status = start_session(st_ses, hw_ses, false);
+ if (status)
+ goto exit_2;
+ STATE_TRANSITION(st_ses, active_state_fn);
+ }
+
+ return 0;
+
+exit_2:
+ if (!st_ses->stdev->ssr_offline_received)
+ hw_ses->fptrs->dereg_sm(hw_ses);
+
+exit_1:
+ if (!st_ses->stdev->ssr_offline_received) {
+ update_sound_model(stc_ses, false);
+ update_merge_conf_levels_payload_with_active_clients(st_ses);
+ }
+
+exit:
+ if (st_ses->stdev->ssr_offline_received) {
+ STATE_TRANSITION(st_ses, ssr_state_fn);
+ status = 0;
+ }
+ return status;
+}
+
+/* This function is called for multi-client */
+static int handle_unload_sm(st_proxy_session_t *st_ses, st_session_t *stc_ses)
+{
+ st_hw_session_t *hw_ses = st_ses->hw_ses_current;
+ int status = 0;
+
+ ALOGV("%s:[c%d-%d]", __func__, stc_ses->sm_handle, st_ses->sm_handle);
+
+ if (!is_other_client_attached(st_ses, stc_ses)) {
+ ALOGE("%s:[c%d] Unexpected without multi-clients", __func__,
+ stc_ses->sm_handle);
+ return -EINVAL;
+ }
+
+ if (st_ses->current_state == buffering_state_fn)
+ hw_ses->fptrs->stop_buffering(hw_ses);
+
+ if (st_ses->current_state == active_state_fn ||
+ st_ses->current_state == detected_state_fn ||
+ st_ses->current_state == buffering_state_fn) {
+ status = stop_session(st_ses, hw_ses, false);
+ if (status)
+ ALOGE("%s:[%d] stop_session failed %d", __func__,
+ st_ses->sm_handle, status);
+ }
+
+ status = hw_ses->fptrs->dereg_sm(hw_ses);
+ if (status)
+ ALOGE("%s:[%d] dereg_sm failed %d", __func__, st_ses->sm_handle, status);
+
+ /* Continue deleting this model */
+ status = update_sound_model(stc_ses, false);
+ if (status)
+ ALOGE("%s:[c%d] update_sound_model delete failed %d", __func__,
+ stc_ses->sm_handle, status);
+
+ hw_ses->sthw_cfg.conf_levels = st_ses->sm_info.cf_levels;
+ hw_ses->sthw_cfg.num_conf_levels = st_ses->sm_info.cf_levels_size;
+ hw_ses->sthw_cfg_updated = true;
+ /*
+ * Sound model merge would have changed the order of merge conf levels,
+ * which need to be re-updated for all current active clients, if any.
+ */
+ update_merge_conf_levels_payload_with_active_clients(st_ses);
+
+ /* Load remaining merged sound model */
+ status = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
+ st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
+ if (status) {
+ ALOGE("%s:[%d] reg_sm failed %d", __func__,
+ st_ses->sm_handle, status);
+ goto exit;
+ }
+
+ if (st_ses->current_state == active_state_fn ||
+ st_ses->current_state == detected_state_fn ||
+ st_ses->current_state == buffering_state_fn) {
+
+ status = start_session(st_ses, hw_ses, false);
+ if (status)
+ goto exit;
+ STATE_TRANSITION(st_ses, active_state_fn);
+ }
+ return 0;
+
+exit:
+ if (st_ses->stdev->ssr_offline_received) {
+ STATE_TRANSITION(st_ses, ssr_state_fn);
+ status = 0;
+ }
+ return status;
+}
+
+static int idle_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
{
int status = 0;
int ret = 0;
+ st_session_t *stc_ses = ev->stc_ses;
st_hw_session_t *hw_ses = st_ses->hw_ses_current;
- struct listnode *node = NULL, *tmp_node = NULL;
- st_arm_second_stage_t *st_sec_stage = NULL;
/* skip parameter check as this is an internal funciton */
- ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
+ ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle, ev->ev_id);
switch (ev->ev_id) {
case ST_SES_EV_LOAD_SM:
- if (!st_ses->sm_data) {
+ if (!stc_ses->phrase_sm) {
ALOGE("%s: sound model data is not initialzed", __func__);
status = -EINVAL;
break;
}
+ status = update_sound_model(stc_ses, true);
+ if (status) {
+ ALOGE("%s:[c%d] update sound model add failed %d", __func__,
+ stc_ses->sm_handle, status);
+ status = -EINVAL;
+ break;
+ }
/*
- * Do retry to handle a corner case that when ADSP SSR ONLINE is received,
- * sometimes ADSP is still not ready to receive cmd from HLOS and thus
- * fails, so try more times to recover the session from SSR state.
+ * Do retry to handle a corner case that when ADSP SSR ONLINE is
+ * received, sometimes ADSP is still not ready to receive cmd from HLOS
+ * and thus fails, so try more times to recover the session from SSR
+ * state.
*/
for (int i = 0; i < REG_SM_RETRY_CNT; i++) {
- status = ret = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_data,
- st_ses->sm_type);
+ status = ret = hw_ses->fptrs->reg_sm(hw_ses, st_ses->sm_info.sm_data,
+ st_ses->sm_info.sm_size, st_ses->sm_info.sm_type);
if (ret) {
if (st_ses->stdev->ssr_offline_received) {
- st_ses->client_req_state = ST_STATE_LOADED;
STATE_TRANSITION(st_ses, ssr_state_fn);
- /*
- * Send success to client because the failure is recovered
- * internally from SSR.
- */
status = 0;
break;
} else {
- ALOGE("%s:[%d] failed to reg sm, err %d, retry cnt %d", __func__,
- st_ses->sm_handle, status, i);
+ ALOGE("%s:[%d] failed to reg sm, err %d, retry cnt %d",
+ __func__, st_ses->sm_handle, status, i);
usleep(REG_SM_WAIT_TIME_MS * 1000);
}
} else {
@@ -607,20 +4029,14 @@
if (ret)
break;
- if (st_ses->enable_second_stage) {
- hw_ses->enable_second_stage = true;
- hw_ses->second_stage_list = &(st_ses->second_stage_list);
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- st_sec_stage->ss_session->st_ses = st_ses;
- st_second_stage_prepare_session(st_sec_stage);
- }
- }
-
STATE_TRANSITION(st_ses, loaded_state_fn);
break;
case ST_SES_EV_SET_EXEC_MODE:
+ stc_ses->exec_mode = ev->payload.exec_mode;
+ if (ev->payload.exec_mode == st_ses->exec_mode)
+ break;
+
st_ses->exec_mode = ev->payload.exec_mode;
if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
st_ses->hw_ses_current = st_ses->hw_ses_cpe;
@@ -630,11 +4046,11 @@
break;
case ST_SES_EV_PAUSE:
- st_ses->paused = true;
+ stc_ses->paused = true;
break;
case ST_SES_EV_RESUME:
- st_ses->paused = false;
+ stc_ses->paused = false;
break;
case ST_SES_EV_SSR_OFFLINE:
@@ -663,164 +4079,158 @@
return status;
}
-static int loaded_state_fn(st_session_t *st_ses, st_session_ev_t *ev)
+static int loaded_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
{
int status = 0;
+ st_session_t *stc_ses = ev->stc_ses;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
st_hw_session_t *hw_ses = st_ses->hw_ses_current;
st_hw_session_t *new_hw_ses = NULL;
st_exec_mode_t new_exec_mode = 0;
- struct listnode *node = NULL, *tmp_node = NULL;
- st_arm_second_stage_t *st_sec_stage = NULL;
- /* skip parameter check as this is an internal funciton */
- ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
+ /* skip parameter check as this is an internal function */
+ ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle, ev->ev_id);
switch (ev->ev_id) {
- case ST_SES_EV_RESUME:
- if (!st_ses->paused)
- break;
- st_ses->paused = false;
- if (st_ses->client_req_state != ST_STATE_ACTIVE)
- break;
- /* If the session is paused and client_req_state is active, fall through
- * and handle similarly to start/restart.
- */
- case ST_SES_EV_START:
- case ST_SES_EV_RESTART:
- st_ses->client_req_state = ST_STATE_ACTIVE;
- if (!st_ses->paused) {
- /*
- * There is a need to be able to differentiate between LAB due to a client
- * request, and LAB due to second stage enablement.
- */
- st_ses->capture_requested = st_ses->rc_config->capture_requested;
- st_ses->lab_enabled =
- (st_ses->capture_requested || st_ses->enable_second_stage);
-
- status = start_session(st_ses, hw_ses, false);
- if (status) {
- if (st_ses->stdev->ssr_offline_received) {
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
- hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
- STATE_TRANSITION(st_ses, ssr_state_fn);
- /* Send success to client because the failure is recovered
- * internally from SSR.
- */
- status = 0;
- } else {
- ALOGE("%s:[%d] failed to start session, err %d", __func__,
- st_ses->sm_handle, status);
- }
- break;
- }
-
- if (st_ses->enable_second_stage) {
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- status = st_second_stage_start_session(st_sec_stage);
- if (status) {
- ALOGE("%s: Failed to start second stage session, exiting", __func__);
- status = -EINVAL;
- break;
- }
- }
- }
- STATE_TRANSITION(st_ses, active_state_fn);
- }
+ case ST_SES_EV_LOAD_SM:
+ /* Valid only in multi-client session usecase */
+ status = handle_load_sm(st_ses, stc_ses);
break;
case ST_SES_EV_UNLOAD_SM:
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
- status = hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
- if (status) {
- /* since this is a teardown scenario dont fail here */
- ALOGE("%s:[%d] dereg_sm failed with err %d", __func__,
- st_ses->sm_handle, status);
- status = 0;
+ if (is_other_client_attached(st_ses, stc_ses)) {
+ status = handle_unload_sm(st_ses, stc_ses);
+ break;
}
+
+ status = hw_ses->fptrs->dereg_sm(hw_ses);
+ if (status)
+ ALOGE("%s:[%d] dereg_sm failed %d", __func__,
+ st_ses->sm_handle, status);
+
+ status = update_sound_model(stc_ses, false);
+ if (status)
+ ALOGE("%s:[c%d] update_sound_model failed %d", __func__,
+ stc_ses->sm_handle, status);
+
+ /* since this is a teardown scenario dont fail here */
+ status = 0;
STATE_TRANSITION(st_ses, idle_state_fn);
break;
+ case ST_SES_EV_RESUME:
+ stc_ses->paused = false;
+ if (!is_any_client_in_state(st_ses, ST_STATE_ACTIVE))
+ break;
+ /* Fall through */
+ case ST_SES_EV_START:
+ case ST_SES_EV_RESTART:
+ if (ev->ev_id == ST_SES_EV_RESTART)
+ update_hw_config_on_restart(st_ses, stc_ses);
+
+ /*
+ * During Resume, the first active client will start the hw sesison.
+ * During Start, check for any paused sessions to delay actual start
+ * to Resume.
+ */
+ if ((ev->ev_id != ST_SES_EV_RESUME) && is_any_client_paused(st_ses))
+ break;
+
+ status = start_session(st_ses, hw_ses, false);
+ if (status) {
+ if (st_ses->stdev->ssr_offline_received) {
+ hw_ses->fptrs->dereg_sm(hw_ses);
+ STATE_TRANSITION(st_ses, ssr_state_fn);
+ status = 0;
+ } else {
+ ALOGE("%s:[%d] failed to start session, err %d", __func__,
+ st_ses->sm_handle, status);
+ }
+ break;
+ }
+ STATE_TRANSITION(st_ses, active_state_fn);
+ break;
+
+ case ST_SES_EV_STOP:
+ /*
+ * Valid in multi-client case.
+ * Reconfig based off other active clients, if any, so that RESUME
+ * can apply this reconfig.
+ */
+ update_hw_config_on_stop(st_ses, stc_ses);
+ break;
+
case ST_SES_EV_SSR_OFFLINE:
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
/* exec mode can be none if ssr occurs during a transition */
if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
- hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
- /*
- * When the session is first loaded, the client_req_state remains
- * in idle state. In this case, client_req_state must be set to
- * loaded before the SSR handling. In other usecases,
- * client_req_state can be either loaded or active, so it should
- * not be changed here.
- */
- if (st_ses->client_req_state == ST_STATE_IDLE)
- st_ses->client_req_state = ST_STATE_LOADED;
+ hw_ses->fptrs->dereg_sm(hw_ses);
STATE_TRANSITION(st_ses, ssr_state_fn);
break;
case ST_SES_EV_PAUSE:
- st_ses->paused = true;
- break;
-
- case ST_SES_EV_STOP:
- st_ses->client_req_state = ST_STATE_LOADED;
+ stc_ses->paused = true;
break;
case ST_SES_EV_SET_EXEC_MODE:
new_exec_mode = ev->payload.exec_mode;
- if ((st_ses->exec_mode != new_exec_mode) &&
- st_ses->enable_trans) {
-
- if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
- st_ses->exec_mode = ST_EXEC_MODE_NONE;
- /* unload sm for current hw session */
- status = hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
- if (status) {
- ALOGE("%s:[%d] dereg_sm failed with err %d", __func__,
- st_ses->sm_handle, status);
- break;
- }
- }
-
- if (new_exec_mode == ST_EXEC_MODE_NONE)
- break;
-
- /* load sm to new hw_ses */
- if (ST_EXEC_MODE_CPE == new_exec_mode) {
- new_hw_ses = st_ses->hw_ses_cpe;
- st_ses->hw_ses_cpe->enable_second_stage =
- st_ses->hw_ses_adsp->enable_second_stage;
- st_ses->hw_ses_cpe->second_stage_list =
- st_ses->hw_ses_adsp->second_stage_list;
- } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
- new_hw_ses = st_ses->hw_ses_adsp;
- st_ses->hw_ses_adsp->enable_second_stage =
- st_ses->hw_ses_cpe->enable_second_stage;
- st_ses->hw_ses_adsp->second_stage_list =
- st_ses->hw_ses_cpe->second_stage_list;
- } else {
- ALOGE("%s: unknown execution mode %d", __func__,
- new_exec_mode);
- status = -EINVAL;
- break;
- }
-
- status = new_hw_ses->fptrs->reg_sm(new_hw_ses,
- st_ses->sm_data, st_ses->sm_type);
- if (status) {
- ALOGE("%s:[%d] reg_sm failed with err %d", __func__,
- st_ses->sm_handle, status);
- break;
- }
- /* switch hw sessions only if successful*/
- st_ses->exec_mode = new_exec_mode;
- st_ses->hw_ses_current = new_hw_ses;
- /* remain in current state */
+ if (new_exec_mode == st_ses->exec_mode) {
+ stc_ses->exec_mode = st_ses->exec_mode;
+ break;
}
+
+ if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
+ st_ses->exec_mode = ST_EXEC_MODE_NONE;
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->exec_mode = ST_EXEC_MODE_NONE;
+ }
+ /* unload sm for current hw session */
+ status = hw_ses->fptrs->dereg_sm(hw_ses);
+ if (status) {
+ ALOGE("%s:[%d] dereg_sm failed with err %d", __func__,
+ st_ses->sm_handle, status);
+ break;
+ }
+ }
+
+ if (new_exec_mode == ST_EXEC_MODE_NONE)
+ break;
+
+ /* load sm to new hw_ses */
+ if (ST_EXEC_MODE_CPE == new_exec_mode) {
+ new_hw_ses = st_ses->hw_ses_cpe;
+ } else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
+ new_hw_ses = st_ses->hw_ses_adsp;
+ } else {
+ ALOGE("%s: unknown execution mode %d", __func__,
+ new_exec_mode);
+ status = -EINVAL;
+ break;
+ }
+
+ status = new_hw_ses->fptrs->reg_sm(new_hw_ses,
+ st_ses->sm_info.sm_data, st_ses->sm_info.sm_size,
+ st_ses->sm_info.sm_type);
+ if (status) {
+ ALOGE("%s:[%d] reg_sm failed with err %d", __func__,
+ st_ses->sm_handle, status);
+ break;
+ }
+ /* switch hw sessions only if successful*/
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->exec_mode = new_exec_mode;
+ if (c_ses->state == ST_STATE_ACTIVE) {
+ dereg_hal_event_session(c_ses);
+ reg_hal_event_session(c_ses, new_hw_ses);
+ }
+ }
+ st_ses->exec_mode = new_exec_mode;
+ st_ses->hw_ses_current = new_hw_ses;
+ /* remain in current state */
break;
case ST_SES_EV_SET_DEVICE:
@@ -850,9 +4260,9 @@
case ST_SES_EV_GET_PARAM_DATA:
status = hw_ses->fptrs->get_param_data(hw_ses,
- ev->payload.getparam.param, ev->payload.getparam.payload,
- ev->payload.getparam.payload_size,
- ev->payload.getparam.param_data_size);
+ ev->payload.getparam.param, ev->payload.getparam.payload,
+ ev->payload.getparam.payload_size,
+ ev->payload.getparam.param_data_size);
break;
case ST_SES_EV_REQUEST_DET:
@@ -864,35 +4274,79 @@
default:
ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
break;
-
};
return status;
}
-static int active_state_fn(st_session_t *st_ses, st_session_ev_t *ev)
+static int active_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
{
int status = 0;
+ st_session_t *stc_ses = ev->stc_ses;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
st_hw_session_t *hw_ses = st_ses->hw_ses_current;
- st_session_ev_t deferred_ev = { .ev_id = ST_SES_EV_DEFERRED_STOP };
st_hw_session_t *new_hw_ses = NULL;
st_exec_mode_t new_exec_mode;
+ st_arm_second_stage_t *st_sec_stage = NULL;
+ struct sound_trigger_recognition_event *event = NULL;
+ recognition_callback_t callback = NULL;
+ void *cookie = NULL;
+ bool lab_enabled = false, enable_second_stage = false, active = false;
/* skip parameter check as this is an internal funciton */
ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
switch (ev->ev_id) {
+ case ST_SES_EV_LOAD_SM:
+ /* Valid in multi-client usecase */
+ status = handle_load_sm(st_ses, stc_ses);
+ break;
+
+ case ST_SES_EV_UNLOAD_SM:
+ /* Valid in multi-client usecase */
+ status = handle_unload_sm(st_ses, stc_ses);
+ break;
+
+ case ST_SES_EV_RESTART:
+ /* Valid in multi-client usecase */
+ update_hw_config_on_restart(st_ses, stc_ses);
+ /* Fall through */
+ case ST_SES_EV_START:
+ /* Valid in multi-client usecase */
+ status = stop_session(st_ses, hw_ses, false);
+ if (!status) {
+ status = start_session(st_ses, hw_ses, false);
+ if (status)
+ ALOGE("%s:[%d] start_session failed %d", __func__,
+ st_ses->sm_handle, status);
+ } else {
+ ALOGE("%s:[%d] stop_session failed %d", __func__,
+ st_ses->sm_handle, status);
+ }
+ if (status & st_ses->stdev->ssr_offline_received) {
+ hw_ses->fptrs->dereg_sm(hw_ses);
+ STATE_TRANSITION(st_ses, ssr_state_fn);
+ status = 0;
+ }
+ break;
+
case ST_SES_EV_SET_EXEC_MODE:
new_exec_mode = ev->payload.exec_mode;
- /* if no change in mode or dynamic transition not enabled then noop */
- if ((new_exec_mode == st_ses->exec_mode) || !st_ses->enable_trans)
+ if (new_exec_mode == st_ses->exec_mode) {
+ stc_ses->exec_mode = st_ses->exec_mode;
break;
+ }
if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
ALOGV("%s: disable current session", __func__);
st_ses->exec_mode = ST_EXEC_MODE_NONE;
status = stop_session(st_ses, hw_ses, true);
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->exec_mode = ST_EXEC_MODE_NONE;
+ }
if (status)
break;
}
@@ -902,22 +4356,26 @@
if (ST_EXEC_MODE_CPE == new_exec_mode) {
new_hw_ses = st_ses->hw_ses_cpe;
- st_ses->hw_ses_cpe->enable_second_stage =
- st_ses->hw_ses_adsp->enable_second_stage;
- st_ses->hw_ses_cpe->second_stage_list =
- st_ses->hw_ses_adsp->second_stage_list;
} else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
new_hw_ses = st_ses->hw_ses_adsp;
- st_ses->hw_ses_adsp->enable_second_stage =
- st_ses->hw_ses_cpe->enable_second_stage;
- st_ses->hw_ses_adsp->second_stage_list =
- st_ses->hw_ses_cpe->second_stage_list;
} else {
ALOGE("%s: unknown execution mode %d", __func__,
new_exec_mode);
status = -EINVAL;
break;
}
+ /*
+ * hw session changed to/from WDSP/ADSP, hence update the
+ * related config.
+ * Not applicable for LPI<->non-LPI transtions as hw session
+ * doesn't change.
+ */
+ status = update_hw_config_on_start(stc_ses, new_hw_ses);
+ if (status) {
+ ALOGE("%s: Update_hw_config_on_start failed %d",
+ __func__, status);
+ break;
+ }
ALOGV("%s: enable current session", __func__);
status = start_session(st_ses, new_hw_ses, true);
@@ -925,216 +4383,298 @@
break;
/* set new exec mode and current session */
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->exec_mode = new_exec_mode;
+ if (c_ses->state == ST_STATE_ACTIVE) {
+ dereg_hal_event_session(c_ses);
+ reg_hal_event_session(c_ses, new_hw_ses);
+ }
+ }
st_ses->exec_mode = new_exec_mode;
st_ses->hw_ses_current = new_hw_ses;
+
ALOGV("%s: end transition", __func__);
break;
case ST_SES_EV_PAUSE:
- st_ses->paused = true;
- /* Fall through to handle pause events similarly to stop events. */
- case ST_SES_EV_STOP:
- if (st_ses->paused)
- st_ses->client_req_state = ST_STATE_ACTIVE;
- else
- st_ses->client_req_state = ST_STATE_LOADED;
+ /*
+ * For multi-client, the first active pausing client stops the hw
+ * session and moves to loaded state.
+ */
+ stc_ses->paused = true;
+ if (stc_ses->state != ST_STATE_ACTIVE)
+ break;
+
status = stop_session(st_ses, hw_ses, false);
+
if (status) {
if (st_ses->stdev->ssr_offline_received) {
STATE_TRANSITION(st_ses, ssr_state_fn);
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
- hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
- /* Send success to client because the failure is recovered
- * internally from SSR.
- */
+ hw_ses->fptrs->dereg_sm(hw_ses);
status = 0;
- break;
} else {
ALOGE("%s:[%d] failed to stop session, err %d", __func__,
st_ses->sm_handle, status);
+ /* Move anyway to loaded state */
+ STATE_TRANSITION(st_ses, loaded_state_fn);
}
+ break;
}
-
STATE_TRANSITION(st_ses, loaded_state_fn);
break;
- case ST_SES_EV_DETECTED:
- {
- size_t payload_size = ev->payload.detected.payload_size;
- struct sound_trigger_recognition_event *event = NULL;
- recognition_callback_t callback;
- bool lab_enabled = false, enable_second_stage = false;
+ case ST_SES_EV_STOP:
+ status = stop_session(st_ses, hw_ses, false);
+ if (status)
+ ALOGE("%s:[%d] start_session failed %d", __func__,
+ st_ses->sm_handle, status);
- if (!st_ses->enable_second_stage ||
- st_ses->detection_requested) {
- status = process_detection_event(st_ses,
- ev->payload.detected.timestamp,
- ev->payload.detected.detect_status,
- ev->payload.detected.detect_payload,
- payload_size, &event);
- if (status || !event) {
- ALOGE("%s:[%d] process_detection_event failed err %d", __func__,
+ /* Continue to reconfig based off other active clients, if any */
+ active = update_hw_config_on_stop(st_ses, stc_ses);
+
+ if (!status) {
+ if (active) {
+ ALOGD("%s: client c%d stopped, start %d due to reconfig",
+ __func__, stc_ses->sm_handle, st_ses->sm_handle);
+ status = start_session(st_ses, hw_ses, false);
+ if (status)
+ ALOGE("%s:[%d] start_session failed %d", __func__,
st_ses->sm_handle, status);
- /* Stop buffering if this is not a successful detection and
- LAB is triggered in hw automatically */
- hw_ses->fptrs->stop_buffering(hw_ses, st_ses->lab_enabled);
-
- if (event)
- free(event);
- break;
- }
+ /* Stay in active state */
} else {
- enable_second_stage = true;
- st_ses->sent_detection_to_client = false;
- get_first_stage_detection_params(st_ses,
- ev->payload.detected.detect_payload, payload_size);
- memcpy(st_ses->det_session_ev, ev, sizeof(st_session_ev_t));
+ STATE_TRANSITION(st_ses, loaded_state_fn);
}
+ }
- /*
- * change to new state before invoking user callback, this will
- * ensure that if user calls start_recognition immediately from the
- * callback it will be handled by one of the two states below
- */
- if (!status && st_ses->lab_enabled) {
- ST_DBG_FILE_OPEN_WR(st_ses->lab_fp, ST_DEBUG_DUMP_LOCATION, "lab_capture",
- "bin", file_cnt++);
- STATE_TRANSITION(st_ses, buffering_state_fn);
- } else {
- STATE_TRANSITION(st_ses, detected_state_fn);
- }
-
- if (!st_ses->callback) {
- ALOGE("%s:[%d] received detection event but no callback",
- __func__, st_ses->sm_handle);
- status = -EINVAL;
- if (event && !enable_second_stage)
- free(event);
- break;
- }
- callback = st_ses->callback;
-
- /*
- * store the current capture requested in-case a new start comes
- * once we exist the critical-section.
- * In this case we continue to operate based on previous capture requested
- * setting untill the new session start is processed and resets the state
- */
- lab_enabled = st_ses->lab_enabled;
- pthread_mutex_unlock(&st_ses->lock);
-
- /*
- * callback to user, assumption is that client does not
- * block in the callback waiting for data otherwise will be a deadlock
- */
- if (!enable_second_stage) {
- ALOGD("%s:[%d] invoking the client callback",
- __func__, st_ses->sm_handle);
- ATRACE_ASYNC_END("sthal: detection success",
- st_ses->sm_handle);
- ATRACE_BEGIN("sthal: client detection callback");
- callback(event, st_ses->cookie);
- ATRACE_END();
- }
-
- /*
- * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
- * the SoundTrigger API header.
- */
- if (lab_enabled &&
- ((ev->payload.detected.detect_status ==
- RECOGNITION_STATUS_SUCCESS) ||
- (ev->payload.detected.detect_status == 3))) {
- /* Cache lab data to internal buffers (blocking call) */
- hw_ses->fptrs->process_lab_capture(hw_ses);
- }
-
- /*
- * It is possible that the client may start/stop/unload the session
- * with the same lock held, before we aqcuire lock here.
- * We need further processing only if client starts in detected state
- * or buffering state if lab was enabled, else return gracefully.
- */
- do {
- status = pthread_mutex_trylock(&st_ses->lock);
- } while (status && ((st_ses->current_state == detected_state_fn) ||
- (st_ses->current_state == buffering_state_fn)));
-
- if (st_ses->current_state != detected_state_fn) {
- ALOGV("%s:[%d] client not in detected state, lock status %d",
- __func__, st_ses->sm_handle, status);
- if (!status) {
- /*
- * Stop session if still in buffering state and no pending
- * stop to be handled i.e. internally buffering was stopped.
- * This is required to avoid further detections in wrong state.
- * Client is expected to issue start recognition for current
- * detection event which will restart the session.
- */
- if ((st_ses->current_state == buffering_state_fn) &&
- !st_ses->pending_stop) {
- ALOGD("%s:[%d] buffering stopped internally, stop session",
- __func__, st_ses->sm_handle);
- stop_session(st_ses, hw_ses, false);
- STATE_TRANSITION(st_ses, loaded_state_fn);
- }
-
- pthread_mutex_unlock(&st_ses->lock);
- }
-
- if (!st_ses->enable_second_stage)
- free(event);
+ if (status) {
+ if (st_ses->stdev->ssr_offline_received) {
+ hw_ses->fptrs->dereg_sm(hw_ses);
+ STATE_TRANSITION(st_ses, ssr_state_fn);
status = 0;
- if (st_ses->detection_requested) {
- st_ses->detection_requested = false;
- enable_second_stage_processing(st_ses, hw_ses);
- }
+ } else {
+ STATE_TRANSITION(st_ses, loaded_state_fn);
+ }
+ }
+
+ break;
+
+ case ST_SES_EV_DETECTED:
+ /*
+ * Find which client is this detection for.
+ * Note that only one keyword detection can happen at a time.
+ */
+ stc_ses = get_detected_client(st_ses,
+ ev->payload.detected.detect_payload,
+ ev->payload.detected.payload_size);
+
+ if (!stc_ses) {
+ ALOGW("%s:[%d] Couldn't find a matching client for detection",
+ __func__, st_ses->sm_handle);
+ /*
+ * Though we set higest conf level 100 for inactive client in merged
+ * sound model, it may be possible it still detects. In case the lab
+ * is enabled due to other active client, stop hw buffering.
+ */
+ if (st_ses->lab_enabled)
+ hw_ses->fptrs->stop_buffering(hw_ses);
+ break;
+ }
+ st_ses->det_stc_ses = stc_ses;
+ st_ses->hw_ses_current->enable_second_stage = false; /* Initialize */
+
+ if (list_empty(&stc_ses->second_stage_list) ||
+ st_ses->detection_requested) {
+ st_ses->detection_requested = false;
+ status = process_detection_event(st_ses,
+ ev->payload.detected.timestamp,
+ ev->payload.detected.detect_status,
+ ev->payload.detected.detect_payload,
+ ev->payload.detected.payload_size,
+ &event);
+ if (status || !event) {
+ ALOGE("%s:[%d] process_detection_event failed err %d", __func__,
+ st_ses->sm_handle, status);
+ /*
+ * Stop buffering if this is not a successful detection and
+ * LAB is triggered in hw automatically
+ */
+ hw_ses->fptrs->stop_buffering(hw_ses);
+ if (event)
+ free(event);
break;
}
+ } else {
+ ALOGV("%s:[c%d] second stage enabled, list_empty %d,"
+ "det_requested %d", __func__, stc_ses->sm_handle,
+ list_empty(&stc_ses->second_stage_list),
+ st_ses->detection_requested);
- if (st_ses->detection_requested) {
- st_ses->detection_requested = false;
- enable_second_stage_processing(st_ses, hw_ses);
- }
+ enable_second_stage = true;
/*
- * If we are not buffering (i.e capture is not requested), then
- * trigger a deferred stop. Most applications issue (re)start
- * almost immediately. Delaying stop allows unnecessary teardown
- * and reinitialization of backend.
+ * Before first stage starts buffering, update the second stage info
+ * to first stage layer for further communication between first and
+ * second stage layers.
*/
- if (!lab_enabled) {
- /*
- * Note that this event will only be posted to the detected state
- * The current state may switch to active if the client
- * issues start/restart before control of the callback thread
- * reaches this point.
- */
- DISPATCH_EVENT(st_ses, deferred_ev, status);
- } else {
- ALOGE("%s:[%d] capture is requested but state is still detected!?",
- __func__, st_ses->sm_handle);
- }
+ st_ses->hw_ses_current->enable_second_stage = true;
+ st_ses->hw_ses_current->second_stage_list =
+ &(stc_ses->second_stage_list);
- if (!enable_second_stage)
+ list_for_each(node, &stc_ses->second_stage_list) {
+ st_sec_stage = node_to_item(node, st_arm_second_stage_t,
+ list_node);
+ st_sec_stage->ss_session->st_ses = st_ses;
+ }
+ get_first_stage_detection_params(st_ses,
+ ev->payload.detected.detect_payload,
+ ev->payload.detected.payload_size);
+ memcpy(st_ses->det_session_ev, ev, sizeof(st_session_ev_t));
+ }
+ /*
+ * change to new state before invoking user callback, this will
+ * ensure that if user calls start_recognition immediately from the
+ * callback it will be handled by one of the two states below
+ */
+ if (!status && st_ses->lab_enabled) {
+ if (stc_ses->rc_config->capture_requested ||
+ !list_empty(&stc_ses->second_stage_list)) {
+ ST_DBG_FILE_OPEN_WR(st_ses->lab_fp, ST_DEBUG_DUMP_LOCATION,
+ "lab_capture", "bin", file_cnt++);
+ STATE_TRANSITION(st_ses, buffering_state_fn);
+ lab_enabled = true;
+ } else {
+ /*
+ * for merged model case the client detected may not have
+ * requested the capture nor enabled the second stage, but the
+ * hw lab could be enabled due to other client requested capture
+ * or enabled second stage.
+ */
+ ALOGV("%s: stop buffering as c%d doesn't need", __func__,
+ stc_ses->sm_handle);
+ hw_ses->fptrs->stop_buffering(hw_ses);
+ STATE_TRANSITION(st_ses, detected_state_fn);
+ lab_enabled = false;
+ }
+ } else {
+ STATE_TRANSITION(st_ses, detected_state_fn);
+ }
+
+ if (!stc_ses->callback) {
+ ALOGE("%s:[c%d] received detection event but no callback",
+ __func__, stc_ses->sm_handle);
+ status = -EINVAL;
+ if (event)
free(event);
break;
}
+ /*
+ * callback to user, assumption is that client does not
+ * block in the callback waiting for data otherwise will be a deadlock.
+ * If second stage is enabled, the detection will be sent later when
+ * second stage successfully detects.
+ */
+ if (!enable_second_stage) {
+ callback = stc_ses->callback;
+ cookie = stc_ses->cookie;
+ ALOGD("%s:[c%d] invoking the client callback",
+ __func__, stc_ses->sm_handle);
+ ATRACE_ASYNC_END("sthal: detection success",
+ st_ses->sm_handle);
+ pthread_mutex_unlock(&st_ses->lock);
+ ATRACE_BEGIN("sthal: client detection callback");
+ callback(event, cookie);
+ ATRACE_END();
+ } else {
+ pthread_mutex_unlock(&st_ses->lock);
+ }
+ if (event)
+ free(event);
+
+ /*
+ * TODO: Add RECOGNITION_STATUS_GET_STATE_RESPONSE to
+ * the SoundTrigger API header.
+ */
+ if (lab_enabled &&
+ ((ev->payload.detected.detect_status ==
+ RECOGNITION_STATUS_SUCCESS) ||
+ (ev->payload.detected.detect_status == 3))) {
+ /* Cache lab data to internal buffers (blocking call) */
+ hw_ses->fptrs->process_lab_capture(hw_ses);
+ }
+
+ /*
+ * It is possible that the client may start/stop/unload the session
+ * with the same lock held, before we aqcuire lock here.
+ * We need further processing only if client starts in detected state
+ * or buffering state if lab was enabled, else return gracefully.
+ * For multi-client scenario, only one client is assumed to be
+ * detected/bufffering, so the logic remains same.
+ */
+ do {
+ status = pthread_mutex_trylock(&st_ses->lock);
+ } while (status && ((st_ses->current_state == detected_state_fn) ||
+ (st_ses->current_state == buffering_state_fn)));
+
+ if (st_ses->current_state != detected_state_fn) {
+ ALOGV("%s:[%d] client not in detected state, lock status %d",
+ __func__, st_ses->sm_handle, status);
+ if (!status) {
+ /*
+ * Stop session if still in buffering state and no pending
+ * stop to be handled i.e. internally buffering was stopped.
+ * This is required to avoid further detections in wrong state.
+ * Client is expected to issue start recognition for current
+ * detection event which will restart the session.
+ */
+ if ((st_ses->current_state == buffering_state_fn) &&
+ !stc_ses->pending_stop) {
+ ALOGD("%s:[%d] buffering stopped internally, post c%d stop",
+ __func__, st_ses->sm_handle,
+ st_ses->det_stc_ses->sm_handle);
+ status = hw_session_notifier_enqueue(stc_ses->sm_handle,
+ ST_SES_EV_DEFERRED_STOP,
+ ST_SES_DEFERRED_STOP_SS_DELAY_MS);
+ if (!status)
+ stc_ses->pending_stop = true;
+ }
+ pthread_mutex_unlock(&st_ses->lock);
+ }
+ status = 0;
+ break;
+ }
+
+ /*
+ * If we are not buffering (i.e capture is not requested), then
+ * trigger a deferred stop. Most applications issue (re)start
+ * almost immediately. Delaying stop allows unnecessary teardown
+ * and reinitialization of backend.
+ */
+ if (!lab_enabled) {
+ /*
+ * Note that this event will only be posted to the detected state
+ * The current state may switch to active if the client
+ * issues start/restart before control of the callback thread
+ * reaches this point.
+ */
+ st_session_ev_t deferred_ev = { .ev_id = ST_SES_EV_DEFERRED_STOP,
+ .stc_ses = stc_ses};
+ DISPATCH_EVENT(st_ses, deferred_ev, status);
+ } else {
+ ALOGE("%s:[%d] capture is requested but state is still detected!?",
+ __func__, st_ses->sm_handle);
+ }
+ break;
case ST_SES_EV_SSR_OFFLINE:
- STATE_TRANSITION(st_ses, ssr_state_fn);
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
/* exec mode can be none if ssr occurs during a transition */
if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
- stop_hw_session(st_ses, hw_ses, true /* unload_sm */);
-
- st_ses->client_req_state = ST_STATE_ACTIVE;
+ stop_session(st_ses, hw_ses, true);
+ STATE_TRANSITION(st_ses, ssr_state_fn);
break;
case ST_SES_EV_SEND_CHMIX_COEFF:
status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
- ev->payload.chmix_coeff_str);
+ ev->payload.chmix_coeff_str);
break;
case ST_SES_EV_SET_DEVICE:
@@ -1143,6 +4683,10 @@
else
status = hw_ses->fptrs->enable_device(hw_ses, true);
+ if (status && st_ses->stdev->ssr_offline_received) {
+ STATE_TRANSITION(st_ses, ssr_state_fn);
+ status = 0;
+ }
break;
case ST_SES_EV_READ_PCM:
@@ -1157,93 +4701,117 @@
case ST_SES_EV_GET_PARAM_DATA:
status = hw_ses->fptrs->get_param_data(hw_ses,
- ev->payload.getparam.param, ev->payload.getparam.payload,
- ev->payload.getparam.payload_size,
- ev->payload.getparam.param_data_size);
+ ev->payload.getparam.param, ev->payload.getparam.payload,
+ ev->payload.getparam.payload_size,
+ ev->payload.getparam.param_data_size);
break;
case ST_SES_EV_REQUEST_DET:
- status = hw_ses->fptrs->send_detection_request(hw_ses);
- if (!status) {
- st_ses->detection_requested = true;
- /*
- * Disable second stage processing if a forced detection is
- * requested.
- */
- disable_second_stage_processing(st_ses, hw_ses);
+ if (!list_empty(&stc_ses->second_stage_list)) {
+ ALOGE("%s:[%d] Event not supported with second stage enabled",
+ __func__, st_ses->sm_handle);
+ status = -EINVAL;
+ break;
}
+ status = hw_ses->fptrs->send_detection_request(hw_ses);
+ if (!status)
+ st_ses->detection_requested = true;
break;
default:
ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
break;
-
};
return status;
}
-static int detected_state_fn(st_session_t *st_ses, st_session_ev_t *ev)
+static int detected_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
{
int status = 0;
- st_exec_mode_t new_exec_mode;
+ st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
+ st_session_t *stc_ses = ev->stc_ses;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
st_hw_session_t *hw_ses = st_ses->hw_ses_current;
st_hw_session_t *new_hw_ses = NULL;
/* skip parameter check as this is an internal funciton */
- ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
+ ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle, ev->ev_id);
switch (ev->ev_id) {
+ case ST_SES_EV_LOAD_SM:
+ /* Valid event only in multi-client usecase */
+ /*
+ * If a detected client deffered stop event is not handled yet,
+ * handle here before moving out of detected state
+ */
+ if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
+ ALOGD("%s:[%d] post deferred stop for c%d", __func__,
+ st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
+ status = hw_session_notifier_enqueue(
+ st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
+ ST_SES_DEFERRED_STOP_DELAY_MS);
+ if (!status)
+ st_ses->det_stc_ses->pending_stop = true;
+ }
+ status = handle_load_sm(st_ses, stc_ses);
+ break;
+
+ case ST_SES_EV_UNLOAD_SM:
+ /* Valid event only in multi-client usecase */
+ /*
+ * If a detected client deffered stop event is not handled yet,
+ * handle here before moving out of detected state
+ */
+ if (st_ses->det_stc_ses && !st_ses->det_stc_ses->pending_stop) {
+ ALOGD("%s:[%d] post deferred stop for client c%d", __func__,
+ st_ses->sm_handle, st_ses->det_stc_ses->sm_handle);
+ status = hw_session_notifier_enqueue(
+ st_ses->det_stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP,
+ ST_SES_DEFERRED_STOP_DELAY_MS);
+ if (!status)
+ st_ses->det_stc_ses->pending_stop = true;
+ }
+ status = handle_unload_sm(st_ses, stc_ses);
+ break;
+
case ST_SES_EV_START:
- /* session already started but config has changed stop and restart */
- status = stop_session(st_ses, hw_ses, false);
- if (status)
- break;
- status = start_session(st_ses, hw_ses, false);
- if (status)
- break;
+ /* For multi-client, other loaded client may start */
STATE_TRANSITION(st_ses, active_state_fn);
+ DISPATCH_EVENT(st_ses, *ev, status);
break;
case ST_SES_EV_RESTART:
- /* session already restarted without any config changes */
- restart_session(st_ses, hw_ses);
- STATE_TRANSITION(st_ses, active_state_fn);
+ status = restart_session(st_ses, hw_ses);
+ if (status && !st_ses->stdev->ssr_offline_received)
+ ALOGE("%s:[%d] failed to start session, err %d", __func__,
+ st_ses->sm_handle, status);
+
+ if (st_ses->stdev->ssr_offline_received) {
+ stop_session(st_ses, hw_ses, true);
+ STATE_TRANSITION(st_ses, ssr_state_fn);
+ status = 0;
+ } else {
+ /* Move anyways to allow client unload */
+ STATE_TRANSITION(st_ses, active_state_fn);
+ }
break;
+
case ST_SES_EV_PAUSE:
- st_ses->paused = true;
- st_ses->client_req_state = ST_STATE_LOADED;
- /* Fall through to handle pause events similarly to stop event. */
case ST_SES_EV_STOP:
/*
* It is possible that the client can issue stop after detection
* callback. This even can be issued internally as part of
- * deferred stop as well.
+ * deferred stop as well. For multi-client, it could be current
+ * detected client stop or other client stop.
*/
- status = stop_session(st_ses, hw_ses, false);
- if (status) {
- if (st_ses->stdev->ssr_offline_received) {
- STATE_TRANSITION(st_ses, ssr_state_fn);
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
- hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
- st_ses->client_req_state = ST_STATE_LOADED;
- /* Send success to client because the failure is recovered
- * internally from SSR.
- */
- status = 0;
- } else {
- ALOGE("%s:[%d] failed to stop session, err %d", __func__,
- st_ses->sm_handle, status);
- }
- break;
- }
-
- STATE_TRANSITION(st_ses, loaded_state_fn);
+ STATE_TRANSITION(st_ses, active_state_fn);
+ DISPATCH_EVENT(st_ses, *ev, status);
break;
+
case ST_SES_EV_SSR_OFFLINE:
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
/*
* Ignore return status during SSR handling
* as the ADSP or CPE might be down so these
@@ -1251,22 +4819,25 @@
* ssr occurs during a transition.
*/
if (st_ses->exec_mode != ST_EXEC_MODE_NONE)
- stop_hw_session(st_ses, hw_ses, true /* unload sm */);
-
- st_ses->client_req_state = ST_STATE_ACTIVE;
+ stop_session(st_ses, hw_ses, true);
STATE_TRANSITION(st_ses, ssr_state_fn);
break;
case ST_SES_EV_SET_EXEC_MODE:
new_exec_mode = ev->payload.exec_mode;
- /* if no change in mode or dynamic transition not enabled then noop */
- if ((new_exec_mode == st_ses->exec_mode) || !st_ses->enable_trans)
+ if (new_exec_mode == st_ses->exec_mode) {
+ stc_ses->exec_mode = st_ses->exec_mode;
break;
+ }
if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
st_ses->exec_mode = ST_EXEC_MODE_NONE;
status = stop_session(st_ses, hw_ses, true);
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->exec_mode = new_exec_mode;
+ }
if (status)
break;
}
@@ -1277,16 +4848,8 @@
/* switch to new hw session */
if (ST_EXEC_MODE_CPE == new_exec_mode) {
new_hw_ses = st_ses->hw_ses_cpe;
- st_ses->hw_ses_cpe->enable_second_stage =
- st_ses->hw_ses_adsp->enable_second_stage;
- st_ses->hw_ses_cpe->second_stage_list =
- st_ses->hw_ses_adsp->second_stage_list;
} else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
new_hw_ses = st_ses->hw_ses_adsp;
- st_ses->hw_ses_adsp->enable_second_stage =
- st_ses->hw_ses_cpe->enable_second_stage;
- st_ses->hw_ses_adsp->second_stage_list =
- st_ses->hw_ses_cpe->second_stage_list;
} else {
ALOGE("%s: unknown execution mode %d", __func__,
new_exec_mode);
@@ -1295,6 +4858,18 @@
}
/*
+ * hw session changed to/from WDSP/ADSP, hence update the
+ * related config.
+ * Not applicable for LPI<->non-LPI transtions as hw session
+ * doesn't change.
+ */
+ status = update_hw_config_on_start(stc_ses, new_hw_ses);
+ if (status) {
+ ALOGE("%s: Update_hw_config_on_start failed %d",
+ __func__, status);
+ break;
+ }
+ /*
* start new hw session and stay in detected state as
* client restart and stop concurrency scenarios are handled
* in this state
@@ -1303,6 +4878,14 @@
if (status)
break;
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->exec_mode = new_exec_mode;
+ if (c_ses->state == ST_STATE_ACTIVE) {
+ dereg_hal_event_session(c_ses);
+ reg_hal_event_session(c_ses, new_hw_ses);
+ }
+ }
st_ses->exec_mode = new_exec_mode;
st_ses->hw_ses_current = new_hw_ses;
break;
@@ -1327,18 +4910,17 @@
case ST_SES_EV_GET_PARAM_DATA:
status = hw_ses->fptrs->get_param_data(hw_ses,
- ev->payload.getparam.param, ev->payload.getparam.payload,
- ev->payload.getparam.payload_size,
- ev->payload.getparam.param_data_size);
+ ev->payload.getparam.param, ev->payload.getparam.payload,
+ ev->payload.getparam.payload_size,
+ ev->payload.getparam.param_data_size);
break;
case ST_SES_EV_DEFERRED_STOP:
ALOGD("%s:[%d] post deferred stop from detected state", __func__,
- st_ses->sm_handle);
- status = hw_session_notifier_enqueue(st_ses->sm_handle,
- ST_SES_EV_DEFERRED_STOP,
- ST_SES_DEFERRED_STOP_DELAY_MS);
+ st_ses->sm_handle);
+ status = hw_session_notifier_enqueue(stc_ses->sm_handle,
+ ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
if (!status)
- st_ses->pending_stop = true;
+ stc_ses->pending_stop = true;
break;
case ST_SES_EV_REQUEST_DET:
ALOGE("%s:[%d] Event not supported in this state",
@@ -1348,26 +4930,41 @@
default:
ALOGD("%s:[%d] unhandled event", __func__, st_ses->sm_handle);
break;
-
};
-
return status;
}
-static int buffering_state_fn(st_session_t *st_ses, st_session_ev_t *ev)
+static int buffering_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
{
int status = 0;
+ st_session_t *stc_ses = ev->stc_ses;
+ struct listnode *node = NULL;
+ st_session_t *c_ses = NULL;
st_hw_session_t *hw_ses = st_ses->hw_ses_current;
- st_exec_mode_t new_exec_mode = 0;
+ st_exec_mode_t new_exec_mode = ST_EXEC_MODE_NONE;
st_hw_session_t *new_hw_ses = NULL;
- st_session_ev_t set_dev_ev = { .ev_id = ST_SES_EV_SET_DEVICE };
/* skip parameter check as this is an internal function */
- ALOGVV("%s:[%d] handle event id %d", __func__, st_ses->sm_handle,
- ev->ev_id);
- switch (ev->ev_id) {
- case ST_SES_EV_READ_PCM:
+ ALOGVV("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle, ev->ev_id);
+ switch (ev->ev_id) {
+ case ST_SES_EV_LOAD_SM:
+ /* Valid in multi-client usecase */
+ ALOGD("%s:[c%d-%d] load sm", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle);
+
+ status = handle_load_sm(st_ses, stc_ses);
+ break;
+
+ case ST_SES_EV_UNLOAD_SM:
+ ALOGD("%s:[c%d-%d] unload sm", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle);
+
+ status = handle_unload_sm(st_ses, stc_ses);
+ break;
+
+ case ST_SES_EV_READ_PCM:
/* Note: this function may block if there is no PCM data ready*/
hw_ses->fptrs->read_pcm(hw_ses, ev->payload.readpcm.out_buff,
ev->payload.readpcm.out_buff_size);
@@ -1375,61 +4972,48 @@
ev->payload.readpcm.out_buff_size);
break;
case ST_SES_EV_END_BUFFERING:
- hw_ses->fptrs->stop_buffering(hw_ses, st_ses->lab_enabled);
- if (!st_ses->pending_stop) {
- ALOGD("%s:[%d] post deferred stop on buffering end", __func__,
- st_ses->sm_handle);
- status = hw_session_notifier_enqueue(st_ses->sm_handle,
- ST_SES_EV_DEFERRED_STOP,
- ST_SES_DEFERRED_STOP_DELAY_MS);
- if (!status)
- st_ses->pending_stop = true;
- } else {
- ALOGD("%s:[%d] skip deferred stop on buffering as already set", __func__,
- st_ses->sm_handle);
+ if (stc_ses == st_ses->det_stc_ses) {
+ hw_ses->fptrs->stop_buffering(hw_ses);
+ if (!stc_ses->pending_stop) {
+ ALOGD("%s:[c%d] post deferred stop on buffering end", __func__,
+ stc_ses->sm_handle);
+ status = hw_session_notifier_enqueue(stc_ses->sm_handle,
+ ST_SES_EV_DEFERRED_STOP, ST_SES_DEFERRED_STOP_DELAY_MS);
+ if (!status)
+ stc_ses->pending_stop = true;
+ } else {
+ ALOGD("%s:[c%d] skip deferred stop on buffering as already set",
+ __func__, stc_ses->sm_handle);
+ }
}
break;
- case ST_SES_EV_PAUSE:
- st_ses->paused = true;
- /* Fall through to handle pause events similarly to stop event. */
- case ST_SES_EV_STOP:
- ALOGD("%s:[%d] handle event STOP %s", __func__, st_ses->sm_handle,
- st_ses->paused ? "(paused)" : "");
- /*
- * These events are related to a tear down sequence, so transition to
- * loaded state even if there is a failure.
- */
- status = hw_ses->fptrs->stop_buffering(hw_ses, st_ses->lab_enabled);
- if (status)
- ALOGE("%s:[%d] failed to stop_buffering err %d", __func__,
- st_ses->sm_handle, status);
- /*
- * We treat pause during buffering with the same semantics as stop.
- * With second stage enabled, the session can be in buffering state
- * without the app requesting it. So if the PAUSE event comes when
- * session is in buffering state, client_req_state needs to be set to
- * active to ensure the session can make it back to the active state.
- */
- if (st_ses->paused)
- st_ses->client_req_state = ST_STATE_ACTIVE;
- else
- st_ses->client_req_state = ST_STATE_LOADED;
- status = stop_session(st_ses, hw_ses, false);
- if (status)
- ALOGE("%s:[%d] failed to stop session, err %d", __func__,
- st_ses->sm_handle, status);
+ case ST_SES_EV_STOP:
+ ALOGD("%s:[c%d-%d] handle event STOP", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle);
+ if (stc_ses != st_ses->det_stc_ses) {
+ ALOGD("%s: c%d buffering, delay c%d stop", __func__,
+ st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
+ update_hw_config_on_stop(st_ses, stc_ses);
+ break;
+ }
+ /* Fall through */
+ case ST_SES_EV_PAUSE:
+ hw_ses->fptrs->stop_buffering(hw_ses);
+ STATE_TRANSITION(st_ses, active_state_fn);
+ DISPATCH_EVENT(st_ses, *ev, status);
ST_DBG_FILE_CLOSE(st_ses->lab_fp);
- STATE_TRANSITION(st_ses, loaded_state_fn);
break;
case ST_SES_EV_SET_DEVICE:
+ ALOGD("%s:[c%d-%d] handle SET_DEVICE", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle);
/*
* Device switch will not wait for buffering to finish. It will instead
* interrupt and stop the buffering and transition to the loaded state.
* The loaded state will then take care of the device switch.
*/
- hw_ses->fptrs->stop_buffering(hw_ses, st_ses->lab_enabled);
+ hw_ses->fptrs->stop_buffering(hw_ses);
status = stop_session(st_ses, hw_ses, false);
if (status && !st_ses->stdev->ssr_offline_received) {
ALOGE("%s:[%d] failed to stop session, err %d", __func__,
@@ -1437,13 +5021,30 @@
break;
}
STATE_TRANSITION(st_ses, loaded_state_fn);
- DISPATCH_EVENT(st_ses, set_dev_ev, status);
+ DISPATCH_EVENT(st_ses, *ev, status);
+ /*
+ * The current detected client may or may not read buffer/restart
+ * recognition. If no other clients are active, get to loaded state.
+ * Otherwise, if any other client than the detected client is active,
+ * we should move to active state for other client detections.
+ */
+ st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START};
+ if (check_and_get_other_active_client(st_ses, st_ses->det_stc_ses)) {
+ start_ev.stc_ses = stc_ses;
+ DISPATCH_EVENT(st_ses, start_ev, status);
+ }
break;
case ST_SES_EV_START:
case ST_SES_EV_RESTART:
- ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle,
- ev->ev_id);
+ ALOGD("%s:[c%d-%d] handle event START/RESTART", __func__,
+ stc_ses->sm_handle, st_ses->sm_handle);
+
+ if (stc_ses != st_ses->det_stc_ses) {
+ ALOGD("%s: c%d buffering, delay c%d start", __func__,
+ st_ses->det_stc_ses->sm_handle, stc_ses->sm_handle);
+ break;
+ }
/*
* Client starts detection again.
* This implies a previous deferred stop hasn't completed yet as
@@ -1451,67 +5052,46 @@
* For a restart event, issue stop buffering and restart the session
* For a start event, stop buffering then stop and start the session
* so that any new parameters take effect.
+ * For multi-client case while the detected is buffering,
+ * the other client stop/start would have been deferred by updating
+ * the config, and later when current detected client restarts after
+ * buffreing is completed, check if hw config is updated due to other
+ * client and stop->start the hw session to apply updated config.
*/
- hw_ses->fptrs->stop_buffering(hw_ses, st_ses->lab_enabled);
- if (ev->ev_id == ST_SES_EV_START) {
+ hw_ses->fptrs->stop_buffering(hw_ses);
+ if (hw_ses->sthw_cfg_updated || ev->ev_id == ST_SES_EV_START) {
status = stop_session(st_ses, hw_ses, false);
- if (status && !st_ses->stdev->ssr_offline_received) {
+ if (status) {
ALOGE("%s:[%d] failed to stop session, err %d", __func__,
- st_ses->sm_handle, status);
- break;
+ st_ses->sm_handle, status);
+ } else {
+ status = start_session(st_ses, hw_ses, false);
+ if (status) {
+ ALOGE("%s:[%d] failed to start session, err %d", __func__,
+ st_ses->sm_handle, status);
+ }
}
- status = start_session(st_ses, hw_ses, false);
} else {
status = restart_session(st_ses, hw_ses);
}
if (status) {
if (st_ses->stdev->ssr_offline_received) {
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
- hw_ses->fptrs->dereg_sm(hw_ses, st_ses->lab_enabled);
- st_ses->client_req_state = ST_STATE_ACTIVE;
+ hw_ses->fptrs->dereg_sm(hw_ses);
STATE_TRANSITION(st_ses, ssr_state_fn);
- /* Send success to client because the failure is recovered
- * internally from SSR.
- */
status = 0;
} else {
- ALOGE("%s:[%d] failed to start session, err %d", __func__,
- st_ses->sm_handle, status);
/* move to active anyways to allow unload sm */
STATE_TRANSITION(st_ses, active_state_fn);
}
} else {
- /* Move state back to active for restart and start events */
STATE_TRANSITION(st_ses, active_state_fn);
}
break;
case ST_SES_EV_SSR_OFFLINE:
- ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle,
- ev->ev_id);
-
- if (st_ses->enable_second_stage) {
- /*
- * Second stage sessions will always buffer in order to be
- * able to make detections. If the SSR occurs before the
- * client is notified of a detection, it needs to recover to
- * the active state. If the SSR occurs after this, or if the
- * second stage detection is rejected, then recovering to
- * the loaded state is sufficient.
- */
- if (!st_ses->sent_detection_to_client || st_ses->paused)
- st_ses->client_req_state = ST_STATE_ACTIVE;
- else
- st_ses->client_req_state = ST_STATE_LOADED;
- } else {
- if (st_ses->paused)
- st_ses->client_req_state = ST_STATE_ACTIVE;
- else
- st_ses->client_req_state = ST_STATE_LOADED;
- }
-
+ ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle, ev->ev_id);
/*
* Ignore return status during SSR handling
* as the ADSP or CPE might be down so these
@@ -1519,35 +5099,35 @@
* ssr occurs during a transition.
*/
if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
- hw_ses->fptrs->stop_buffering(hw_ses,
- st_ses->lab_enabled);
- if (st_ses->enable_second_stage)
- stop_second_stage_session(st_ses);
- stop_hw_session(st_ses, hw_ses, true /* unload sm */);
+ hw_ses->fptrs->stop_buffering(hw_ses);
+ stop_session(st_ses, hw_ses, true);
}
STATE_TRANSITION(st_ses, ssr_state_fn);
break;
case ST_SES_EV_SET_EXEC_MODE:
- ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle,
- ev->ev_id);
+ ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle, ev->ev_id);
new_exec_mode = ev->payload.exec_mode;
-
- /* if no change in mode or dynamic transition not enabled then noop */
- if ((new_exec_mode == st_ses->exec_mode) || !st_ses->enable_trans)
+ if (new_exec_mode == st_ses->exec_mode) {
+ stc_ses->exec_mode = st_ses->exec_mode;
break;
+ }
if (st_ses->exec_mode != ST_EXEC_MODE_NONE) {
st_ses->exec_mode = ST_EXEC_MODE_NONE;
- status = hw_ses->fptrs->stop_buffering(hw_ses, st_ses->lab_enabled);
+ status = hw_ses->fptrs->stop_buffering(hw_ses);
if (status) {
ALOGE("%s:[%d] failed to stop_buffering err %d", __func__,
st_ses->sm_handle, status);
break;
}
-
status = stop_session(st_ses, hw_ses, true);
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->exec_mode = new_exec_mode;
+ }
if (status) {
ALOGE("%s:[%d] failed to stop session, err %d", __func__,
st_ses->sm_handle, status);
@@ -1561,29 +5141,40 @@
/* switch to new hw session */
if (ST_EXEC_MODE_CPE == new_exec_mode) {
new_hw_ses = st_ses->hw_ses_cpe;
- st_ses->hw_ses_cpe->enable_second_stage =
- st_ses->hw_ses_adsp->enable_second_stage;
- st_ses->hw_ses_cpe->second_stage_list =
- st_ses->hw_ses_adsp->second_stage_list;
} else if (ST_EXEC_MODE_ADSP == new_exec_mode) {
new_hw_ses = st_ses->hw_ses_adsp;
- st_ses->hw_ses_adsp->enable_second_stage =
- st_ses->hw_ses_cpe->enable_second_stage;
- st_ses->hw_ses_adsp->second_stage_list =
- st_ses->hw_ses_cpe->second_stage_list;
} else {
ALOGE("%s: unknown execution mode %d", __func__,
new_exec_mode);
status = -EINVAL;
break;
}
-
+ /*
+ * hw session changed to/from WDSP/ADSP, hence update the
+ * related config.
+ * Not applicable for LPI<->non-LPI transtions as hw session
+ * doesn't change.
+ */
+ status = update_hw_config_on_start(stc_ses, new_hw_ses);
+ if (status) {
+ ALOGE("%s: Update_hw_config_on_start failed %d",
+ __func__, status);
+ break;
+ }
status = start_session(st_ses, new_hw_ses, true);
if (status) {
ALOGE("%s:[%d] failed to start hw ses, err %d", __func__,
st_ses->sm_handle, status);
break;
}
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ c_ses->exec_mode = new_exec_mode;
+ if (c_ses->state == ST_STATE_ACTIVE) {
+ dereg_hal_event_session(c_ses);
+ reg_hal_event_session(c_ses, new_hw_ses);
+ }
+ }
st_ses->exec_mode = new_exec_mode;
st_ses->hw_ses_current = new_hw_ses;
STATE_TRANSITION(st_ses, active_state_fn);
@@ -1591,14 +5182,14 @@
case ST_SES_EV_SEND_CHMIX_COEFF:
status = hw_ses->fptrs->send_custom_chmix_coeff(hw_ses,
- ev->payload.chmix_coeff_str);
+ ev->payload.chmix_coeff_str);
break;
case ST_SES_EV_GET_PARAM_DATA:
status = hw_ses->fptrs->get_param_data(hw_ses,
- ev->payload.getparam.param, ev->payload.getparam.payload,
- ev->payload.getparam.payload_size,
- ev->payload.getparam.param_data_size);
+ ev->payload.getparam.param, ev->payload.getparam.payload,
+ ev->payload.getparam.payload_size,
+ ev->payload.getparam.param_data_size);
break;
case ST_SES_EV_REQUEST_DET:
@@ -1611,94 +5202,122 @@
ALOGD("%s:[%d] unhandled event, id %d", __func__, st_ses->sm_handle,
ev->ev_id);
break;
-
};
return status;
}
-static int ssr_state_fn(st_session_t *st_ses, st_session_ev_t *ev)
+static int ssr_state_fn(st_proxy_session_t *st_ses, st_session_ev_t *ev)
{
int status = 0;
- st_session_ev_t load_ev = { .ev_id = ST_SES_EV_LOAD_SM };
- st_session_ev_t start_ev = { .ev_id = ST_SES_EV_START };
- st_session_ev_t exec_mode_ev = { .ev_id = ST_SES_EV_SET_EXEC_MODE };
+ st_session_t *stc_ses = ev->stc_ses;
+ st_session_ev_t load_ev = {.ev_id = ST_SES_EV_LOAD_SM};
+ st_session_ev_t start_ev = {.ev_id = ST_SES_EV_START};
+ st_session_ev_t exec_mode_ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE};
+ bool active = false;
- /* skip parameter check as this is an internal funciton */
- ALOGD("%s:[%d] handle event id %d", __func__, st_ses->sm_handle, ev->ev_id);
+ /* skip parameter check as this is an internal function */
+ ALOGD("%s:[c%d-%d] handle event id %d", __func__, stc_ses->sm_handle,
+ st_ses->sm_handle, ev->ev_id);
switch (ev->ev_id) {
case ST_SES_EV_SSR_ONLINE:
ALOGV("%s:[%d] SSR ONLINE received", __func__, st_ses->sm_handle);
+ /*
+ * Load and start all clients at once instead of unload/loading
+ * due to each subsequent client dispatch. It is expected the
+ * upper layer calls SSR_ONLINE for all clients.
+ */
+ stc_ses->pending_load = true;
+ if (is_any_client_not_pending_load(st_ses))
+ break;
+
+ reset_clients_pending_load(st_ses);
STATE_TRANSITION(st_ses, idle_state_fn);
- if ((st_ses->ssr_transit_exec_mode == ST_EXEC_MODE_CPE) ||
- (st_ses->ssr_transit_exec_mode == ST_EXEC_MODE_ADSP)) {
- exec_mode_ev.payload.exec_mode = st_ses->ssr_transit_exec_mode;
+ if ((stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_CPE) ||
+ (stc_ses->ssr_transit_exec_mode == ST_EXEC_MODE_ADSP)) {
+ exec_mode_ev.stc_ses = stc_ses;
+ exec_mode_ev.payload.exec_mode = stc_ses->ssr_transit_exec_mode;
DISPATCH_EVENT(st_ses, exec_mode_ev, status);
- st_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
+ if (status)
+ break;
+ stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
}
-
- if ((ST_STATE_ACTIVE == st_ses->client_req_state) ||
- (ST_STATE_LOADED == st_ses->client_req_state)) {
+ active = is_any_client_in_state(st_ses, ST_STATE_ACTIVE);
+ if (active || is_any_client_in_state(st_ses, ST_STATE_LOADED)) {
+ load_ev.stc_ses = stc_ses;
DISPATCH_EVENT(st_ses, load_ev, status);
if (status)
break;
}
-
- if ((ST_STATE_ACTIVE == st_ses->client_req_state) &&
- !st_ses->paused) {
+ if (active) {
+ start_ev.stc_ses = stc_ses;
DISPATCH_EVENT(st_ses, start_ev, status);
- if (status)
- break;
}
break;
case ST_SES_EV_LOAD_SM:
- if (ST_STATE_IDLE == st_ses->client_req_state) {
- st_ses->client_req_state = ST_STATE_LOADED;
+ if (ST_STATE_IDLE == stc_ses->state) {
+ status = update_sound_model(stc_ses, true);
+ if (status) {
+ ALOGE("%s:[c%d] update sound model add failed %d", __func__,
+ stc_ses->sm_handle, status);
+ status = -EINVAL;
+ break;
+ }
+ prepapre_second_stage_for_client(stc_ses);
+ stc_ses->state = ST_STATE_LOADED;
} else {
- ALOGE("%s: received unexpected event, client_req_state = %d",
- __func__, st_ses->client_req_state);
+ ALOGE("%s: received unexpected event, client state = %d",
+ __func__, stc_ses->state);
}
break;
case ST_SES_EV_UNLOAD_SM:
- if (ST_STATE_LOADED == st_ses->client_req_state) {
- st_ses->client_req_state = ST_STATE_IDLE;
+ if (ST_STATE_LOADED == stc_ses->state) {
+ status = update_sound_model(stc_ses, false);
+ if (status)
+ ALOGE("%s:[c%d] update sound_model failed %d", __func__,
+ stc_ses->sm_handle, status);
+ stop_second_stage_for_client(stc_ses);
+ stc_ses->state = ST_STATE_IDLE;
} else {
- ALOGE("%s: received unexpected event, client_req_state = %d",
- __func__, st_ses->client_req_state);
+ ALOGE("%s: received unexpected event, client state = %d",
+ __func__, stc_ses->state);
}
break;
case ST_SES_EV_START:
case ST_SES_EV_RESTART:
- if (ST_STATE_LOADED == st_ses->client_req_state) {
- st_ses->client_req_state = ST_STATE_ACTIVE;
+ if (ST_STATE_LOADED == stc_ses->state) {
+ if (ev->ev_id == ST_SES_EV_RESTART)
+ update_hw_config_on_restart(st_ses, stc_ses);
+ stc_ses->state = ST_STATE_ACTIVE;
} else {
- ALOGE("%s: received unexpected event, client_req_state = %d",
- __func__, st_ses->client_req_state);
+ ALOGE("%s: received unexpected event, client state = %d",
+ __func__, stc_ses->state);
}
break;
case ST_SES_EV_STOP:
- if (ST_STATE_ACTIVE == st_ses->client_req_state) {
- st_ses->client_req_state = ST_STATE_LOADED;
+ if (ST_STATE_ACTIVE == stc_ses->state) {
+ update_hw_config_on_stop(st_ses, stc_ses);
+ stc_ses->state = ST_STATE_LOADED;
} else {
- ALOGE("%s: received unexpected event, client_req_state = %d",
- __func__, st_ses->client_req_state);
+ ALOGE("%s: received unexpected event, client state = %d",
+ __func__, stc_ses->state);
}
break;
case ST_SES_EV_PAUSE:
- st_ses->paused = true;
+ stc_ses->paused = true;
break;
case ST_SES_EV_RESUME:
- st_ses->paused = false;
+ stc_ses->paused = false;
break;
case ST_SES_EV_READ_PCM:
@@ -1714,7 +5333,12 @@
break;
case ST_SES_EV_SET_EXEC_MODE:
+ stc_ses->exec_mode = ev->payload.exec_mode;
+ if (ev->payload.exec_mode == st_ses->exec_mode)
+ break;
+
st_ses->exec_mode = ev->payload.exec_mode;
+
if (ST_EXEC_MODE_CPE == st_ses->exec_mode)
st_ses->hw_ses_current = st_ses->hw_ses_cpe;
else if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
@@ -1736,849 +5360,138 @@
return status;
}
-/*
- * This function sets the opaque data size for the DSP's generic detection
- * events. This opaque data can now have varying size based on the requested
- * params.
- */
-static size_t set_opaque_data_size(void *payload, size_t payload_size,
- uint32_t version)
-{
- size_t count_size = 0, opaque_size = 0;
- uint8_t *payload_ptr = (uint8_t *)payload;
- uint32_t key_id = 0, key_payload_size = 0;
-
- while (count_size < payload_size) {
- key_id = *(uint32_t *)payload_ptr;
- key_payload_size = *((uint32_t *)payload_ptr + 1);
-
- switch (key_id) {
- case KEY_ID_CONFIDENCE_LEVELS:
- opaque_size += sizeof(struct st_param_header);
- if (version != CONF_LEVELS_INTF_VERSION_0002) {
- opaque_size +=
- sizeof(struct st_confidence_levels_info);
- } else {
- opaque_size +=
- sizeof(struct st_confidence_levels_info_v2);
- }
- count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
- payload_ptr += count_size;
- break;
-
- case KEY_ID_KEYWORD_POSITION_STATS:
- opaque_size += sizeof(struct st_param_header) +
- sizeof(struct st_keyword_indices_info);
- count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
- payload_ptr += count_size;
- break;
-
- default:
- ALOGE("%s: Unsupported generic detection event key id", __func__);
- }
- }
-
- opaque_size += sizeof(struct st_param_header) + sizeof(struct st_timestamp_info);
-
- return opaque_size;
-}
-
-/*
- * This function packs the updated opaque data confidence levels which are
- * passed to the client via callback.
- */
-static int pack_opaque_data_conf_levels(
- st_session_t *st_ses, void *opaque_data,
- uint8_t *payload)
-{
- uint8_t *payload_ptr = payload;
- unsigned int i, j, k, user_id;
- st_arm_second_stage_t *st_sec_stage;
- struct listnode *node = NULL, *tmp_node = NULL;
- struct st_confidence_levels_info *conf_levels = NULL;
- struct st_confidence_levels_info_v2 *conf_levels_v2 = NULL;
- int32_t kw_level = 0, user_level = 0;
-
- if (st_ses->enable_second_stage) {
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
- kw_level = st_sec_stage->ss_session->confidence_score;
- } else if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_VOP) {
- user_level = st_sec_stage->ss_session->confidence_score;
- }
- }
- }
- if (st_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
- conf_levels = (struct st_confidence_levels_info *)opaque_data;
- for (i = 0; i < conf_levels->num_sound_models; i++) {
- if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
- for (j = 0;
- j < conf_levels->conf_levels[i].num_kw_levels; j++) {
- conf_levels->conf_levels[i].kw_levels[j].kw_level =
- payload_ptr[j];
- for (k = 0;
- k < conf_levels->conf_levels[i].kw_levels[j].num_user_levels;
- k++) {
- user_id =
- conf_levels->conf_levels[i].kw_levels[j].
- user_levels[k].user_id;
- conf_levels->conf_levels[i].kw_levels[j].
- user_levels[k].level = payload_ptr[user_id];
- }
- }
- } else if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_CNN) {
- conf_levels->conf_levels[i].kw_levels[0].kw_level = kw_level;
- } else if (conf_levels->conf_levels[i].sm_id == ST_SM_ID_SVA_VOP) {
- /*
- * Fill both the keyword and user confidence level with the
- * confidence score returned from the voiceprint algorithm.
- */
- conf_levels->conf_levels[i].kw_levels[0].kw_level =
- (uint8_t)user_level;
- conf_levels->conf_levels[i].kw_levels[0].user_levels[0].level =
- (uint8_t)user_level;
- }
- }
- } else {
- conf_levels_v2 = (struct st_confidence_levels_info_v2 *)opaque_data;
- for (i = 0; i < conf_levels_v2->num_sound_models; i++) {
- if (conf_levels_v2->conf_levels[i].sm_id == ST_SM_ID_SVA_GMM) {
- for (j = 0;
- j < conf_levels_v2->conf_levels[i].num_kw_levels; j++) {
- conf_levels_v2->conf_levels[i].kw_levels[j].kw_level =
- payload_ptr[j];
- for (k = 0;
- k < conf_levels_v2->conf_levels[i].kw_levels[j].num_user_levels;
- k++) {
- user_id =
- conf_levels_v2->conf_levels[i].kw_levels[j].
- user_levels[k].user_id;
- conf_levels_v2->conf_levels[i].kw_levels[j].
- user_levels[k].level = payload_ptr[user_id];
- }
- }
- } else if (conf_levels_v2->conf_levels[i].sm_id == ST_SM_ID_SVA_CNN) {
- conf_levels_v2->conf_levels[i].kw_levels[0].kw_level = kw_level;
- } else if (conf_levels_v2->conf_levels[i].sm_id == ST_SM_ID_SVA_VOP) {
- /*
- * Fill both the keyword and user confidence level with the
- * confidence score returned from the voiceprint algorithm.
- */
- conf_levels_v2->conf_levels[i].kw_levels[0].kw_level = user_level;
- conf_levels_v2->conf_levels[i].kw_levels[0].user_levels[0].level =
- user_level;
- }
- }
- }
-
- return 0;
-}
-
-/* This function packs the sound trigger API confidence levels */
-static int pack_recognition_event_conf_levels(
- st_session_t *st_ses, uint8_t *payload_ptr,
- struct sound_trigger_phrase_recognition_event *local_event)
-{
- unsigned int j = 0, k = 0, user_id = 0;
- st_arm_second_stage_t *st_sec_stage;
- struct listnode *node = NULL, *tmp_node = NULL;
- struct sound_trigger_phrase_sound_model *phrase_sm =
- (struct sound_trigger_phrase_sound_model *)st_ses->sm_data;
-
- /*
- * Fill in the GMM confidence levels to the sound trigger recognition event
- * APIs first. If any second stage session is enabled, overwrite the APIs
- * with the second stage confidence levels.
- */
- for (j = 0; j < st_ses->rc_config->num_phrases; j++) {
- local_event->phrase_extras[j].id = st_ses->rc_config->phrases[j].id;
- local_event->phrase_extras[j].recognition_modes =
- phrase_sm->phrases[j].recognition_mode;
- local_event->phrase_extras[j].num_levels =
- st_ses->rc_config->phrases[j].num_levels;
- local_event->phrase_extras[j].confidence_level = payload_ptr[j];
- for (k = 0; k < st_ses->rc_config->phrases[j].num_levels; k++) {
- user_id = st_ses->rc_config->phrases[j].levels[k].user_id;
- local_event->phrase_extras[j].levels[k].user_id = user_id;
- local_event->phrase_extras[j].levels[k].level =
- payload_ptr[user_id];
- }
- }
-
- if (st_ses->enable_second_stage) {
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
- local_event->phrase_extras[0].confidence_level =
- (uint8_t)st_sec_stage->ss_session->confidence_score;
- } else if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_VOP) {
- local_event->phrase_extras[0].levels[0].level =
- (uint8_t)st_sec_stage->ss_session->confidence_score;
- }
- }
- }
-
- return 0;
-}
-
-static int parse_generic_event_and_pack_opaque_data(
- st_session_t *st_ses, uint8_t **opaque_data,
- uint8_t *payload_ptr, size_t payload_size,
- struct sound_trigger_phrase_recognition_event *local_event)
-{
- uint32_t key_id = 0, key_payload_size = 0;
- struct st_param_header *param_hdr = NULL;
- struct st_keyword_indices_info *kw_indices = NULL;
- struct st_timestamp_info *timestamps = NULL;
- size_t count_size = 0;
- st_arm_second_stage_t *st_sec_stage;
- struct listnode *node = NULL, *tmp_node = NULL;
- st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
- int status = 0;
- uint8_t *conf_payload_ptr = NULL;
-
- while (count_size < payload_size) {
- key_id = *(uint32_t *)payload_ptr;
- key_payload_size = *((uint32_t *)payload_ptr + 1);
-
- switch (key_id) {
- case KEY_ID_CONFIDENCE_LEVELS:
- /* Pack the opaque data confidence levels structure */
- param_hdr = (struct st_param_header *)(*opaque_data);
- param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
- *opaque_data += sizeof(struct st_param_header);
- if (st_ses->conf_levels_intf_version !=
- CONF_LEVELS_INTF_VERSION_0002) {
- param_hdr->payload_size =
- sizeof(struct st_confidence_levels_info);
- } else {
- param_hdr->payload_size =
- sizeof(struct st_confidence_levels_info_v2);
- }
- memcpy(*opaque_data, st_hw_ses->conf_levels_info,
- param_hdr->payload_size);
- conf_payload_ptr = payload_ptr + (4 * sizeof(uint32_t));
- pack_opaque_data_conf_levels(st_ses, (void *)*opaque_data,
- conf_payload_ptr);
- pack_recognition_event_conf_levels(st_ses, conf_payload_ptr,
- local_event);
- *opaque_data += param_hdr->payload_size;
- break;
-
- case KEY_ID_KEYWORD_POSITION_STATS:
- /* Pack the opaque data keyword indices structure */
- param_hdr = (struct st_param_header *)(*opaque_data);
- param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
- param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
- *opaque_data += sizeof(struct st_param_header);
- kw_indices = (struct st_keyword_indices_info *)(*opaque_data);
- kw_indices->version = 0x1;
- kw_indices->start_index = *((uint32_t *)payload_ptr + 3);
- kw_indices->end_index = *((uint32_t *)payload_ptr + 4);
-
- if (st_ses->enable_second_stage) {
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
- kw_indices->start_index = st_sec_stage->ss_session->kw_start_idx;
- kw_indices->end_index = st_sec_stage->ss_session->kw_end_idx;
- }
- }
- }
-
- *opaque_data += sizeof(struct st_keyword_indices_info);
- break;
-
- default:
- ALOGE("%s: Unsupported generic detection event key id", __func__);
- status = -EINVAL;
- goto exit;
- }
- count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
- payload_ptr += count_size;
- }
-
- /* Pack the opaque data detection timestamp structure */
- param_hdr = (struct st_param_header *)(*opaque_data);
- param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
- param_hdr->payload_size = sizeof(struct st_timestamp_info);
- *opaque_data += sizeof(struct st_param_header);
- timestamps = (struct st_timestamp_info *)(*opaque_data);
- timestamps->version = 0x1;
- timestamps->first_stage_det_event_time =
- st_ses->hw_ses_current->first_stage_det_event_time;
- if (st_ses->enable_second_stage)
- timestamps->second_stage_det_event_time =
- st_ses->hw_ses_current->second_stage_det_event_time;
- *opaque_data += sizeof(struct st_timestamp_info);
-
-exit:
- return status;
-}
-
-static int parse_generic_event_without_opaque_data(
- st_session_t *st_ses, uint8_t *payload_ptr, size_t payload_size,
- struct sound_trigger_phrase_recognition_event *local_event)
-{
- uint32_t key_id = 0, key_payload_size = 0;
- size_t count_size = 0;
- int status = 0;
- uint8_t *conf_payload_ptr;
-
- while (count_size < payload_size) {
- key_id = *(uint32_t *)payload_ptr;
- key_payload_size = *((uint32_t *)payload_ptr + 1);
-
- switch (key_id) {
- case KEY_ID_CONFIDENCE_LEVELS:
- conf_payload_ptr = payload_ptr + (4 * sizeof(uint32_t));
- pack_recognition_event_conf_levels(st_ses, conf_payload_ptr,
- local_event);
- return status;
-
- case KEY_ID_KEYWORD_POSITION_STATS:
- count_size += GENERIC_DET_EVENT_HEADER_SIZE + key_payload_size;
- payload_ptr += count_size;
- break;
-
- default:
- ALOGE("%s: Unsupported generic detection event key id", __func__);
- status = -EINVAL;
- return status;
- }
- }
-
- return status;
-}
-
-/*
- * This function handles detection payloads in the format of the DSP's
- * generic detection event.
- */
-int process_detection_event_keyphrase_v2(
- st_session_t *st_ses, int detect_status,
- void *payload, size_t payload_size,
- struct sound_trigger_phrase_recognition_event **event)
-{
- st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
- unsigned int i, j;
- int status = 0;
- uint8_t *opaque_data = NULL, *payload_ptr = NULL;
- size_t opaque_size = 0;
- struct sound_trigger_phrase_recognition_event *local_event = NULL;
-
- if (st_ses->vendor_uuid_info->is_qcva_uuid)
- opaque_size = set_opaque_data_size(payload, payload_size,
- st_ses->conf_levels_intf_version);
- else
- opaque_size = payload_size;
-
- local_event = calloc(1, sizeof(struct sound_trigger_phrase_recognition_event) + opaque_size);
- if (!local_event) {
- ALOGE("%s: local_event allocation failed, opaque data size = %d", __func__,
- (unsigned int)opaque_size);
- return -ENOMEM;
- }
-
- local_event->num_phrases = st_ses->rc_config->num_phrases;
- local_event->common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
- local_event->common.data_size = opaque_size;
- opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
- payload_ptr = (uint8_t *)payload;
-
- if (st_ses->vendor_uuid_info->is_qcva_uuid) {
- if (st_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) {
- status = parse_generic_event_and_pack_opaque_data(st_ses, &opaque_data,
- payload_ptr, payload_size, local_event);
- if (status) {
- ALOGE("%s: Failed to parse generic detection event with opaque data %d",
- __func__, status);
- goto exit;
- }
-
- ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
- ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
- "detection_opaque_data", "bin", opaque_cnt++);
- ST_DBG_FILE_WRITE(opaque_fd, (uint8_t *)local_event +
- local_event->common.data_offset, opaque_size);
- ST_DBG_FILE_CLOSE(opaque_fd);
- } else {
- status = parse_generic_event_without_opaque_data(st_ses, payload_ptr,
- payload_size, local_event);
- if (status) {
- ALOGE("%s: Failed to parse generic detection event without opaque data %d",
- __func__, status);
- goto exit;
- }
- }
-
- } else {
- local_event = calloc(1, sizeof(*local_event) + payload_size);
- if (!local_event) {
- ALOGE("%s: event allocation failed, size %zd", __func__,
- payload_size);
- status = -ENOMEM;
- goto exit;
- }
- memcpy(local_event->phrase_extras,
- st_ses->rc_config->phrases, st_ses->rc_config->num_phrases *
- sizeof(struct sound_trigger_phrase_recognition_extra));
- local_event->num_phrases = st_ses->rc_config->num_phrases;
- local_event->common.data_offset = sizeof(*local_event);
- local_event->common.data_size = payload_size;
- memcpy((char *)local_event + local_event->common.data_offset, payload,
- payload_size);
- opaque_data += opaque_size;
- }
-
- /* fill the remaining recognition event parameters not specific
- to soundmodel lib */
- local_event->common.status = detect_status;
- local_event->common.type = st_ses->sm_data->common.type;
- local_event->common.model = st_ses->sm_handle;
- local_event->common.capture_available = st_ses->capture_requested;
- local_event->common.capture_delay_ms = 0;
- local_event->common.capture_preamble_ms = 0;
- local_event->common.audio_config.sample_rate =
- SOUND_TRIGGER_SAMPLING_RATE_16000;
- local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
- local_event->common.audio_config.channel_mask =
- audio_channel_in_mask_from_count(st_hw_ses->config.channels);
-
- for (i = 0; i < local_event->num_phrases; ++i) {
- ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
- local_event->phrase_extras[i].id,
- local_event->phrase_extras[i].confidence_level);
- for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
- ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
- local_event->phrase_extras[i].levels[j].user_id,
- local_event->phrase_extras[i].levels[j].level);
- }
- }
-
- ALOGI("%s:[%d]", __func__, st_ses->sm_handle);
-
- ALOGV("%s:[%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
- "num_phrases=%d id=%d", __func__,
- st_ses->sm_handle, local_event->common.status, local_event->common.type,
- local_event->common.model, local_event->common.capture_available,
- local_event->num_phrases, local_event->phrase_extras[0].id);
-
- *event = local_event;
- return 0;
-
-exit:
-
- if (local_event)
- free(local_event);
- return status;
-}
-
-/*
- * This function handles detection payloads in the format of the DSP's
- * legacy (non-generic) detection event.
- */
-static int process_detection_event_keyphrase(
- st_session_t *st_ses, int detect_status,
- void *payload, size_t payload_size,
- struct sound_trigger_phrase_recognition_event **event)
-{
- st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
- unsigned int i, j;
- int status = 0;
- struct sound_trigger_phrase_recognition_event *local_event = NULL;
- size_t opaque_size = 0;
- uint8_t *opaque_data = NULL, *payload_ptr = NULL;
- struct st_param_header *param_hdr = NULL;
- st_arm_second_stage_t *st_sec_stage;
- struct listnode *node = NULL, *tmp_node = NULL;
- struct st_keyword_indices_info *kw_indices = NULL;
- struct st_timestamp_info *timestamps = NULL;
- bool enable_kw_indices = false;
-
- if ((st_ses->rc_config->data_size > CUSTOM_CONFIG_OPAQUE_DATA_SIZE) &&
- st_ses->vendor_uuid_info->is_qcva_uuid) {
- /*
- * This logic is for the updated opaque data format. Sound trigger recognition
- * event APIs are filled along with the opaque data's confidence levels, keyword
- * indices, and timestamp parameters.
- */
- opaque_size = (2 * sizeof(struct st_param_header)) +
- sizeof(struct st_timestamp_info);
- if (st_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002)
- opaque_size += sizeof(struct st_confidence_levels_info);
- else
- opaque_size += sizeof(struct st_confidence_levels_info_v2);
-
- if (st_ses->enable_second_stage) {
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
- enable_kw_indices = true;
- opaque_size += sizeof(struct st_param_header) +
- sizeof(struct st_keyword_indices_info);
- break;
- }
- }
- }
-
- local_event = calloc(1,
- sizeof(struct sound_trigger_phrase_recognition_event) + opaque_size);
- if (!local_event) {
- ALOGE("%s: local_event allocation failed, opaque data size = %d", __func__,
- (unsigned int)opaque_size);
- return -ENOMEM;
- }
-
- local_event->num_phrases = st_ses->rc_config->num_phrases;
- local_event->common.data_offset = sizeof(struct sound_trigger_phrase_recognition_event);
- local_event->common.data_size = opaque_size;
- opaque_data = (uint8_t *)local_event + local_event->common.data_offset;
- if ((st_ses->exec_mode == ST_EXEC_MODE_CPE) && st_ses->stdev->is_gcs) {
- payload_ptr = (uint8_t *)payload + 2;
- } else if ((st_ses->exec_mode == ST_EXEC_MODE_ADSP) || !st_ses->stdev->is_gcs) {
- payload_ptr = (uint8_t *)payload;
- } else {
- ALOGE("%s: Invalid execution mode, exiting", __func__);
- status = -EINVAL;
- goto err_exit;
- }
-
- /* Pack the opaque data confidence levels structure */
- param_hdr = (struct st_param_header *)opaque_data;
- param_hdr->key_id = ST_PARAM_KEY_CONFIDENCE_LEVELS;
- opaque_data += sizeof(struct st_param_header);
- if (st_ses->conf_levels_intf_version != CONF_LEVELS_INTF_VERSION_0002) {
- param_hdr->payload_size =
- sizeof(struct st_confidence_levels_info);
- } else {
- param_hdr->payload_size =
- sizeof(struct st_confidence_levels_info_v2);
- }
- memcpy(opaque_data, st_hw_ses->conf_levels_info,
- param_hdr->payload_size);
- pack_opaque_data_conf_levels(st_ses, (void *)opaque_data, payload_ptr);
- pack_recognition_event_conf_levels(st_ses, payload_ptr,
- local_event);
- opaque_data += param_hdr->payload_size;
-
- /* Pack the opaque data keyword indices structure */
- if (enable_kw_indices) {
- param_hdr = (struct st_param_header *)opaque_data;
- param_hdr->key_id = ST_PARAM_KEY_KEYWORD_INDICES;
- param_hdr->payload_size = sizeof(struct st_keyword_indices_info);
- opaque_data += sizeof(struct st_param_header);
- kw_indices = (struct st_keyword_indices_info *)opaque_data;
- kw_indices->version = 0x1;
-
- if (st_ses->enable_second_stage) {
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
- if (st_sec_stage->ss_info->sm_id == ST_SM_ID_SVA_CNN) {
- kw_indices->start_index = st_sec_stage->ss_session->kw_start_idx;
- kw_indices->end_index = st_sec_stage->ss_session->kw_end_idx;
- }
- }
- }
- opaque_data += sizeof(struct st_keyword_indices_info);
- }
-
- /* Pack the opaque data detection timestamp structure */
- param_hdr = (struct st_param_header *)opaque_data;
- param_hdr->key_id = ST_PARAM_KEY_TIMESTAMP;
- param_hdr->payload_size = sizeof(struct st_timestamp_info);
- opaque_data += sizeof(struct st_param_header);
- timestamps = (struct st_timestamp_info *)opaque_data;
- timestamps->version = 0x1;
- timestamps->first_stage_det_event_time =
- st_ses->hw_ses_current->first_stage_det_event_time;
- if (st_ses->enable_second_stage)
- timestamps->second_stage_det_event_time =
- st_ses->hw_ses_current->second_stage_det_event_time;
- opaque_data += sizeof(struct st_timestamp_info);
-
- ST_DBG_DECLARE(FILE *opaque_fd = NULL; static int opaque_cnt = 0);
- ST_DBG_FILE_OPEN_WR(opaque_fd, ST_DEBUG_DUMP_LOCATION,
- "detection_opaque_data", "bin", opaque_cnt++);
- ST_DBG_FILE_WRITE(opaque_fd, (opaque_data - opaque_size), opaque_size);
- ST_DBG_FILE_CLOSE(opaque_fd);
-
- } else {
- /* This logic is for the legacy opaque data format or third party vendors */
- if (st_ses->vendor_uuid_info &&
- st_ses->vendor_uuid_info->smlib_handle) {
- /* if smlib is present, get the event from it else send the
- DSP recieved payload as it is to App */
- /* TODO: checking is_gcs should be avoided here */
- if (st_ses->stdev->is_gcs &&
- ST_EXEC_MODE_CPE == st_ses->exec_mode &&
- !st_ses->hw_ses_current->is_generic_event) {
- ALOGD("%s: about to call generate_st_phrase_recognition_event_v2",
- __func__);
- status = st_ses->vendor_uuid_info->
- generate_st_phrase_recognition_event_v2(st_ses->sm_data,
- st_ses->rc_config, payload, payload_size, &local_event);
- } else {
- status = st_ses->vendor_uuid_info->
- generate_st_phrase_recognition_event(st_ses->sm_data,
- st_ses->rc_config, payload, payload_size, &local_event);
- }
-
- if (status) {
- ALOGW("%s: smlib fill recognition event failed, status %d",
- __func__, status);
- goto exit;
- }
- } else if (!st_ses->vendor_uuid_info &&
- st_ses->stdev->smlib_handle) {
- /* This is SVA non topology solution */
- /* TODO: checking is_gcs should be avoided here */
- if (st_ses->stdev->is_gcs) {
- status = st_ses->stdev->generate_st_phrase_recognition_event_v2(
- st_ses->sm_data, st_ses->rc_config, payload, payload_size,
- &local_event);
- } else {
- status = st_ses->stdev->generate_st_phrase_recognition_event(
- st_ses->sm_data, st_ses->rc_config, payload, payload_size,
- &local_event);
- }
-
- if (status) {
- ALOGW("%s: SVA smlib fill recognition event failed, status\
- %d", __func__, status);
- goto exit;
- }
- } else {
- local_event = calloc(1, sizeof(*local_event) + payload_size);
- if (!local_event) {
- ALOGE("%s: event allocation failed, size %zd", __func__,
- payload_size);
- status = -ENOMEM;
- goto exit;
- }
- memcpy(local_event->phrase_extras,
- st_ses->rc_config->phrases, st_ses->rc_config->num_phrases *
- sizeof(struct sound_trigger_phrase_recognition_extra));
- local_event->num_phrases = st_ses->rc_config->num_phrases;
- local_event->common.data_offset = sizeof(*local_event);
- local_event->common.data_size = payload_size;
- memcpy((char *)local_event + local_event->common.data_offset, payload,
- payload_size);
- }
- }
-
- /* fill the remaining recognition event parameters not specific
- to soundmodel lib */
- local_event->common.status = detect_status;
- local_event->common.type = st_ses->sm_data->common.type;
- local_event->common.model = st_ses->sm_handle;
- local_event->common.capture_available = st_ses->capture_requested;
- local_event->common.capture_delay_ms = 0;
- local_event->common.capture_preamble_ms = 0;
- local_event->common.audio_config.sample_rate =
- SOUND_TRIGGER_SAMPLING_RATE_16000;
- local_event->common.audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
- local_event->common.audio_config.channel_mask =
- audio_channel_in_mask_from_count(st_hw_ses->config.channels);
-
- for (i = 0; i < local_event->num_phrases; ++i) {
- ALOGV("%s: [%d] kw_id %d level %d", __func__, i,
- local_event->phrase_extras[i].id,
- local_event->phrase_extras[i].confidence_level);
- for (j = 0; j < local_event->phrase_extras[i].num_levels; ++j) {
- ALOGV("%s: [%d] user_id %d level %d ", __func__, i,
- local_event->phrase_extras[i].levels[j].user_id,
- local_event->phrase_extras[i].levels[j].level);
- }
- }
-
- ALOGI("%s:[%d]", __func__, st_ses->sm_handle);
-
- ALOGV("%s:[%d] status=%d, type=%d, model=%d, capture_avaiable=%d, "
- "num_phrases=%d id=%d", __func__,
- st_ses->sm_handle, local_event->common.status, local_event->common.type,
- local_event->common.model, local_event->common.capture_available,
- local_event->num_phrases, local_event->phrase_extras[0].id);
-
- *event = local_event;
- return 0;
-
-err_exit:
- if (local_event)
- free(local_event);
-
-exit:
- return status;
-}
-
-static int process_detection_event_generic(st_session_t *st_ses,
- int detect_status,
- void *payload, size_t payload_size,
- struct sound_trigger_recognition_event **event)
-{
- st_hw_session_t *st_hw_ses = st_ses->hw_ses_current;
- struct st_vendor_info *v_info = st_ses->vendor_uuid_info;
- int status = 0;
- struct sound_trigger_recognition_event *local_event = NULL;
-
- local_event = calloc(1, sizeof(*local_event) + payload_size);
- if (!local_event) {
- ALOGE("%s: event allocation failed, size %zd", __func__,
- payload_size);
- status = -ENOMEM;
- goto exit;
- }
-
- local_event->status = detect_status;
- local_event->type = st_ses->sm_type;
- local_event->model = st_ses->sm_handle;
- local_event->capture_available = st_ses->capture_requested;
- local_event->capture_delay_ms = 0;
- local_event->capture_preamble_ms = 0;
- local_event->audio_config.sample_rate = v_info ?
- v_info->sample_rate : SOUND_TRIGGER_SAMPLING_RATE_16000;
- local_event->audio_config.format = AUDIO_FORMAT_PCM_16_BIT;
- local_event->audio_config.channel_mask =
- audio_channel_in_mask_from_count(st_hw_ses->config.channels);
-
- local_event->data_offset = sizeof(*local_event);
- local_event->data_size = payload_size;
- memcpy((char *)local_event + local_event->data_offset,
- payload, payload_size);
-
- ALOGI("%s:[%d]", __func__, st_ses->sm_handle);
- ALOGV("%s:[%d] status=%d, type=%d, model=%d, capture_avaiable=%d",
- __func__, st_ses->sm_handle, local_event->status,
- local_event->type, local_event->model,
- local_event->capture_available);
-
- *event = local_event;
-
-exit:
- return status;
-}
-
-static inline int process_detection_event(st_session_t *st_ses,
- uint64_t timestamp __unused,
- int detect_status,
- void *payload, size_t payload_size,
- struct sound_trigger_recognition_event **event)
-{
- int ret;
- struct sound_trigger_phrase_recognition_event *phrase_event = NULL;
-
- *event = NULL;
- if (st_ses->sm_type == SOUND_MODEL_TYPE_KEYPHRASE) {
- if (sthw_extn_check_process_det_ev_support())
- ret = sthw_extn_process_detection_event_keyphrase(st_ses,
- timestamp, detect_status,
- payload, payload_size, &phrase_event);
- else if (st_ses->hw_ses_current->is_generic_event &&
- !st_ses->vendor_uuid_info->is_qcmd_uuid)
- ret = process_detection_event_keyphrase_v2(st_ses, detect_status,
- payload, payload_size,
- &phrase_event);
- else
- ret = process_detection_event_keyphrase(st_ses, detect_status,
- payload, payload_size,
- &phrase_event);
- if (phrase_event)
- *event = &phrase_event->common;
- } else {
- ret = process_detection_event_generic(st_ses, detect_status, payload,
- payload_size, event);
- }
- return ret;
-}
-
-int st_session_load_sm(st_session_t *st_ses)
+int st_session_load_sm(st_session_t *stc_ses)
{
int status = 0;
- if (!st_ses)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
- /* SM is stored in the session by st_device, hence set NULL below */
- st_session_loadsm_payload_t payload = { NULL };
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_loadsm_payload_t payload = { .phrase_sm = stc_ses->phrase_sm };
st_session_ev_t ev = { .ev_id = ST_SES_EV_LOAD_SM,
- .payload.loadsm = payload };
-
- /*
- * no need to lock mutex when loading sm as session is just being
- * being created and handle not returned to caller yet
- */
- DISPATCH_EVENT(st_ses, ev, status);
- return status;
-}
-
-int st_session_unload_sm(st_session_t *st_ses)
-{
- int status = 0;
- if (!st_ses)
- return -EINVAL;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_UNLOAD_SM };
+ .payload.loadsm = payload, .stc_ses = stc_ses };
pthread_mutex_lock(&st_ses->lock);
DISPATCH_EVENT(st_ses, ev, status);
+ if (!status) {
+ prepapre_second_stage_for_client(stc_ses);
+ stc_ses->state = ST_STATE_LOADED;
+ }
pthread_mutex_unlock(&st_ses->lock);
return status;
}
-int st_session_start(st_session_t *st_ses)
+int st_session_unload_sm(st_session_t *stc_ses)
{
int status = 0;
- if (!st_ses)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_START };
-
- /* lock to serialize event handling */
- pthread_mutex_lock(&st_ses->lock);
- DISPATCH_EVENT(st_ses, ev, status);
- pthread_mutex_unlock(&st_ses->lock);
- return status;
-}
-
-int st_session_stop(st_session_t *st_ses)
-{
- int status = 0;
- if (!st_ses)
- return -EINVAL;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_STOP };
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = { .ev_id = ST_SES_EV_UNLOAD_SM, .stc_ses = stc_ses };
pthread_mutex_lock(&st_ses->lock);
DISPATCH_EVENT(st_ses, ev, status);
+ stop_second_stage_for_client(stc_ses);
+ stc_ses->state = ST_STATE_IDLE;
pthread_mutex_unlock(&st_ses->lock);
return status;
}
-int st_session_restart(st_session_t *st_ses)
+int st_session_start(st_session_t *stc_ses)
{
int status = 0;
- if (!st_ses)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_RESTART };
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = { .ev_id = ST_SES_EV_START, .stc_ses = stc_ses };
- /* lock to serialize event handling */
pthread_mutex_lock(&st_ses->lock);
+ if (stc_ses->pending_stop) {
+ ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
+ stc_ses->sm_handle);
+ hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
+ stc_ses->pending_stop = false;
+ }
+
DISPATCH_EVENT(st_ses, ev, status);
+ if (!status) {
+ reg_hal_event_session(stc_ses, st_ses->hw_ses_current);
+ start_second_stage_for_client(stc_ses);
+ stc_ses->state = ST_STATE_ACTIVE;
+ }
pthread_mutex_unlock(&st_ses->lock);
return status;
}
-int st_session_ssr_offline(st_session_t *st_ses,
+int st_session_stop(st_session_t *stc_ses)
+{
+ int status = 0;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return -EINVAL;
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = { .ev_id = ST_SES_EV_STOP, .stc_ses = stc_ses };
+
+ pthread_mutex_lock(&st_ses->lock);
+ DISPATCH_EVENT(st_ses, ev, status);
+ dereg_hal_event_session(stc_ses);
+ stc_ses->pending_stop = false;
+ stc_ses->state = ST_STATE_LOADED;
+ pthread_mutex_unlock(&st_ses->lock);
+
+ return status;
+}
+
+int st_session_restart(st_session_t *stc_ses)
+{
+ int status = 0;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return -EINVAL;
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = { .ev_id = ST_SES_EV_RESTART, .stc_ses = stc_ses };
+
+ pthread_mutex_lock(&st_ses->lock);
+ if (stc_ses->pending_stop) {
+ ALOGV("%s:[c%d] cancel ST_SES_EV_DEFERRED_STOP", __func__,
+ stc_ses->sm_handle);
+ hw_session_notifier_cancel(stc_ses->sm_handle, ST_SES_EV_DEFERRED_STOP);
+ stc_ses->pending_stop = false;
+ }
+
+ DISPATCH_EVENT(st_ses, ev, status);
+ if (!status) {
+ start_second_stage_for_client(stc_ses);
+ stc_ses->state = ST_STATE_ACTIVE;
+ } else {
+ dereg_hal_event_session(stc_ses);
+ stc_ses->state = ST_STATE_LOADED;
+ }
+ pthread_mutex_unlock(&st_ses->lock);
+
+ return status;
+}
+
+int st_session_ssr_offline(st_session_t *stc_ses,
enum ssr_event_status ssr_type)
{
int status = 0;
- if (!st_ses)
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_OFFLINE,
- .payload.ssr = ssr_type };
+ .payload.ssr = ssr_type, .stc_ses = stc_ses };
pthread_mutex_lock(&st_ses->lock);
/*
@@ -2597,9 +5510,9 @@
((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
(SND_CARD_STATUS_OFFLINE == ssr_type)) ||
((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
- (((ST_EXEC_MODE_CPE == st_ses->ssr_transit_exec_mode) &&
+ (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
(SND_CARD_STATUS_OFFLINE == ssr_type)) ||
- ((ST_EXEC_MODE_ADSP == st_ses->ssr_transit_exec_mode) &&
+ ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
(CPE_STATUS_OFFLINE == ssr_type)))) ||
((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
(SND_CARD_STATUS_OFFLINE == ssr_type) &&
@@ -2610,15 +5523,17 @@
return status;
}
-int st_session_ssr_online(st_session_t *st_ses,
+int st_session_ssr_online(st_session_t *stc_ses,
enum ssr_event_status ssr_type)
{
int status = 0;
- if (!st_ses)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
st_session_ev_t ev = { .ev_id = ST_SES_EV_SSR_ONLINE,
- .payload.ssr = ssr_type };
+ .payload.ssr = ssr_type, .stc_ses = stc_ses };
pthread_mutex_lock(&st_ses->lock);
/*
@@ -2637,37 +5552,45 @@
((ST_EXEC_MODE_ADSP == st_ses->exec_mode) &&
(SND_CARD_STATUS_ONLINE == ssr_type)) ||
((ST_EXEC_MODE_NONE == st_ses->exec_mode) &&
- (((ST_EXEC_MODE_CPE == st_ses->ssr_transit_exec_mode) &&
+ (((ST_EXEC_MODE_CPE == stc_ses->ssr_transit_exec_mode) &&
(SND_CARD_STATUS_ONLINE == ssr_type)) ||
- ((ST_EXEC_MODE_ADSP == st_ses->ssr_transit_exec_mode) &&
+ ((ST_EXEC_MODE_ADSP == stc_ses->ssr_transit_exec_mode) &&
(CPE_STATUS_ONLINE == ssr_type)))) ||
((ST_EXEC_MODE_CPE == st_ses->exec_mode) &&
(SND_CARD_STATUS_ONLINE == ssr_type) &&
(st_ses->stdev->bg_kwd)))
DISPATCH_EVENT(st_ses, ev, status);
+
pthread_mutex_unlock(&st_ses->lock);
return status;
}
-int st_session_pause(st_session_t *st_ses)
+int st_session_pause(st_session_t *stc_ses)
{
int status = 0;
- if (!st_ses)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_PAUSE };
- pthread_mutex_lock(&st_ses->lock);
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = { .ev_id = ST_SES_EV_PAUSE, .stc_ses = stc_ses };
+
+ pthread_mutex_lock(&stc_ses->lock);
DISPATCH_EVENT(st_ses, ev, status);
- pthread_mutex_unlock(&st_ses->lock);
+ pthread_mutex_unlock(&stc_ses->lock);
return status;
}
-int st_session_resume(st_session_t *st_ses)
+int st_session_resume(st_session_t *stc_ses)
{
int status = 0;
- if (!st_ses)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_RESUME };
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = { .ev_id = ST_SES_EV_RESUME, .stc_ses = stc_ses };
pthread_mutex_lock(&st_ses->lock);
DISPATCH_EVENT(st_ses, ev, status);
@@ -2675,41 +5598,70 @@
return status;
}
-int st_session_disable_device(st_session_t *st_ses)
+int st_session_disable_device(st_session_t *stc_ses)
{
int status = 0;
- if (!st_ses)
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = {.ev_id = ST_SES_EV_SET_DEVICE,
+ .payload.enable = false, .stc_ses = stc_ses};
+
+ pthread_mutex_lock(&st_ses->lock);
+ /*
+ * Avoid dispatching for each attached multi-client, instead
+ * defer it until last client
+ */
+ stc_ses->pending_set_device = true;
+ if (is_any_client_not_pending_set_device(st_ses)) {
+ pthread_mutex_unlock(&st_ses->lock);
+ return status;
+ }
+ reset_clients_pending_set_device(st_ses);
+
+ DISPATCH_EVENT(st_ses, ev, status);
+ pthread_mutex_unlock(&st_ses->lock);
+ return status;
+}
+
+int st_session_enable_device(st_session_t *stc_ses)
+{
+ int status = 0;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return -EINVAL;
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
st_session_ev_t ev = { .ev_id = ST_SES_EV_SET_DEVICE,
- .payload.enable = false };
+ .payload.enable = true, .stc_ses = stc_ses };
pthread_mutex_lock(&st_ses->lock);
+ /*
+ * Avoid dispatching for each attached multi-client, instead
+ * defer it until last client
+ */
+ stc_ses->pending_set_device = true;
+ if (is_any_client_not_pending_set_device(st_ses)) {
+ pthread_mutex_unlock(&st_ses->lock);
+ return status;
+ }
+ reset_clients_pending_set_device(st_ses);
+
DISPATCH_EVENT(st_ses, ev, status);
pthread_mutex_unlock(&st_ses->lock);
return status;
}
-int st_session_enable_device(st_session_t *st_ses)
+bool st_session_is_detected(st_session_t *stc_ses)
{
- int status = 0;
+ bool ret = false;
- if (!st_ses)
- return -EINVAL;
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return ret;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_SET_DEVICE,
- .payload.enable = true };
-
- pthread_mutex_lock(&st_ses->lock);
- DISPATCH_EVENT(st_ses, ev, status);
- pthread_mutex_unlock(&st_ses->lock);
- return status;
-}
-
-bool st_session_is_detected(st_session_t *st_ses)
-{
- bool ret;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
pthread_mutex_lock(&st_ses->lock);
ret = (st_ses->current_state == detected_state_fn) ? true : false;
@@ -2718,9 +5670,14 @@
return ret;
}
-bool st_session_is_active(st_session_t *st_ses)
+bool st_session_is_active(st_session_t *stc_ses)
{
- bool ret;
+ bool ret = false;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return ret;
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
pthread_mutex_lock(&st_ses->lock);
ret = (st_ses->current_state == active_state_fn) ? true : false;
@@ -2729,9 +5686,14 @@
return ret;
}
-bool st_session_is_buffering(st_session_t *st_ses)
+bool st_session_is_buffering(st_session_t *stc_ses)
{
- bool ret;
+ bool ret = false;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return ret;
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
pthread_mutex_lock(&st_ses->lock);
ret = (st_ses->current_state == buffering_state_fn) ? true : false;
@@ -2740,9 +5702,14 @@
return ret;
}
-bool st_session_is_ssr_state(st_session_t *st_ses)
+bool st_session_is_ssr_state(st_session_t *stc_ses)
{
- bool ret;
+ bool ret = false;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return ret;
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
pthread_mutex_lock(&st_ses->lock);
ret = (st_ses->current_state == ssr_state_fn) ? true : false;
@@ -2751,31 +5718,40 @@
return ret;
}
-int st_session_read_pcm(st_session_t *st_ses, uint8_t *buff,
+int st_session_read_pcm(st_session_t *stc_ses, uint8_t *buff,
size_t buff_size, size_t *read_size)
{
int status = 0;
- if (!st_ses || !buff || buff_size == 0 || read_size == 0)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses || !buff || buff_size == 0 ||
+ read_size == 0)
return -EINVAL;
- st_session_readpcm_payload_t payload = { .out_buff = buff,
- .out_buff_size = buff_size, .actual_read_size = read_size };
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_readpcm_payload_t payload = {.out_buff = buff,
+ .out_buff_size = buff_size, .actual_read_size = read_size};
- st_session_ev_t ev = { .ev_id = ST_SES_EV_READ_PCM,
- .payload.readpcm = payload };
+ st_session_ev_t ev = {.ev_id = ST_SES_EV_READ_PCM,
+ .payload.readpcm = payload, .stc_ses = stc_ses};
- /* Do not lock when handling this event, this event
- can go in parallel with other events */
+ /*
+ * Do not lock when handling this event, this event
+ * can go in parallel with other events as multiple
+ * sessions can buffer in parallel.
+ */
DISPATCH_EVENT(st_ses, ev, status);
return status;
}
-int st_session_stop_lab(st_session_t *st_ses)
+int st_session_stop_lab(st_session_t *stc_ses)
{
int status = 0;
- if (!st_ses)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_END_BUFFERING };
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = {.ev_id = ST_SES_EV_END_BUFFERING, .stc_ses = stc_ses};
pthread_mutex_lock(&st_ses->lock);
DISPATCH_EVENT(st_ses, ev, status);
@@ -2783,32 +5759,69 @@
return status;
}
-int st_session_set_exec_mode(st_session_t *st_ses, st_exec_mode_t exec)
+int st_session_set_exec_mode(st_session_t *stc_ses, st_exec_mode_t exec)
{
int status = 0;
- if (!st_ses)
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
ALOGV("%s: exec mode %d", __func__, exec);
- st_session_ev_t ev = { .ev_id = ST_SES_EV_SET_EXEC_MODE,
- .payload.exec_mode = exec };
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = {.ev_id = ST_SES_EV_SET_EXEC_MODE,
+ .payload.exec_mode = exec, .stc_ses = stc_ses};
pthread_mutex_lock(&st_ses->lock);
- DISPATCH_EVENT(st_ses, ev, status);
+ if (st_ses->enable_trans)
+ DISPATCH_EVENT(st_ses, ev, status);
pthread_mutex_unlock(&st_ses->lock);
return status;
}
-int st_session_send_custom_chmix_coeff(st_session_t *st_ses, char *str)
+int st_session_update_recongition_config(st_session_t *stc_ses)
+{
+
+ int status = 0;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return -EINVAL;
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+
+ pthread_mutex_lock(&st_ses->lock);
+ status = update_hw_config_on_start(stc_ses, st_ses->hw_ses_current);
+ pthread_mutex_unlock(&st_ses->lock);
+ return status;
+
+}
+
+int st_session_get_preroll(st_session_t *stc_ses)
+{
+ int val = 0;
+
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
+ return 0;
+
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+
+ pthread_mutex_lock(&st_ses->lock);
+ val = st_ses->hw_ses_current->sthw_cfg.client_req_preroll;
+ pthread_mutex_unlock(&st_ses->lock);
+
+ return val;
+}
+
+int st_session_send_custom_chmix_coeff(st_session_t *stc_ses, char *str)
{
int status = 0;
- if (!st_ses)
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
st_session_ev_t ev = { .ev_id = ST_SES_EV_SEND_CHMIX_COEFF,
- .payload.chmix_coeff_str = str};
+ .payload.chmix_coeff_str = str, .stc_ses = stc_ses};
pthread_mutex_lock(&st_ses->lock);
if (ST_EXEC_MODE_ADSP == st_ses->exec_mode)
@@ -2817,32 +5830,35 @@
return status;
}
-int st_session_get_config(st_session_t *st_ses, struct pcm_config *config)
+int st_session_get_config(st_session_t *stc_ses, struct pcm_config *config)
{
- if (!st_ses)
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
- st_hw_session_t *hw_ses = st_ses->hw_ses_current;
- memcpy(config, &hw_ses->config, sizeof(struct pcm_config));
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+
+ pthread_mutex_lock(&st_ses->lock);
+ memcpy(config, &st_ses->hw_ses_current->config, sizeof(struct pcm_config));
+ pthread_mutex_unlock(&st_ses->lock);
return 0;
}
-int st_session_get_param_data(st_session_t *st_ses, const char *param,
- void *payload, size_t payload_size,
- size_t *param_data_size)
+int st_session_get_param_data(st_session_t *stc_ses, const char *param,
+ void *payload, size_t payload_size, size_t *param_data_size)
{
int status = 0;
- if (!st_ses)
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
st_session_getparam_payload_t getparam_payload = { .param = param,
.payload = payload,
.payload_size = payload_size,
.param_data_size = param_data_size};
st_session_ev_t ev = { .ev_id = ST_SES_EV_GET_PARAM_DATA,
- .payload.getparam = getparam_payload};
+ .payload.getparam = getparam_payload, .stc_ses = stc_ses};
pthread_mutex_lock(&st_ses->lock);
/* Currently get param data supported for ARM & ADSP mode */
@@ -2854,310 +5870,105 @@
return status;
}
-/*
- * If the keyword detection session detects before the user verification
- * session, signal to process user verification. If the keyword detection
- * session rejects before the user verification session, signal to stop
- * processing user verification.
- */
-static void handle_vop_pending_detection(st_arm_ss_session_t *ss_session,
- unsigned int det_status,
- unsigned int kw_det_buff_sz)
+int st_session_ss_init(st_session_t *stc_ses)
{
- if (det_status & KEYWORD_DETECTION_SUCCESS) {
- if (kw_det_buff_sz > ss_session->unread_bytes)
- ss_session->buff_sz = kw_det_buff_sz;
- else
- ss_session->buff_sz = ss_session->unread_bytes;
-
- /*
- * It is possible that VOP started processing by already consuming
- * data from unread_bytes while CNN detects. In this case, it does
- * not need to be signaled.
- */
- if (ss_session->unread_bytes >= ss_session->buff_sz) {
- ALOGD("%s: Processing UV due to KW detection success", __func__);
- pthread_cond_signal(&ss_session->cond);
- }
- } else if (det_status & KEYWORD_DETECTION_REJECT) {
- ss_session->exit_buffering = true;
- ALOGD("%s: Exiting from UV due to KW detection rejection", __func__);
- pthread_cond_signal(&ss_session->cond);
- }
-}
-
-/*
- * If the user verification session rejects before the keyword detection
- * session, signal to stop processing keyword detection.
- */
-static void handle_cnn_pending_detection(st_arm_ss_session_t *ss_session,
- unsigned int det_status)
-{
- if (det_status & USER_VERIFICATION_REJECT) {
- ss_session->exit_buffering = true;
- ALOGD("%s: Exiting from KW detection due to UV rejection", __func__);
- pthread_cond_signal(&ss_session->cond);
- }
-}
-
-/*
- * This thread handles detection events from the second stage sessions
- * and aggregates them into 1 final decision. It will call the client callback
- * or restart the first stage session based on this decision.
- */
-static void *aggregator_thread_loop(void *st_session)
-{
- st_session_t *st_ses = (st_session_t *)st_session;
- recognition_callback_t callback = NULL;
- struct listnode *node = NULL, *tmp_node = NULL;
+ int status = 0;
+ struct listnode *node = NULL;
st_arm_second_stage_t *st_sec_stage = NULL;
- int status = 0, lock_status = 0;
- unsigned int kw_det_buff_sz = 0, det_status = 0;
- struct timespec tspec = {0};
- struct sound_trigger_recognition_event *event = NULL;
- st_session_ev_t restart_ev = { .ev_id = ST_SES_EV_RESTART };
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
- ALOGV("%s: Enter", __func__);
-
- pthread_mutex_lock(&st_ses->ss_detections_lock);
- while (!st_ses->exit_aggregator_loop) {
- det_status = 0;
- lock_status = 0;
- ALOGV("%s: waiting on cond", __func__);
- pthread_cond_wait(&st_ses->ss_detections_cond,
- &st_ses->ss_detections_lock);
- ALOGV("%s: done waiting on cond", __func__);
- if (st_ses->exit_aggregator_loop) {
- pthread_mutex_unlock(&st_ses->ss_detections_lock);
- return NULL;
- }
-
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t,
- list_node);
-
- pthread_mutex_lock(&st_sec_stage->ss_session->lock);
- det_status |= st_sec_stage->ss_session->det_status;
- if (st_sec_stage->ss_session->det_status ==
- KEYWORD_DETECTION_SUCCESS)
- kw_det_buff_sz = st_sec_stage->ss_session->bytes_processed;
- pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
- }
-
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
- st_sec_stage = node_to_item(node, st_arm_second_stage_t,
- list_node);
-
- pthread_mutex_lock(&st_sec_stage->ss_session->lock);
- if ((st_sec_stage->ss_info->sm_detection_type ==
- ST_SM_TYPE_USER_VERIFICATION) &&
- (det_status & USER_VERIFICATION_PENDING)) {
- handle_vop_pending_detection(st_sec_stage->ss_session,
- det_status, kw_det_buff_sz);
- } else if ((st_sec_stage->ss_info->sm_detection_type ==
- ST_SM_TYPE_KEYWORD_DETECTION) &&
- (det_status & KEYWORD_DETECTION_PENDING)) {
- handle_cnn_pending_detection(st_sec_stage->ss_session,
- det_status);
- }
- pthread_mutex_unlock(&st_sec_stage->ss_session->lock);
- }
-
- if (!IS_SS_DETECTION_PENDING(det_status)) {
- pthread_mutex_lock(&st_ses->lock);
- /*
- * If the client stops before 2nd stage finishes processing, or a
- * transition is in progress, the detection event should not be
- * handled.
- */
- if ((st_ses->current_state != buffering_state_fn) ||
- (st_ses->exec_mode == ST_EXEC_MODE_NONE)) {
- ALOGW("%s: First stage is not in a valid state, continuing",
- __func__);
- pthread_mutex_unlock(&st_ses->lock);
- continue;
- }
- if (IS_SS_DETECTION_SUCCESS(det_status)) {
- clock_gettime(CLOCK_MONOTONIC, &tspec);
- st_ses->hw_ses_current->second_stage_det_event_time =
- get_current_time_ns();
- ATRACE_ASYNC_END("sthal: detection success",
- st_ses->sm_handle);
- status = process_detection_event(st_ses,
- st_ses->det_session_ev->payload.detected.timestamp,
- st_ses->det_session_ev->payload.detected.detect_status,
- st_ses->det_session_ev->payload.detected.detect_payload,
- st_ses->det_session_ev->payload.detected.payload_size,
- &event);
- if (status || !event) {
- ALOGE("%s:[%d] process_detection_event failed err %d",
- __func__, st_ses->sm_handle, status);
- /* Stop buffering if this is not a successful detection and
- LAB is triggered in hw automatically */
- st_ses->hw_ses_current->fptrs->stop_buffering(
- st_ses->hw_ses_current, st_ses->lab_enabled);
-
- pthread_mutex_unlock(&st_ses->lock);
- if (event) {
- free(event);
- event = NULL;
- }
- goto exit;
- }
- callback = st_ses->callback;
- ALOGD("%s: Second stage detected successfully"
- ", calling client callback", __func__);
- st_ses->sent_detection_to_client = true;
- pthread_mutex_unlock(&st_ses->lock);
- ATRACE_BEGIN("sthal: client detection callback");
- callback(event, st_ses->cookie);
- ATRACE_END();
-
- /*
- * The client could unload the sound model during the callback,
- * which would join this thread and wait for this thread exit
- * as part of st_session_deinit() with st_session_lock held. By
- * this time, the state is also moved to idle. To avoid
- * deadlock, upon return from client callback, try acquiring
- * lock only if not in idle state, else exit right away.
- */
- do {
- lock_status = pthread_mutex_trylock(&st_ses->lock);
- } while (lock_status && (st_ses->current_state !=
- idle_state_fn));
-
- if (st_ses->current_state == idle_state_fn) {
- ALOGV("%s:[%d] client unloaded after callback"
- ", lock status %d", __func__, st_ses->sm_handle,
- lock_status);
- if (!lock_status)
- pthread_mutex_unlock(&st_ses->lock);
- free(event);
- event = NULL;
- goto exit;
- }
-
- if (!st_ses->capture_requested)
- st_ses->hw_ses_current->fptrs->stop_buffering(
- st_ses->hw_ses_current, st_ses->lab_enabled);
- free(event);
- event = NULL;
- } else {
- ATRACE_ASYNC_END("sthal: detection reject",
- st_ses->sm_handle);
- ALOGD("%s: Second stage did NOT detect, restarting st_session",
- __func__);
- st_ses->hw_ses_current->fptrs->stop_buffering(
- st_ses->hw_ses_current, st_ses->lab_enabled);
- DISPATCH_EVENT(st_ses, restart_ev, status);
- }
- pthread_mutex_unlock(&st_ses->lock);
- } else {
- ALOGV("%s: There is a second stage session pending, continuing",
- __func__);
- }
- }
-exit:
- pthread_mutex_unlock(&st_ses->ss_detections_lock);
- ALOGV("%s: Exit", __func__);
- return NULL;
-}
-
-static void init_det_event_aggregator(st_session_t *st_ses)
-{
- int status = 0;
- pthread_condattr_t attr;
-
- st_ses->exit_aggregator_loop = false;
- pthread_mutex_init(&(st_ses->ss_detections_lock), NULL);
- pthread_condattr_init(&attr);
- pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
- pthread_cond_init(&(st_ses->ss_detections_cond), &attr);
- pthread_condattr_destroy(&attr);
- status = pthread_create(&st_ses->aggregator_thread, NULL,
- aggregator_thread_loop, st_ses);
- if (status)
- ALOGE("%s: Error creating aggregator thread. status = %d",
- __func__, status);
-
-}
-
-static void destroy_det_event_aggregator(st_session_t *st_ses)
-{
- int status = 0;
-
- st_ses->exit_aggregator_loop = true;
- pthread_mutex_lock(&st_ses->ss_detections_lock);
- pthread_cond_signal(&st_ses->ss_detections_cond);
- pthread_mutex_unlock(&st_ses->ss_detections_lock);
- status = pthread_join(st_ses->aggregator_thread, NULL);
- if (status)
- ALOGE("%s: Error joining aggregator thread. status = %d",
- __func__, status);
- pthread_cond_destroy(&(st_ses->ss_detections_cond));
- pthread_mutex_destroy(&(st_ses->ss_detections_lock));
-}
-
-int st_session_ss_init(st_session_t *st_ses)
-{
- int status = 0;
- struct listnode *node = NULL, *tmp_node = NULL;
- st_arm_second_stage_t *st_sec_stage = NULL;
-
- init_det_event_aggregator(st_ses);
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
+ list_for_each(node, &stc_ses->second_stage_list) {
st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
status = st_second_stage_module_init(st_sec_stage,
(void *)st_sec_stage->ss_info->lib_name);
if (status) {
- ALOGE("%s: initializing second stage session failed %d",
- __func__, status);
+ ALOGE("%s:[c%d] initializing second stage session failed %d",
+ __func__, stc_ses->sm_handle, status);
goto ss_cleanup;
}
}
+ pthread_mutex_lock(&st_ses->lock);
+ if (st_ses->aggregator_thread_created) {
+ pthread_mutex_unlock(&st_ses->lock);
+ return 0;
+ }
+ /*
+ * Aggregator is not maintatined per client as there is only one
+ * client keyword detection happens at a time in multi-client scenario.
+ * Instead use single aggregator thread at proxy level, processing the
+ * second stage for detected client at run time.
+ */
+ init_det_event_aggregator(st_ses);
+
st_ses->det_session_ev = calloc(1, sizeof(st_session_ev_t));
if (!st_ses->det_session_ev) {
ALOGE("%s: Failed to allocate st_session_ev_t, exiting", __func__);
status = -ENOMEM;
goto ss_cleanup;
}
+ pthread_mutex_unlock(&st_ses->lock);
return 0;
ss_cleanup:
destroy_det_event_aggregator(st_ses);
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
+ list_for_each(node, &stc_ses->second_stage_list) {
st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
st_second_stage_module_deinit(st_sec_stage);
}
+ pthread_mutex_unlock(&st_ses->lock);
return status;
}
-int st_session_ss_deinit(st_session_t *st_ses)
+int st_session_ss_deinit(st_session_t *stc_ses)
{
- struct listnode *node = NULL, *tmp_node = NULL;
+ struct listnode *node = NULL;
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
st_arm_second_stage_t *st_sec_stage = NULL;
+ st_session_t *c_ses = NULL;
+ bool aggregator_needed = false;
- destroy_det_event_aggregator(st_ses);
- list_for_each_safe(node, tmp_node, &st_ses->second_stage_list) {
+ list_for_each(node, &stc_ses->second_stage_list) {
st_sec_stage = node_to_item(node, st_arm_second_stage_t, list_node);
st_second_stage_module_deinit(st_sec_stage);
}
+ pthread_mutex_lock(&st_ses->lock);
+ if (!st_ses->aggregator_thread_created) {
+ pthread_mutex_unlock(&st_ses->lock);
+ return 0;
+ }
+ /* If other client has second stage enabled, keep the aggregator */
+ list_for_each(node, &st_ses->clients_list) {
+ c_ses = node_to_item(node, st_session_t, hw_list_node);
+ if (c_ses != stc_ses && !list_empty(&c_ses->second_stage_list)) {
+ aggregator_needed = true;
+ break;
+ }
+ }
+ if (aggregator_needed) {
+ pthread_mutex_unlock(&st_ses->lock);
+ return 0;
+ }
+
+ destroy_det_event_aggregator(st_ses);
+
if (st_ses->det_session_ev)
free(st_ses->det_session_ev);
+ pthread_mutex_unlock(&st_ses->lock);
return 0;
}
-int st_session_request_detection(st_session_t *st_ses)
+int st_session_request_detection(st_session_t *stc_ses)
{
int status = 0;
- if (!st_ses)
+ if (!stc_ses || !stc_ses->hw_proxy_ses)
return -EINVAL;
- st_session_ev_t ev = { .ev_id = ST_SES_EV_REQUEST_DET };
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+ st_session_ev_t ev = {.ev_id = ST_SES_EV_REQUEST_DET, .stc_ses = stc_ses};
/* lock to serialize event handling */
pthread_mutex_lock(&st_ses->lock);
@@ -3166,28 +5977,33 @@
return status;
}
-int st_session_init(st_session_t *st_ses, struct sound_trigger_device *stdev,
+int st_session_init(st_session_t *stc_ses, struct sound_trigger_device *stdev,
st_exec_mode_t exec_mode, sound_model_handle_t sm_handle)
{
int status = 0;
- struct st_vendor_info *v_info;
+ struct st_vendor_info *v_info = NULL;
+ st_proxy_session_t *st_ses = NULL;
+ struct listnode *node = NULL;
+ struct st_session *c_ses = NULL;
pthread_mutexattr_t attr;
- if (!st_ses || !stdev) {
- status = -EINVAL;
- return status;
- }
- st_ses->stdev = stdev;
+ if (!stc_ses || !stdev)
+ return -EINVAL;
- /* caller must set vendor_uuid_info directly if present */
- v_info = st_ses->vendor_uuid_info;
+ st_ses = calloc(1, sizeof(st_proxy_session_t));
+ if (!st_ses) {
+ ALOGE("%s: hw_proxy_ses allocation failed", __func__);
+ return -ENOMEM;
+ }
+ st_ses->stdev = stc_ses->stdev = stdev;
+ v_info = stc_ses->vendor_uuid_info;
if (v_info && (EXEC_MODE_CFG_DYNAMIC == v_info->exec_mode_cfg)) {
st_ses->enable_trans = true;
-
if (stdev->is_gcs) {
/* alloc and init cpe session*/
- st_ses->hw_ses_cpe = (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
+ st_ses->hw_ses_cpe =
+ (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
if (!st_ses->hw_ses_cpe) {
status = -ENOMEM;
goto cleanup;
@@ -3201,7 +6017,8 @@
}
/* alloc and init adsp session*/
- st_ses->hw_ses_adsp = (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
+ st_ses->hw_ses_adsp =
+ (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
if (!st_ses->hw_ses_adsp) {
st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
status = -ENOMEM;
@@ -3218,7 +6035,8 @@
} else {
/* alloc and init cpe session*/
- st_ses->hw_ses_cpe = (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
+ st_ses->hw_ses_cpe =
+ (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
if (!st_ses->hw_ses_cpe) {
status = -ENOMEM;
goto cleanup;
@@ -3231,13 +6049,13 @@
goto cleanup;
}
/* alloc and init adsp session*/
- st_ses->hw_ses_adsp = (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
+ st_ses->hw_ses_adsp =
+ (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
if (!st_ses->hw_ses_adsp) {
status = -ENOMEM;
st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
goto cleanup;
}
-
status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
(void *)st_ses, ST_EXEC_MODE_ADSP, v_info, sm_handle, stdev);
if (status) {
@@ -3246,18 +6064,17 @@
goto cleanup;
}
}
-
/* set current hw_session */
if (exec_mode == ST_EXEC_MODE_CPE)
st_ses->hw_ses_current = st_ses->hw_ses_cpe;
else if (exec_mode == ST_EXEC_MODE_ADSP)
st_ses->hw_ses_current = st_ses->hw_ses_adsp;
-
} else if (v_info && (EXEC_MODE_CFG_CPE == v_info->exec_mode_cfg)) {
st_ses->enable_trans = false;
if (stdev->is_gcs) {
ALOGD("%s: initializing gcs hw session", __func__);
- st_ses->hw_ses_cpe = (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
+ st_ses->hw_ses_cpe =
+ (st_hw_session_t *)calloc(1, sizeof(st_hw_session_gcs_t));
if (!st_ses->hw_ses_cpe) {
status = -ENOMEM;
goto cleanup;
@@ -3270,7 +6087,8 @@
goto cleanup;
}
} else {
- st_ses->hw_ses_cpe = (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
+ st_ses->hw_ses_cpe =
+ (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
if (!st_ses->hw_ses_cpe) {
status = -ENOMEM;
goto cleanup;
@@ -3284,22 +6102,50 @@
}
}
st_ses->hw_ses_current = st_ses->hw_ses_cpe;
-
} else if (v_info && (EXEC_MODE_CFG_APE == v_info->exec_mode_cfg)) {
- st_ses->enable_trans = false;
- st_ses->hw_ses_adsp = (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
- if (!st_ses->hw_ses_adsp) {
- status = -ENOMEM;
- goto cleanup;
- }
- status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
- (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
- if (status) {
- ALOGE("%s: initializing lsm hw session failed %d",
- __func__, status);
- goto cleanup;
- }
- st_ses->hw_ses_current = st_ses->hw_ses_adsp;
+ /*
+ * Check for merge sound model support and return the existing hw
+ * session. If any other clients have already created it.
+ */
+ if (v_info->merge_fs_soundmodels) {
+ if (!v_info->is_qcva_uuid) {
+ ALOGE("%s: merge sound model not supported for non SVA engines",
+ __func__);
+ status = -ENOSYS;
+ goto cleanup;
+ }
+ list_for_each(node, &stdev->sound_model_list) {
+ c_ses = node_to_item(node, st_session_t, list_node);
+ if ((c_ses != stc_ses) &&
+ c_ses->vendor_uuid_info->is_qcva_uuid &&
+ c_ses->vendor_uuid_info->merge_fs_soundmodels) {
+ stc_ses->hw_proxy_ses = c_ses->hw_proxy_ses;
+ list_add_tail(&stc_ses->hw_proxy_ses->clients_list,
+ &stc_ses->hw_list_node);
+ ALOGD("%s: another client attached: h%d <-- c%d", __func__,
+ stc_ses->hw_proxy_ses->sm_handle, sm_handle);
+ free(st_ses);
+ st_ses = NULL;
+ break;
+ }
+ }
+ }
+ if (st_ses) { /* If no other client exist */
+ st_ses->hw_ses_adsp =
+ (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
+ if (!st_ses->hw_ses_adsp) {
+ status = -ENOMEM;
+ goto cleanup;
+ }
+ status = st_hw_sess_lsm_init(st_ses->hw_ses_adsp, hw_sess_cb,
+ (void *)st_ses, exec_mode, v_info, sm_handle, stdev);
+ if (status) {
+ ALOGE("%s: initializing lsm hw session failed %d",
+ __func__, status);
+ goto cleanup;
+ }
+ st_ses->hw_ses_current = st_ses->hw_ses_adsp;
+ }
} else if (v_info && (EXEC_MODE_CFG_ARM == v_info->exec_mode_cfg)) {
st_ses->enable_trans = false;
st_ses->hw_ses_arm = calloc(1, sizeof(st_hw_session_pcm_t));
@@ -3316,7 +6162,8 @@
}
st_ses->hw_ses_current = st_ses->hw_ses_arm;
} else if (!v_info) {
- st_ses->hw_ses_cpe = (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
+ st_ses->hw_ses_cpe =
+ (st_hw_session_t *)calloc(1, sizeof(st_hw_session_lsm_t));
if (!st_ses->hw_ses_cpe) {
status = -ENOMEM;
goto cleanup;
@@ -3332,46 +6179,81 @@
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&st_ses->lock, (const pthread_mutexattr_t *)&attr);
+ pthread_mutex_init(&stc_ses->lock, (const pthread_mutexattr_t *)&attr);
- st_ses->exec_mode = exec_mode;
- st_ses->sm_handle = sm_handle;
- st_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
- st_ses->lab_fp = NULL;
+ stc_ses->exec_mode = exec_mode;
+ stc_ses->sm_handle = sm_handle;
+ stc_ses->ssr_transit_exec_mode = ST_EXEC_MODE_NONE;
+ stc_ses->client_req_det_mode = ST_DET_UNKNOWN_MODE;
+ stc_ses->state = ST_STATE_IDLE;
- /* start in idle state */
- STATE_TRANSITION(st_ses, idle_state_fn);
+ if (st_ses) { /* Could get freed if other client exists */
+ st_ses ->vendor_uuid_info = v_info;
+ st_ses->exec_mode = exec_mode;
+ st_ses->sm_handle = sm_handle;
+ st_ses->lab_fp = NULL;
+ pthread_mutex_init(&st_ses->lock, (const pthread_mutexattr_t *)&attr);
+ stc_ses->hw_proxy_ses = st_ses;
+ list_init(&st_ses->clients_list);
+ list_add_tail(&st_ses->clients_list, &stc_ses->hw_list_node);
+ ALOGD("%s: client attached: h%d <-- c%d", __func__,
+ st_ses->sm_handle, sm_handle);
+
+ if (!stdev->ssr_offline_received) {
+ STATE_TRANSITION(st_ses, idle_state_fn);
+ } else {
+ STATE_TRANSITION(st_ses, ssr_state_fn);
+ status = 0;
+ }
+ }
return status;
cleanup:
- if (st_ses->hw_ses_cpe)
- free(st_ses->hw_ses_cpe);
- if (st_ses->hw_ses_adsp)
- free(st_ses->hw_ses_adsp);
+ if (st_ses) {
+ if (st_ses->hw_ses_cpe)
+ free(st_ses->hw_ses_cpe);
+ if (st_ses->hw_ses_adsp)
+ free(st_ses->hw_ses_adsp);
+ free(st_ses);
+ }
return status;
}
-int st_session_deinit(st_session_t *st_ses)
+int st_session_deinit(st_session_t *stc_ses)
{
+ st_proxy_session_t *st_ses = stc_ses->hw_proxy_ses;
+
+ pthread_mutex_lock(&st_ses->lock);
+ list_remove(&stc_ses->hw_list_node);
+ ALOGV("%s: client detatched: h%d <-- c%d", __func__, st_ses->sm_handle,
+ stc_ses->sm_handle);
+ if (stc_ses == st_ses->det_stc_ses)
+ st_ses->det_stc_ses = NULL;
+
+ if (!list_empty(&st_ses->clients_list)) {
+ pthread_mutex_unlock(&st_ses->lock);
+ return 0;
+ }
/* deinit cpe session */
if (st_ses->hw_ses_cpe) {
if (st_ses->stdev->is_gcs)
st_hw_sess_gcs_deinit(st_ses->hw_ses_cpe);
else
st_hw_sess_lsm_deinit(st_ses->hw_ses_cpe);
- free((void *)st_ses->hw_ses_cpe);
+ free(st_ses->hw_ses_cpe);
st_ses->hw_ses_cpe = NULL;
}
-
/* deinit adsp session */
if (st_ses->hw_ses_adsp) {
st_hw_sess_lsm_deinit(st_ses->hw_ses_adsp);
- free((void *)st_ses->hw_ses_adsp);
+ free(st_ses->hw_ses_adsp);
st_ses->hw_ses_adsp = NULL;
}
-
+ pthread_mutex_unlock(&st_ses->lock);
pthread_mutex_destroy(&st_ses->lock);
+ free(stc_ses->hw_proxy_ses);
+ stc_ses->hw_proxy_ses = NULL;
return 0;
}
diff --git a/st_session.h b/st_session.h
index 774e2a4..c37751b 100644
--- a/st_session.h
+++ b/st_session.h
@@ -41,8 +41,6 @@
#include "sound_trigger_platform.h"
#include "st_common_defs.h"
-#define MAX_STATE_NAME_LEN 50
-
/* Below are the states that can be requested from the client */
enum client_states_t {
ST_STATE_IDLE,
@@ -50,6 +48,12 @@
ST_STATE_ACTIVE
};
+typedef enum {
+ ST_DET_LOW_POWER_MODE,
+ ST_DET_HIGH_PERF_MODE,
+ ST_DET_UNKNOWN_MODE = 0xFF,
+} st_det_perf_mode_t;
+
typedef enum st_session_event_id {
ST_SES_EV_LOAD_SM,
ST_SES_EV_UNLOAD_SM,
@@ -76,12 +80,30 @@
typedef struct st_session_ev st_session_ev_t;
typedef struct st_session st_session_t;
-typedef int (*st_session_state_fn_t)(st_session_t*, st_session_ev_t *ev);
+typedef struct st_proxy_session st_proxy_session_t;
+typedef int (*st_proxy_session_state_fn_t)(st_proxy_session_t*,
+ st_session_ev_t *ev);
+
+struct sound_model_info {
+ unsigned char *sm_data;
+ unsigned int sm_size;
+ sound_trigger_sound_model_type_t sm_type;
+ unsigned int num_keyphrases;
+ unsigned int num_users;
+ char **keyphrases;
+ char **users;
+ char **cf_levels_kw_users;
+ unsigned char *cf_levels;
+ unsigned char *det_cf_levels;
+ unsigned int cf_levels_size;
+ bool sm_merged;
+};
struct st_session {
/* TODO: decouple device below from session */
struct listnode list_node;
struct listnode transit_list_node;
+ struct listnode hw_list_node;
struct sound_trigger_device *stdev;
struct st_vendor_info *vendor_uuid_info;
@@ -89,23 +111,49 @@
pthread_mutex_t lock;
st_exec_mode_t exec_mode;
st_exec_mode_t ssr_transit_exec_mode;
- bool enable_trans;
- struct sound_trigger_phrase_sound_model *sm_data;
+ struct sound_trigger_phrase_sound_model *phrase_sm;
struct sound_trigger_recognition_config *rc_config;
-
sound_trigger_sound_model_type_t sm_type;
-
sound_model_handle_t sm_handle;
recognition_callback_t callback;
void *cookie;
audio_io_handle_t capture_handle;
-
bool capture_requested;
- bool lab_enabled;
unsigned int num_phrases;
unsigned int num_users;
unsigned int recognition_mode;
+ enum client_states_t state;
+ bool paused;
+ bool pending_stop;
+ bool pending_load;
+ bool pending_set_device;
+ st_det_perf_mode_t client_req_det_mode;
+ unsigned int hist_buf_duration;
+ unsigned int preroll_duration;
+
+ struct listnode second_stage_list;
+ uint32_t conf_levels_intf_version;
+ void *st_conf_levels;
+
+ st_proxy_session_t *hw_proxy_ses;
+ struct sound_model_info sm_info;
+};
+
+struct st_proxy_session {
+ struct listnode clients_list; /* Attached client sessions */
+ struct sound_trigger_device *stdev;
+ struct st_vendor_info *vendor_uuid_info;
+
+ pthread_mutex_t lock;
+ st_exec_mode_t exec_mode;
+ bool enable_trans;
+
+ struct sound_trigger_recognition_config *rc_config;
+ sound_trigger_sound_model_type_t sm_type;
+ sound_model_handle_t sm_handle;
+ bool lab_enabled;
+ unsigned int recognition_mode;
st_hw_session_t *hw_ses_cpe; /* cpe hw session */
st_hw_session_t *hw_ses_adsp; /* adsp hw session */
@@ -113,29 +161,31 @@
st_hw_session_t *hw_ses_current; /* current hw session, this is set every
time there is an exec_mode change and points to one of the above
hw sessions */
- bool paused;
- bool hw_session_started;
- /* flag gets set if user restarts
- session right after detection before we have a chance to stop the
- session */
+ st_hw_session_t *hw_ses_prev; /* cached hw_ses_current,
+ used for WDSP<->ADSP transitions */
+ st_session_t *det_stc_ses; /* Current detected client */
- st_session_state_fn_t current_state;
- enum client_states_t client_req_state; /* holds the state that was requested by
- user this is used for recovering from SSR */
+ /*
+ * flag gets set if user restarts
+ * session right after detection before we have a chance to stop the
+ * session
+ */
+ bool hw_session_started;
+
+ st_proxy_session_state_fn_t current_state;
bool device_disabled;
- bool pending_stop;
pthread_t aggregator_thread;
pthread_mutex_t ss_detections_lock;
pthread_cond_t ss_detections_cond;
- bool sent_detection_to_client;
+ bool aggregator_thread_created;
bool exit_aggregator_loop;
- struct listnode second_stage_list;
bool enable_second_stage;
st_session_ev_t *det_session_ev;
int rc_config_update_counter;
bool detection_requested;
- uint32_t conf_levels_intf_version;
+
+ struct sound_model_info sm_info;
FILE *lab_fp;
};
@@ -169,7 +219,6 @@
enum ssr_event_status ssr_type);
int st_session_pause(st_session_t *st_ses);
int st_session_resume(st_session_t *st_ses);
-void st_session_query_state(st_session_t *st_ses, char *state_name, size_t len);
int st_session_restart(st_session_t *st_ses);
int st_session_send_custom_chmix_coeff(st_session_t *st_ses, char *str);
int st_session_get_config(st_session_t *st_ses, struct pcm_config *config);
@@ -182,10 +231,13 @@
int st_session_set_exec_mode(st_session_t *st_ses, st_exec_mode_t exec);
int st_session_get_param_data(st_session_t *st_ses, const char *param,
void *payload, size_t payload_size, size_t *param_data_size);
+int st_session_request_detection(st_session_t *st_ses);
+int st_session_update_recongition_config(st_session_t *st_ses);
+int st_session_get_preroll(st_session_t *st_ses);
+
int process_detection_event_keyphrase_v2(
- st_session_t *st_ses, int detect_status,
+ st_proxy_session_t *st_ses, int detect_status,
void *payload, size_t payload_size,
struct sound_trigger_phrase_recognition_event **event);
-int st_session_request_detection(st_session_t *st_ses);
#endif /* ST_SESSION_H */