diff options
Diffstat (limited to '4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c')
-rw-r--r-- | 4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c b/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c new file mode 100644 index 0000000..95e9099 --- /dev/null +++ b/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2018 "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 <string.h> + +#include <wrap-json.h> + +#include <afb/afb-binding.h> + +#include "4a-hal-utilities-data.h" + +#include "4a-hal-utilities-hal-streams-handler.h" +#include "4a-hal-utilities-verbs-loader.h" + +#include "../4a-hal-manager/4a-hal-manager.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, + struct InternalHalMixerData **mixerDataList, + json_object *currentDataJ, + enum MixerDataType dataType) +{ + int idx, mixerDataNb, verbStart, size; + int err = (int) MIXER_NO_ERROR; + + char *currentDataVerbName, *currentStreamCardId; + + json_type currentDataType; + json_object *currentJ; + + struct InternalHalMixerData *currentMixerData; + + 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 (int) MIXER_ERROR_DATA_EMPTY; + } + + 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"); + err += (int) MIXER_ERROR_DATA_NAME_UNAVAILABLE; + } + else if(dataType == MIXER_DATA_STREAMS && wrap_json_unpack(currentJ, "{s:s}", "alsa", ¤tStreamCardId)) { + AFB_API_ERROR(apiHandle, "Can't find card id in current data object"); + err += (int) MIXER_ERROR_DATA_CARDID_UNAVAILABLE; + } + else { + switch(dataType) { + case MIXER_DATA_STREAMS: + 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); + err += (int) MIXER_ERROR_STREAM_NOT_ADDED; + } + + break; + + case MIXER_DATA_PLAYBACKS: + case MIXER_DATA_CAPTURES: + currentMixerData = HalUtlAddMixerDataToMixerDataList(mixerDataList); + + currentMixerData->verb = strdup((dataType == MIXER_DATA_PLAYBACKS) ? HAL_PLAYBACK_ID : HAL_CAPTURE_ID); + currentMixerData->verbToCall = strdup(currentDataVerbName); + + if((! currentMixerData->verb) || + (! currentMixerData->verbToCall)) { + HalUtlRemoveSelectedMixerData(mixerDataList, currentMixerData); + err += (int) MIXER_ERROR_STREAM_ALLOCATION_FAILED; + } + break; + + default: + break; + } + } + } + + if(dataType == MIXER_DATA_PLAYBACKS) { + if(afb_api_add_verb(apiHandle, + HAL_PLAYBACK_ID, + "Playback action transferred to mixer", + HalUtlActionOnPlayback, + (void *) *mixerDataList, + NULL, + 0, + 0)) { + AFB_API_ERROR(apiHandle, "Error while creating verb for playbacks : '%s'", HAL_PLAYBACK_ID); + err += (int) MIXER_ERROR_PLAYBACK_VERB_NOT_CREATED; + } + } + + if(dataType == MIXER_DATA_CAPTURES) { + if(afb_api_add_verb(apiHandle, + HAL_CAPTURE_ID, + "Capture action transferred to mixer", + HalUtlActionOnCapture, + (void *) *mixerDataList, + NULL, + 0, + 0)) { + AFB_API_ERROR(apiHandle, "Error while creating verb for captures : '%s'", HAL_CAPTURE_ID); + err += (int) MIXER_ERROR_CAPTURE_VERB_NOT_CREATED; + } + } + + return err; +} + +int InternalHalHandleMixerAttachResponse(afb_api_t apiHandle, struct InternalHalData *currentHalSpecificData, json_object *mixerResponseJ) +{ + int err = (int) MIXER_NO_ERROR; + + json_object *mixerStreamsJ = NULL, *mixerPlaybacksJ = NULL, *mixerCapturesJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Can't get current hal api handle"); + return (int) MIXER_ERROR_API_UNAVAILABLE; + } + + if(wrap_json_unpack(mixerResponseJ, "{s?:o s?:o s?:o}", "streams", &mixerStreamsJ, "playbacks", &mixerPlaybacksJ, "captures", &mixerCapturesJ)) { + AFB_API_ERROR(apiHandle, "Can't get streams|playbacks|captures object in '%s'", json_object_get_string(mixerResponseJ)); + return (int) MIXER_ERROR_DATA_UNAVAILABLE; + } + + if(mixerStreamsJ) { + err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->streamsData, mixerStreamsJ, MIXER_DATA_STREAMS); + if(err) + AFB_API_ERROR(apiHandle, "Error during handling response mixer streams data '%s'", json_object_get_string(mixerStreamsJ)); + } + + if(mixerPlaybacksJ) { + err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->playbacksData, mixerPlaybacksJ, MIXER_DATA_PLAYBACKS); + if(err) + AFB_API_ERROR(apiHandle, "Error during handling response mixer playbacks data '%s'", json_object_get_string(mixerPlaybacksJ)); + } + + if(mixerCapturesJ) { + err += InternalHalHandleMixerData(apiHandle, ¤tHalSpecificData->capturesData, mixerCapturesJ, MIXER_DATA_CAPTURES); + if(err) + AFB_API_ERROR(apiHandle, "Error during handling response mixer captures data '%s'", json_object_get_string(mixerCapturesJ)); + } + + if(! currentHalSpecificData->streamsData) { + AFB_API_WARNING(apiHandle, "No stream detected in mixer response, %s verb won't be created", HAL_ALL_STREAMS_VERB); + } + else if(afb_api_add_verb(apiHandle, + HAL_ALL_STREAMS_VERB, + "Send a stream action on all streams", + HalUtlActionOnAllStream, + (void *) currentHalSpecificData->streamsData, + NULL, + 0, + 0)) { + AFB_API_ERROR(apiHandle, "Error while creating verb for all streams : '%s'", HAL_ALL_STREAMS_VERB); + return (int) MIXER_ERROR_ALL_STREAMS_VERB_NOT_CREATED; + } + + return err; +} + +int InternalHalAttachToMixer(afb_api_t apiHandle) +{ + int err = 0, mixerError; + + char *apiToCall, *returnedError = NULL, *returnedInfo = NULL; + + CtlConfigT *ctrlConfig; + + struct HalData *currentHalData, *concurentHalData = NULL; + + json_object *responseJ = NULL; + + if(! apiHandle) { + AFB_API_ERROR(apiHandle, "Can't get current internal hal api handle"); + return -1; + } + + if(! (ctrlConfig = (CtlConfigT *) afb_api_get_userdata(apiHandle))) { + AFB_API_ERROR(apiHandle, "Can't get current hal controller config"); + return -2; + } + + currentHalData = (struct HalData *) getExternalData(ctrlConfig); + if(! currentHalData) { + AFB_API_ERROR(apiHandle, "Can't get current hal controller data"); + return -3; + } + + switch(currentHalData->status) { + case HAL_STATUS_UNAVAILABLE: + AFB_API_ERROR(apiHandle, "Seems that the hal corresponding card was not found by alsacore at startup"); + return -4; + + case HAL_STATUS_READY: + AFB_API_NOTICE(apiHandle, "Seems that the hal mixer is already initialized"); + return 1; + + case HAL_STATUS_AVAILABLE: + break; + } + + concurentHalData = HalUtlSearchReadyHalDataByCardId(HalMngGetHalDataList(), currentHalData->sndCardId); + if(concurentHalData) { + AFB_API_ERROR(apiHandle, + "Trying to attach mixer for hal '%s' but the alsa device %i is already in use with mixer by hal '%s'", + currentHalData->apiName, + currentHalData->sndCardId, + concurentHalData->apiName); + return -5; + } + + apiToCall = currentHalData->internalHalData->mixerApiName; + if(! apiToCall) { + AFB_API_ERROR(apiHandle, "Can't get mixer api"); + return -6; + } + + if(afb_api_call_sync(apiHandle, + apiToCall, + MIXER_ATTACH_VERB, + json_object_get(currentHalData->internalHalData->halMixerJ), + &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 = -7; + } + else if(! responseJ) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but no response was returned", + MIXER_ATTACH_VERB, + apiToCall); + err = -8; + } + else { + mixerError = InternalHalHandleMixerAttachResponse(apiHandle, currentHalData->internalHalData, responseJ); + if(mixerError != (int) MIXER_NO_ERROR) { + AFB_API_ERROR(apiHandle, + "Seems that %s call to api %s succeed but this warning was risen by response decoder : %i '%s'", + MIXER_ATTACH_VERB, + apiToCall, + mixerError, + json_object_get_string(responseJ)); + err = -9; + } + 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)); + currentHalData->status = HAL_STATUS_READY; + } + } + + 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; +}
\ No newline at end of file |