summaryrefslogtreecommitdiffstats
path: root/ahl-utilities/ahl-policy-utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'ahl-utilities/ahl-policy-utils.h')
-rw-r--r--ahl-utilities/ahl-policy-utils.h177
1 files changed, 177 insertions, 0 deletions
diff --git a/ahl-utilities/ahl-policy-utils.h b/ahl-utilities/ahl-policy-utils.h
new file mode 100644
index 0000000..6adfa4e
--- /dev/null
+++ b/ahl-utilities/ahl-policy-utils.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2017 "Audiokinetic Inc"
+ *
+ * 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.
+ */
+
+#ifndef AHL_POLICY_UTILS_INCLUDE
+#define AHL_POLICY_UTILS_INCLUDE
+
+#define AFB_BINDING_VERSION 2
+#include <json-c/json.h>
+#include <afb/afb-binding.h>
+#include <glib.h>
+
+#define AHL_POLICY_ACCEPT 1
+#define AHL_POLICY_REJECT 0
+#define AHL_POLICY_UTIL_SUCCESS 0
+#define AHL_POLICY_UTIL_FAIL 1
+
+typedef int endpointID_t;
+typedef int streamID_t;
+
+typedef enum StreamEvent {
+ STREAM_EVENT_START = 0, // Stream is inactive
+ STREAM_EVENT_STOP, // Stream is running
+ STREAM_EVENT_PAUSE, // Audio stream paused
+ STREAM_EVENT_RESUME, // Audio stream resumed
+ STREAM_EVENT_MUTED, // Audio stream muted
+ STREAM_EVENT_UNMUTED, // Audio stream unmuted
+ STREAM_EVENT_MAXVALUE // Enum count, keep at the end
+} StreamEventT;
+
+typedef enum StreamMute {
+ STREAM_UNMUTED = 0, // Stream is not muted
+ STREAM_MUTED, // Stream is muted
+ STREAM_MUTE_MAXVALUE, // Enum count, keep at the end
+} StreamMuteT;
+
+typedef enum EndpointType {
+ ENDPOINTTYPE_SOURCE = 0, // source devices
+ ENDPOINTTYPE_SINK, // sink devices
+ ENDPOINTTYPE_MAXVALUE // Enum count, keep at the end
+} EndpointTypeT;
+
+typedef enum StreamState {
+ STREAM_STATE_IDLE = 0, // Stream is inactive
+ STREAM_STATE_RUNNING, // Stream is active and running
+ STREAM_STATE_PAUSED, // Stream is active but paused
+ STREAM_STATE_MAXVALUE // Enum count, keep at the end
+} StreamStateT;
+
+// Define default behavior of audio role when interrupting lower priority sources
+typedef enum InterruptBehavior {
+ INTERRUPTBEHAVIOR_CONTINUE = 0, // Continue to play lower priority source when interrupted (e.g. media may be ducked)
+ INTERRUPTBEHAVIOR_CANCEL, // Abort playback of lower priority source when interrupted (e.g. non-important HMI feedback that does not make sense later)
+ INTERRUPTBEHAVIOR_PAUSE, // Pause lower priority source when interrupted, to be resumed afterwards (e.g. non-temporal guidance)
+ INTERRUPTBEHAVIOR_MAXVALUE, // Enum count, keep at the end
+} InterruptBehaviorT;
+
+typedef enum DeviceURIType {
+ DEVICEURITYPE_ALSA_HW = 0, // Alsa hardware device URI
+ DEVICEURITYPE_ALSA_DMIX, // Alsa Dmix device URI (only for playback devices)
+ DEVICEURITYPE_ALSA_DSNOOP, // Alsa DSnoop device URI (only for capture devices)
+ DEVICEURITYPE_ALSA_SOFTVOL, // Alsa softvol device URI
+ DEVICEURITYPE_ALSA_PLUG, // Alsa plug device URI
+ DEVICEURITYPE_ALSA_OTHER, // Alsa domain URI device of unspecified type
+ DEVICEURITYPE_NOT_ALSA, // Unknown (not ALSA domain)
+ DEVICEURITYPE_MAXVALUE // Enum count, keep at the end
+} DeviceURITypeT;
+
+// CPU endianness assumed in all formats
+typedef enum SampleType {
+ AHL_FORMAT_UNKNOWN = -1, // Unknown
+ AHL_FORMAT_U8 = 0, // Unsigned 8 bit
+ AHL_FORMAT_S16, // Signed 16 bit Little Endian
+ AHL_FORMAT_S24, // Signed 24 bit Little Endian using low three bytes in 32-bit word
+ AHL_FORMAT_S32, // Signed 32 bit Little Endian
+ AHL_FORMAT_FLOAT, // Float 32 bit Little Endian, Range -1.0 to 1.0
+ AHL_FORMAT_FLOAT64, // Float 64 bit Little Endian, Range -1.0 to 1.0
+ AHL_FORMAT_IEC958, // IEC-958 Little Endian (SPDIF)
+ AHL_FORMAT_MU_LAW, // Mu-Law
+ AHL_FORMAT_A_LAW, // A-Law
+ AHL_FORMAT_IMA_ADPCM, // Ima-ADPCM
+ AHL_FORMAT_MPEG, // MPEG
+ AHL_FORMAT_GSM, // GSM
+ AHL_FORMAT_G723, // G723
+ AHL_FORMAT_DSD, // Direct stream digital
+ AHL_FORMAT_MAXVALUE, // Enum count, keep at the end
+} SampleTypeT;
+
+typedef struct AudioFormat {
+ int sampleRate; // Sample rate
+ int numChannels; // Number of channels
+ SampleTypeT sampleType; // Sample type
+ // TODO: Interleaving?
+ // TODO: Sample sub format?
+} AudioFormatT;
+
+typedef struct AlsaDeviceInfo {
+ int cardNum; // HW card number
+ int deviceNum; // HW device number
+ int subDeviceNum; // HW sub device number
+} AlsaDeviceInfoT;
+
+typedef enum EndpointSelectionMode {
+ ENDPOINTSELMODE_AUTO = 0, // Automatic endpoint selection based on config priority
+ ENDPOINTSELMODE_MANUAL, // Explicit endpoint selection
+ ENDPOINTSELMODEMAXVALUE, // Enum count, keep at the end
+} EndpointSelectionModeT;
+
+typedef struct EndpointInfo
+{
+ endpointID_t endpointID; // Unique endpoint ID (per type)
+ EndpointTypeT type; // Source or sink device
+ char * gsDeviceName; // Unique device card name
+ char * gsDisplayName; // Application display name
+ char * gsDeviceURI; // Associated URI
+ char * gsDeviceDomain; // Device URI domain (e.g. alsa or pulse)
+ char * pRoleName; // Role assigned to this endpoint
+ DeviceURITypeT deviceURIType; // Device URI type (includes audio domain information)
+ char * gsHALAPIName; // HAL associated with the device (for volume control)
+ AlsaDeviceInfoT alsaInfo; // ALSA specific device information
+ AudioFormatT format; // Preferred audio format supported (later could be array of supported formats)
+ int iVolume; // Storage for current endpoint volume (policy effected).
+ GHashTable * pPropTable; // Storage for array of properties (policy effected)
+} EndpointInfoT;
+
+typedef struct StreamInfo {
+ streamID_t streamID; // Stream unique ID
+ EndpointInfoT * pEndpointInfo; // Associated endpoint information (reference)
+ StreamStateT streamState; // Stream activity state
+ StreamMuteT streamMute; // Stream mute state
+ struct afb_event streamStateEvent; // Stream specific event for stream state changes
+ EndpointSelectionModeT endpointSelMode; // Automatic (priority based) or manual endpoint selection
+ char * pRoleName; // Role string identifier (from role config but could be programatically overriden later)
+ int iPriority; // Role normalized priority (0-100) (from role config but could be programatically overriden later)
+ InterruptBehaviorT eInterruptBehavior; // Role behavior when interrupting lower priority streams (from role config but could be programatically overriden later)
+} StreamInfoT;
+
+
+typedef struct StreamPolicyInfo {
+ streamID_t streamID;
+ int RolePriority;
+ char * pAudioRole;
+ InterruptBehaviorT interruptBehavior;
+ int iDuckVolume; //duck Volume
+} StreamPolicyInfoT;
+
+typedef struct EndPointPolicyInfo {
+ endpointID_t endpointID;
+ EndpointTypeT type;
+ DeviceURITypeT deviceType;
+ char * pDeviceName;
+ char * pHalApiName;
+ int iVolume; //Current Volume
+ GArray * streamInfo; //List of playing or duck stream at a given endpoint
+} EndPointPolicyInfoT;
+
+void Add_Endpoint_Property_Double( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, double in_dPropertyValue);
+void Add_Endpoint_Property_Int( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, int in_iPropertyValue);
+void Add_Endpoint_Property_String( EndpointInfoT * io_pEndpointInfo, char * in_pPropertyName, const char * in_pPropertyValue);
+int PolicyEndpointStructToJSON(EndpointInfoT * pPolicyEndpoint, json_object **ppPolicyEndpointJ);
+int PolicyCtxJSONToEndpoint(json_object *pEndpointJ, EndpointInfoT * pPolicyStream);
+int PolicyStreamStructToJSON(StreamInfoT * pPolicyStream, json_object **ppPolicyStreamJ);
+int PolicyCtxJSONToStream(json_object *pStreamJ, StreamInfoT * pPolicyStream);
+
+#endif // AHL_POLICY_UTILS_INCLUDE
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
###########################################################################
# Copyright 2015, 2016, 2017 IoT.bzh
#
# author: Fulup Ar Foll <fulup@iot.bzh>
# contrib: 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.
###########################################################################

