aboutsummaryrefslogtreecommitdiffstats
path: root/4a-hal/4a-hal-controllers/4a-hal-controllers-cb.c
blob: 9e25c6166510ecd5f2a7a04f632358ac0cfdfa1d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 * Copyright (C) 2016 "IoT.bzh"
 * Author Romain Forlot <romain.forlot@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 AFB_BINDING_VERSION 2
#include <afb/afb-binding.h>
#include <systemd/sd-event.h>
#include <json-c/json_object.h>
#include <stdbool.h>
#include <string.h>

#include "signal-composer.hpp"
#include "ctl-config.h"
#include "wrap-json.h"

extern "C"
{

CTLP_LUALOAD
CTLP_REGISTER("lua2c-interface");

typedef struct CtxS {
	struct signalCBT* pluginHandle;
} CtxT;

static CtxT *pluginCtx = NULL;

// Call at initialisation time
CTLP_ONLOAD(plugin, handle) {
	pluginCtx = (CtxT*)calloc (1, sizeof(CtxT));
	pluginCtx->pluginHandle = (struct signalCBT*)handle;

	AFB_NOTICE ("Low-can plugin: label='%s' version='%s' info='%s'",
		plugin->label,
		plugin->version,
		plugin->info);

	return (void*)pluginCtx;
}

CTLP_LUA2C (setSignalValueWrap, label, argsJ)
{
	const char* name = nullptr;
	double resultNum;
	uint64_t timestamp;
	if(! wrap_json_unpack(argsJ, "{ss, sF, sF? !}",
		"name", &name,
		"value", &resultNum,
		"timestamp", &timestamp))
	{
		AFB_ERROR("Fail to set value for label: %s, argsJ: %s", label, json_object_to_json_string(argsJ));
		return -1;
	}

	struct signalValue result = {0,0,1, resultNum, 0, ""};
	pluginCtx->pluginHandle->setSignalValue(name, timestamp, result);
	return 0;
}

// extern "C" closure
}
6 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
/*
 * 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 "../4a-hal-utilities/4a-hal-utilities-data.h"
#include "../4a-hal-utilities/4a-hal-utilities-appfw-responses-handler.h"

#include "4a-hal-controllers-cb.h"
#include "4a-hal-controllers-alsacore-link.h"
#include "4a-hal-controllers-mixer-link.h"
#include "4a-hal-controllers-value-handler.h"

/*******************************************************************************
 *		HAL controller event handler function			       *
 ******************************************************************************/

void HalCtlsDispatchApiEvent(AFB_ApiT apiHandle, const char *evtLabel, json_object *eventJ)
{
	int numid, idx = 0, cardidx;

	CtlConfigT *ctrlConfig;
	CtlSourceT source;

	struct SpecificHalData *currentHalData;
	struct CtlHalAlsaMapT *currentHalAlsaCtlsT;

	json_object *valuesJ;

	AFB_ApiDebug(apiHandle, "Evtname=%s [msg=%s]", evtLabel, json_object_get_string(eventJ));

	ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(apiHandle);
	if(! ctrlConfig) {
		AFB_ApiError(apiHandle, "Can't get current hal controller config");
		return;
	}

	currentHalData = (struct SpecificHalData *) getExternalData(ctrlConfig);
	if(! currentHalData) {
		AFB_ApiWarning(apiHandle, "Can't get current hal controller data");
		return;
	}

	// Extract sound card index from event
	while(evtLabel[idx] != '\0' && evtLabel[idx] != ':')
		idx++;

	if(evtLabel[idx] != '\0' &&
	   sscanf(&evtLabel[idx + 1], "%d", &cardidx) == 1 &&
	   currentHalData->sndCardId == cardidx) {
		if(wrap_json_unpack(eventJ, "{s:i s:o !}", "id", &numid, "val", &valuesJ)) {
			AFB_ApiError(apiHandle, "Invalid Alsa Event label=%s value=%s", evtLabel, json_object_get_string(eventJ));
			return;
		}

		currentHalAlsaCtlsT = currentHalData->ctlHalSpecificData->ctlHalAlsaMapT;

		// Search for corresponding numid in halCtls, if found, launch callback (if available)
		for(idx = 0; idx < currentHalAlsaCtlsT->ctlsCount; idx++) {
			if(currentHalAlsaCtlsT->ctls[idx].ctl.numid == numid) {
				if(currentHalAlsaCtlsT->ctls[idx].action) {
					source.uid = currentHalAlsaCtlsT->ctls[idx].action->uid;
					source.api = currentHalAlsaCtlsT->ctls[idx].action->api;
					source.request = NULL;

					(void) ActionExecOne(&source, currentHalAlsaCtlsT->ctls[idx].action, valuesJ);
				}
				else {
					AFB_ApiNotice(apiHandle,
						      "The alsa control id '%i' is corresponding to a known control but without any action registered",
						      numid);
				}

				return;
			}
		}

		AFB_ApiWarning(apiHandle, "Alsacore event with an unrecognized numid: %i, evtname=%s [msg=%s]",
					  numid,
					  evtLabel,
					  json_object_get_string(eventJ));

		return;
	}

	AFB_ApiInfo(apiHandle,
		    "Not an alsacore event '%s' [msg=%s]",
		    evtLabel,
		    json_object_get_string(eventJ));

	CtrlDispatchApiEvent(apiHandle, evtLabel, eventJ);
}

