Merge 'eel' into 'master' 31/14731/1
authorLoïc Collignon <loic.collignon@iot.bzh>
Wed, 27 Jun 2018 15:30:37 +0000 (17:30 +0200)
committerLoïc Collignon <loic.collignon@iot.bzh>
Wed, 27 Jun 2018 15:30:37 +0000 (17:30 +0200)
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>
24 files changed:
.gitignore
.gitmodules [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
afb-helpers [new submodule]
app/CMakeLists.txt [new file with mode: 0644]
app/Mixer.qml
app/app.pri [deleted file]
app/app.pro [deleted file]
app/main.cpp
app/mixer.cpp [new file with mode: 0644]
app/mixer.h [new file with mode: 0644]
app/paclient.cpp [deleted file]
app/paclient.h [deleted file]
app/pacontrolmodel.cpp [deleted file]
app/pacontrolmodel.h [deleted file]
conf.d/app-templates [new submodule]
conf.d/autobuild/agl/autobuild [new file with mode: 0755]
conf.d/autobuild/linux/autobuild [new file with mode: 0755]
conf.d/cmake/config.cmake [new file with mode: 0644]
conf.d/wgt/config.xml.in [new file with mode: 0644]
conf.d/wgt/icon.svg [moved from package/icon.svg with 100% similarity]
mixer.pro [deleted file]
package/config.xml [deleted file]
package/package.pro [deleted file]

index 89f64c7..3e1d785 100644 (file)
@@ -1 +1,3 @@
 *.pro.*
+build/
+.vscode/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..af9d4e3
--- /dev/null
@@ -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 (file)
index 0000000..8c1fc7c
--- /dev/null
@@ -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 (submodule)
index 0000000..43ec971
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 43ec9716bf83d8a6e5ff15909705cb1adc3c1892
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8f8bd1e
--- /dev/null
@@ -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/)
index 96875e0..8b1ba06 100644 (file)
  * 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 (file)
index 014646f..0000000
+++ /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 (file)
index a33fc0d..0000000
+++ /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)
index bfce498..9c6339f 100644 (file)
@@ -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 (file)
index 0000000..6614569
--- /dev/null
@@ -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 (file)
index 0000000..a46c8a1
--- /dev/null
@@ -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 (file)
index bd53cde..0000000
+++ /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 (file)
index 73137f2..0000000
+++ /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 (file)
index 9489052..0000000
+++ /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 (file)
index 81eb70b..0000000
+++ /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 (submodule)
index 0000000..1f2944e
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 1f2944eea3a418ec02920673a390ed4b5d417a2b
diff --git a/conf.d/autobuild/agl/autobuild b/conf.d/autobuild/agl/autobuild
new file mode 100755 (executable)
index 0000000..ea352e7
--- /dev/null
@@ -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 (executable)
index 0000000..3a1ba5f
--- /dev/null
@@ -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 (file)
index 0000000..03bf212
--- /dev/null
@@ -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 (file)
index 0000000..597f19d
--- /dev/null
@@ -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>
similarity index 100%
rename from package/icon.svg
rename to conf.d/wgt/icon.svg
diff --git a/mixer.pro b/mixer.pro
deleted file mode 100644 (file)
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 (file)
index bee25a0..0000000
+++ /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 (file)
index 3d37bd7..0000000
+++ /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