diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | .gitmodules | 6 | ||||
-rw-r--r-- | CMakeLists.txt | 23 | ||||
m--------- | afb-helpers | 0 | ||||
-rw-r--r-- | app/CMakeLists.txt | 57 | ||||
-rw-r--r-- | app/Mixer.qml | 151 | ||||
-rw-r--r-- | app/app.pri | 12 | ||||
-rw-r--r-- | app/app.pro | 18 | ||||
-rw-r--r-- | app/main.cpp | 27 | ||||
-rw-r--r-- | app/mixer.cpp | 91 | ||||
-rw-r--r-- | app/mixer.h | 54 | ||||
-rw-r--r-- | app/paclient.cpp | 329 | ||||
-rw-r--r-- | app/paclient.h | 97 | ||||
-rw-r--r-- | app/pacontrolmodel.cpp | 208 | ||||
-rw-r--r-- | app/pacontrolmodel.h | 92 | ||||
m--------- | conf.d/app-templates | 0 | ||||
-rwxr-xr-x | conf.d/autobuild/agl/autobuild | 21 | ||||
-rwxr-xr-x | conf.d/autobuild/linux/autobuild | 67 | ||||
-rw-r--r-- | conf.d/cmake/config.cmake | 201 | ||||
-rw-r--r-- | conf.d/wgt/config.xml.in | 21 | ||||
-rw-r--r-- | conf.d/wgt/icon.svg (renamed from package/icon.svg) | 0 | ||||
-rw-r--r-- | mixer.pro | 3 | ||||
-rw-r--r-- | package/config.xml | 18 | ||||
-rw-r--r-- | package/package.pro | 19 |
24 files changed, 627 insertions, 890 deletions
@@ -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 <loic.collignon@iot.bzh> + Matt Porter <mporter@konsulko.com> + </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 <mporter@konsulko.com></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 |