/* * 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-appfw-responses-handler.h" #include "4a-hal-utilities-hal-streams-handler.h" /******************************************************************************* * Actions to be call when a stream verb is called * ******************************************************************************/ void HalUtlActionOnMixer(AFB_ReqT request, enum ActionOnMixerType actionType) { int idx, count; char *apiToCall; AFB_ApiT apiHandle; CtlConfigT *ctrlConfig; struct SpecificHalData *currentCtlHalData; struct CtlHalMixerData *currentMixerData = NULL; json_object *requestJson, *returnJ = NULL, *responseJ, *toReturnJ = NULL; apiHandle = (AFB_ApiT) AFB_ReqGetApi(request); if(! apiHandle) { AFB_ReqFail(request, "api_handle", "Can't get current hal controller api handle"); return; } ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(apiHandle); if(! ctrlConfig) { AFB_ReqFail(request, "hal_controller_config", "Can't get current hal controller config"); return; } currentCtlHalData = (struct SpecificHalData *) getExternalData(ctrlConfig); if(! currentCtlHalData) { AFB_ReqFail(request, "hal_controller_data", "Can't get current hal controller data"); return; } requestJson = AFB_ReqJson(request); if(! requestJson) { AFB_ReqFail(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 = currentCtlHalData->ctlHalSpecificData->mixerApiName; if(! apiToCall) { AFB_ReqFail(request, "mixer_api", "Can't get mixer api"); return; } if(currentCtlHalData->status != HAL_STATUS_READY) { AFB_ReqFail(request, "hal_not_ready", "Seems that hal is not ready"); return; } if(! (currentMixerData = (struct CtlHalMixerData *) AFB_ReqVCBData(request))) { AFB_ReqFail(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_ReqFail(request, "hal_call_data", "Can't get current call data"); return; } for(idx = 0; idx < count; idx++) { if(AFB_ServiceSync(apiHandle, apiToCall, currentMixerData->verbToCall, json_object_get(requestJson), &returnJ)) { HalUtlHandleAppFwCallErrorInRequest(request, apiToCall, currentMixerData->verbToCall, returnJ, "call_action"); json_object_put(returnJ); if(toReturnJ) json_object_put(toReturnJ); return; } if(wrap_json_unpack(returnJ, "{s:o}", "response", &responseJ)) { AFB_ReqFailF(request, "Seems that %s call to api %s succeed, but no response was found in : '%s'", currentMixerData->verbToCall, apiToCall, json_object_get_string(returnJ)); json_object_put(returnJ); if(toReturnJ) json_object_put(toReturnJ); 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_EventPush(currentMixerData->event, json_object_get(responseJ)) < 0))) { AFB_ApiError(apiHandle, "Couldn't generate an event for stream %s", currentMixerData->verb); } switch(actionType) { case ACTION_ON_MIXER_STREAM: toReturnJ = json_object_get(responseJ); break; case ACTION_ON_MIXER_PLAYBACK: case ACTION_ON_MIXER_CAPTURE: json_object_object_add(toReturnJ, currentMixerData->verbToCall, json_object_get(responseJ)); break; case ACTION_ON_MIXER_ALL_STREAM: json_object_object_add(toReturnJ, currentMixerData->verb, json_object_get(responseJ)); break; default: break; } json_object_put(returnJ); switch(actionType) { case ACTION_ON_MIXER_PLAYBACK: case ACTION_ON_MIXER_CAPTURE: case ACTION_ON_MIXER_ALL_STREAM: currentMixerData = currentMixerData->next; break; default: break; } } switch(actionType) { case ACTION_ON_MIXER_STREAM: AFB_ReqSuccessF(request, toReturnJ, "Action %s correctly transferred to %s without any error raised", currentMixerData->verbToCall, apiToCall); break; case ACTION_ON_MIXER_PLAYBACK: AFB_ReqSuccess(request, toReturnJ, "Actions correctly transferred to all playbacks without any error raised"); break; case ACTION_ON_MIXER_CAPTURE: AFB_ReqSuccess(request, toReturnJ, "Actions correctly transferred to all captures without any error raised"); break; case ACTION_ON_MIXER_ALL_STREAM: AFB_ReqSuccess(request, toReturnJ, "Actions correctly transferred to all streams without any error raised"); break; default: break; } } void HalUtlActionOnStream(AFB_ReqT request) { HalUtlActionOnMixer(request, ACTION_ON_MIXER_STREAM); } void HalUtlActionOnPlayback(AFB_ReqT request) { HalUtlActionOnMixer(request, ACTION_ON_MIXER_PLAYBACK); } void HalUtlActionOnCapture(AFB_ReqT request) { HalUtlActionOnMixer(request, ACTION_ON_MIXER_CAPTURE); } void HalUtlActionOnAllStream(AFB_ReqT request) { HalUtlActionOnMixer(request, ACTION_ON_MIXER_ALL_STREAM); } /******************************************************************************* * Add stream data and verb function * ******************************************************************************/ struct CtlHalMixerData *HalUtlAddStreamDataAndCreateStreamVerb(AFB_ApiT apiHandle, char *verb, char *verbToCall, char *streamCardId) { json_object *streamAddedEventJ; CtlConfigT *ctrlConfig; struct SpecificHalData *currentSpecificHalData; struct CtlHalMixerData *createdStreamData; if(! apiHandle || ! verb || ! verbToCall || ! streamCardId) return NULL; if((! (ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(apiHandle))) || (! (currentSpecificHalData = (struct SpecificHalData *) getExternalData(ctrlConfig))) || (! currentSpecificHalData->ctlHalSpecificData)) return NULL; if(! (createdStreamData = HalUtlAddMixerDataToMixerDataList(¤tSpecificHalData->ctlHalSpecificData->ctlHalStreamsData))) return NULL; createdStreamData->verb = strdup(verb); createdStreamData->verbToCall = strdup(verbToCall); createdStreamData->streamCardId = strdup(streamCardId); if((! createdStreamData->verb) || (! createdStreamData->verbToCall) || (! createdStreamData->streamCardId)) { HalUtlRemoveSelectedMixerData(¤tSpecificHalData->ctlHalSpecificData->ctlHalStreamsData, createdStreamData); return NULL; } createdStreamData->event = AFB_EventMake(apiHandle, createdStreamData->verb); if(! AFB_EventIsValid(createdStreamData->event)) { HalUtlRemoveSelectedMixerData(¤tSpecificHalData->ctlHalSpecificData->ctlHalStreamsData, createdStreamData); return NULL; } if(AFB_ApiAddVerb(apiHandle, createdStreamData->verb, "Stream action transferred to mixer", HalUtlActionOnStream, (void *) createdStreamData, NULL, 0, 0)) { AFB_ApiError(apiHandle,"Error while creating verb for stream : '%s'", createdStreamData->verb); HalUtlRemoveSelectedMixerData(¤tSpecificHalData->ctlHalSpecificData->ctlHalStreamsData, createdStreamData); return NULL; } wrap_json_pack(&streamAddedEventJ, "{s:s, s:s, s:s}", "action", "added", "name", createdStreamData->verb, "cardId", createdStreamData->streamCardId); AFB_EventPush(currentSpecificHalData->ctlHalSpecificData->streamUpdates, streamAddedEventJ); return createdStreamData; } int8_t HalUtlRemoveStreamDataAndDeleteStreamVerb(AFB_ApiT apiHandle, char *verb, char *verbToCall, char *streamCardId) { int8_t returnedErr = 0; json_object *streamRemovedEventJ; CtlConfigT *ctrlConfig; struct SpecificHalData *currentSpecificHalData; struct CtlHalMixerData *toRemoveStreamData; if(! apiHandle || ! verb || ! verbToCall || ! streamCardId) return -1; if((! (ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(apiHandle))) || (! (currentSpecificHalData = (struct SpecificHalData *) getExternalData(ctrlConfig))) || (! currentSpecificHalData->ctlHalSpecificData)) return -2; if(! (toRemoveStreamData = HalUtlSearchMixerDataByProperties(¤tSpecificHalData->ctlHalSpecificData->ctlHalStreamsData, verb, verbToCall, streamCardId))) return -3; 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_ApiError(apiHandle,"Error while deleting verb for stream : '%s'", verb); json_object_put(streamRemovedEventJ); return -4; } if((returnedErr = HalUtlRemoveSelectedMixerData(¤tSpecificHalData->ctlHalSpecificData->ctlHalStreamsData, toRemoveStreamData))) { AFB_ApiError(apiHandle,"Error %i while removing data for stream : '%s'", returnedErr, verb); json_object_put(streamRemovedEventJ); return -5; } AFB_EventPush(currentSpecificHalData->ctlHalSpecificData->streamUpdates, streamRemovedEventJ); return 0; }