#--------------------------------------------------------------------------
#  WARNING:
#     Do not change this cmake template
#     Customise your preferences in "./conf.d/cmake/config.cmake"
#--------------------------------------------------------------------------
# CMake 3.6 imported macros to simulate list(FILTER ...) subcommand
# -----------------------
MACRO(PARSE_ARGUMENTS prefix arg_names option_names)
SET(DEFAULT_ARGS)
FOREACH(arg_name ${arg_names})
  SET(${prefix}_${arg_name})
ENDFOREACH(arg_name)
FOREACH(option ${option_names})
  SET(${prefix}_${option} FALSE)
ENDFOREACH(option)

SET(current_arg_name DEFAULT_ARGS)
SET(current_arg_list)
FOREACH(arg ${ARGN})
  LIST_CONTAINS(is_arg_name ${arg} ${arg_names})
  IF (is_arg_name)
	SET(${prefix}_${current_arg_name} ${current_arg_list})
	SET(current_arg_name ${arg})
	SET(current_arg_list)
  ELSE (is_arg_name)
	LIST_CONTAINS(is_option ${arg} ${option_names})
	IF (is_option)
  SET(${prefix}_${arg} TRUE)
	ELSE (is_option)
  SET(current_arg_list ${current_arg_list} ${arg})
	ENDIF (is_option)
  ENDIF (is_arg_name)
