From 01d55ed8cdd01ca4a7b391ca61c80084bd5a6f2f Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Wed, 5 Dec 2018 14:05:10 +0100 Subject: Adds support for bluetooth audio through bluez-alsa Implements a new bluealsa plugin to the HAL manager, reacting to the changes of the available transports. This plugin is linked with the new bluealsa.so shared library. New transports (SCO & A2DP) result in softmixer invocations of the "attach" verb, that creates the new capture (eg, A2DP capture from bluealsa ioplug PCM, SCO microphone capture), playbacks (SCO playback to a softmixer zone, and SCO output to bluealsa iogplug PCM). When a transport disappears, the hal manager calls the transaction deletion verb that will tell the softmixer to remove the created streams and associated objects. Change-Id: I36037a4f14ef7fee38070fc0df66c40b4ce46e8b Signed-off-by: Thierry Bultel --- plugins/lib/bluetooth/hal-bt.c | 437 ----------------------------------------- 1 file changed, 437 deletions(-) delete mode 100644 plugins/lib/bluetooth/hal-bt.c (limited to 'plugins/lib/bluetooth/hal-bt.c') diff --git a/plugins/lib/bluetooth/hal-bt.c b/plugins/lib/bluetooth/hal-bt.c deleted file mode 100644 index f270593..0000000 --- a/plugins/lib/bluetooth/hal-bt.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Copyright (C) 2018 "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 - -#include "hal-bt.h" -#include "hal-bt-cb.h" -#include "hal-bt-data.h" -#include "hal-bt-mixer-link.h" - -CTLP_CAPI_REGISTER(HAL_BT_PLUGIN_NAME) - -// Call at initialisation time -CTLP_ONLOAD(plugin, callbacks) -{ - struct HalBtPluginData *currentBtPluginData; - - AFB_ApiInfo(plugin->api, "%s Plugin Registering: uid='%s' 'info='%s'", HAL_BT_PLUGIN_NAME, plugin->uid, plugin->info); - - currentBtPluginData = calloc(1, sizeof(struct HalBtPluginData)); - if(! currentBtPluginData) { - AFB_ApiError(plugin->api, "An error happenned during allocation of %s plugin data structure ", HAL_BT_PLUGIN_NAME); - return -1; - } - - setPluginContext(plugin, (void *) currentBtPluginData); - - currentBtPluginData->currentHalApiHandle = plugin->api; - - AFB_ApiNotice(plugin->api, "%s Plugin Registered correctly: uid='%s' 'info='%s'", HAL_BT_PLUGIN_NAME, plugin->uid, plugin->info); - - return 0; -} - -CTLP_INIT(plugin, callbacks) -{ - int btChannelsNumber; - - unsigned int idx; - - char *btStreamZone, *returnedInfo; - - CtlConfigT *ctrlConfig; - - struct HalBtPluginData *currentBtPluginData; - - json_object *actionsToAdd, *returnedJ, *halMixerJ, *halOrigCaptureJ, *halNewCaptureJ, *halOrigStreamJ, *halNewStreamJ, *btCaptureJ, *btCaptureParamsJ, *btStreamJ; - - AFB_ApiInfo(plugin->api, "Plugin initialization of %s plugin", HAL_BT_PLUGIN_NAME); - - if(AFB_RequireApi(plugin->api, BT_MANAGER_API, 1)) { - AFB_ApiWarning(plugin->api, "Didn't succeed to require %s api, bluetooth is disable because not reachable", BT_MANAGER_API); - return 0; - } - - if(! (currentBtPluginData = (struct HalBtPluginData *) getPluginContext(plugin))) { - AFB_ApiError(plugin->api, "Can't get current %s plugin data", HAL_BT_PLUGIN_NAME); - return -1; - } - - if(! (ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(plugin->api))) { - AFB_ApiError(plugin->api, "Can't get current hal controller config"); - return -2; - } - - if(! (currentBtPluginData->currentHalData = getExternalData(ctrlConfig))) { - AFB_ApiError(plugin->api, "Can't get current hal controller data"); - return -3; - } - - if(currentBtPluginData->currentHalData->status != HAL_STATUS_AVAILABLE) { - AFB_ApiWarning(plugin->api, "Controller initialization of %s plugin cannot be done because hal is not ready to be used", HAL_BT_PLUGIN_NAME); - return 0; - } - - if((! currentBtPluginData->currentHalData->ctlHalSpecificData) || - (! (halMixerJ = currentBtPluginData->currentHalData->ctlHalSpecificData->halMixerJ))) { - AFB_ApiError(plugin->api, "Can't get current hal mixer json section"); - return -4; - } - - if(AFB_ServiceSync(plugin->api, BT_MANAGER_API, BT_MANAGER_GET_POWER_INFO, NULL, &returnedJ)) { - if((! wrap_json_unpack(returnedJ, "{s:{s:s}}", "request", "info", &returnedInfo)) && - (! strncmp(returnedInfo, "Unable to get power status", strlen(returnedInfo)))) { - AFB_ApiWarning(plugin->api, - "No bluetooth receiver detected when calling verb '%s' of '%s' api, bluetooth is disable because not reachable", - BT_MANAGER_GET_POWER_INFO, - BT_MANAGER_API); - return 0; - } - else { - AFB_ApiError(plugin->api, - "Error during call to verb '%s' of '%s' api (%s)", - BT_MANAGER_GET_POWER_INFO, - BT_MANAGER_API, - json_object_get_string(returnedJ)); - return -5; - } - } - - if((! json_object_is_type(plugin->paramsJ, json_type_object)) || - (wrap_json_unpack(plugin->paramsJ, "{s:i, s:s}", "channels", &btChannelsNumber, "zone", &btStreamZone))) { - AFB_ApiError(plugin->api, "Can't get %s plugin parameters from json ('%s')", HAL_BT_PLUGIN_NAME, json_object_get_string(plugin->paramsJ)); - return -6; - } - - wrap_json_pack(&actionsToAdd, "{s:s s:s}", - "uid", "Bluetooth-Manager/device_updated", - "action", "plugin://hal-bt#events"); - - idx = 0; - while(ctrlConfig->sections[idx].key && strcasecmp(ctrlConfig->sections[idx].key, "events")) - idx++; - - if(! ctrlConfig->sections[idx].key) { - AFB_ApiError(plugin->api, "Wasn't able to add '%s' as a new event, 'events' section not found", json_object_get_string(actionsToAdd)); - json_object_put(actionsToAdd); - return -7; - } - - if(AddActionsToSection(plugin->api, &ctrlConfig->sections[idx], actionsToAdd, 0)) { - AFB_ApiError(plugin->api, "Wasn't able to add '%s' as a new event to %s", json_object_get_string(actionsToAdd), ctrlConfig->sections[idx].key); - json_object_put(actionsToAdd); - return -8; - } - - wrap_json_pack(&actionsToAdd, "{s:s s:s s:s}", - "uid", "init-bt-plugin", - "info", "Init Bluetooth hal plugin", - "action", "plugin://hal-bt#init"); - - idx = 0; - while(ctrlConfig->sections[idx].key && strcasecmp(ctrlConfig->sections[idx].key, "onload")) - idx++; - - if(! ctrlConfig->sections[idx].key) { - AFB_ApiError(plugin->api, "Wasn't able to add '%s' as a new onload, 'onload' section not found", json_object_get_string(actionsToAdd)); - json_object_put(actionsToAdd); - return -9; - } - - if(AddActionsToSection(plugin->api, &ctrlConfig->sections[idx], actionsToAdd, 0)) { - AFB_ApiError(plugin->api, "Wasn't able to add '%s' as a new onload to %s", json_object_get_string(actionsToAdd), ctrlConfig->sections[idx].uid); - json_object_put(actionsToAdd); - return -10; - } - - btCaptureJ = json_tokener_parse(MIXER_BT_CAPTURE_JSON_SECTION); - wrap_json_pack(&btCaptureParamsJ, "{s:i}", "channels", btChannelsNumber); - json_object_object_add(btCaptureJ, "params", btCaptureParamsJ); - - if(! json_object_object_get_ex(halMixerJ, "captures", &halOrigCaptureJ)) { - halNewCaptureJ = json_object_new_array(); - json_object_array_add(halNewCaptureJ, btCaptureJ); - json_object_object_add(halMixerJ, "captures", halNewCaptureJ); - } - else if(json_object_is_type(halOrigCaptureJ, json_type_array)) { - halNewCaptureJ = halOrigCaptureJ; - json_object_array_add(halNewCaptureJ, btCaptureJ); - } - else if(json_object_is_type(halOrigCaptureJ, json_type_object)) { - json_object_get(halOrigCaptureJ); - json_object_object_del(halMixerJ, "captures"); - halNewCaptureJ = json_object_new_array(); - json_object_array_add(halNewCaptureJ, halOrigCaptureJ); - json_object_array_add(halNewCaptureJ, btCaptureJ); - json_object_object_add(halMixerJ, "captures", halNewCaptureJ); - } - else { - AFB_ApiError(plugin->api, "Unrecognized 'halmixer' captures format"); - return -11; - } - - btStreamJ = json_tokener_parse(MIXER_BT_STREAM_JSON_SECTION); - json_object_object_add(btStreamJ, "zone", json_object_new_string(btStreamZone)); - - if(! json_object_object_get_ex(halMixerJ, "streams", &halOrigStreamJ)) { - halNewStreamJ = json_object_new_array(); - json_object_array_add(halNewStreamJ, btStreamJ); - json_object_object_add(halMixerJ, "streams", halNewStreamJ); - } - else if(json_object_is_type(halOrigStreamJ, json_type_array)) { - halNewStreamJ = halOrigStreamJ; - json_object_array_add(halNewStreamJ, btStreamJ); - } - else if(json_object_is_type(halOrigStreamJ, json_type_object)) { - json_object_get(halOrigStreamJ); - json_object_object_del(halMixerJ, "streams"); - halNewStreamJ = json_object_new_array(); - json_object_array_add(halNewStreamJ, halOrigStreamJ); - json_object_array_add(halNewStreamJ, btStreamJ); - json_object_object_add(halMixerJ, "streams", halNewStreamJ); - } - else { - AFB_ApiError(plugin->api, "Unrecognized 'halmixer' streams format"); - return -12; - } - - currentBtPluginData->halBtPluginEnabled = 1; - - AFB_ApiNotice(plugin->api, "Plugin initialization of %s plugin correctly done", HAL_BT_PLUGIN_NAME); - - return 0; -} - -// Call at contoller onload time -CTLP_CAPI(init, source, argsJ, queryJ) -{ - int err; - - char *returnedInfo; - - struct HalBtPluginData *currentBtPluginData; - - json_object *toSendJ, *returnedJ, *returnedBtList = NULL; - - if(! (currentBtPluginData = (struct HalBtPluginData *) getPluginContext(source->plugin))) { - AFB_ApiError(source->api, "Can't get current %s plugin data", HAL_BT_PLUGIN_NAME); - return -1; - } - - if(! currentBtPluginData->halBtPluginEnabled) { - AFB_ApiWarning(source->api, "Controller onload initialization of %s plugin cannot be done because bluetooth is not reachable", HAL_BT_PLUGIN_NAME); - return 0; - } - - AFB_ApiInfo(source->api, "Controller onload initialization of %s plugin", HAL_BT_PLUGIN_NAME); - - // Loading hal BT plugin specific verbs - if(AFB_ApiAddVerb(source->api, - HAL_BT_GET_STREAMING_STATUS_VERB, - "Get Bluetooth streaming status", - HalBtGetStreamingStatus, - (void *) currentBtPluginData, - NULL, - 0, - 0)) { - AFB_ApiError(source->api, "Error while creating verb for bluetooth plugin : '%s'", HAL_BT_GET_STREAMING_STATUS_VERB); - return -2; - } - - if(AFB_ApiAddVerb(source->api, - HAL_BT_SET_STREAMING_STATUS_VERB, - "Set Bluetooth streaming status", - HalBtSetStreamingStatus, - (void *) currentBtPluginData, - NULL, - 0, - 0)) { - AFB_ApiError(source->api, "Error while creating verb for bluetooth plugin : '%s'", HAL_BT_SET_STREAMING_STATUS_VERB); - return -3; - } - - if(AFB_ApiAddVerb(source->api, - HAL_BT_GET_CONNECTED_A2DP_DEVICES_VERB, - "Get connected Bluetooth A2DP devices list", - HalBtGetA2DPBluetoothDevices, - (void *) currentBtPluginData, - NULL, - 0, - 0)) { - AFB_ApiError(source->api, "Error while creating verb for bluetooth plugin : '%s'", HAL_BT_GET_CONNECTED_A2DP_DEVICES_VERB); - return -4; - } - - if(AFB_ApiAddVerb(source->api, - HAL_BT_GET_SELECTED_A2DP_DEVICE_VERB, - "Get selected Bluetooth A2DP device", - HalBtGetSelectedA2DPBluetoothDevice, - (void *) currentBtPluginData, - NULL, - 0, - 0)) { - AFB_ApiError(source->api, "Error while creating verb for bluetooth plugin : '%s'", HAL_BT_GET_SELECTED_A2DP_DEVICE_VERB); - return -5; - } - - if(AFB_ApiAddVerb(source->api, - HAL_BT_SET_SELECTED_A2DP_DEVICE_VERB, - "Set selected Bluetooth A2DP device", - HalBtSetSelectedA2DPBluetoothDevice, - (void *) currentBtPluginData, - NULL, - 0, - 0)) { - AFB_ApiError(source->api, "Error while creating verb for bluetooth plugin : '%s'", HAL_BT_SET_SELECTED_A2DP_DEVICE_VERB); - return -6; - } - - // Register to Bluetooth manager - wrap_json_pack(&toSendJ, "{s:s}", "value", BT_MANAGER_DEVICE_UPDATE_EVENT); - if(AFB_ServiceSync(source->api, BT_MANAGER_API, BT_MANAGER_SUBSCRIBE_VERB, toSendJ, &returnedJ)) { - AFB_ApiError(source->api, - "Error during call to verb '%s' of '%s' api (%s)", - BT_MANAGER_SUBSCRIBE_VERB, - BT_MANAGER_API, - json_object_get_string(returnedJ)); - - return -7; - } - else if(! wrap_json_unpack(returnedJ, "{s:{s:s}}", "request", "info", &returnedInfo)) { - AFB_ApiError(source->api, - "Couldn't subscribe to event '%s' during call to verb '%s' of api '%s' (error '%s')", - BT_MANAGER_DEVICE_UPDATE_EVENT, - BT_MANAGER_SUBSCRIBE_VERB, - BT_MANAGER_API, - returnedInfo); - json_object_put(returnedJ); - return -7; - } - json_object_put(returnedJ); - - if(AFB_ServiceSync(source->api, BT_MANAGER_API, BT_MANAGER_GET_DEVICES_VERB, NULL, &returnedJ)) { - if((! wrap_json_unpack(returnedJ, "{s:{s:s}}", "request", "info", &returnedInfo)) && - (! strncmp(returnedInfo, "No find devices", strlen(returnedInfo)))) { - AFB_ApiInfo(source->api, - "No bluetooth devices returned by call to verb '%s' of '%s' api", - BT_MANAGER_GET_DEVICES_VERB, - BT_MANAGER_API); - } - else { - AFB_ApiError(source->api, - "Error during call to verb '%s' of '%s' api (%s)", - BT_MANAGER_GET_DEVICES_VERB, - BT_MANAGER_API, - json_object_get_string(returnedJ)); - - return -8; - } - } - else if(wrap_json_unpack(returnedJ, "{s:{s:o}}", "response", "list", &returnedBtList)) { - AFB_ApiError(source->api, - "Couldn't get bluetooth device list during call to verb '%s' of api '%s'", - BT_MANAGER_GET_DEVICES_VERB, - BT_MANAGER_API); - json_object_put(returnedJ); - return -8; - } - - if((returnedBtList) && (err = HalBtDataHandleReceivedMutlipleBtDeviceData(currentBtPluginData, returnedBtList))) - return (10 * err); - - json_object_put(returnedJ); - - if(currentBtPluginData->selectedBtDevice) { - currentBtPluginData->btStreamEnabled = 1; - - AFB_ApiInfo(source->api, "Useable bluetooth device detected at initialization, will try to use it"); - - if(HalBtMixerLinkSetBtStreamingSettings(source->api, - currentBtPluginData->currentHalData->ctlHalSpecificData->mixerApiName, - currentBtPluginData->btStreamEnabled, - currentBtPluginData->selectedBtDevice->hci, - currentBtPluginData->selectedBtDevice->address)) { - AFB_ApiError(source->api, - "Couldn't set bluetooth streaming settings during call to verb '%s' of api '%s'", - MIXER_SET_STREAMED_BT_DEVICE_VERB, - currentBtPluginData->currentHalData->ctlHalSpecificData->mixerApiName); - return -9; - } - } - - AFB_ApiNotice(source->api, "Controller onload initialization of %s plugin correctly done", HAL_BT_PLUGIN_NAME); - - return 0; -} - -// This receive Hal bluetooth plugin events -CTLP_CAPI(events, source, argsJ, queryJ) -{ - struct HalBtPluginData *currentBtPluginData; - - struct HalBtDeviceData *previouslySelectedBtDevice; - - if(! (currentBtPluginData = (struct HalBtPluginData *) getPluginContext(source->plugin))) { - AFB_ApiError(source->api, "Can't get current %s plugin data", HAL_BT_PLUGIN_NAME); - return -1; - } - - if(! currentBtPluginData->halBtPluginEnabled) { - AFB_ApiWarning(source->api, "Bluetooth event received but cannot be handled because bluetooth is not reachable"); - return 0; - } - - previouslySelectedBtDevice = currentBtPluginData->selectedBtDevice; - - if(HalBtDataHandleReceivedSingleBtDeviceData(currentBtPluginData, queryJ)) { - AFB_ApiError(source->api, "Error while decoding bluetooth event received json (%s)", json_object_get_string(queryJ)); - return -2; - } - - if(currentBtPluginData->selectedBtDevice == previouslySelectedBtDevice) { - AFB_ApiDebug(source->api, "Bluetooth event received but device didn't change"); - return 0; - } - - if(currentBtPluginData->selectedBtDevice) - currentBtPluginData->btStreamEnabled = 1; - else - currentBtPluginData->btStreamEnabled = 0; - - if(HalBtMixerLinkSetBtStreamingSettings(source->api, - currentBtPluginData->currentHalData->ctlHalSpecificData->mixerApiName, - currentBtPluginData->btStreamEnabled, - currentBtPluginData->selectedBtDevice ? currentBtPluginData->selectedBtDevice->hci : NULL, - currentBtPluginData->selectedBtDevice ? currentBtPluginData->selectedBtDevice->address : NULL)) { - AFB_ApiError(source->api, - "Couldn't set bluetooth streaming settings during call to verb '%s' of api '%s'", - MIXER_SET_STREAMED_BT_DEVICE_VERB, - currentBtPluginData->currentHalData->ctlHalSpecificData->mixerApiName); - return -3; - } - - return 0; -} \ No newline at end of file -- cgit 1.2.3-korg