/*******************************************************************************
 *		HAL controllers sections parsing functions		       *
 ******************************************************************************/

int HalCtlsHalMixerConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *MixerJ)
{
	int err = 0;

	CtlConfigT *ctrlConfig;
	struct SpecificHalData *currentHalData;

	if(! apiHandle || ! section)
		return -1;

	ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(apiHandle);
	if(! ctrlConfig)
		return -2;

	currentHalData = (struct SpecificHalData *) getExternalData(ctrlConfig);
	if(! currentHalData)
		return -3;

	if(MixerJ) {
		if(json_object_is_type(MixerJ, json_type_object))
			currentHalData->ctlHalSpecificData->halMixerJ = MixerJ;
		else
			return -4;

		if(wrap_json_unpack(MixerJ, "{s:s}", "mixerapi", &currentHalData->ctlHalSpecificData->mixerApiName))
			return -5;

		wrap_json_unpack(MixerJ, "{s?:s}", "prefix", &currentHalData->ctlHalSpecificData->prefix);
	}
	else if(currentHalData->status == HAL_STATUS_AVAILABLE &&
		(err = HalCtlsAttachToMixer(apiHandle))) {
		AFB_ApiError(apiHandle, "%s: Error %i while attaching to mixer", __func__, err);
		return -6;
	}

	return 0;
}

int HalCtlsProcessOneHalMapObject(AFB_ApiT apiHandle, struct CtlHalAlsaMap *alsaMap, json_object *AlsaMapJ)
{
	char *action = NULL, *typename = NULL;

	json_object *alsaJ = NULL, *createAlsaCtlJ = NULL;

	AFB_ApiDebug(apiHandle, "AlsaMapJ=%s", json_object_get_string(AlsaMapJ));

	if(wrap_json_unpack(AlsaMapJ, "{s:s s?:s s:o s?:s !}",
				      "uid", &alsaMap->uid,
				      "info", &alsaMap->info,
				      "alsa", &alsaJ,
				      "action", &action)) {
		AFB_ApiError(apiHandle, "Parsing error, map should only contains [label]|[uid]|[tag]|[info]|[alsa]|[action] in:\n-- %s", json_object_get_string(AlsaMapJ));
		return -1;
	}

	if(wrap_json_unpack(alsaJ, "{s?:s s?:i s?:i s?:o !}",
				   "name", &alsaMap->ctl.name,
				   "numid", &alsaMap->ctl.numid,
				   "value", &alsaMap->ctl.value,
				   "create", &createAlsaCtlJ)) {
		AFB_ApiError(apiHandle, "Parsing error, alsa json should only contains [name]|[numid]||[value]|[create] in:\n-- %s", json_object_get_string(alsaJ));
		return -2;
	}

	if(createAlsaCtlJ) {
		alsaMap->ctl.alsaCtlCreation = &alsaMap->ctl.alsaCtlProperties;

		if(wrap_json_unpack(createAlsaCtlJ,
				    "{s:s s:i s:i s:i s:i !}",
				    "type", &typename,
				    "count", &alsaMap->ctl.alsaCtlCreation->count,
				    "minval", &alsaMap->ctl.alsaCtlCreation->minval,
				    "maxval", &alsaMap->ctl.alsaCtlCreation->maxval,
				    "step", &alsaMap->ctl.alsaCtlCreation->step)) {
			AFB_ApiError(apiHandle, "Parsing error, alsa creation json should only contains [type]|[count]|[minval]|[maxval]|[step] in:\n-- %s", json_object_get_string(alsaJ));
			return -3;
		}

		if(typename && (alsaMap->ctl.alsaCtlCreation->type = HalCtlsMapsAlsaTypeToEnum(typename)) == SND_CTL_ELEM_TYPE_NONE) {
			AFB_ApiError(apiHandle, "Couldn't get alsa type from string %s in:\n-- %s", typename, json_object_get_string(alsaJ));
			return -4;
		}

		if(! alsaMap->ctl.name)
			alsaMap->ctl.name = (char *) alsaMap->uid;
	}
	else if(alsaMap->ctl.name && alsaMap->ctl.numid > 0) {
		AFB_ApiError(apiHandle,
			     "Can't have both a control name (%s) and a control uid (%i) in alsa object:\n-- %s",
			     alsaMap->ctl.name,
			     alsaMap->ctl.numid,
			     json_object_get_string(alsaJ));
		return -5;
	}
	else if(! alsaMap->ctl.name && alsaMap->ctl.numid <= 0) {
		AFB_ApiError(apiHandle,
			     "Need at least a control name or a control uid in alsa object:\n-- %s",
			     json_object_get_string(alsaJ));
		return -6;
	}

	if(action)
		alsaMap->actionJ = AlsaMapJ;

	return 0;
}

