From 40a55bf64139a51123dd93a4a268088848b0dd17 Mon Sep 17 00:00:00 2001 From: Jonathan Aillet Date: Mon, 17 Dec 2018 19:42:32 +0100 Subject: Add streams events generation for each hal Each hal will now have subscribe/unsubscribe verbs to allow other bindings to be notified when a modification (volume, mute, ...) happened on a stream. Bug-AGL: SPEC-1313 Change-Id: If68d3b4b4e39385c1fffdd04b9f3e2b7fa5ae108 Signed-off-by: Jonathan Aillet --- .../4a-hal-controllers-api-loader.c | 2 + 4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c | 156 +++++++++++++++++++++ 4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h | 8 ++ .../4a-hal-controllers-mixer-link.c | 8 ++ .../4a-hal-controllers-mixer-link.h | 1 + 4a-hal/4a-hal-utilities/4a-hal-utilities-data.h | 1 + 6 files changed, 176 insertions(+) diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c b/4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c index e60136d..f6acaef 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-api-loader.c @@ -62,6 +62,8 @@ static AFB_ApiVerbs CtlHalDynApiStaticVerbs[] = { /* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */ { .verb = "info", .callback = HalCtlsInfo, .info = "List available streams/playbacks/captures/controls for this api" }, + { .verb = "subscribe", .callback = HalCtlsSubscribe, .info = "Subscribe to event(s) for values changes (streams/playbacks/captures/controls) for this api" }, + { .verb = "unsubscribe", .callback = HalCtlsUnsubscribe, .info = "Unsubscribe to event(s) for values changes (streams/playbacks/captures/controls) for this api" }, { .verb = NULL } // Marker for end of the array }; diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c b/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c index 07dd49c..f5099c3 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c @@ -508,6 +508,14 @@ void HalCtlsActionOnMixer(AFB_ReqT request, enum ActionOnMixerType actionType) 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); @@ -758,4 +766,152 @@ void HalCtlsInfo(AFB_ReqT request) "controls", controlsArray); AFB_ReqSuccess(request, requestAnswer, "Requested data"); +} + +void HalCtlsSubscribeUnsubscribe(AFB_ReqT request, enum SubscribeUnsubscribeType subscribeUnsubscribeType) +{ + int arrayIdx, searchIdx, count, subscriptionFound, subscriptionDoneNb = 0; + + char *currentSubscriptionString; + + AFB_ApiT apiHandle; + CtlConfigT *ctrlConfig; + + struct SpecificHalData *currentCtlHalData; + struct CtlHalMixerDataT *halStreamsData; + + json_object *requestJson, *requestedSubscriptionsJ, *requestedSubscriptionJ = NULL; + json_type requestJsonType; + + 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 *) ctrlConfig->external; + if(! currentCtlHalData) { + AFB_ReqFail(request, "hal_controller_data", "Can't get current hal controller data"); + return; + } + + if(! currentCtlHalData->ctlHalSpecificData) { + AFB_ReqFail(request, "hal_controller_data", "Can't get current hal specific data"); + return; + } + + halStreamsData = ¤tCtlHalData->ctlHalSpecificData->ctlHalStreamsData; + + requestJson = AFB_ReqJson(request); + if(! requestJson) { + AFB_ReqFail(request, "request_json", "Can't get request json"); + } + + if(wrap_json_unpack(requestJson, "{s:o}", "events", &requestedSubscriptionsJ)) { + AFB_ReqFail(request, "request_json", "Request json invalid"); + return; + } + + requestJsonType = json_object_get_type(requestedSubscriptionsJ); + switch(requestJsonType) { + case json_type_string: + count = 1; + requestedSubscriptionJ = requestedSubscriptionsJ; + break; + + case json_type_array: + count = (int) json_object_array_length(requestedSubscriptionsJ); + break; + + default: + AFB_ReqFail(request, "request_json", "Request json invalid"); + return; + } + + for(arrayIdx = 0; arrayIdx < count; arrayIdx++) { + if(requestJsonType == json_type_array) { + requestedSubscriptionJ = json_object_array_get_idx(requestedSubscriptionsJ, arrayIdx); + if(! json_object_is_type(requestedSubscriptionJ, json_type_string)) { + AFB_ReqFailF(request, "request_json", "Request json number %i in array invalid", arrayIdx); + return; + } + } + + subscriptionFound = 0; + currentSubscriptionString = (char *) json_object_get_string(requestedSubscriptionJ); + + searchIdx = 0; + while((searchIdx < halStreamsData->count) && + (! subscriptionFound)) { + if(! strcasecmp(currentSubscriptionString, halStreamsData->data[searchIdx].verb)) { + if(halStreamsData->data[searchIdx].event && + subscribeUnsubscribeType == SUBSCRIPTION && + afb_req_subscribe(request, halStreamsData->data[searchIdx].event)) { + AFB_ReqFailF(request, + "request_stream_event", + "Error while trying to subscribe to %s stream events", + halStreamsData->data[searchIdx].verb); + return; + } + else if(halStreamsData->data[searchIdx].event && + subscribeUnsubscribeType == UNSUBSCRIPTION && + afb_req_unsubscribe(request, halStreamsData->data[searchIdx].event)) { + AFB_ReqFailF(request, + "request_stream_event", + "Error while trying to unsubscribe to %s stream events", + halStreamsData->data[searchIdx].verb); + return; + } + + subscriptionFound = 1; + subscriptionDoneNb++; + + break; + } + + searchIdx++; + } + } + + if(subscriptionDoneNb == 0) + AFB_ReqFailF(request, + "events_not_found", + "%s failed, event(s) were not found", + subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription"); + if(subscriptionDoneNb == count) + AFB_ReqSuccessF(request, + json_object_new_int(subscriptionDoneNb), + "%s succeed for all the %i events requested", + subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", + subscriptionDoneNb); + else if(subscriptionDoneNb < count) + AFB_ReqSuccessF(request, + json_object_new_int(subscriptionDoneNb), + "%s succeed but only to %i events requested out of %i", + subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", + subscriptionDoneNb, + count); + else + AFB_ReqSuccessF(request, + json_object_new_int(subscriptionDoneNb), + "%s succeed but to more events than requested (%i out of %i)", + subscribeUnsubscribeType == SUBSCRIPTION ? "Subscription" : "Unsubscription", + subscriptionDoneNb, + count); +} + +void HalCtlsSubscribe(AFB_ReqT request) +{ + HalCtlsSubscribeUnsubscribe(request, SUBSCRIPTION); +} + +void HalCtlsUnsubscribe(AFB_ReqT request) +{ + HalCtlsSubscribeUnsubscribe(request, UNSUBSCRIPTION); } \ No newline at end of file diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h b/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h index 1f91b62..66cbc8c 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.h @@ -32,6 +32,12 @@ enum ActionOnMixerType { ACTION_ON_MIXER_ALL_STREAM = 4 }; +// Enum for the type of subscription/subscription +enum SubscribeUnsubscribeType { + SUBSCRIPTION = 1, + UNSUBSCRIPTION = 2 +}; + // HAL controller event handler function void HalCtlsDispatchApiEvent(afb_dynapi *apiHandle, const char *evtLabel, json_object *eventJ); @@ -45,5 +51,7 @@ void HalCtlsActionOnPlayback(AFB_ReqT request); void HalCtlsActionOnCapture(AFB_ReqT request); void HalCtlsActionOnAllStream(AFB_ReqT request); void HalCtlsInfo(AFB_ReqT request); +void HalCtlsSubscribe(AFB_ReqT request); +void HalCtlsUnsubscribe(AFB_ReqT request); #endif /* _HALMGR_CB_INCLUDE_ */ \ No newline at end of file diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-mixer-link.c b/4a-hal/4a-hal-controllers/4a-hal-controllers-mixer-link.c index aa169c7..3a21541 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-mixer-link.c +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-mixer-link.c @@ -106,6 +106,14 @@ int HalCtlsHandleMixerData(AFB_ApiT apiHandle, struct CtlHalMixerDataT *currentM currentMixerDataT->data[idx].verb); err += (int) MIXER_ERROR_STREAM_VERB_NOT_CREATED; } + + currentMixerDataT->data[idx].event = AFB_EventMake(apiHandle, currentMixerDataT->data[idx].verb); + if(! AFB_EventIsValid(currentMixerDataT->data[idx].event)) { + AFB_ApiError(apiHandle, + "Error while creating event for stream : '%s'", + currentMixerDataT->data[idx].verb); + err += (int) MIXER_ERROR_STREAM_EVENT_NOT_CREATED; + } } else if(dataType == MIXER_DATA_PLAYBACKS) { currentMixerDataT->data[idx].verb = strdup(HAL_PLAYBACK_ID); diff --git a/4a-hal/4a-hal-controllers/4a-hal-controllers-mixer-link.h b/4a-hal/4a-hal-controllers/4a-hal-controllers-mixer-link.h index 7deef1b..165b70d 100644 --- a/4a-hal/4a-hal-controllers/4a-hal-controllers-mixer-link.h +++ b/4a-hal/4a-hal-controllers/4a-hal-controllers-mixer-link.h @@ -53,6 +53,7 @@ enum MixerStatus { MIXER_ERROR_DATA_NAME_UNAVAILABLE=-10, MIXER_ERROR_DATA_CARDID_UNAVAILABLE=-1000, MIXER_ERROR_STREAM_VERB_NOT_CREATED =-100000, + MIXER_ERROR_STREAM_EVENT_NOT_CREATED =-10000000 }; // HAL controllers handle mixer calls functions diff --git a/4a-hal/4a-hal-utilities/4a-hal-utilities-data.h b/4a-hal/4a-hal-utilities/4a-hal-utilities-data.h index eb07a5d..01b3db7 100644 --- a/4a-hal/4a-hal-utilities/4a-hal-utilities-data.h +++ b/4a-hal/4a-hal-utilities/4a-hal-utilities-data.h @@ -40,6 +40,7 @@ struct CtlHalMixerData { char *verb; char *verbToCall; char *streamCardId; + AFB_EventT event; }; // Structure to store stream data table -- cgit 1.2.3-korg