summaryrefslogtreecommitdiffstats
path: root/4a-hal/4a-internals-hal/4a-internals-hal-mixer-link.c
diff options
context:
space:
mode:
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.c389
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", &currentDataVerbName)) {
+ 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", &currentStreamCardId)) {
+ 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,
+ &currentDataVerbName[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, &currentHalSpecificData->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, &currentHalSpecificData->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, &currentHalSpecificData->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