int HalCtlsHandleOneHalMapObject(AFB_ApiT apiHandle, char *cardId, struct CtlHalAlsaMap *alsaMap)
{
	int err;

	json_object *valueJ, *convertedValueJ = NULL;

	if(alsaMap->ctl.alsaCtlCreation) {
		if(HalCtlsCreateAlsaCtl(apiHandle, cardId, &alsaMap->ctl)) {
			AFB_ApiError(apiHandle, "An error happened when trying to create a new alsa control");
			return -1;
		}
	}
	else if(HalCtlsUpdateAlsaCtlProperties(apiHandle, cardId, &alsaMap->ctl)) {
		AFB_ApiError(apiHandle, "An error happened when trying to get existing alsa control info");
		return -2;
	}

	if(alsaMap->ctl.value) {
		// TBD JAI : handle alsa controls type
		valueJ = json_object_new_int(alsaMap->ctl.value);
		err = 0;

		if(HalCtlsConvertJsonValues(apiHandle, &alsaMap->ctl.alsaCtlProperties, valueJ, &convertedValueJ, CONVERSION_NORMALIZED_TO_ALSACORE)) {
			AFB_ApiError(apiHandle, "Error when trying to convert initiate value json '%s'", json_object_get_string(valueJ));
			err = -3;
		}
		else if(HalCtlsSetAlsaCtlValue(apiHandle, cardId, alsaMap->ctl.numid, convertedValueJ)) {
			AFB_ApiError(apiHandle,
				     "Error while trying to set initial value on alsa control %i, device '%s', value '%s'",
				     alsaMap->ctl.numid,
				     cardId,
				     json_object_get_string(valueJ));
			err = -4;
		}

		json_object_put(valueJ);

		if(convertedValueJ)
			json_object_put(convertedValueJ);

		if(err)
			return err;
	}

	if(alsaMap->actionJ) {
		alsaMap->action = calloc(1, sizeof(CtlActionT));
		if(ActionLoadOne(apiHandle, alsaMap->action, alsaMap->actionJ, 0)) {
			AFB_ApiError(apiHandle,
				     "Didn't succeed to load action using alsa object:\n-- %s",
				     json_object_get_string(alsaMap->actionJ));
			return -5;
		}
	}

	if(AFB_ApiAddVerb(apiHandle, alsaMap->uid, alsaMap->info, HalCtlsActionOnAlsaCtl, (void *) alsaMap, NULL, 0, 0)) {
		AFB_ApiError(apiHandle,
			     "Didn't to create verb for current alsa control to load action using alsa object:\n-- %s",
			     json_object_get_string(alsaMap->actionJ));
		return -6;
	}

	return 0;
}