ENDFOREACH(arg)
SET(${prefix}_${current_arg_name} ${current_arg_list})
ENDMACRO(PARSE_ARGUMENTS)

MACRO(LIST_CONTAINS var value)
SET(${var})
FOREACH (value2 ${ARGN})
  IF (${value} STREQUAL ${value2})
	SET(${var} TRUE)
  ENDIF (${value} STREQUAL ${value2})
ENDFOREACH (value2)
ENDMACRO(LIST_CONTAINS)

MACRO(LIST_FILTER)
PARSE_ARGUMENTS(LIST_FILTER "OUTPUT_VARIABLE" "" ${ARGV})
# Check arguments.
LIST(LENGTH LIST_FILTER_DEFAULT_ARGS LIST_FILTER_default_length)
IF(${LIST_FILTER_default_length} EQUAL 0)
  MESSAGE(FATAL_ERROR "LIST_FILTER: missing list variable.")
ENDIF(${LIST_FILTER_default_length} EQUAL 0)
IF(${LIST_FILTER_default_length} EQUAL 1)
  MESSAGE(FATAL_ERROR "LIST_FILTER: missing regular expression variable.")
ENDIF(${LIST_FILTER_default_length} EQUAL 1)
# Reset output variable
IF(NOT LIST_FILTER_OUTPUT_VARIABLE)
  SET(LIST_FILTER_OUTPUT_VARIABLE "LIST_FILTER_internal_output")
ENDIF(NOT LIST_FILTER_OUTPUT_VARIABLE)
SET(${LIST_FILTER_OUTPUT_VARIABLE})
# Extract input list from arguments
LIST(GET LIST_FILTER_DEFAULT_ARGS 0 LIST_FILTER_input_list)
LIST(REMOVE_AT LIST_FILTER_DEFAULT_ARGS 0)
FOREACH(LIST_FILTER_item ${${LIST_FILTER_input_list}})
  FOREACH(LIST_FILTER_regexp_var ${LIST_FILTER_DEFAULT_ARGS})
	FOREACH(LIST_FILTER_regexp ${${LIST_FILTER_regexp_var}})
	  IF(${LIST_FILTER_item} MATCHES ${LIST_FILTER_regexp})
		LIST(APPEND ${LIST_FILTER_OUTPUT_VARIABLE} ${LIST_FILTER_item})
	  ENDIF(${LIST_FILTER_item} MATCHES ${LIST_FILTER_regexp})
	ENDFOREACH(LIST_FILTER_regexp ${${LIST_FILTER_regexp_var}})
  ENDFOREACH(LIST_FILTER_regexp_var)
