aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Mixer.qml2
-rw-r--r--app/app.pro4
-rw-r--r--app/main.cpp25
-rw-r--r--app/pac.c225
-rw-r--r--app/pac.h54
-rw-r--r--app/paclient.cpp228
-rw-r--r--app/paclient.h89
-rw-r--r--app/pacontrolmodel.cpp16
-rw-r--r--app/pacontrolmodel.h20
9 files changed, 359 insertions, 304 deletions
diff --git a/app/Mixer.qml b/app/Mixer.qml
index 7a099ce..75673fe 100644
--- a/app/Mixer.qml
+++ b/app/Mixer.qml
@@ -53,7 +53,7 @@ ApplicationWindow {
anchors.top: title.bottom
anchors.margins: 80
anchors.fill: parent
- model: PaControlModel {}
+ model: PaControlModel { objectName: "pacm" }
delegate: ColumnLayout {
width: parent.width
spacing: 40
diff --git a/app/app.pro b/app/app.pro
index e8fe05b..34c37f4 100644
--- a/app/app.pro
+++ b/app/app.pro
@@ -3,11 +3,11 @@ QT = quickcontrols2
HEADERS += \
pacontrolmodel.h \
- pac.h
+ paclient.h
SOURCES = main.cpp \
pacontrolmodel.cpp \
- pac.c
+ paclient.cpp
CONFIG += link_pkgconfig
PKGCONFIG += libpulse
diff --git a/app/main.cpp b/app/main.cpp
index d89287c..76e755b 100644
--- a/app/main.cpp
+++ b/app/main.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2016 The Qt Company Ltd.
- * Copyright (C) 2016 Konsulko Group
+ * 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.
@@ -15,9 +15,13 @@
* limitations under the License.
*/
+#include "paclient.h"
+#include "pacontrolmodel.h"
+
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QStandardPaths>
+#include <QtCore/QThread>
#include <QtGui/QGuiApplication>
#include <QtQml/QQmlApplicationEngine>
#include <QtQml/QQmlContext>
@@ -26,7 +30,6 @@
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
-#include "pacontrolmodel.h"
#ifdef HAVE_LIBHOMESCREEN
#include <libhomescreen.hpp>
@@ -47,10 +50,28 @@ int main(int argc, char *argv[])
QQuickStyle::setStyle("AGL");
+ // 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");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/Mixer.qml")));
+ // Find the instantiated model QObject and connect the signals/slots
+ QList<QObject *> mobjs = engine.rootObjects();
+ PaControlModel *pacm = mobjs.first()->findChild<PaControlModel *>("pacm");
+ QObject::connect(client, SIGNAL(controlAdded(int, QString, int, int, const char *, int)),
+ pacm, SLOT(addOneControl(int, QString, int, int, const char *, int)));
+ 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/pac.c b/app/pac.c
deleted file mode 100644
index 83b4604..0000000
--- a/app/pac.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2016 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <errno.h>
-#include <unistd.h>
-#include <limits.h>
-#include <assert.h>
-
-#include <pulse/pulseaudio.h>
-#include <sys/queue.h>
-
-#include "pacontrolmodel.h"
-#include "pac.h"
-
-/* FIXME: move these into a pac context */
-static pa_threaded_mainloop* m;
-TAILQ_HEAD(pac_cstateq, pac_cstate);
-static struct pac_cstateq cstateq;
-
-static void add_one_cstate(int type, int index, const pa_cvolume *cvolume)
-{
- struct pac_cstate *cstate;
- int i;
-
- cstate = pa_xnew(struct pac_cstate, 1);
- cstate->type = type;
- cstate->index = index;
- cstate->cvolume.channels = cvolume->channels;
- for (i = 0; i < cvolume->channels; i++)
- cstate->cvolume.values[i] = cvolume->values[i];
-
- TAILQ_INSERT_TAIL(&cstateq, cstate, tailq);
-}
-
-static void get_source_list_cb(pa_context *c,
- const pa_source_info *i,
- int eol,
- void *data)
-{
- int chan;
-
- if (eol < 0) {
- fprintf(stderr, "get source list: %s\n",
- pa_strerror(pa_context_errno(c)));
-
- pa_threaded_mainloop_stop(m);
- return;
- }
-
- if (!eol) {
- assert(i);
- add_one_cstate(C_SOURCE, i->index, &i->volume);
- for (chan = 0; chan < i->channel_map.channels; chan++) {
- add_one_control(data, i->index, i->description,
- C_SOURCE, chan,
- channel_position_string[i->channel_map.map[chan]],
- i->volume.values[chan]);
- }
- }
-}
-
-static void get_sink_list_cb(pa_context *c,
- const pa_sink_info *i,
- int eol,
- void *data)
-{
- int chan;
-
- if(eol < 0) {
- fprintf(stderr, "get sink list: %s\n",
- pa_strerror(pa_context_errno(c)));
-
- pa_threaded_mainloop_stop(m);
- return;
- }
-
- if(!eol) {
- assert(i);
- add_one_cstate(C_SINK, i->index, &i->volume);
- for (chan = 0; chan < i->channel_map.channels; chan++) {
- add_one_control(data, i->index, i->description,
- C_SINK, chan,
- channel_position_string[i->channel_map.map[chan]],
- i->volume.values[chan]);
- }
- }
-}
-
-static void context_state_cb(pa_context *c, void *data) {
- pa_operation *o;
-
- assert(c);
- 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))) {
- fprintf(stderr, "get source info list: %s\n",
- 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))) {
- fprintf(stderr, "get sink info list: %s\n",
- pa_strerror(pa_context_errno(c)));
- return;
- }
- break;
- case PA_CONTEXT_TERMINATED:
- pa_threaded_mainloop_stop(m);
- break;
- case PA_CONTEXT_FAILED:
- default:
- fprintf(stderr, "PA connection failed: %s\n",
- pa_strerror(pa_context_errno(c)));
- pa_threaded_mainloop_stop(m);
- }
-}
-
-static void pac_set_source_volume_cb(pa_context *c, int success, void *userdata __attribute__((unused))) {
- assert(c);
- if (!success)
- fprintf(stderr, "Set source volume: %s\n",
- pa_strerror(pa_context_errno(c)));
-}
-
-static void pac_set_sink_volume_cb(pa_context *c, int success, void *userdata __attribute__((unused))) {
- assert(c);
- if (!success)
- fprintf(stderr, "Set source volume: %s\n",
- pa_strerror(pa_context_errno(c)));
-}
-
-void pac_set_volume(pa_context *c, uint32_t type, uint32_t idx, uint32_t channel, uint32_t volume)
-{
- pa_operation *o;
- struct pac_cstate *cstate;
-
- TAILQ_FOREACH(cstate, &cstateq, tailq)
- if (cstate->index == idx)
- break;
- cstate->cvolume.values[channel] = volume;
-
- if (type == C_SOURCE) {
- if (!(o = pa_context_set_source_volume_by_index(c, idx, &cstate->cvolume, pac_set_source_volume_cb, NULL))) {
- fprintf(stderr, "set source #%d channel #%d volume: %s\n",
- idx, channel, pa_strerror(pa_context_errno(c)));
- return;
- }
- pa_operation_unref(o);
- } else if (type == C_SINK) {
- if (!(o = pa_context_set_sink_volume_by_index(c, idx, &cstate->cvolume, pac_set_sink_volume_cb, NULL))) {
- fprintf(stderr, "set sink #%d channel #%d volume: %s\n",
- idx, channel, pa_strerror(pa_context_errno(c)));
- return;
- }
- pa_operation_unref(o);
- }
-}
-
-pa_context *pac_init(void *this, const char *name) {
- pa_context *c;
- pa_mainloop_api *mapi;
- char *server = NULL;
- char *client = pa_xstrdup(name);
-
- TAILQ_INIT(&cstateq);
-
- if (!(m = pa_threaded_mainloop_new())) {
- fprintf(stderr, "pa_mainloop_new() failed.\n");
- return NULL;
- }
-
- pa_threaded_mainloop_set_name(m, "pa_mainloop");
- mapi = pa_threaded_mainloop_get_api(m);
-
- if (!(c = pa_context_new(mapi, client))) {
- fprintf(stderr, "pa_context_new() failed.\n");
- goto exit;
- }
-
- pa_context_set_state_callback(c, context_state_cb, this);
- if (pa_context_connect(c, server, 0, NULL) < 0) {
- fprintf(stderr, "pa_context_connect(): %s", pa_strerror(pa_context_errno(c)));
- goto exit;
- }
-
- if (pa_threaded_mainloop_start(m) < 0) {
- fprintf(stderr, "pa_mainloop_run() failed.\n");
- goto exit;
- }
-
- return c;
-
-exit:
- if (c)
- pa_context_unref(c);
-
- if (m)
- pa_threaded_mainloop_free(m);
-
- pa_xfree(client);
-
- return NULL;
-}
diff --git a/app/pac.h b/app/pac.h
deleted file mode 100644
index ef0209d..0000000
--- a/app/pac.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sys/queue.h>
-
-#ifdef __cplusplus
-extern "C" void pac_set_volume(pa_context *, uint32_t, uint32_t, uint32_t, uint32_t);
-extern "C" pa_context *pac_init(void *, const char *);
-#else
-static char * 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
-};
-
-struct pac_cstate
-{
- TAILQ_ENTRY(pac_cstate) tailq;
- int type;
- uint32_t index;
- pa_cvolume cvolume;
-};
-
-#endif
diff --git a/app/paclient.cpp b/app/paclient.cpp
new file mode 100644
index 0000000..78567ce
--- /dev/null
+++ b/app/paclient.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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 __attribute__((unused)))
+{
+ 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 __attribute__((unused)))
+{
+ 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();
+ CState *cstate = NULL;
+
+ foreach (cstate, m_cstatelist)
+ if ((cstate->index == index) && (cstate->type == type))
+ break;
+
+ cstate->cvolume.values[channel] = volume;
+
+ if (type == C_SINK) {
+ if (!(o = pa_context_set_sink_volume_by_index(c, index, &cstate->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) {
+ if (!(o = pa_context_set_source_volume_by_index(c, index, &cstate->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++) {
+ emit self->controlAdded(i->index, 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)
+{
+ int chan;
+ PaClient *self = reinterpret_cast<PaClient*>(data);
+
+ 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->description), C_SINK, chan,
+ channel_position_string[i->channel_map.map[chan]],
+ i->volume.values[chan]);
+ }
+ }
+}
+
+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;
+ }
+ 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)
+{
+ int i;
+ CState *cstate;
+
+ cstate = new CState;
+ cstate->type = type;
+ cstate->index = index;
+ cstate->cvolume.channels = cvolume->channels;
+ for (i = 0; i < cvolume->channels; i++)
+ cstate->cvolume.values[i] = cvolume->values[i];
+
+ m_cstatelist.append(cstate);
+}
diff --git a/app/paclient.h b/app/paclient.h
new file mode 100644
index 0000000..1367e81
--- /dev/null
+++ b/app/paclient.h
@@ -0,0 +1,89 @@
+/*
+ * 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/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);
+
+ public slots:
+ void setVolume(uint32_t type, uint32_t index, uint32_t channel, uint32_t volume);
+
+ signals:
+ void controlAdded(int cindex, QString desc, int type, int channel, const char *cdesc, int volume);
+
+ private:
+ bool m_init;
+ pa_threaded_mainloop *m_ml;
+ pa_mainloop_api *m_mlapi;
+ pa_context *m_ctx;
+ QList<CState *> m_cstatelist;
+};
diff --git a/app/pacontrolmodel.cpp b/app/pacontrolmodel.cpp
index 520233b..bca72c5 100644
--- a/app/pacontrolmodel.cpp
+++ b/app/pacontrolmodel.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Konsulko Group
+ * 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.
@@ -15,7 +15,6 @@
*/
#include "pacontrolmodel.h"
-#include "pac.h"
PaControl::PaControl(const quint32 &cindex, const QString &desc, const quint32 &type, const quint32 &channel, const QString &cdesc, const quint32 &volume)
: m_cindex(cindex), m_desc(desc), m_type(type), m_channel(channel), m_cdesc(cdesc), m_volume(volume)
@@ -79,18 +78,17 @@ void PaControl::setCDesc(const QVariant &cdesc)
m_cdesc = cdesc.toString();
}
-void PaControl::setVolume(pa_context *pa_ctx, const QVariant &volume)
+void PaControl::setVolume(PaControlModel *pacm, const QVariant &volume)
{
if (volume != m_volume) {
m_volume = volume.toUInt();
- pac_set_volume(pa_ctx, type(), cindex(), channel(), m_volume);
+ emit pacm->volumeChanged(type(), cindex(), channel(), m_volume);
}
}
PaControlModel::PaControlModel(QObject *parent)
: QAbstractListModel(parent)
{
- pa_ctx = pac_init(this, "Mixer");
}
void PaControlModel::addControl(const PaControl &control)
@@ -100,11 +98,9 @@ void PaControlModel::addControl(const PaControl &control)
endInsertRows();
}
-void add_one_control(void *ctx, int cindex, const char *desc, int type, int channel, const char *cdesc, int volume)
+void PaControlModel::addOneControl(int cindex, QString desc, int type, int channel, const char *cdesc, int volume)
{
- // Get the PaControlModel object from the opaque pointer context
- PaControlModel *pacm = static_cast<PaControlModel*>(ctx);
- pacm->addControl(PaControl(cindex, desc, type, channel, cdesc, volume));
+ addControl(PaControl(cindex, desc, type, channel, cdesc, volume));
}
int PaControlModel::rowCount(const QModelIndex & parent) const {
@@ -127,7 +123,7 @@ bool PaControlModel::setData(const QModelIndex &index, const QVariant &value, in
else if (role == CDescRole)
control.setCDesc(value);
else if (role == VolumeRole)
- control.setVolume(pa_ctx, value);
+ control.setVolume(this, value);
emit dataChanged(index, index);
return true;
}
diff --git a/app/pacontrolmodel.h b/app/pacontrolmodel.h
index aa34a79..475f7ce 100644
--- a/app/pacontrolmodel.h
+++ b/app/pacontrolmodel.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 Konsulko Group
+ * 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.
@@ -16,13 +16,8 @@
#include <pulse/pulseaudio.h>
-#ifndef __cplusplus
-extern void add_one_control(void *ctx, int, const char *, int, int, const char *, int);
-#else
-extern "C" void add_one_control(void *ctx, int, const char *, int, int, const char *, int);
-
-#include <QAbstractListModel>
-#include <QStringList>
+#include <QtCore/QAbstractListModel>
+#include <QtCore/QList>
class PaControlModel;
@@ -42,7 +37,7 @@ class PaControl
void setType(const QVariant&);
void setChannel(const QVariant&);
void setCDesc(const QVariant&);
- void setVolume(pa_context *, const QVariant&);
+ void setVolume(PaControlModel *, const QVariant&);
private:
quint32 m_cindex;
@@ -78,10 +73,15 @@ class PaControlModel : public QAbstractListModel
Qt::ItemFlags flags(const QModelIndex &index) const;
+ public slots:
+ void addOneControl(int cindex, QString desc, int type, int channel, const char *cdesc, int 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;
};
-#endif // __cplusplus