int HalCtlsProcessAllHalMap(AFB_ApiT apiHandle, json_object *AlsaMapJ, struct CtlHalAlsaMapT *currentCtlHalAlsaMapT)
{
	int idx, err = 0;

	struct CtlHalAlsaMap *ctlMaps;

	json_type alsaMapType;

	alsaMapType = json_object_get_type(AlsaMapJ);
	switch(alsaMapType) {
		case json_type_array:
			currentCtlHalAlsaMapT->ctlsCount = (unsigned int) json_object_array_length(AlsaMapJ);
			break;

		case json_type_object:
			currentCtlHalAlsaMapT->ctlsCount = 1;
			break;

		default:
			currentCtlHalAlsaMapT->ctlsCount = 0;
			currentCtlHalAlsaMapT->ctls = NULL;
			AFB_ApiWarning(apiHandle, "Couldn't get content of 'halmap' section in:\n-- %s", json_object_get_string(AlsaMapJ));
			return -1;
	}

	ctlMaps = calloc(currentCtlHalAlsaMapT->ctlsCount, sizeof(struct CtlHalAlsaMap));

	for(idx = 0; idx < currentCtlHalAlsaMapT->ctlsCount; idx++)
		err += HalCtlsProcessOneHalMapObject(apiHandle, &ctlMaps[idx], alsaMapType == json_type_array ? json_object_array_get_idx(AlsaMapJ, idx) : AlsaMapJ);

	currentCtlHalAlsaMapT->ctls = ctlMaps;

	return err;
}

int HalCtlsHandleAllHalMap(AFB_ApiT apiHandle, int sndCardId, struct CtlHalAlsaMapT *currentCtlHalAlsaMapT)
{
	int idx, err = 0;

	char cardIdString[6];

	snprintf(cardIdString, 6, "hw:%i", sndCardId);

	HalCtlsSubscribeToAlsaCardEvent(apiHandle, cardIdString);

	for(idx = 0; idx < currentCtlHalAlsaMapT->ctlsCount; idx++)
		err += HalCtlsHandleOneHalMapObject(apiHandle, cardIdString, &currentCtlHalAlsaMapT->ctls[idx]);

	return err;
}

int HalCtlsHalMapConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *AlsaMapJ)
{
	CtlConfigT *ctrlConfig;
	struct SpecificHalData *currentHalData;

	ctrlConfig = (CtlConfigT *) AFB_ApiGetUserData(apiHandle);
	if(! ctrlConfig)
		return -1;

	currentHalData = (struct SpecificHalData *) getExternalData(ctrlConfig);
	if(! currentHalData)
		return -2;

	if(AlsaMapJ) {
		currentHalData->ctlHalSpecificData->ctlHalAlsaMapT = calloc(1, sizeof(struct CtlHalAlsaMapT));

		if(HalCtlsProcessAllHalMap(apiHandle, AlsaMapJ, currentHalData->ctlHalSpecificData->ctlHalAlsaMapT)) {
			AFB_ApiError(apiHandle, "Failed to process 'halmap' section");
			return -3;
		}
	}
	else if(currentHalData->status == HAL_STATUS_UNAVAILABLE) {
		AFB_ApiWarning(apiHandle, "Hal is unavailable, 'halmap' section data can't be handle");
		return 1;
	}
	else if(currentHalData->sndCardId < 0) {
		AFB_ApiError(apiHandle, "Hal alsa card id is not valid, 'halmap' section data can't be handle");
		return -6;
	}
	else if(! currentHalData->ctlHalSpecificData->ctlHalAlsaMapT) {
		AFB_ApiWarning(apiHandle, "'halmap' section data is empty");
		return 2;
	}
	else if(! (currentHalData->ctlHalSpecificData->ctlHalAlsaMapT->ctlsCount > 0)) {
		AFB_ApiWarning(apiHandle, "No alsa controls defined in 'halmap' section");
		return 3;
	}
	else if(HalCtlsHandleAllHalMap(apiHandle, currentHalData->sndCardId, currentHalData->ctlHalSpecificData->ctlHalAlsaMapT)) {
		AFB_ApiError(apiHandle, "Failed to handle 'halmap' section");
		return -9;
	}

	return 0;
}