ENDFOREACH(LIST_FILTER_item)
# If OUTPUT_VARIABLE is not specified, overwrite the input list.
IF(${LIST_FILTER_OUTPUT_VARIABLE} STREQUAL "LIST_FILTER_internal_output")
  SET(${LIST_FILTER_input_list} ${${LIST_FILTER_OUTPUT_VARIABLE}})
ENDIF(${LIST_FILTER_OUTPUT_VARIABLE} STREQUAL "LIST_FILTER_internal_output")
ENDMACRO(LIST_FILTER)

# Generic useful macro
# -----------------------
macro(PROJECT_TARGET_ADD TARGET_NAME)
	set_property(GLOBAL APPEND PROPERTY PROJECT_TARGETS ${TARGET_NAME})
	set(TARGET_NAME ${TARGET_NAME})
endmacro(PROJECT_TARGET_ADD)

macro(PROJECT_PKGDEP_ADD PKG_NAME)
	set_property(GLOBAL APPEND PROPERTY PROJECT_PKG_DEPS ${PKG_NAME})
endmacro(PROJECT_PKGDEP_ADD)

macro(defstr name value)
	add_definitions(-D${name}=${value})
endmacro(defstr)

macro(configure_files_in_dir dir)
	file(GLOB filelist "${dir}/*in")
	foreach(file ${filelist})
		get_filename_component(filename ${file} NAME)
		string(REGEX REPLACE "target" "${RSYNC_TARGET}" destinationfile ${filename})
		string(REGEX REPLACE ".in$" "" destinationfile ${destinationfile})
		configure_file(${file} ${CMAKE_CURRENT_BINARY_DIR}/target/${destinationfile})
		set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/target/${destinationfile}")
	endforeach()
endmacro(configure_files_in_dir)

# Create custom target dedicated for HTML5 and DATA AGL target type
macro(add_input_files INPUT_FILES)
	if(NOT DEFINED XML_FILES)
		set(ext_reg "xml$")
		set(XML_LIST ${INPUT_FILES})
		list_filter(XML_LIST ext_reg)
	endif()
	if(NOT DEFINED LUA_LIST)
		set(ext_reg "lua$")
		set(LUA_LIST ${INPUT_FILES})
		list_filter(LUA_LIST ext_reg)
	endif()
	if(NOT DEFINED JSON_FILES)
		set(ext_reg "json$")
		set(JSON_LIST ${INPUT_FILES})
		list_filter(JSON_LIST ext_reg)
	endif()

	# These are v3.6 subcommand. Not used as default for now as
	# many dev use Ubuntu 16.04 which have only 3.5 version
	#list(FILTER XML_LIST INCLUDE REGEX "xml$")
	#list(FILTER LUA_LIST INCLUDE REGEX "lua$")
	#list(FILTER JSON_LIST INCLUDE REGEX "json$")

	add_custom_target(${TARGET_NAME} ALL
	DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}
	)

	foreach(file ${XML_LIST})
		add_custom_command(TARGET ${TARGET_NAME}
			PRE_BUILD
			WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
			COMMAND ${XML_CHECKER} ${file}
		)
	endforeach()
	foreach(file ${LUA_LIST})
	add_custom_command(TARGET ${TARGET_NAME}
		PRE_BUILD
		WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
		COMMAND ${LUA_CHECKER} ${file}
	)
	endforeach()
	foreach(file ${JSON_LIST})
	add_custom_command(TARGET ${TARGET_NAME}
		PRE_BUILD
		WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
		COMMAND cat ${file} | ${JSON_CHECKER}
	)
	endforeach()

	add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}
	DEPENDS ${INPUT_FILES}
	COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}
	COMMAND touch ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}
	COMMAND cp -r ${INPUT_FILES} ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}
	)
endmacro()

# Set the name of the OPENAPI definition JSON file for binding v2
macro(set_openapi_filename openapi_filename)
	set(OPENAPI_DEF ${openapi_filename} CACHE STRING "OpenAPI JSON file name used to generate binding header file before building a binding v2 target.")
