/* * Copyright (C) 2019 "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" /******************************************************************************* * Actions to be call when a stream verb is called * ******************************************************************************/ void HalUtlActionOnMixer(afb_req_t request, enum ActionOnMixerType actionType) { int idx, count; char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; afb_api_t apiHandle; CtlConfigT *ctrlConfig; struct HalData *currentHalData; struct InternalHalMixerData *currentMixerData = NULL; json_object *requestJson, *responseJ = NULL, *toReturnJ = NULL, *verboseBooleanJ; apiHandle = afb_req_get_api(request); if(! apiHandle) { afb_req_fail(request, "api_handle", "Can't get current hal api handle"); return; } ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) { afb_req_fail(request, "hal_controller_config", "Can't get current internal hal controller config"); return; } currentHalData = (struct HalData *) getExternalData(ctrlConfig); if(! currentHalData) { afb_req_fail(request, "hal_controller_data", "Can't get current internal hal controller data"); return; } requestJson = afb_req_json(request); if(! requestJson) { afb_req_fail(request, "request_json", "Can't get request json"); return; } if(json_object_is_type(requestJson, json_type_object) && json_object_get_object(requestJson)->count > 0) { verboseBooleanJ = json_object_new_boolean(1); if(! verboseBooleanJ) { afb_req_fail(request, "verbose_boolean_allocation", "Didn't succeed to allocate verbose value json boolean"); return; } json_object_object_add(requestJson, "verbose", verboseBooleanJ); } apiToCall = currentHalData->internalHalData->mixerApiName; if(! apiToCall) { afb_req_fail(request, "mixer_api", "Can't get mixer api"); return; } if(currentHalData->status != HAL_STATUS_READY) { afb_req_fail(request, "hal_not_ready", "Seems that hal is not ready"); return; } currentMixerData = (struct InternalHalMixerData *) afb_req_get_vcbdata(request); if(! currentMixerData) { afb_req_fail(request, "hal_call_data", "Can't get current call data"); return; } switch(actionType) { case ACTION_ON_MIXER_STREAM: count = 1; break; case ACTION_ON_MIXER_PLAYBACK: case ACTION_ON_MIXER_CAPTURE: case ACTION_ON_MIXER_ALL_STREAM: count = (int) HalUtlGetNumberOfMixerDataInList(¤tMixerData); toReturnJ = json_object_new_object(); if(! toReturnJ) { afb_req_fail(request, "response_json_object", "Didn't succeed to allocate response json object"); return; } break; default: afb_req_fail(request, "mixer_action_type", "Action type is unknown"); return; } for(idx = 0; idx < count; idx++) { if(afb_api_call_sync(apiHandle, apiToCall, currentMixerData->verbToCall, json_object_get(requestJson), &responseJ, &returnedError, &returnedInfo)) { if(responseJ) json_object_put(responseJ); if(toReturnJ) json_object_put(toReturnJ); afb_req_fail_f(request, "mixer_call", "Something went wrong during call to verb '%s' of api '%s' with error '%s' and info '%s' (call to mixer %i out of %i)", currentMixerData->verbToCall, apiToCall, returnedError ? returnedError : "not returned", returnedInfo ? returnedInfo : "not returned", idx, count); free(returnedError); free(returnedInfo); return; } if(! responseJ) { if(toReturnJ) json_object_put(toReturnJ); afb_req_fail_f(request, "mixer_call", "Seems that %s call to api %s succeed but no response was returned (call to mixer %i out of %i)", currentMixerData->verbToCall, apiToCall, idx, count); free(returnedError); free(returnedInfo); return; } // TBD JAI : When mixer events will be available, use them instead of generating events at calls if((actionType == ACTION_ON_MIXER_STREAM || actionType == ACTION_ON_MIXER_ALL_STREAM) && ((! currentMixerData->event) || (afb_event_push(currentMixerData->event, json_object_get(responseJ)) < 0))) { AFB_API_ERROR(apiHandle, "Could not generate an event for stream %s", currentMixerData->verb); } switch(actionType) { case ACTION_ON_MIXER_STREAM: toReturnJ = responseJ; break; case ACTION_ON_MIXER_PLAYBACK: case ACTION_ON_MIXER_CAPTURE: json_object_object_add(toReturnJ, currentMixerData->verbToCall, responseJ); currentMixerData = currentMixerData->next; break; case ACTION_ON_MIXER_ALL_STREAM: json_object_object_add(toReturnJ, currentMixerData->verb, responseJ); currentMixerData = currentMixerData->next; break; default: break; } } switch(actionType) { case ACTION_ON_MIXER_STREAM: afb_req_success_f(request, toReturnJ, "Action %s correctly transferred to %s without any error raised", currentMixerData->verbToCall, apiToCall); break; case ACTION_ON_MIXER_PLAYBACK: afb_req_success(request, toReturnJ, "Actions correctly transferred to all playbacks without any error raised"); break; case ACTION_ON_MIXER_CAPTURE: afb_req_success(request, toReturnJ, "Actions correctly transferred to all captures without any error raised"); break; case ACTION_ON_MIXER_ALL_STREAM: afb_req_success(request, toReturnJ, "Actions correctly transferred to all streams without any error raised"); break; default: break; } } void HalUtlActionOnStream(afb_req_t request) { HalUtlActionOnMixer(request, ACTION_ON_MIXER_STREAM); } void HalUtlActionOnPlayback(afb_req_t request) { HalUtlActionOnMixer(request, ACTION_ON_MIXER_PLAYBACK); } void HalUtlActionOnCapture(afb_req_t request) { HalUtlActionOnMixer(request, ACTION_ON_MIXER_CAPTURE); } void HalUtlActionOnAllStream(afb_req_t request) { HalUtlActionOnMixer(request, ACTION_ON_MIXER_ALL_STREAM); } /******************************************************************************* * Add stream data and verb function * ******************************************************************************/ struct InternalHalMixerData *HalUtlAddStreamDataAndCreateStreamVerb(afb_api_t apiHandle, char *verb, char *verbToCall, char *streamCardId) { int wrapRet; json_object *streamAddedEventJ; CtlConfigT *ctrlConfig; struct HalData *currentHalData; struct InternalHalMixerData *createdStreamData; if(! apiHandle || ! verb || ! verbToCall || ! streamCardId) return NULL; ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) return NULL; currentHalData = (struct HalData *) getExternalData(ctrlConfig); if(! currentHalData || ! currentHalData->internalHalData) return NULL; createdStreamData = HalUtlAddMixerDataToMixerDataList(¤tHalData->internalHalData->streamsData); if(! createdStreamData) return NULL; createdStreamData->verb = strdup(verb); createdStreamData->verbToCall = strdup(verbToCall); createdStreamData->streamCardId = strdup(streamCardId); if(! createdStreamData->verb || ! createdStreamData->verbToCall || ! createdStreamData->streamCardId) { HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); return NULL; } createdStreamData->event = afb_api_make_event(apiHandle, createdStreamData->verb); if(! createdStreamData->event) { HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); return NULL; } if(afb_api_add_verb(apiHandle, createdStreamData->verb, "Stream action transferred to mixer", HalUtlActionOnStream, (void *) createdStreamData, NULL, 0, 0)) { AFB_API_ERROR(apiHandle,"Error while creating verb for stream : '%s'", createdStreamData->verb); HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); return NULL; } wrapRet = wrap_json_pack(&streamAddedEventJ, "{s:s, s:s, s:s}", "action", "added", "name", createdStreamData->verb, "cardId", createdStreamData->streamCardId); if(wrapRet) { AFB_API_ERROR(apiHandle,"Didn't succeed to allocate added stream event json object"); HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, createdStreamData); return NULL; } afb_event_push(currentHalData->internalHalData->streamUpdates, streamAddedEventJ); return createdStreamData; } int HalUtlRemoveStreamDataAndDeleteStreamVerb(afb_api_t apiHandle, char *verb, char *verbToCall, char *streamCardId) { int returnedErr = 0, wrapRet; json_object *streamRemovedEventJ; CtlConfigT *ctrlConfig; struct HalData *currentHalData; struct InternalHalMixerData *toRemoveStreamData; if(! apiHandle || ! verb || ! verbToCall || ! streamCardId) return -1; ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle); if(! ctrlConfig) return -2; currentHalData = (struct HalData *) getExternalData(ctrlConfig); if(! currentHalData || ! currentHalData->internalHalData) return -3; toRemoveStreamData = HalUtlSearchMixerDataByProperties(¤tHalData->internalHalData->streamsData, verb, verbToCall, streamCardId); if(! toRemoveStreamData) return -4; if(afb_api_del_verb(apiHandle, verb, NULL)) { AFB_API_ERROR(apiHandle,"Error while deleting verb for stream : '%s'", verb); json_object_put(streamRemovedEventJ); return -5; } returnedErr = HalUtlRemoveSelectedMixerData(¤tHalData->internalHalData->streamsData, toRemoveStreamData); if(returnedErr) { AFB_API_ERROR(apiHandle,"Error %i while removing data for stream : '%s'", returnedErr, verb); json_object_put(streamRemovedEventJ); return -6; } wrapRet = wrap_json_pack(&streamRemovedEventJ, "{s:s, s:s, s:s}", "action", "removed", "name", toRemoveStreamData->verb, "cardId", toRemoveStreamData->streamCardId); if(wrapRet) { AFB_API_ERROR(apiHandle,"Didn't succeed to allocate removed stream event json object"); return -7; } afb_event_push(currentHalData->internalHalData->streamUpdates, streamRemovedEventJ); return 0; }