/*******************************************************************************
 *		HAL controllers verbs functions				       *
 ******************************************************************************/

void HalCtlsActionOnMixer(AFB_ReqT request, enum ActionOnMixerType actionType)
{
	int idx, count;

	char *apiToCall;

	AFB_ApiT apiHandle;
	CtlConfigT *ctrlConfig;

	struct SpecificHalData *currentCtlHalData;
	struct CtlHalMixerData *currentMixerData = NULL;
	struct CtlHalMixerDataT *currentMixerDataT = 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;
	}

	switch(actionType) {
		case ACTION_ON_MIXER_STREAM:
			currentMixerData = (struct CtlHalMixerData *) AFB_ReqVCBData(request);
			if(! currentMixerData) {
				AFB_ReqFail(request, "hal_call_data", "Can't get current call data");
				return;
			}
			count = 1;
			break;

		case ACTION_ON_MIXER_PLAYBACK:
		case ACTION_ON_MIXER_CAPTURE:
		case ACTION_ON_MIXER_ALL_STREAM:
			currentMixerDataT = (struct CtlHalMixerDataT *) AFB_ReqVCBData(request);
			if(! currentMixerDataT) {
				AFB_ReqFail(request, "hal_call_data", "Can't get current call data");
				return;
			}
			count = currentMixerDataT->count;
			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++) {
		switch(actionType) {
			case ACTION_ON_MIXER_PLAYBACK:
			case ACTION_ON_MIXER_CAPTURE:
			case ACTION_ON_MIXER_ALL_STREAM:
				currentMixerData = &currentMixerDataT->data[idx];
				break;

			default:
				break;
		}

		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;
		}

		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_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 HalCtlsActionOnStream(AFB_ReqT request)
{
	HalCtlsActionOnMixer(request, ACTION_ON_MIXER_STREAM);
}

void HalCtlsActionOnPlayback(AFB_ReqT request)
{
	HalCtlsActionOnMixer(request, ACTION_ON_MIXER_PLAYBACK);
}

void HalCtlsActionOnCapture(AFB_ReqT request)
{
	HalCtlsActionOnMixer(request, ACTION_ON_MIXER_CAPTURE);
}

void HalCtlsActionOnAllStream(AFB_ReqT request)
{
	HalCtlsActionOnMixer(request, ACTION_ON_MIXER_ALL_STREAM);
}

json_object *HalCtlsGetJsonArrayForMixerDataTable(AFB_ApiT apiHandle, struct CtlHalMixerDataT *currentMixerDataT, enum MixerDataType dataType)
{
	unsigned int idx;

	json_object *mixerDataArray, *currentMixerData;

	if(! apiHandle) {
		AFB_ApiError(apiHandle, "Can't get current hal controller api handle");
		return NULL;
	}

	if(! currentMixerDataT) {
		AFB_ApiError(apiHandle, "Can't get mixer data table to handle");
		return NULL;
	}

	mixerDataArray = json_object_new_array();
	if(! mixerDataArray) {
		AFB_ApiError(apiHandle, "Can't generate json mixer data array");
		return NULL;
	}

	for(idx = 0; idx < currentMixerDataT->count; idx++) {
		switch(dataType) {
			case MIXER_DATA_STREAMS:
				wrap_json_pack(&currentMixerData,
					       "{s:s s:s}",
					       "name", currentMixerDataT->data[idx].verb,
					       "cardId", currentMixerDataT->data[idx].streamCardId);
				break;

			case MIXER_DATA_PLAYBACKS:
			case MIXER_DATA_CAPTURES :
				wrap_json_pack(&currentMixerData,
					       "{s:s s:s}",
					       "name", currentMixerDataT->data[idx].verb,
					       "mixer-name", currentMixerDataT->data[idx].verbToCall,
					       "uid", currentMixerDataT->data[idx].streamCardId ? currentMixerDataT->data[idx].streamCardId : "none");
				break;

			default:
				json_object_put(mixerDataArray);
				return NULL;
		}
		json_object_array_add(mixerDataArray, currentMixerData);
	}

	return mixerDataArray;
}

