The VolumeModule class acts as the interface between the QML-based UI and the QPPS library. This C++ class exposes the volume level, which is read through PPS, as a Q_PROPERTY consumable by QML.
#ifndef VOLUMEMODULE_H
#define VOLUMEMODULE_H
#include <QObject>
#include "qpps/object.h"
class VolumeModule : public QObject
{
Q_OBJECT
// Volume setting, accessible by QML
Q_PROPERTY(double volume READ volume WRITE setVolume
NOTIFY volumeChanged)
public:
// Constructor
explicit VolumeModule(QObject *parent = NULL);
Q_INVOKABLE double volume() const;
Q_INVOKABLE void setVolume(const double value) const;
public Q_SLOTS:
// Updates volume level when volume change is reported by PPS
void audioStatusChanged(const QString &name,
const QPps::Variant &attribute);
Q_SIGNALS:
// Emitted when the volume level changes
void volumeChanged();
private:
// Reference to PPS object containing audio volume level
QPps::Object *m_ppsAudioStatus;
// Volume setting
double m_volume;
};
#endif // VOLUMEMODULE_H
#include "volumemodule.h"
VolumeModule::VolumeModule(QObject *parent)
: QObject(parent)
{
// Access PPS object that stores audio device status
m_ppsAudioStatus = new QPps::Object(
QStringLiteral("/pps/services/audio/status"),
QPps::Object::PublishAndSubscribeMode, false, this);
if (!m_ppsAudioStatus->isValid()) {
// Print error message if unable to read audio device
// status through PPS
qCritical("%s Could not open %s: %s", Q_FUNC_INFO,
qPrintable(m_ppsAudioStatus->path()),
qPrintable(m_ppsAudioStatus->errorString()));
}
else {
// Connect signal for changed attribute in PPS object
// to handler for audio status changes
connect(m_ppsAudioStatus,
SIGNAL(attributeChanged(QString,QPps::Variant)),
this,
SLOT(audioStatusChanged(QString,QPps::Variant)));
}
}
double VolumeModule::volume() const {
return m_volume;
}
void VolumeModule::setVolume(const double value) const {
if (value == m_volume) {
//Don't set the volume if it's already set to that
return;
}
if (!m_ppsAudioStatus->isValid()) {
qCritical("%s Could not write %s: %s", Q_FUNC_INFO,
qPrintable(m_ppsAudioStatus->path()),
qPrintable(m_ppsAudioStatus->errorString()));
return;
}
if (!m_ppsAudioStatus->setAttribute(
"output.speaker.volume", value)) {
qWarning("%s SetAttribute failed %s: %s", Q_FUNC_INFO,
qPrintable(m_ppsAudioStatus->path()),
qPrintable(m_ppsAudioStatus->errorString()));
}
}
void VolumeModule::audioStatusChanged(
const QString &name,
const QPps::Variant &attribute)
{
if (name == QStringLiteral("output.speaker.volume")) {
m_volume = attribute.toDouble();
emit volumeChanged();
}
}
#include <QtGui/QGuiApplication>
#include <QtQuick/QQuickView>
#include <QScreen>
#include <QQmlContext>
#include <qqml.h>
// BEGIN NEW CODE
#include "volumemodule.h"
void setupVolumeModule(QQuickView* view)
{
// Register with the Qt Metatype system
qmlRegisterUncreatableType<VolumeModule>(
"com.mycompany.hmi",
1, 0, "VolumeModule",
QStringLiteral("Access to object"));
// By passing in the view as a parent object, the
// VolumeModule will be deleted when its parent is deleted
VolumeModule* volumeModule = new VolumeModule(view);
// Give the view access to the VolumeModule
view->rootContext()->setContextProperty(
QStringLiteral("_volumeModule"),
volumeModule);
}
// END NEW CODE
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
// Get the screens so we can dynamically size our display
QList<QScreen*> screens = QGuiApplication::screens();
// Quit if no screen is connected
if (screens.empty()) {
return 1;
}
// Get the width and height of the display
int w = screens[0]->size().width();
int h = screens[0]->size().height();
QQuickView view;
// BEGIN NEW CODE
// Set up the volume control
setupVolumeModule(&view);
// END NEW CODE
// Set the main QML UI file to this view
view.setSource(QUrl("qrc:/qml/main.qml"));
// Set up the view to have the proper size
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.resize(w, h);
// Show our user interface
view.show();
return app.exec();
}