aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Collignon <loic.collignon@iot.bzh>2018-06-27 17:30:37 +0200
committerLoïc Collignon <loic.collignon@iot.bzh>2018-06-27 17:30:37 +0200
commit63dc51c35d26c837295ac0ef33c1b8e41353ea35 (patch)
tree24918fe062c14b29f1c69b2e024cb8d66d045c50
parentd9bb450ee8898cb810027897a32afd3adcb05d9f (diff)
Merge 'eel' into 'master'
Replace content from 'master' by content from 'eel' as it's the new version based on 4a on which new development will be done. Change-Id: I2966af7dcee59701ff3a344487c008d7e65e68ed Signed-off-by: Loïc Collignon <loic.collignon@iot.bzh>
-rw-r--r--.gitignore2
-rw-r--r--.gitmodules6
-rw-r--r--CMakeLists.txt23
m---------afb-helpers0
-rw-r--r--app/CMakeLists.txt57
-rw-r--r--app/Mixer.qml151
-rw-r--r--app/app.pri12
-rw-r--r--app/app.pro18
-rw-r--r--app/main.cpp27
-rw-r--r--app/mixer.cpp91
-rw-r--r--app/mixer.h54
-rw-r--r--app/paclient.cpp329
-rw-r--r--app/paclient.h97
-rw-r--r--app/pacontrolmodel.cpp208
-rw-r--r--app/pacontrolmodel.h92
m---------conf.d/app-templates0
-rwxr-xr-xconf.d/autobuild/agl/autobuild21
-rwxr-xr-xconf.d/autobuild/linux/autobuild67
-rw-r--r--conf.d/cmake/config.cmake201
-rw-r--r--conf.d/wgt/config.xml.in21
-rw-r--r--conf.d/wgt/icon.svg (renamed from package/icon.svg)0
-rw-r--r--mixer.pro3
-rw-r--r--package/config.xml18
-rw-r--r--package/package.pro19
24 files changed, 627 insertions, 890 deletions
diff --git a/.gitignore b/.gitignore
index 89f64c7..3e1d785 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
*.pro.*
+build/
+.vscode/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..af9d4e3
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "conf.d/app-templates"]
+ path = conf.d/app-templates
+ url = https://gerrit.automotivelinux.org/gerrit/p/apps/app-templates.git
+[submodule "afb-helpers"]
+ path = afb-helpers
+ url = https://gerrit.automotivelinux.org/gerrit/apps/app-afb-helpers-submodule
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..8c1fc7c
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,23 @@
+###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Loïc Collognon <loic.collignon@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.
+###########################################################################
+
+CMAKE_MINIMUM_REQUIRED(VERSION 3.3)
+
+set(AFB_HELPERS_QTWSCLIENT ON CACHE BOOL "enable Qt's WebSocket client" FORCE)
+
+include(${CMAKE_CURRENT_SOURCE_DIR}/conf.d/cmake/config.cmake)
diff --git a/afb-helpers b/afb-helpers
new file mode 160000
+Subproject 43ec9716bf83d8a6e5ff15909705cb1adc3c189
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
new file mode 100644
index 0000000..8f8bd1e
--- /dev/null
+++ b/app/CMakeLists.txt
@@ -0,0 +1,57 @@
+###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Loïc Collignon <loic.collignon@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.
+###########################################################################
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_CXX_STANDARD 14)
+
+find_package(Qt5 COMPONENTS Core Gui QuickControls2 WebSockets QuickWidgets REQUIRED)
+qt5_add_resources(RESOURCES Mixer.qrc)
+
+PROJECT_TARGET_ADD(mixer)
+
+add_executable(mixer
+ main.cpp
+ mixer.cpp
+ ${RESOURCES}
+)
+
+set_target_properties(mixer PROPERTIES
+ LABELS "EXECUTABLE"
+ PREFIX ""
+ COMPILE_FLAGS "${EXTRAS_CFLAGS} -DFOR_AFB_BINDING"
+ LINK_FLAGS "${BINDINGS_LINK_FLAG}"
+ LINK_LIBRARIES "${EXTRAS_LIBRARIES}"
+ OUTPUT_NAME "${TARGET_NAME}"
+)
+
+target_link_libraries(mixer
+ Qt5::QuickControls2
+ Qt5::WebSockets
+ homescreen
+ qtWindowmanagerWrapper
+ json-c
+ afb-helpers
+)
+
+#add_custom_command(TARGET ${TARGET_NAME}
+#PRE_BUILD
+#COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/htdocs
+#COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../htdocs ${CMAKE_CURRENT_BINARY_DIR}/../package/
+#COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/../package/etc
+#COMMAND cp -rv ${CMAKE_CURRENT_SOURCE_DIR}/../etc ${CMAKE_CURRENT_BINARY_DIR}/../package/)
diff --git a/app/Mixer.qml b/app/Mixer.qml
index 96875e0..8b1ba06 100644
--- a/app/Mixer.qml
+++ b/app/Mixer.qml
@@ -14,85 +14,94 @@
* limitations under the License.
*/
+// BUG: ValueChanged event is raised by sliders when you are moving the caret, should be raised only when you release it.
+// TODO: Call mixer.setVolume(sliderName, Value) on value change
+// TODO: Call mixer.getVolume(sliderName) on load
+
import QtQuick 2.6
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.0
import AGL.Demo.Controls 1.0
-import PaControlModel 1.0
+import Mixer 1.0
ApplicationWindow {
- id: root
+ id: root
+
+ Mixer {
+ id: mixer
+ Component.objectName: {
+ mixer.open(bindingAddress)
+ }
+ onRolesChanged: {
+ // Remove existing sliders
+ for(var i = sliders.children.length; i > 0 ; --i) {
+ console.log("destroying: " + i)
+ sliders.children[i-1].destroy()
+ }
+
+ // Add slider for each role
+ for(var j = 0; j < mixer.roles.length; ++j) {
+ addSlider(mixer.roles[j])
+ }
+ }
- Label {
- id: title
- font.pixelSize: 48
- text: "Mixer"
- anchors.horizontalCenter: parent.horizontalCenter
- }
+ function addSlider(name) {
+ Qt.createQmlObject("
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.0
+RowLayout {
+ property int value
+ id: slider_" + name + "
+ Layout.minimumHeight: 75
+ Label {
+ font.pixelSize: 24
+ text: \"" + name+ "\"
+ Layout.minimumWidth: 150
+ }
+ Label {
+ id: slider_" + name + "_textvalue
+ font.pixelSize: 24
+ text: \"0 %\"
+ }
+ Slider {
+ id: slider_" + name + "_slider
+ Layout.fillWidth: true
+ from: 0
+ to: 100
+ stepSize: 1
+ snapMode: Slider.SnapOnRelease
+ onValueChanged: {
+ slider_" + name + "_textvalue.text = value + \" %\"
+ mixer.setVolume(\"" + name + "\", value)
+ }
+ Component.objectName: {
+ mixer.getVolume(\"" + name + "\")
+ }
+ }
+ }", sliders, "volumeslider")
+ }
- Component {
- id: ctldesc
- Label {
- font.pixelSize: 32
- width: listView.width
- wrapMode: Text.WordWrap
- property var typeString: {modelType ? "Output" : "Input"}
- text: "[" + typeString + " #" + modelCIndex + "]: " + modelDesc
- }
- }
+ function deleteChilds(item) {
+ for(var i = item.children.length; i > 0 ; i--) {
+ deleteChilds(item.children[i-1])
+ }
+ item.destroy()
+ }
+ }
- Component {
- id: empty
- Item {
- }
- }
+ Label {
+ id: title
+ font.pixelSize: 48
+ text: "Mixer"
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
- ListView {
- id: listView
- anchors.left: parent.left
- anchors.top: title.bottom
- anchors.margins: 80
- anchors.fill: parent
- model: PaControlModel { objectName: "pacm" }
- delegate: ColumnLayout {
- width: parent.width
- spacing: 40
- Connections {
- target: listView.model
- onDataChanged: slider.value = volume
- }
- Loader {
- property int modelType: type
- property int modelCIndex: cindex
- property string modelDesc: name
- sourceComponent: (channel == 0) ? ctldesc : empty
- }
- RowLayout {
- Layout.minimumHeight: 75
- Label {
- font.pixelSize: 24
- text: cdesc
- Layout.minimumWidth: 150
- }
- Label {
- font.pixelSize: 24
- text: "0 %"
- }
- Slider {
- id: slider
- Layout.fillWidth: true
- from: 0
- to: 65536
- stepSize: 256
- snapMode: Slider.SnapOnRelease
- onValueChanged: volume = value
- Component.onCompleted: value = volume
- }
- Label {
- font.pixelSize: 24
- text: "100 %"
- }
- }
- }
- }
+ ColumnLayout {
+ id: sliders
+ anchors.margins: 80
+ anchors.top: title.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ }
}
+
diff --git a/app/app.pri b/app/app.pri
deleted file mode 100644
index 014646f..0000000
--- a/app/app.pri
+++ /dev/null
@@ -1,12 +0,0 @@
-TEMPLATE = app
-
-load(configure)
-qtCompileTest(libhomescreen)
-
-config_libhomescreen {
- CONFIG += link_pkgconfig
- PKGCONFIG += homescreen
- DEFINES += HAVE_LIBHOMESCREEN
-}
-
-DESTDIR = $${OUT_PWD}/../package/root/bin
diff --git a/app/app.pro b/app/app.pro
deleted file mode 100644
index a33fc0d..0000000
--- a/app/app.pro
+++ /dev/null
@@ -1,18 +0,0 @@
-TARGET = mixer
-QT = quickcontrols2
-
-HEADERS += \
- pacontrolmodel.h \
- paclient.h
-
-SOURCES = main.cpp \
- pacontrolmodel.cpp \
- paclient.cpp
-
-CONFIG += link_pkgconfig
-PKGCONFIG += libhomescreen qlibwindowmanager libpulse
-
-RESOURCES += \
- Mixer.qrc
-
-include(app.pri)
diff --git a/app/main.cpp b/app/main.cpp
index bfce498..9c6339f 100644
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2016 The Qt Company Ltd.
* Copyright (C) 2016,2017 Konsulko Group
+ * Copyright (C) 2018 IoT.bzh
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +16,6 @@
* limitations under the License.
*/
-#include "paclient.h"
-#include "pacontrolmodel.h"
-
#include <QtCore/QDebug>
#include <QtCore/QCommandLineParser>
#include <QtCore/QUrlQuery>
@@ -34,6 +32,7 @@
#include <QQuickWindow>
#include <libhomescreen.hpp>
#include <qlibwindowmanager.h>
+#include "mixer.h"
int main(int argc, char *argv[])
{
@@ -51,14 +50,7 @@ int main(int argc, char *argv[])
parser.process(app);
QStringList positionalArguments = parser.positionalArguments();
- // Fire up PA client QThread
- QThread* pat = new QThread;
- PaClient* client = new PaClient();
- client->moveToThread(pat);
- pat->start();
-
- // Register the PA Control Model
- qmlRegisterType<PaControlModel>("PaControlModel", 1, 0, "PaControlModel");
+ qmlRegisterType<Mixer>("Mixer", 1, 0, "Mixer");
QQmlApplicationEngine engine;
if (positionalArguments.length() == 2) {
@@ -88,7 +80,7 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
// Create an event callbnewack against an event type. Here a lambda is called when SyncDraw event occurs
- qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm, myname](json_object *object) {
+ qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [qwm, myname](json_object*) {
fprintf(stderr, "Surface got syncDraw!\n");
qwm->endDraw(myname);
});
@@ -116,17 +108,6 @@ int main(int argc, char *argv[])
QQuickWindow *window = qobject_cast<QQuickWindow *>(mobjs.first());
QObject::connect(window, SIGNAL(frameSwapped()), qwm, SLOT(slotActivateSurface()));
-
- PaControlModel *pacm = mobjs.first()->findChild<PaControlModel *>("pacm");
- QObject::connect(client, SIGNAL(controlAdded(int, QString, QString, int, int, const char *, int)),
- pacm, SLOT(addOneControl(int, QString, QString, int, int, const char *, int)));
- QObject::connect(client, SIGNAL(volumeExternallyChanged(uint32_t, uint32_t, uint32_t, uint32_t)),
- pacm, SLOT(changeExternalVolume(uint32_t, uint32_t, uint32_t, uint32_t)));
- QObject::connect(pacm, SIGNAL(volumeChanged(uint32_t, uint32_t, uint32_t, uint32_t)),
- client, SLOT(setVolume(uint32_t, uint32_t, uint32_t, uint32_t)));
-
- // Initalize PA client
- client->init();
}
return app.exec();
}
diff --git a/app/mixer.cpp b/app/mixer.cpp
new file mode 100644
index 0000000..6614569
--- /dev/null
+++ b/app/mixer.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (C) 2016,2017 Konsulko Group
+ * Copyright (C) 2018 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.
+ */
+
+#include <QJsonArray>
+#include <QJsonObject>
+#include <QtDebug>
+#include "mixer.h"
+
+Mixer::Mixer(QObject* parent)
+ : QObject(parent)
+{
+ connect(&m_client, SIGNAL(connected()), this, SLOT(onClientConnected()));
+}
+
+QStringList Mixer::roles() const
+{
+ return m_roles;
+}
+
+void Mixer::open(const QUrl &url)
+{
+ m_client.open(url);
+}
+
+void Mixer::onClientConnected()
+{
+ // Call HAL to populate list
+ m_client.call("ahl-4a", "get_roles", QJsonValue(), [this](bool r, const QJsonValue& val) {
+ if (r)
+ {
+ m_roles.clear();
+ //BUG: should be able to add this, but not handled right now: m_roles.append("playback");
+ QJsonArray cards = val.toObject()["response"].toArray();
+ foreach (const QJsonValue& card, cards)
+ {
+ m_roles.append(card.toString());
+ qDebug() << "Mixer::onClientConnected - added this HAL: " << card.toString();
+ }
+ emit rolesChanged();
+ }
+ });
+}
+
+void Mixer::setVolume(const QString& name, int value)
+{
+ QJsonObject arg;
+ arg.insert("action", "volume");
+ arg.insert("value", QJsonValue(value));
+ m_client.call("ahl-4a", name, arg, [this, name](bool r, const QJsonValue& v) {
+ if (r && v.isObject())
+ {
+ // TODO: Success, update the slider
+ }
+ else
+ {
+ // TODO: Failed, reset the slider to previous value
+ }
+ });
+}
+
+void Mixer::getVolume(const QString& name)
+{
+ QJsonObject arg;
+ arg.insert("action", "volume");
+ arg.insert("value", QJsonValue("+0")); // FIXME: Hack to get volume: ask for a relative change with a delta of zero
+ m_client.call("ahl-4a", name, arg, [this, name](bool r, const QJsonValue& v) {
+ if (r && v.isObject())
+ {
+ // TODO: Success, update the slider
+ }
+ else
+ {
+ // TODO: Failed, what to do ?
+ }
+ });
+}
diff --git a/app/mixer.h b/app/mixer.h
new file mode 100644
index 0000000..a46c8a1
--- /dev/null
+++ b/app/mixer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016 The Qt Company Ltd.
+ * Copyright (C) 2016,2017 Konsulko Group
+ * Copyright (C) 2018 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.
+ */
+#pragma once
+
+#include <QObject>
+#include <QString>
+#include <QSharedPointer>
+#include <QStringList>
+#include "qafbwebsocketclient.h"
+//#include "volumeslider.h"
+
+class Mixer
+ : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QStringList roles READ roles NOTIFY rolesChanged)
+
+private:
+
+public:
+ explicit Mixer(QObject* parent = nullptr);
+ Mixer(const Mixer&) = delete;
+
+ Q_INVOKABLE void open(const QUrl& url);
+ Q_INVOKABLE QStringList roles() const;
+ Q_INVOKABLE void setVolume(const QString& name, int value);
+ Q_INVOKABLE void getVolume(const QString& name);
+
+signals:
+ void rolesChanged();
+ void volumeChanged(const QString& name, int value);
+
+private slots:
+ void onClientConnected();
+
+private:
+ QStringList m_roles;
+ QAfbWebsocketClient m_client;
+};
diff --git a/app/paclient.cpp b/app/paclient.cpp
deleted file mode 100644
index bd53cde..0000000
--- a/app/paclient.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2016,2017 Konsulko Group
- *
- * 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.
- */
-
-#include "paclient.h"
-
-#include <QtCore/QDebug>
-
-PaClient::PaClient()
- : m_init(false), m_ml(nullptr), m_mlapi(nullptr), m_ctx(nullptr)
-{
-}
-
-PaClient::~PaClient()
-{
- if (m_init)
- close();
-}
-
-void PaClient::close()
-{
- if (!m_init) return;
- pa_threaded_mainloop_stop(m_ml);
- pa_threaded_mainloop_free(m_ml);
- m_init = false;
-}
-
-static void set_sink_volume_cb(pa_context *c, int success, void *data)
-{
- Q_UNUSED(data);
-
- if (!success)
- qWarning() << "PaClient: set sink volume: " <<
- pa_strerror(pa_context_errno(c));
-}
-
-static void set_source_volume_cb(pa_context *c, int success, void *data)
-{
- Q_UNUSED(data);
-
- if (!success)
- qWarning() << "PaClient: set source volume: " <<
- pa_strerror(pa_context_errno(c));
-}
-
-void PaClient::setVolume(uint32_t type, uint32_t index, uint32_t channel, uint32_t volume)
-{
- pa_operation *o;
- pa_context *c = context();
- pa_cvolume *cvolume = NULL;
-
- if (type == C_SINK) {
- cvolume = m_sink_states.value(index);
- cvolume->values[channel] = volume;
- if (!(o = pa_context_set_sink_volume_by_index(c, index, cvolume, set_sink_volume_cb, NULL))) {
- qWarning() << "PaClient: set sink #" << index <<
- " channel #" << channel <<
- " volume: " << pa_strerror(pa_context_errno(c));
- return;
- }
- pa_operation_unref(o);
- } else if (type == C_SOURCE) {
- cvolume = m_source_states.value(index);
- cvolume->values[channel] = volume;
- if (!(o = pa_context_set_source_volume_by_index(c, index, cvolume, set_source_volume_cb, NULL))) {
- qWarning() << "PaClient: set source #" << index <<
- " channel #" << channel <<
- " volume: " << pa_strerror(pa_context_errno(c));
- return;
- }
- pa_operation_unref(o);
- }
-}
-
-void get_source_list_cb(pa_context *c,
- const pa_source_info *i,
- int eol,
- void *data)
-{
- int chan;
-
- PaClient *self = reinterpret_cast<PaClient*>(data);
-
- if (eol < 0) {
- qWarning() << "PaClient: get source list: " <<
- pa_strerror(pa_context_errno(c));
-
- self->close();
- return;
- }
-
- if (!eol) {
- self->addOneControlState(C_SOURCE, i->index, &i->volume);
- for (chan = 0; chan < i->channel_map.channels; chan++) {
- // NOTE: hide input control
- if (QString(i->name).endsWith("monitor"))
- continue;
-
- emit self->controlAdded(i->index, QString(i->name), QString(i->description),
- C_SOURCE, chan, channel_position_string[i->channel_map.map[chan]],
- i->volume.values[chan]);
- }
- }
-}
-
-void get_sink_list_cb(pa_context *c,
- const pa_sink_info *i,
- int eol,
- void *data)
-{
- PaClient *self = reinterpret_cast<PaClient*>(data);
- int chan;
-
- if(eol < 0) {
- qWarning() << "PaClient: get sink list: " <<
- pa_strerror(pa_context_errno(c));
- self->close();
- return;
- }
-
- if(!eol) {
- self->addOneControlState(C_SINK, i->index, &i->volume);
- for (chan = 0; chan < i->channel_map.channels; chan++) {
- emit self->controlAdded(i->index, QString(i->name), QString(i->description),
- C_SINK, chan, channel_position_string[i->channel_map.map[chan]],
- i->volume.values[chan]);
- }
- }
-}
-
-void get_sink_info_change_cb(pa_context *c,
- const pa_sink_info *i,
- int eol,
- void *data)
-{
- Q_UNUSED(c);
- Q_ASSERT(i);
- Q_ASSERT(data);
-
- if (eol) return;
-
- for (int chan = 0; chan < i->channel_map.channels; chan++) {
- PaClient *self = reinterpret_cast<PaClient*>(data);
- QHash<int, pa_cvolume *> states = self->sink_states();
- pa_cvolume *cvolume = states.value(i->index);
- // Check each channel for volume change
- if (cvolume->values[chan] != i->volume.values[chan]) {
- // On change, update cache and signal
- cvolume->values[chan] = i->volume.values[chan];
- emit self->volumeExternallyChanged(C_SINK, i->index, chan, i->volume.values[chan]);
- }
- }
-}
-
-void get_source_info_change_cb(pa_context *c,
- const pa_source_info *i,
- int eol,
- void *data)
-{
- Q_UNUSED(c);
- Q_ASSERT(i);
- Q_ASSERT(data);
-
- if (eol) return;
-
- for (int chan = 0; chan < i->channel_map.channels; chan++) {
- PaClient *self = reinterpret_cast<PaClient*>(data);
- QHash<int, pa_cvolume *> states = self->source_states();
- pa_cvolume *cvolume = states.value(i->index);
- // Check each channel for volume change
- if (cvolume->values[chan] != i->volume.values[chan]) {
- // On change, update cache and signal
- cvolume->values[chan] = i->volume.values[chan];
- emit self->volumeExternallyChanged(C_SOURCE, i->index, chan, i->volume.values[chan]);
- }
- }
-}
-
-
-void subscribe_cb(pa_context *c,
- pa_subscription_event_type_t type,
- uint32_t index,
- void *data)
-{
- pa_operation *o;
-
- if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE) {
- qWarning("PaClient: unhandled subscribe event operation");
- return;
- }
-
- switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
- case PA_SUBSCRIPTION_EVENT_SINK:
- if (!(o = pa_context_get_sink_info_by_index(c, index, get_sink_info_change_cb, data))) {
- qWarning() << "PaClient: get sink info by index: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- break;
- case PA_SUBSCRIPTION_EVENT_SOURCE:
- if (!(o = pa_context_get_source_info_by_index(c, index, get_source_info_change_cb, data))) {
- qWarning() << "PaClient: get source info by index: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- break;
- default:
- qWarning("PaClient: unhandled subscribe event facility");
- }
-}
-
-void context_state_cb(pa_context *c, void *data)
-{
- pa_operation *o;
- PaClient *self = reinterpret_cast<PaClient*>(data);
-
- switch (pa_context_get_state(c)) {
- case PA_CONTEXT_CONNECTING:
- case PA_CONTEXT_AUTHORIZING:
- case PA_CONTEXT_SETTING_NAME:
- break;
- case PA_CONTEXT_READY:
- // Fetch the controls of interest
- if (!(o = pa_context_get_source_info_list(c, get_source_list_cb, data))) {
- qWarning() << "PaClient: get source info list: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- pa_operation_unref(o);
- if (!(o = pa_context_get_sink_info_list(c, &get_sink_list_cb, data))) {
- qWarning() << "PaClient: get sink info list: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- pa_operation_unref(o);
- pa_context_set_subscribe_callback(c, subscribe_cb, data);
- if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t)(PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE), NULL, NULL))) {
- qWarning() << "PaClient: subscribe: " <<
- pa_strerror(pa_context_errno(c));
- return;
- }
- break;
- case PA_CONTEXT_TERMINATED:
- self->close();
- break;
-
- case PA_CONTEXT_FAILED:
- default:
- qCritical() << "PaClient: connection failed: " <<
- pa_strerror(pa_context_errno(c));
- self->close();
- break;
- }
-}
-
-void PaClient::init()
-{
- m_ml = pa_threaded_mainloop_new();
- if (!m_ml) {
- qCritical("PaClient: failed to create mainloop");
- return;
- }
-
- pa_threaded_mainloop_set_name(m_ml, "PaClient mainloop");
-
- m_mlapi = pa_threaded_mainloop_get_api(m_ml);
-
- lock();
-
- m_ctx = pa_context_new(m_mlapi, "Mixer");
- if (!m_ctx) {
- qCritical("PaClient: failed to create context");
- pa_threaded_mainloop_free(m_ml);
- return;
- }
- pa_context_set_state_callback(m_ctx, context_state_cb, this);
-
- if (pa_context_connect(m_ctx, 0, (pa_context_flags_t)0, 0) < 0) {
- qCritical("PaClient: failed to connect");
- pa_context_unref(m_ctx);
- pa_threaded_mainloop_free(m_ml);
- return;
- }
-
- if (pa_threaded_mainloop_start(m_ml) != 0) {
- qCritical("PaClient: failed to start mainloop");
- pa_context_unref(m_ctx);
- pa_threaded_mainloop_free(m_ml);
- return;
- }
-
- unlock();
-
- m_init = true;
-}
-
-void PaClient::addOneControlState(int type, int index, const pa_cvolume *cvolume)
-{
- pa_cvolume *cvolume_new = new pa_cvolume;
- cvolume_new->channels = cvolume->channels;
- for (int i = 0; i < cvolume->channels; i++)
- cvolume_new->values[i] = cvolume->values[i];
- if (type == C_SINK)
- m_sink_states.insert(index, cvolume_new);
- else if (type == C_SOURCE)
- m_source_states.insert(index, cvolume_new);
-}
-
-QHash<int, pa_cvolume *> PaClient::sink_states(void)
-{
- return m_sink_states;
-}
-
-QHash<int, pa_cvolume *> PaClient::source_states(void)
-{
- return m_source_states;
-}
diff --git a/app/paclient.h b/app/paclient.h
deleted file mode 100644
index 73137f2..0000000
--- a/app/paclient.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2016,2017 Konsulko Group
- *
- * 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.
- */
-
-#include <pulse/pulseaudio.h>
-
-#include <QtCore/QHash>
-#include <QtCore/QObject>
-
-const char * const channel_position_string[] =
-{
- "Mono",
- "Front Left",
- "Front Right",
- "Center",
- "Rear Center",
- "Rear Left",
- "Rear Right",
- "LFE",
- "Left Center",
- "Right Center",
- "Side Left",
- "Side Right",
-};
-
-enum control_type
-{
- C_SOURCE,
- C_SINK
-};
-
-typedef struct
-{
- uint32_t type;
- uint32_t index;
- pa_cvolume cvolume;
-} CState;
-
-class PaClient : public QObject
-{
- Q_OBJECT
- public:
- PaClient();
- ~PaClient();
-
- void init();
- void close();
-
- inline pa_context *context() const
- {
- return m_ctx;
- }
-
- inline void lock()
- {
- pa_threaded_mainloop_lock(m_ml);
- }
-
- inline void unlock()
- {
- pa_threaded_mainloop_unlock(m_ml);
- }
-
- void addOneControlState(int type, int index, const pa_cvolume *cvolume);
-
- QHash<int, pa_cvolume *> sink_states();
- QHash<int, pa_cvolume *> source_states();
-
- public slots:
- void setVolume(uint32_t type, uint32_t index, uint32_t channel, uint32_t volume);
-
- signals:
- void controlAdded(int cindex, QString name, QString desc, int type, int channel, const char *cdesc, int volume);
- void volumeExternallyChanged(uint32_t type, uint32_t cindex, uint32_t channel, uint32_t volume);
-
- private:
- bool m_init;
- pa_threaded_mainloop *m_ml;
- pa_mainloop_api *m_mlapi;
- pa_context *m_ctx;
- QHash<int, pa_cvolume *> m_sink_states;
- QHash<int, pa_cvolume *> m_source_states;
-
- public slots:
-};
diff --git a/app/pacontrolmodel.cpp b/app/pacontrolmodel.cpp
deleted file mode 100644
index 9489052..0000000
--- a/app/pacontrolmodel.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2016,2017 Konsulko Group
- *
- * 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.
- */
-
-#include "pacontrolmodel.h"
-
-PaControl::PaControl(const quint32 &cindex, const QString &name, const QString &desc, const quint32 &type, const quint32 &channel, const QString &cdesc, const quint32 &volume)
- : m_cindex(cindex), m_name(name), m_desc(desc), m_type(type), m_channel(channel), m_cdesc(cdesc), m_volume(volume)
-{
-}
-
-quint32 PaControl::cindex() const
-{
- return m_cindex;
-}
-
-QString PaControl::name() const
-{
- QStringList list = m_name.split(".");
-
- return list.at(1);
-}
-
-QString PaControl::desc() const
-{
- return m_desc;
-}
-
-quint32 PaControl::type() const
-{
- return m_type;
-}
-
-quint32 PaControl::channel() const
-{
- return m_channel;
-}
-
-QString PaControl::cdesc() const
-{
- return m_cdesc;
-}
-
-
-quint32 PaControl::volume() const
-{
- return m_volume;
-}
-
-// FIXME: Not all of these should be editable roles
-void PaControl::setCIndex(const QVariant &cindex)
-{
- m_cindex = cindex.toUInt();
-}
-
-void PaControl::setName(const QVariant &name)
-{
- m_name = name.toString();
-}
-
-void PaControl::setDesc(const QVariant &desc)
-{
- m_desc = desc.toString();
-}
-
-void PaControl::setType(const QVariant &type)
-{
- m_type = type.toUInt();
-}
-
-void PaControl::setChannel(const QVariant &channel)
-{
- m_channel = channel.toUInt();
-}
-
-void PaControl::setCDesc(const QVariant &cdesc)
-{
- m_cdesc = cdesc.toString();
-}
-
-void PaControl::setVolume(PaControlModel *pacm, const QVariant &volume)
-{
- if (volume != m_volume) {
- m_volume = volume.toUInt();
- if (pacm)
- emit pacm->volumeChanged(type(), cindex(), channel(), m_volume);
- }
-}
-
-PaControlModel::PaControlModel(QObject *parent)
- : QAbstractListModel(parent)
-{
-}
-
-void PaControlModel::addControl(const PaControl &control)
-{
- beginInsertRows(QModelIndex(), rowCount(), rowCount());
- m_controls << control;
- endInsertRows();
-}
-
-void PaControlModel::addOneControl(int cindex, QString name, QString desc, int type, int channel, const char *cdesc, int volume)
-{
- addControl(PaControl(cindex, name, desc, type, channel, cdesc, volume));
-}
-
-void PaControlModel::changeExternalVolume(uint32_t type, uint32_t cindex, uint32_t channel, uint32_t volume)
-{
- QList<PaControl>::iterator i;
- int row;
-
- for (i = m_controls.begin(), row = 0; i < m_controls.end(); ++i, ++row) {
- if ((i->type() == type) &&
- (i->cindex() == cindex) &&
- (i->channel() == channel)) {
- break;
- }
- }
-
- i->setVolume(NULL, QVariant(volume));
- QModelIndex qmindex = index(row);
- QVector<int> roles;
- roles.push_back(VolumeRole);
- emit dataChanged(qmindex, qmindex, roles);
-}
-
-int PaControlModel::rowCount(const QModelIndex & parent) const {
- Q_UNUSED(parent);
- return m_controls.count();
-}
-
-bool PaControlModel::setData(const QModelIndex &index, const QVariant &value, int role) {
- if (index.row() < 0 || index.row() >= m_controls.count())
- return false;
- PaControl &control = m_controls[index.row()];
- if (role == CIndexRole)
- control.setCIndex(value);
- else if (role == NameRole)
- control.setName(value);
- else if (role == DescRole)
- control.setDesc(value);
- else if (role == TypeRole)
- control.setType(value);
- else if (role == ChannelRole)
- control.setChannel(value);
- else if (role == CDescRole)
- control.setCDesc(value);
- else if (role == VolumeRole)
- control.setVolume(this, value);
- QVector<int> roles;
- roles.push_back(role);
- emit dataChanged(index, index, roles);
- return true;
-}
-
-QVariant PaControlModel::data(const QModelIndex & index, int role) const {
- if (index.row() < 0 || index.row() >= m_controls.count())
- return QVariant();
-
- const PaControl &control = m_controls[index.row()];
- if (role == CIndexRole)
- return control.cindex();
- else if (role == NameRole)
- return control.name();
- else if (role == DescRole)
- return control.desc();
- else if (role == TypeRole)
- return control.type();
- else if (role == ChannelRole)
- return control.channel();
- else if (role == CDescRole)
- return control.cdesc();
- else if (role == VolumeRole)
- return control.volume();
- return QVariant();
-}
-
-Qt::ItemFlags PaControlModel::flags(const QModelIndex &index) const
-{
- if (!index.isValid())
- return Qt::ItemIsEnabled;
-
- return QAbstractListModel::flags(index) | Qt::ItemIsEditable;
-}
-
-QHash<int, QByteArray> PaControlModel::roleNames() const {
- QHash<int, QByteArray> roles;
- roles[CIndexRole] = "cindex";
- roles[NameRole] = "name";
- roles[DescRole] = "desc";
- roles[TypeRole] = "type";
- roles[ChannelRole] = "channel";
- roles[CDescRole] = "cdesc";
- roles[VolumeRole] = "volume";
- return roles;
-}
diff --git a/app/pacontrolmodel.h b/app/pacontrolmodel.h
deleted file mode 100644
index 81eb70b..0000000
--- a/app/pacontrolmodel.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2016,2017 Konsulko Group
- *
- * 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.
- */
-
-#include <pulse/pulseaudio.h>
-
-#include <QtCore/QAbstractListModel>
-#include <QtCore/QList>
-
-class PaControlModel;
-
-class PaControl
-{
- public:
- PaControl(const quint32 &index, const QString &name, const QString &desc, const quint32 &type, const quint32 &channel, const QString &cdesc, const quint32 &volume);
-
- quint32 cindex() const;
- QString name() const;
- QString desc() const;
- quint32 type() const;
- quint32 channel() const;
- QString cdesc() const;
- quint32 volume() const;
- void setCIndex(const QVariant&);
- void setName(const QVariant&);
- void setDesc(const QVariant&);
- void setType(const QVariant&);
- void setChannel(const QVariant&);
- void setCDesc(const QVariant&);
- void setVolume(PaControlModel *, const QVariant&);
-
- private:
- quint32 m_cindex;
- QString m_name;
- QString m_desc;
- quint32 m_type;
- quint32 m_channel;
- QString m_cdesc;
- quint32 m_volume;
-};
-
-class PaControlModel : public QAbstractListModel
-{
- Q_OBJECT
- public:
- enum PaControlRoles {
- CIndexRole = Qt::UserRole + 1,
- NameRole,
- DescRole,
- TypeRole,
- ChannelRole,
- CDescRole,
- VolumeRole
- };
-
- PaControlModel(QObject *parent = 0);
-
- void addControl(const PaControl &control);
-
- int rowCount(const QModelIndex &parent = QModelIndex()) const;
-
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-
- bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
-
- Qt::ItemFlags flags(const QModelIndex &index) const;
-
- public slots:
- void addOneControl(int cindex, QString name, QString desc, int type, int channel, const char *cdesc, int volume);
- void changeExternalVolume(uint32_t type, uint32_t cindex, uint32_t chan, uint32_t volume);
-
- signals:
- void volumeChanged(uint32_t type, uint32_t index, uint32_t channel, uint32_t volume);
-
- protected:
- QHash<int, QByteArray> roleNames() const;
- private:
- QList<PaControl> m_controls;
- pa_context *pa_ctx;
-};
diff --git a/conf.d/app-templates b/conf.d/app-templates
new file mode 160000
+Subproject 1f2944eea3a418ec02920673a390ed4b5d417a2
diff --git a/conf.d/autobuild/agl/autobuild b/conf.d/autobuild/agl/autobuild
new file mode 100755
index 0000000..ea352e7
--- /dev/null
+++ b/conf.d/autobuild/agl/autobuild
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+SOURCE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/../../../"
+BUILD_DIR=$( echo "$2" | cut -d'=' -f2 )
+
+# HACK: alias should be expanded in script for cmake to work properly
+shopt -s expand_aliases
+# HACK: source again the SDK because of the alias
+source $SDKTARGETSYSROOT/../../environment-setup-*
+
+pushd $BUILD_DIR
+
+ cmake $SOURCE_DIR
+ make
+
+ if [ "$1" == "package" ]; then
+ make widget
+ fi
+
+popd
+
diff --git a/conf.d/autobuild/linux/autobuild b/conf.d/autobuild/linux/autobuild
new file mode 100755
index 0000000..3a1ba5f
--- /dev/null
+++ b/conf.d/autobuild/linux/autobuild
@@ -0,0 +1,67 @@
+#!/usr/bin/make -f
+# Copyright (C) 2015, 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.
+
+THISFILE := $(lastword $(MAKEFILE_LIST))
+BUILD_DIR := $(abspath $(dir $(THISFILE)/../../../../..)/build)
+DEST := ${BUILD_DIR}/target
+
+.PHONY: all clean distclean configure build package help update
+
+all: help
+
+help:
+ @echo "List of targets available:"
+ @echo ""
+ @echo "- all"
+ @echo "- clean"
+ @echo "- distclean"
+ @echo "- configure"
+ @echo "- build: compilation, link and prepare files for package into a widget"
+ @echo "- package: output a widget file '*.wgt'"
+ @echo "- install: install in your ${CMAKE_INSTALL_DIR} directory"
+ @echo ""
+ @echo "Usage: ./conf.d/autobuild/agl/autobuild package DEST=${HOME}/opt"
+ @echo "Don't use your build dir as DEST as wgt file is generated at this location"
+
+update: configure
+ @cmake --build ${BUILD_DIR} --target autobuild
+
+clean:
+ @([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean) || echo Nothing to clean
+
+distclean:
+ @rm -rf ${BUILD_DIR}
+
+configure: ${BUILD_DIR}/Makefile
+
+build: configure
+ @cmake --build ${BUILD_DIR} ${BUILD_ARGS} --target all
+
+package: build
+ @mkdir -p ${BUILD_DIR}/$@/bin
+ @mkdir -p ${BUILD_DIR}/$@/etc
+ @mkdir -p ${BUILD_DIR}/$@/lib
+ @mkdir -p ${BUILD_DIR}/$@/htdocs
+ @mkdir -p ${BUILD_DIR}/$@/data
+ @cmake --build ${BUILD_DIR} --target widget
+ @mkdir -p ${DEST} && cp ${BUILD_DIR}/*wgt ${DEST}
+
+install: build
+ @cmake --build ${BUILD_DIR} --target install
+
+${BUILD_DIR}/Makefile:
+ @[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}
+ @[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CONFIGURE_ARGS} ..)
diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake
new file mode 100644
index 0000000..03bf212
--- /dev/null
+++ b/conf.d/cmake/config.cmake
@@ -0,0 +1,201 @@
+###########################################################################
+# Copyright 2018 IoT.bzh
+#
+# author: Loïc Collignon <loic.collignon@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.
+###########################################################################
+
+# Project Info
+# ------------------
+set(PROJECT_NAME mixer)
+set(PROJECT_PRETTY_NAME "Mixer")
+set(PROJECT_DESCRIPTION "AGL Default Mixer")
+set(PROJECT_URL "https://gerrit.automotivelinux.org/gerrit/apps/mixer")
+set(PROJECT_ICON "icon.svg")
+set(PROJECT_AUTHOR "Collignon, Loïc")
+set(PROJECT_AUTHOR_MAIL "loic.collignon@iot.bzh")
+set(PROJECT_LICENSE "APL2.0")
+set(PROJECT_LANGUAGES "C")
+
+# Where are stored default templates files from submodule or subtree app-templates in your project tree
+# relative to the root project directory
+set(PROJECT_APP_TEMPLATES_DIR "conf.d/app-templates")
+
+# Where are stored your external libraries for your project. This is 3rd party library that you don't maintain
+# but used and must be built and linked.
+# set(PROJECT_LIBDIR "libs")
+
+# Which directories inspect to find CMakeLists.txt target files
+# set(PROJECT_SRC_DIR_PATTERN "*")
+
+# Compilation Mode (DEBUG, RELEASE)
+# ----------------------------------
+#set(CMAKE_BUILD_TYPE "DEBUG")
+set(USE_EFENCE 1)
+
+# Kernel selection if needed. You can choose between a
+# mandatory version to impose a minimal version.
+# Or check Kernel minimal version and just print a Warning
+# about missing features and define a preprocessor variable
+# to be used as preprocessor condition in code to disable
+# incompatibles features. Preprocessor define is named
+# KERNEL_MINIMAL_VERSION_OK.
+#
+# NOTE*** FOR NOW IT CHECKS KERNEL Yocto environment and
+# Yocto SDK Kernel version.
+# -----------------------------------------------
+#set (kernel_mandatory_version 4.8)
+#set (kernel_minimal_version 4.8)
+
+# Compiler selection if needed. Impose a minimal version.
+# -----------------------------------------------
+set (gcc_minimal_version 4.9)
+
+# PKG_CONFIG required packages
+# -----------------------------
+set (PKG_REQUIRED_LIST
+ json-c
+ libsystemd>=222
+ afb-daemon
+ #libhomescreen
+ # qlibwindowmanager
+)
+
+# Prefix path where will be installed the files
+# Default: /usr/local (need root permission to write in)
+# ------------------------------------------------------
+#set(CMAKE_INSTALL_PREFIX $ENV{HOME}/opt)
+
+# Customize link option
+# -----------------------------
+#list(APPEND link_libraries -an-option)
+
+# Compilation options definition
+# Use CMake generator expressions to specify only for a specific language
+# Values are prefilled with default options that is currently used.
+# Either separate options with ";", or each options must be quoted separately
+# DO NOT PUT ALL OPTION QUOTED AT ONCE , COMPILATION COULD FAILED !
+# ----------------------------------------------------------------------------
+#set(COMPILE_OPTIONS
+# -Wall
+# -Wextra
+# -Wconversion
+# -Wno-unused-parameter
+# -Wno-sign-compare
+# -Wno-sign-conversion
+# -Werror=maybe-uninitialized
+# -Werror=implicit-function-declaration
+# -ffunction-sections
+# -fdata-sections
+# -fPIC
+# CACHE STRING "Compilation flags")
+#set(C_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C language.")
+#set(CXX_COMPILE_OPTIONS "" CACHE STRING "Compilation flags for C++ language.")
+#set(PROFILING_COMPILE_OPTIONS
+# -g
+# -O0
+# -pg
+# -Wp,-U_FORTIFY_SOURCE
+# CACHE STRING "Compilation flags for PROFILING build type.")
+#set(DEBUG_COMPILE_OPTIONS
+# -g
+# -ggdb
+# -Wp,-U_FORTIFY_SOURCE
+# CACHE STRING "Compilation flags for DEBUG build type.")
+#set(CCOV_COMPILE_OPTIONS
+# -g
+# -O2
+# --coverage
+# CACHE STRING "Compilation flags for CCOV build type.")
+#set(RELEASE_COMPILE_OPTIONS
+# -g
+# -O2
+# CACHE STRING "Compilation flags for RELEASE build type.")
+
+# (BUG!!!) as PKG_CONFIG_PATH does not work [should be an env variable]
+# ---------------------------------------------------------------------
+set(CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/lib64/pkgconfig ${CMAKE_INSTALL_PREFIX}/lib/pkgconfig)
+set(LD_LIBRARY_PATH ${CMAKE_INSTALL_PREFIX}/lib64 ${CMAKE_INSTALL_PREFIX}/lib)
+
+# Optional location for config.xml.in
+# -----------------------------------
+#set(WIDGET_ICON "\"conf.d/wgt/${PROJECT_ICON}\"" CACHE PATH "Path to the widget icon")
+set(WIDGET_CONFIG_TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/conf.d/wgt/config.xml.in" CACHE PATH "Path to widget config file template (config.xml.in)")
+
+# Mandatory widget Mimetype specification of the main unit
+# --------------------------------------------------------------------------
+# Choose between :
+#- text/html : HTML application,
+# content.src designates the home page of the application
+#
+#- application/vnd.agl.native : AGL compatible native,
+# content.src designates the relative path of the binary.
+#
+# - application/vnd.agl.service: AGL service, content.src is not used.
+#
+#- ***application/x-executable***: Native application,
+# content.src designates the relative path of the binary.
+# For such application, only security setup is made.
+#
+set(WIDGET_TYPE application/vnd.agl.native)
+
+# Mandatory Widget entry point file of the main unit
+# --------------------------------------------------------------
+# This is the file that will be executed, loaded,
+# at launch time by the application framework.
+#
+set(WIDGET_ENTRY_POINT mixer)
+
+# Optional dependencies order
+# ---------------------------
+#set(EXTRA_DEPENDENCIES_ORDER)
+
+# Optional Extra global include path
+# -----------------------------------
+#set(EXTRA_INCLUDE_DIRS)
+
+# Optional extra libraries
+# -------------------------
+#set(EXTRA_LINK_LIBRARIES)
+
+# Optional force binding Linking flag
+# ------------------------------------
+# set(BINDINGS_LINK_FLAG LinkOptions )
+
+# Optional force package prefix generation, like widget
+# -----------------------------------------------------
+# set(PKG_PREFIX DestinationPath)
+
+# Optional Application Framework security token
+# and port use for remote debugging.
+#------------------------------------------------------------
+set(AFB_TOKEN "" CACHE PATH "Default binder security token")
+set(AFB_REMPORT "1234" CACHE PATH "Default binder listening port")
+
+# Print a helper message when every thing is finished
+# ----------------------------------------------------
+set(CLOSING_MESSAGE "Typical binding launch: afb-daemon --port=${AFB_REMPORT} --workdir=${CMAKE_BINARY_DIR}/package --ldpaths=lib --roothttp=htdocs --token=\"${AFB_TOKEN}\" --tracereq=common --verbose")
+set(PACKAGE_MESSAGE "Install widget file using in the target : afm-util install ${PROJECT_NAME}.wgt")
+
+# Optional schema validator about now only XML, LUA and JSON
+# are supported
+#------------------------------------------------------------
+#set(LUA_CHECKER "luac" "-p" CACHE STRING "LUA compiler")
+#set(XML_CHECKER "xmllint" CACHE STRING "XML linter")
+#set(JSON_CHECKER "json_verify" CACHE STRING "JSON linter")
+
+# This include is mandatory and MUST happens at the end
+# of this file, else you expose you to unexpected behavior
+# -----------------------------------------------------------
+include(${PROJECT_APP_TEMPLATES_DIR}/cmake/common.cmake)
diff --git a/conf.d/wgt/config.xml.in b/conf.d/wgt/config.xml.in
new file mode 100644
index 0000000..597f19d
--- /dev/null
+++ b/conf.d/wgt/config.xml.in
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets" id="@PROJECT_NAME@" version="@PROJECT_VERSION@">
+ <name>@PROJECT_NAME@</name>
+ <icon src="@PROJECT_ICON@"/>
+ <content src="@WIDGET_ENTRY_POINT@" type="@WIDGET_TYPE@"/>
+ <description>@PROJECT_DESCRIPTION@</description>
+ <author>
+ <author href="https://www.automotivelinux.org/" email = "info@automotivelinux.org">
+ Loïc Collignon &lt;loic.collignon@iot.bzh&gt;
+ Matt Porter &lt;mporter@konsulko.com&gt;
+ </author>
+ <license>@PROJECT_LICENSE@</license>
+ <feature name="urn:AGL:widget:required-api">
+ <param name="windowmanager" value="ws" />
+ <param name="homescreen" value="ws" />
+ </feature>
+ <feature name="urn:AGL:widget:required-permission">
+ <param name="urn:AGL:permission::public:no-htdocs" value="required" />
+ <param name="urn:AGL:permission::public:4a-audio-mixer" value="required" />
+ </feature>
+</widget>
diff --git a/package/icon.svg b/conf.d/wgt/icon.svg
index 85f7384..85f7384 100644
--- a/package/icon.svg
+++ b/conf.d/wgt/icon.svg
diff --git a/mixer.pro b/mixer.pro
deleted file mode 100644
index 579a952..0000000
--- a/mixer.pro
+++ /dev/null
@@ -1,3 +0,0 @@
-TEMPLATE = subdirs
-SUBDIRS = app package
-package.depends += app
diff --git a/package/config.xml b/package/config.xml
deleted file mode 100644
index bee25a0..0000000
--- a/package/config.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<widget xmlns="http://www.w3.org/ns/widgets" id="mixer" version="0.1">
- <name>Mixer</name>
- <icon src="icon.svg"/>
- <content src="bin/mixer" type="application/vnd.agl.native"/>
- <description>Simple PulseAudio mixer app</description>
- <author>Matt Porter &lt;mporter@konsulko.com&gt;</author>
- <license>APL 2.0</license>
- <feature name="urn:AGL:widget:required-api">
- <param name="windowmanager" value="ws" />
- <param name="homescreen" value="ws" />
- </feature>
- <feature name="urn:AGL:widget:required-permission">
- <param name="urn:AGL:permission::public:no-htdocs" value="required" />
- </feature>
-</widget>
-
-
diff --git a/package/package.pro b/package/package.pro
deleted file mode 100644
index 3d37bd7..0000000
--- a/package/package.pro
+++ /dev/null
@@ -1,19 +0,0 @@
-
-DISTFILES = icon.svg config.xml
-
-copy_icon.target = $$OUT_PWD/root/icon.svg
-copy_icon.depends = $$_PRO_FILE_PWD_/icon.svg
-copy_icon.commands = $(COPY_FILE) \"$$replace(copy_icon.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_icon.target, /, $$QMAKE_DIR_SEP)\"
-QMAKE_EXTRA_TARGETS += copy_icon
-PRE_TARGETDEPS += $$copy_icon.target
-
-copy_config.target = $$OUT_PWD/root/config.xml
-copy_config.depends = $$_PRO_FILE_PWD_/config.xml
-copy_config.commands = $(COPY_FILE) \"$$replace(copy_config.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_config.target, /, $$QMAKE_DIR_SEP)\"
-QMAKE_EXTRA_TARGETS += copy_config
-PRE_TARGETDEPS += $$copy_config.target
-
-wgt.target = package
-wgt.commands = wgtpkg-pack -f -o mixer.wgt root
-
-QMAKE_EXTRA_TARGETS += wgt