json_object *HalCtlsGetJsonArrayForControls(AFB_ApiT apiHandle, struct CtlHalAlsaMapT *currentAlsaMapDataT)
{
	unsigned int idx;

	json_object *alsaMapDataArray, *currentAlsaMapData;

	if(! apiHandle) {
		AFB_ApiError(apiHandle, "Can't get current hal controller api handle");
		return NULL;
	}

	if(! currentAlsaMapDataT) {
		AFB_ApiError(apiHandle, "Can't get Alsa map data table to handle");
		return NULL;
	}

	alsaMapDataArray = json_object_new_array();
	if(! alsaMapDataArray) {
		AFB_ApiError(apiHandle, "Can't generate json mixer data array");
		return NULL;
	}

	for(idx = 0; idx < currentAlsaMapDataT->ctlsCount; idx++) {
		wrap_json_pack(&currentAlsaMapData,
			       "{s:s s:s}",
			       "name", currentAlsaMapDataT->ctls[idx].uid,
			       "info", currentAlsaMapDataT->ctls[idx].info ? currentAlsaMapDataT->ctls[idx].info : "none");

		json_object_array_add(alsaMapDataArray, currentAlsaMapData);
	}

	return alsaMapDataArray;
}

void HalCtlsInfo(AFB_ReqT request)
{
	char *apiToCall, *returnedStatus = NULL, *returnedInfo = NULL;

	AFB_ApiT apiHandle;
	CtlConfigT *ctrlConfig;

	struct SpecificHalData *currentCtlHalData;

	json_object *requestJson, *toReturnJ = NULL, *requestAnswer, *streamsArray, *playbacksArray, *capturesArray, *controlsArray;

	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_ReqNotice(request, "Can't get request json");
	}
	else if(json_object_is_type(requestJson, json_type_object) && json_object_get_object(requestJson)->count > 0) {
		apiToCall = currentCtlHalData->ctlHalSpecificData->mixerApiName;
		if(! apiToCall) {
			AFB_ReqFail(request, "mixer_api", "Can't get mixer api");
			return;
		}

		if(HalCtlsGetInfoFromMixer(apiHandle, apiToCall, requestJson, &toReturnJ, &returnedStatus, &returnedInfo)) {
			if(returnedStatus && returnedInfo) {
				AFB_ReqFailF(request,
					     "mixer_info",
					     "Call to mixer info verb didn't succeed with status '%s' and info '%s'",
					     returnedStatus,
					     returnedInfo);
			}
			else {
				AFB_ReqFail(request, "mixer_info", "Call to mixer info verb didn't succeed");
			}
			return;
		}

		AFB_ReqSuccess(request, toReturnJ, "Mixer requested data");
		return;
	}

	if(! (streamsArray = HalCtlsGetJsonArrayForMixerDataTable(apiHandle,
								  &currentCtlHalData->ctlHalSpecificData->ctlHalStreamsData,
								  MIXER_DATA_STREAMS))) {
		AFB_ReqFail(request, "streams_data", "Didn't succeed to generate streams data array");
		return;
	}

	if(! (playbacksArray = HalCtlsGetJsonArrayForMixerDataTable(apiHandle,
								    &currentCtlHalData->ctlHalSpecificData->ctlHalPlaybacksData,
								    MIXER_DATA_PLAYBACKS))) {
		AFB_ReqFail(request, "playbacks_data", "Didn't succeed to generate playbacks data array");
		return;
	}

	if(! (capturesArray = HalCtlsGetJsonArrayForMixerDataTable(apiHandle,
								   &currentCtlHalData->ctlHalSpecificData->ctlHalCapturesData,
								   MIXER_DATA_CAPTURES))) {
		AFB_ReqFail(request, "captures_data", "Didn't succeed to generate captures data array");
		return;
	}

	if(! (controlsArray = HalCtlsGetJsonArrayForControls(apiHandle,
							     currentCtlHalData->ctlHalSpecificData->ctlHalAlsaMapT))) {
		AFB_ReqFail(request, "controls_data", "Didn't succeed to generate controls data array");
		return;
	}

	wrap_json_pack(&requestAnswer,
		       "{s:o s:o s:o s:o}",
		       "streams", streamsArray,
		       "playbacks", playbacksArray,
		       "captures", capturesArray,
		       "controls", controlsArray);

	AFB_ReqSuccess(request, requestAnswer, "Requested data");
}