endmacro()

# Pre-packaging
macro(project_targets_populate)
	# Default Widget default directory
	set(BINDIR bin)
	set(ETCDIR etc)
	set(LIBDIR lib)
	set(HTTPDIR htdocs)
	set(DATADIR data)
	set(PACKAGE_BINDIR  ${PROJECT_PKG_BUILD_DIR}/${BINDIR})
	set(PACKAGE_ETCDIR  ${PROJECT_PKG_BUILD_DIR}/${ETCDIR})
	set(PACKAGE_LIBDIR  ${PROJECT_PKG_BUILD_DIR}/${LIBDIR})
	set(PACKAGE_HTTPDIR ${PROJECT_PKG_BUILD_DIR}/${HTTPDIR})
	set(PACKAGE_DATADIR ${PROJECT_PKG_BUILD_DIR}/${DATADIR})

	add_custom_command(OUTPUT ${PACKAGE_BINDIR} ${PACKAGE_ETCDIR} ${PACKAGE_LIBDIR} ${PACKAGE_HTTPDIR} ${PACKAGE_DATADIR}
		COMMAND mkdir -p ${PACKAGE_BINDIR} ${PACKAGE_ETCDIR} ${PACKAGE_LIBDIR} ${PACKAGE_HTTPDIR} ${PACKAGE_DATADIR})
	add_custom_target(populate DEPENDS ${PACKAGE_BINDIR} ${PACKAGE_ETCDIR} ${PACKAGE_LIBDIR} ${PACKAGE_HTTPDIR} ${PACKAGE_DATADIR})

	INSTALL(CODE "execute_process(COMMAND make populate)")
	INSTALL(DIRECTORY ${PROJECT_PKG_BUILD_DIR}/
		DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}
	)

	get_property(PROJECT_TARGETS GLOBAL PROPERTY PROJECT_TARGETS)
	foreach(TARGET ${PROJECT_TARGETS})
	get_target_property(T ${TARGET} LABELS)
	if(T)
		# Declaration of a custom command that will populate widget tree with the target
		set(POPULE_PACKAGE_TARGET "project_populate_${TARGET}")

		get_target_property(P ${TARGET} PREFIX)
		get_target_property(BD ${TARGET} BINARY_DIR)
		get_target_property(SD ${TARGET} SOURCE_DIR)
		get_target_property(OUT ${TARGET} OUTPUT_NAME)

		if(P MATCHES "NOTFOUND$")
			if (${T} STREQUAL "BINDING")
				set(P "lib")
			else()
				set(P "")
			endif()
		endif()

		if(${T} STREQUAL "BINDING")
			list(APPEND BINDINGS_LIST "${P}${OUT}")
			add_custom_command(OUTPUT ${PACKAGE_LIBDIR}/${P}${OUT}.so
				DEPENDS ${BD}/${P}${OUT}.so
				COMMAND mkdir -p ${PACKAGE_LIBDIR}
				COMMAND cp ${BD}/${P}${OUT}.so ${PACKAGE_LIBDIR}
			)
			add_custom_target(${POPULE_PACKAGE_TARGET} DEPENDS ${PACKAGE_LIBDIR}/${P}${OUT}.so)
			add_dependencies(populate ${POPULE_PACKAGE_TARGET})
			add_dependencies(${POPULE_PACKAGE_TARGET} ${TARGET})
		elseif(${T} STREQUAL "BINDINGV2")
			if (OPENAPI_DEF)
				add_custom_command(OUTPUT ${SD}/${OPENAPI_DEF}.h
					DEPENDS ${SD}/${OPENAPI_DEF}.json
					COMMAND afb-genskel ${SD}/${OPENAPI_DEF}.json > ${SD}/${OPENAPI_DEF}.h
				)
				add_custom_target("${TARGET}_GENSKEL" DEPENDS ${SD}/${OPENAPI_DEF}.h
					COMMENT "Generating OpenAPI header file ${OPENAPI_DEF}.h")
				add_dependencies(${TARGET} "${TARGET}_GENSKEL")
			else()
				add_custom_command(OUTPUT ${SD}/${OUT}-apidef.h
					DEPENDS ${SD}/${OUT}-apidef.json
					COMMAND afb-genskel ${SD}/${OUT}-apidef.json > ${SD}/${OUT}-apidef.h
				)
				add_custom_target("${TARGET}_GENSKEL" DEPENDS ${SD}/${OUT}-apidef.h
					COMMENT "Generating OpenAPI header file ${OUT}-apidef.h")
				add_dependencies(${TARGET} "${TARGET}_GENSKEL")
			endif()

			add_custom_command(OUTPUT ${PACKAGE_LIBDIR}/${P}${OUT}.so
					DEPENDS ${BD}/${P}${OUT}.so
					COMMAND mkdir -p ${PACKAGE_LIBDIR}
					COMMAND cp ${BD}/${P}${OUT}.so ${PACKAGE_LIBDIR}
				)
				add_custom_target(${POPULE_PACKAGE_TARGET} DEPENDS ${PACKAGE_LIBDIR}/${P}${OUT}.so)
				add_dependencies(populate ${POPULE_PACKAGE_TARGET})
				add_dependencies(${POPULE_PACKAGE_TARGET} ${TARGET})
		elseif(${T} STREQUAL "EXECUTABLE")
			add_custom_command(OUTPUT ${PACKAGE_BINDIR}/${P}${OUT}
				DEPENDS ${BD}/${P}${OUT}
				COMMAND mkdir -p ${PACKAGE_BINDIR}
				COMMAND cp ${BD}/${P}${OUT} ${PACKAGE_BINDIR}
			)
			add_custom_target(${POPULE_PACKAGE_TARGET} DEPENDS ${PACKAGE_BINDIR}/${P}${OUT})
			add_dependencies(populate ${POPULE_PACKAGE_TARGET})
			add_dependencies(${POPULE_PACKAGE_TARGET} ${TARGET})
		elseif(${T} STREQUAL "HTDOCS")
			add_custom_command(OUTPUT ${PACKAGE_HTTPDIR}-xx
				DEPENDS ${BD}/${P}${OUT}
				COMMAND mkdir -p ${PACKAGE_HTTPDIR}
				COMMAND touch ${PACKAGE_HTTPDIR}
				COMMAND cp -r ${BD}/${P}${OUT}/* ${PACKAGE_HTTPDIR}
			)
			add_custom_target(${POPULE_PACKAGE_TARGET} DEPENDS ${PACKAGE_HTTPDIR}-xx)
			add_dependencies(populate ${POPULE_PACKAGE_TARGET})
			add_dependencies(${POPULE_PACKAGE_TARGET} ${TARGET})
		elseif(${T} STREQUAL "DATA")
			# Generate list of output files instead of just one output directory
			get_target_property(SF ${TARGET} SOURCES)
			foreach(file ${SF})
				get_filename_component(JUST_FILENAME ${file} NAME)
				list(APPEND OUTPUT_FILES ${PACKAGE_DATADIR}/${JUST_FILENAME})
			endforeach()
			add_custom_target(${POPULE_PACKAGE_TARGET})
			add_custom_command(TARGET ${POPULE_PACKAGE_TARGET}
				POST_BUILD
				COMMAND mkdir -p ${PACKAGE_DATADIR}
				COMMAND touch ${PACKAGE_DATADIR}
				COMMAND cp -r ${BD}/${TARGET} ${PACKAGE_DATADIR}
			)
			add_dependencies(populate ${POPULE_PACKAGE_TARGET})
			add_dependencies(${POPULE_PACKAGE_TARGET} ${TARGET})
		endif(${T} STREQUAL "BINDING")
		elseif(${CMAKE_BUILD_TYPE} MATCHES "[Dd][Ee][Bb][Uu][Gg]")
			MESSAGE("${Yellow}.. Warning: ${TARGET} ignored when packaging.${ColourReset}")
		endif()
	endforeach()
endmacro(project_targets_populate)

macro(remote_targets_populate)
	if (DEFINED ENV{RSYNC_TARGET})
		set (RSYNC_TARGET $ENV{RSYNC_TARGET})
	endif()
	if (DEFINED ENV{RSYNC_PREFIX})
		set (RSYNC_PREFIX $ENV{RSYNC_PREFIX})
	endif()

	set(
		REMOTE_LAUNCH "Test on target with: ${CMAKE_CURRENT_BINARY_DIR}/target/start-on-${RSYNC_TARGET}.sh"
		CACHE STRING "Command to start ${PROJECT_NAME} on remote target ${RSYNC_TARGET}"
	)

	if(NOT RSYNC_TARGET OR NOT RSYNC_PREFIX)
		message ("${Yellow}.. Warning: RSYNC_TARGET RSYNC_PREFIX not defined 'make remote-target-populate' not instanciated${ColourReset}")
		add_custom_target(remote-target-populate
			COMMENT "${Red}*** Fatal: RSYNC_TARGET RSYNC_PREFIX environment variables required with 'make remote-target-populate'${ColourReset}"
			COMMAND exit -1
		)
	else()
		set(BINDINGS_REGEX "not_set")
		if(DEFINED BINDINGS_LIST)
			list(LENGTH BINDINGS_LIST BINDINGS_LIST_LENGTH)
			if(BINDINGS_LIST_LENGTH EQUAL 1)
				list(GET BINDINGS_LIST 0 BINDINGS_REGEX)
				string(APPEND BINDINGS_REGEX ".so")
			elseif(BINDINGS_LIST_LENGTH GREATER 1)
				foreach(B IN LISTS BINDINGS_LIST)
					STRING(APPEND BINDINGS_STR "${B}|")
				endforeach()
					STRING(REGEX REPLACE "^(.*)\\|$" "(\\1).so" BINDINGS_REGEX ${BINDINGS_STR})
			endif()
		endif()

		configure_files_in_dir(${TEMPLATE_DIR})
		configure_files_in_dir(${TEMPLATE_DIR})

		add_custom_target(remote-target-populate
			COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/target/*.sh
			COMMAND rsync -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" --archive --delete ${PROJECT_PKG_BUILD_DIR}/ ${RSYNC_TARGET}:${RSYNC_PREFIX}/${PROJECT_NAME}
		)

		add_custom_command(TARGET remote-target-populate
		POST_BUILD
		COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --green --bold ${REMOTE_LAUNCH}
		)

		add_dependencies(remote-target-populate populate)
	endif()
endmacro(remote_targets_populate)

macro(wgt_package_build)
	if(NOT EXISTS ${WIDGET_CONFIG_TEMPLATE})
		MESSAGE(FATAL_ERROR "${Red}WARNING ! Missing mandatory files to build widget file.\nYou need a config.xml template: please specify WIDGET_CONFIG_TEMPLATE correctly.${ColourReset}")
	endif()
	if(NOT WIDGET_TYPE)
		MESSAGE(FATAL_ERROR "WIDGET_TYPE must be set in your config.cmake.\neg.: set(WIDGET_TYPE application/vnd.agl.service)")
	endif()
	if(NOT DEFINED PROJECT_ICON)
		if( ${WIDGET_TYPE} MATCHES "agl.native")
			set(ICON_PATH ${PKG_APP_TEMPLATE_DIR}/wgt/icon-native.png)
		elseif( ${WIDGET_TYPE} MATCHES "agl.service")
			set(ICON_PATH ${PKG_APP_TEMPLATE_DIR}/wgt/icon-service.png)
		elseif( ${WIDGET_TYPE} MATCHES "x-executable")
			set(ICON_PATH ${PKG_APP_TEMPLATE_DIR}/wgt/icon-qml.png)
		elseif( ${WIDGET_TYPE} MATCHES "text/html")
			set(ICON_PATH ${PKG_APP_TEMPLATE_DIR}/wgt/icon-html5.png)
		endif()
	elseif(EXISTS "${CMAKE_SOURCE_DIR}/${WIDGET_ICON}")
		set(ICON_PATH "${CMAKE_SOURCE_DIR}/${WIDGET_ICON}")
	elseif(EXISTS "${WIDGET_ICON}")
		set(ICON_PATH "${WIDGET_ICON}")
	else()
		set(ICON_PATH ${CMAKE_SOURCE_DIR}/${PROJECT_APP_TEMPLATES_DIR}/wgt/icon-default.png)
	endif()

	if(NOT WIDGET_ENTRY_POINT)
		set(WIDGET_ENTRY_POINT lib)
	endif()

	add_custom_command(OUTPUT ${PROJECT_PKG_BUILD_DIR}/config.xml
		COMMAND ${CMAKE_COMMAND} -DINFILE=${WIDGET_CONFIG_TEMPLATE} -DOUTFILE=${PROJECT_PKG_BUILD_DIR}/config.xml -DPROJECT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_APP_TEMPLATES_DIR}/cmake/configure_file.cmake
		COMMAND cp ${ICON_PATH} ${PROJECT_PKG_BUILD_DIR}/${PROJECT_ICON}

	)
	add_custom_target(packaging_wgt DEPENDS ${PROJECT_PKG_BUILD_DIR}/config.xml)

	# Fulup ??? copy any extra file in wgt/etc into populate package before building the widget
	file(GLOB PROJECT_CONF_FILES "${TEMPLATE_DIR}/etc/*")
	if(${PROJECT_CONF_FILES})
		file(COPY "${TEMPLATE_DIR}/etc/*" DESTINATION ${PROJECT_PKG_BUILD_DIR}/etc/)
	endif(${PROJECT_CONF_FILES})

	add_custom_command(OUTPUT ${PROJECT_NAME}.wgt
		DEPENDS ${PROJECT_TARGETS}
		COMMAND wgtpkg-pack -f -o ${PROJECT_NAME}.wgt ${PROJECT_PKG_BUILD_DIR}
	)

	add_custom_target(widget DEPENDS ${PROJECT_NAME}.wgt)
	add_dependencies(widget populate packaging_wgt)
	set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.wgt")

	if(NOT RSYNC_TARGET)
		message ("${Yellow}.. Warning: RSYNC_TARGET not defined 'make widget-target-install' not instanciated${ColourReset}")
		add_custom_target(widget-target-install
			COMMENT "${Red}*** Fatal: RSYNC_TARGET RSYNC_PREFIX environment variables required with 'make widget-target-install'${ColourReset}"
			COMMAND exit -1
		)
	else()
	configure_files_in_dir(${TEMPLATE_DIR})
	add_custom_target(widget-target-install
	DEPENDS widget
	COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/target/install-wgt-on-${RSYNC_TARGET}.sh
	COMMAND ${CMAKE_CURRENT_BINARY_DIR}/target/install-wgt-on-${RSYNC_TARGET}.sh
	)
endif()

	if(PACKAGE_MESSAGE)
	add_custom_command(TARGET widget
		POST_BUILD
		COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan "++ ${PACKAGE_MESSAGE}")
	endif()
endmacro(wgt_package_build)

macro(rpm_package_build)
	add_custom_command(OUTPUT ${NPKG_PROJECT_NAME}.spec
		DEPENDS ${PROJECT_TARGETS}
				archive
				packaging
		COMMAND rpmbuild --define=\"%_sourcedir ${PROJECT_PKG_ENTRY_POINT}\" -ba  ${PROJECT_PKG_ENTRY_POINT}/${NPKG_PROJECT_NAME}.spec
	)

	add_custom_target(rpm DEPENDS ${NPKG_PROJECT_NAME}.spec)
	add_dependencies(rpm populate packaging)

	if(PACKAGE_MESSAGE)
	add_custom_command(TARGET rpm
		POST_BUILD
		COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan "++ ${PACKAGE_MESSAGE}")
	endif()
endmacro(rpm_package_build)

macro(deb_package_build)
#TODO
endmacro(deb_package_build)

macro(project_package_build)
	if(EXISTS ${TEMPLATE_DIR})
		rpm_package_build()
	endif()

	if(EXISTS ${TEMPLATE_DIR})
		wgt_package_build()
	endif()

	if(EXISTS ${TEMPLATE_DIR})
		deb_package_build()
	endif()
endmacro(project_package_build)

macro(project_subdirs_add)
	set (ARGSLIST ${ARGN})
	list(LENGTH ARGSLIST ARGSNUM)
	if(${ARGSNUM} GREATER 0)
		file(GLOB filelist "${ARGV0}")
	else()
	file(GLOB filelist "*")
	endif()

	foreach(filename ${filelist})
		if(EXISTS "${filename}/CMakeLists.txt")
			add_subdirectory(${filename})
		endif(EXISTS "${filename}/CMakeLists.txt")
	endforeach()
endmacro(project_subdirs_add)

# Print developer helper message when build is done
# -------------------------------------------------------
macro(project_closing_msg)
	get_property(PROJECT_TARGETS_SET GLOBAL PROPERTY PROJECT_TARGETS SET)
	get_property(PROJECT_TARGETS GLOBAL PROPERTY PROJECT_TARGETS)
	if(CLOSING_MESSAGE AND ${PROJECT_TARGETS_SET})
		add_custom_target(${PROJECT_NAME}_build_done ALL
			COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan "++ ${CLOSING_MESSAGE}"
		)
		add_dependencies(${PROJECT_NAME}_build_done
			${PROJECT_TARGETS} populate)
	endif()
endmacro()