diff options
Diffstat (limited to 'lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c')
-rw-r--r-- | lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c b/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c new file mode 100644 index 0000000..ed06b27 --- /dev/null +++ b/lib/4a-hal-utilities/4a-hal-utilities-hal-streams-handler.c @@ -0,0 +1,355 @@ +/* + * Copyright (C) 2019 "IoT.bzh" + * Author Jonathan Aillet <jonathan.aillet@iot.bzh> + * + * 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 <stdio.h> +#include <json-c/json.h> + +#include <afb/afb-binding.h> + +#include <ctl-config.h> + +#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; + + if(! (apiHandle = afb_req_get_api(request))) { + afb_req_fail(request, "api_handle", "Can't get current hal controller api handle"); + return; + } + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { + afb_req_fail(request, "hal_controller_config", "Can't get current hal controller config"); + return; + } + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) { + afb_req_fail(request, "hal_controller_data", "Can't get current hal controller data"); + return; + } + + if(! (requestJson = afb_req_json(request))) { + 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) + json_object_object_add(requestJson, "verbose", json_object_new_boolean(1)); + + 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(); + 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) +{ + 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; + } + + if(! (createdStreamData->event = afb_api_make_event(apiHandle, createdStreamData->verb))) { + 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; + } + + wrap_json_pack(&streamAddedEventJ, + "{s:s, s:s, s:s}", + "action", "added", + "name", createdStreamData->verb, + "cardId", createdStreamData->streamCardId); + + afb_event_push(currentHalData->internalHalData->streamUpdates, streamAddedEventJ); + + return createdStreamData; +} + +int8_t HalUtlRemoveStreamDataAndDeleteStreamVerb(afb_api_t apiHandle, + char *verb, + char *verbToCall, + char *streamCardId) +{ + int8_t returnedErr = 0; + + 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; + + wrap_json_pack(&streamRemovedEventJ, + "{s:s, s:s, s:s}", + "action", "removed", + "name", toRemoveStreamData->verb, + "cardId", toRemoveStreamData->streamCardId); + + 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; + } + + afb_event_push(currentHalData->internalHalData->streamUpdates, streamRemovedEventJ); + + return 0; +}
\ No newline at end of file |