/* * Copyright (C) 2018 "IoT.bzh" * Author Jonathan Aillet * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include #include #include #include "4a-hal-utilities-data.h" #include "4a-hal-utilities-hal-streams-handler.h" #include "4a-internals-hal-mixer-link.h" #include "4a-internals-hal-cb.h" /******************************************************************************* * Internals HAL handle mixer calls functions * ******************************************************************************/ int InternalHalHandleMixerData(afb_api_t apiHandle, json_object *currentDataJ) { int idx, mixerDataNb, verbStart, size; char *currentDataVerbName, *currentStreamCardId; json_type currentDataType; json_object *currentJ; currentDataType = json_object_get_type(currentDataJ); switch(currentDataType) { case json_type_object: mixerDataNb = 1; break; case json_type_array: mixerDataNb = (unsigned int) json_object_array_length(currentDataJ); break; default: mixerDataNb = 0; AFB_API_ERROR(apiHandle, "No data returned"); return -1; } for(idx = 0; idx < mixerDataNb; idx++) { if(currentDataType == json_type_array) currentJ = json_object_array_get_idx(currentDataJ, (int) idx); else currentJ = currentDataJ; if(wrap_json_unpack(currentJ, "{s:s}", "verb", ¤tDataVerbName)) { AFB_API_ERROR(apiHandle, "Can't find verb in current data object"); return -2; } else if(wrap_json_unpack(currentJ, "{s:s}", "alsa", ¤tStreamCardId)) { AFB_API_ERROR(apiHandle, "Can't find card id in current data object"); return -3; } else { size = (int) strlen(currentDataVerbName); for(verbStart = 0; verbStart < size; verbStart++) { if(currentDataVerbName[verbStart] == '#') { verbStart++; break; } } if(verbStart == size) verbStart = 0; if(! HalUtlAddStreamDataAndCreateStreamVerb(apiHandle, ¤tDataVerbName[verbStart], currentDataVerbName, currentStreamCardId)) { AFB_API_ERROR(apiHandle, "Error while adding stream '%s'", currentDataVerbName); HalUtlRemoveAllStreamsDataAndDeleteAllStreamsVerb(apiHandle); return -4; } } } return 0; } int InternalHalHandleMixerAttachResponse(afb_api_t apiHandle, struct InternalHalData *currentHalSpecificData, json_object *mixerResponseJ) { int err; json_object *mixerStreamsJ = NULL; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Can't get current hal api handle"); return -1; } if(wrap_json_unpack(mixerResponseJ, "{s?:o}", "streams", &mixerStreamsJ)) { AFB_API_ERROR(apiHandle, "An error happened when tried to decode mixer response ('%s')", json_object_get_string(mixerResponseJ)); return -2; } if(mixerStreamsJ) { err = InternalHalHandleMixerData(apiHandle, mixerStreamsJ); if(err) { AFB_API_ERROR(apiHandle, "Error %i during handling response mixer streams data '%s'", err, json_object_get_string(mixerStreamsJ)); HalUtlRemoveAllMixerData(¤tHalSpecificData->streamsDataListHead); return -3; } } else { AFB_API_WARNING(apiHandle, "No stream was created by mixer ('%s')", json_object_get_string(mixerResponseJ)); return 1; } return 0; } int InternalHalAttachDependencyToMixer(afb_api_t apiHandle, struct InternalHalProbedDevice *probedDeviceToAttach) { int err = 0, mixerError; char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; CtlConfigT *ctrlConfig; struct HalData *currentHalData; json_object *requestJ, *dependencyJ, *responseJ = NULL; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Can't get current internal hal api handle"); return -1; } ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) { AFB_API_ERROR(apiHandle, "Can't get current internal hal controller config"); return -2; } currentHalData = (struct HalData *) getExternalData(ctrlConfig); if(! currentHalData) { AFB_API_ERROR(apiHandle, "Can't get current internal hal controller data"); return -3; } switch(currentHalData->status) { case HAL_STATUS_INIT_FAILED: AFB_API_ERROR(apiHandle, "Seems that the hal initialization failed, will not be able to attach this hal"); return -4; case HAL_STATUS_UNAVAILABLE: AFB_API_ERROR(apiHandle, "Seems that the hal corresponding card was not found by alsacore at startup"); return -5; case HAL_STATUS_READY: AFB_API_NOTICE(apiHandle, "Seems that the hal mixer is already initialized"); return 1; case HAL_STATUS_AVAILABLE: break; } apiToCall = currentHalData->internalHalData->mixerApiName; if(! apiToCall) { AFB_API_ERROR(apiHandle, "Can't get mixer api"); return -6; } dependencyJ = HalUtlGetJsonArrayForAllDependenciesInfoWithHandledDependency(apiHandle, ¤tHalData->internalHalData->probedDevicesListHead, DEPENDENCY_COMPACT_JSON, probedDeviceToAttach->uid); if(! dependencyJ) { AFB_API_ERROR(apiHandle, "Didn't succeed to generate available dependencies compact json array"); return -7; } requestJ = wrap_json_clone(currentHalData->internalHalData->halMixerJ); json_object_object_add(requestJ, "dependencies", dependencyJ); if(afb_api_call_sync(apiHandle, apiToCall, MIXER_ATTACH_VERB, requestJ, &responseJ, &returnedError, &returnedInfo)) { AFB_API_ERROR(apiHandle, "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", MIXER_ATTACH_VERB, apiToCall, returnedError ? returnedError : "not returned", returnedInfo ? returnedInfo : "not returned"); err = -8; } else if(! responseJ) { AFB_API_WARNING(apiHandle, "Seems that %s call to api %s succeed but no response was returned", MIXER_ATTACH_VERB, apiToCall); } else { mixerError = InternalHalHandleMixerAttachResponse(apiHandle, currentHalData->internalHalData, responseJ); if(mixerError < 0) { AFB_API_ERROR(apiHandle, "Seems that %s call to api %s succeed but this error was send by response decoder : %i '%s'", MIXER_ATTACH_VERB, apiToCall, mixerError, json_object_get_string(responseJ)); err = -9; } else if(mixerError > 0) { AFB_API_WARNING(apiHandle, "Seems that %s call to api %s succeed but warning %i was rised by response decoder : '%s'", MIXER_ATTACH_VERB, apiToCall, mixerError, json_object_get_string(responseJ)); } else { AFB_API_NOTICE(apiHandle, "Seems that %s call to api %s succeed with no warning raised : '%s'", MIXER_ATTACH_VERB, apiToCall, json_object_get_string(responseJ)); } } if(err) probedDeviceToAttach->mixerLinkStatus = DEPENDENCY_MIXER_ATTACH_FAILED; else probedDeviceToAttach->mixerLinkStatus = DEPENDENCY_MIXER_ATTACH_SUCCEED; if(responseJ) json_object_put(responseJ); free(returnedError); free(returnedInfo); return err; } int InternalHalGetInfoFromMixer(afb_api_t apiHandle, char *apiToCall, json_object *requestJson, json_object **toReturnJ, char **returnedError, char **returnedInfo) { json_object *responseJ = NULL; if(! apiHandle) { AFB_API_ERROR(apiHandle, "Can't get current hal api handle"); return -1; } if(! apiToCall) { AFB_API_ERROR(apiHandle, "Can't get mixer api"); return -2; } if(! requestJson) { AFB_API_ERROR(apiHandle, "Can't get request json"); return -3; } if(*returnedError || *returnedInfo) { AFB_API_ERROR(apiHandle, "'returnedError' and 'returnedInfo' strings should be empty and set to 'NULL'"); return -4; } if(*toReturnJ) { AFB_API_ERROR(apiHandle, "'toReturnJ' should be empty and set to 'NULL'"); return -5; } if(afb_api_call_sync(apiHandle, apiToCall, MIXER_INFO_VERB, json_object_get(requestJson), &responseJ, returnedError, returnedInfo)) { AFB_API_ERROR(apiHandle, "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s'", apiToCall, MIXER_INFO_VERB, *returnedError ? *returnedError : "not returned", *returnedInfo ? *returnedInfo : "not returned"); return -6; } else if(! responseJ) { AFB_API_ERROR(apiHandle, "Seems that %s call to api %s succeed but no response was returned", MIXER_INFO_VERB, apiToCall); json_object_put(responseJ); return -7; } else { AFB_API_NOTICE(apiHandle, "Seems that %s call to api %s succeed with no warning raised : '%s'", MIXER_INFO_VERB, apiToCall, json_object_get_string(responseJ)); *toReturnJ = responseJ; } return 0; }