Reimplemented Tablet Audio screen using C++ model

This commit is contained in:
Vladyslav Stelmakhovskyi 2017-04-28 23:02:28 +02:00
parent c7ab4994ea
commit d18ac6dd49
7 changed files with 208 additions and 48 deletions

View file

@ -35,11 +35,6 @@ Rectangle {
property string title: "Audio Options"
signal sendToScript(var message);
//set models after Components is shown
Component.onCompleted: {
refreshTimer.start()
refreshTimerOutput.start()
}
Component {
id: separator
@ -138,30 +133,34 @@ Rectangle {
}
ListView {
Timer {
id: refreshTimer
interval: 1
repeat: false
onTriggered: {
//refresh model
inputAudioListView.model = undefined
inputAudioListView.model = AudioDevice.inputAudioDevices
}
}
id: inputAudioListView
anchors { left: parent.left; right: parent.right; leftMargin: 70 }
height: 125
spacing: 16
spacing: 0
clip: true
snapMode: ListView.SnapToItem
delegate: AudioCheckbox {
model: AudioDevice
delegate: Item {
width: parent.width
checkbox.checked: (modelData === AudioDevice.getInputDevice())
text.text: modelData
onCheckBoxClicked: {
if (checked) {
AudioDevice.setInputDevice(modelData)
refreshTimer.start()
visible: devicemode === 0
height: visible ? 36 : 0
AudioCheckbox {
id: cbin
anchors.verticalCenter: parent.verticalCenter
Binding {
target: cbin.checkbox
property: 'checked'
value: devicechecked
}
width: parent.width
cbchecked: devicechecked
text.text: devicename
onCheckBoxClicked: {
if (checked) {
AudioDevice.setInputDeviceAsync(devicename)
}
}
}
}
@ -191,31 +190,33 @@ Rectangle {
text: qsTr("CHOOSE OUTPUT DEVICE")
}
}
ListView {
id: outputAudioListView
Timer {
id: refreshTimerOutput
interval: 1
repeat: false
onTriggered: {
//refresh model
outputAudioListView.model = undefined
outputAudioListView.model = AudioDevice.outputAudioDevices
}
}
anchors { left: parent.left; right: parent.right; leftMargin: 70 }
height: 250
spacing: 16
spacing: 0
clip: true
snapMode: ListView.SnapToItem
delegate: AudioCheckbox {
model: AudioDevice
delegate: Item {
width: parent.width
checkbox.checked: (modelData === AudioDevice.getOutputDevice())
text.text: modelData
onCheckBoxClicked: {
if (checked) {
AudioDevice.setOutputDevice(modelData)
refreshTimerOutput.start()
visible: devicemode === 1
height: visible ? 36 : 0
AudioCheckbox {
id: cbout
width: parent.width
anchors.verticalCenter: parent.verticalCenter
Binding {
target: cbout.checkbox
property: 'checked'
value: devicechecked
}
text.text: devicename
onCheckBoxClicked: {
if (checked) {
AudioDevice.setOutputDeviceAsync(devicename)
}
}
}
}

View file

@ -8,6 +8,7 @@ Row {
id: row
spacing: 16
property alias checkbox: cb
property alias cbchecked: cb.checked
property alias text: txt
signal checkBoxClicked(bool checked)
@ -17,6 +18,7 @@ Row {
colorScheme: hifi.colorSchemes.dark
anchors.verticalCenter: parent.verticalCenter
onClicked: checkBoxClicked(cb.checked)
onCheckedChanged: console.log("checked", checked, "device ",txt.text)
}
RalewayBold {
id: txt

View file

@ -33,11 +33,17 @@ bool AudioDeviceScriptingInterface::muted()
return getMuted();
}
AudioDeviceScriptingInterface::AudioDeviceScriptingInterface() {
AudioDeviceScriptingInterface::AudioDeviceScriptingInterface(): QAbstractListModel(nullptr) {
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::muteToggled,
this, &AudioDeviceScriptingInterface::muteToggled);
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::deviceChanged,
this, &AudioDeviceScriptingInterface::deviceChanged);
this, &AudioDeviceScriptingInterface::onDeviceChanged, Qt::QueuedConnection);
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::currentInputDeviceChanged,
this, &AudioDeviceScriptingInterface::onCurrentInputDeviceChanged, Qt::QueuedConnection);
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::currentOutputDeviceChanged,
this, &AudioDeviceScriptingInterface::onCurrentOutputDeviceChanged, Qt::QueuedConnection);
//fill up model
onDeviceChanged();
}
bool AudioDeviceScriptingInterface::setInputDevice(const QString& deviceName) {
@ -51,13 +57,27 @@ bool AudioDeviceScriptingInterface::setInputDevice(const QString& deviceName) {
bool AudioDeviceScriptingInterface::setOutputDevice(const QString& deviceName) {
bool result;
QTime a; a.start();
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "switchOutputToAudioDevice",
Qt::BlockingQueuedConnection,
Q_RETURN_ARG(bool, result),
Q_ARG(const QString&, deviceName));
qDebug() << "switching to" << deviceName << "elapsed" << a.elapsed();
return result;
}
void AudioDeviceScriptingInterface::setInputDeviceAsync(const QString& deviceName) {
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "switchInputToAudioDevice",
Qt::QueuedConnection,
Q_ARG(const QString&, deviceName));
}
void AudioDeviceScriptingInterface::setOutputDeviceAsync(const QString& deviceName) {
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), "switchOutputToAudioDevice",
Qt::QueuedConnection,
Q_ARG(const QString&, deviceName));
}
QString AudioDeviceScriptingInterface::getInputDevice() {
return DependencyManager::get<AudioClient>()->getDeviceName(QAudio::AudioInput);
}
@ -116,3 +136,94 @@ void AudioDeviceScriptingInterface::setMuted(bool muted)
bool AudioDeviceScriptingInterface::getMuted() {
return DependencyManager::get<AudioClient>()->isMuted();
}
QVariant AudioDeviceScriptingInterface::data(const QModelIndex& index, int role) const {
//sanity
if (!index.isValid() || index.row() >= _devices.size())
return QVariant();
if (role == Qt::DisplayRole || role == DisplayNameRole) {
return _devices.at(index.row()).name;
} else if (role == SelectedRole) {
return _devices.at(index.row()).selected;
} else if (role == AudioModeRole) {
return (int)_devices.at(index.row()).mode;
}
return QVariant();
}
int AudioDeviceScriptingInterface::rowCount(const QModelIndex& parent) const {
Q_UNUSED(parent)
return _devices.size();
}
QHash<int, QByteArray> AudioDeviceScriptingInterface::roleNames() const {
QHash<int, QByteArray> roles;
roles.insert(DisplayNameRole, "devicename");
roles.insert(SelectedRole, "devicechecked");
roles.insert(AudioModeRole, "devicemode");
return roles;
}
void AudioDeviceScriptingInterface::onDeviceChanged()
{
beginResetModel();
_devices.clear();
const QString &outDevice = getOutputDevice();
for (QString name: getOutputDevices()) {
AudioDeviceInfo di;
di.name = name;
di.selected = (name == outDevice);
di.mode = QAudio::AudioOutput;
_devices.append(di);
}
const QString &inDevice = getInputDevice();
for (QString name: getInputDevices()) {
AudioDeviceInfo di;
di.name = name;
di.selected = (name == inDevice);
di.mode = QAudio::AudioInput;
_devices.append(di);
}
endResetModel();
emit deviceChanged();
}
void AudioDeviceScriptingInterface::onCurrentInputDeviceChanged()
{
currentDeviceUpdate(getInputDevice(), QAudio::AudioInput);
emit currentInputDeviceChanged();
}
void AudioDeviceScriptingInterface::onCurrentOutputDeviceChanged()
{
currentDeviceUpdate(getOutputDevice(), QAudio::AudioOutput);
emit currentOutputDeviceChanged();
}
void AudioDeviceScriptingInterface::currentDeviceUpdate(const QString &name, QAudio::Mode mode)
{
QVector<int> role;
role.append(SelectedRole);
qDebug() << "device update" << name << mode;
for (int i = 0; i < _devices.size(); i++) {
AudioDeviceInfo di = _devices.at(i);
if (di.mode != mode)
continue;
if (di.selected && di.name != name ) {
di.selected = false;
_devices[i] = di;
emit dataChanged(index(i, 0), index(i, 0), role);
}
if (di.name == name) {
di.selected = true;
_devices[i] = di;
emit dataChanged(index(i, 0), index(i, 0), role);
qDebug() << "device updated" << di.name << i;
}
}
}

View file

@ -15,10 +15,18 @@
#include <QObject>
#include <QString>
#include <QVector>
#include <QAbstractListModel>
#include <QAudio>
class AudioEffectOptions;
class AudioDeviceScriptingInterface : public QObject {
struct AudioDeviceInfo {
QString name;
bool selected;
QAudio::Mode mode;
};
class AudioDeviceScriptingInterface : public QAbstractListModel {
Q_OBJECT
Q_PROPERTY(QStringList inputAudioDevices READ inputAudioDevices NOTIFY inputAudioDevicesChanged)
@ -32,6 +40,22 @@ public:
QStringList outputAudioDevices() const;
bool muted();
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QHash<int, QByteArray> roleNames() const override;
enum Roles {
DisplayNameRole = Qt::UserRole,
SelectedRole,
AudioModeRole
};
private slots:
void onDeviceChanged();
void onCurrentInputDeviceChanged();
void onCurrentOutputDeviceChanged();
void currentDeviceUpdate(const QString &name, QAudio::Mode mode);
public slots:
bool setInputDevice(const QString& deviceName);
bool setOutputDevice(const QString& deviceName);
@ -55,15 +79,22 @@ public slots:
void setMuted(bool muted);
void setInputDeviceAsync(const QString &deviceName);
void setOutputDeviceAsync(const QString &deviceName);
private:
AudioDeviceScriptingInterface();
signals:
void muteToggled();
void deviceChanged();
void currentInputDeviceChanged();
void currentOutputDeviceChanged();
void mutedChanged(bool muted);
void inputAudioDevicesChanged(QStringList inputAudioDevices);
void outputAudioDevicesChanged(QStringList outputAudioDevices);
private:
QVector<AudioDeviceInfo> _devices;
};
#endif // hifi_AudioDeviceScriptingInterface_h

View file

@ -769,7 +769,8 @@ QString AudioClient::getDefaultDeviceName(QAudio::Mode mode) {
QVector<QString> AudioClient::getDeviceNames(QAudio::Mode mode) {
QVector<QString> deviceNames;
foreach(QAudioDeviceInfo audioDevice, getAvailableDevices(mode)) {
const QList<QAudioDeviceInfo> &availableDevice = getAvailableDevices(mode);
foreach(const QAudioDeviceInfo &audioDevice, availableDevice) {
deviceNames << audioDevice.deviceName().trimmed();
}
return deviceNames;
@ -1371,6 +1372,7 @@ bool AudioClient::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceIn
if (!inputDeviceInfo.isNull()) {
qCDebug(audioclient) << "The audio input device " << inputDeviceInfo.deviceName() << "is available.";
_inputAudioDeviceName = inputDeviceInfo.deviceName().trimmed();
emit currentInputDeviceChanged();
if (adjustedFormatForAudioDevice(inputDeviceInfo, _desiredInputFormat, _inputFormat)) {
qCDebug(audioclient) << "The format to be used for audio input is" << _inputFormat;
@ -1488,6 +1490,7 @@ bool AudioClient::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDevice
if (!outputDeviceInfo.isNull()) {
qCDebug(audioclient) << "The audio output device " << outputDeviceInfo.deviceName() << "is available.";
_outputAudioDeviceName = outputDeviceInfo.deviceName().trimmed();
emit currentOutputDeviceChanged();
if (adjustedFormatForAudioDevice(outputDeviceInfo, _desiredOutputFormat, _outputFormat)) {
qCDebug(audioclient) << "The format to be used for audio output is" << _outputFormat;

View file

@ -240,6 +240,9 @@ signals:
void muteEnvironmentRequested(glm::vec3 position, float radius);
void currentOutputDeviceChanged();
void currentInputDeviceChanged();
protected:
AudioClient();
~AudioClient();

View file

@ -64,13 +64,14 @@ function setupAudioMenus() {
// Setup audio input devices
Menu.addSeparator("Audio", "Input Audio Device");
var inputDevices = AudioDevice.getInputDevices();
var currentInputDevice = AudioDevice.getInputDevice()
for (var i = 0; i < inputDevices.length; i++) {
var audioDeviceMenuString = "Use " + inputDevices[i] + " for Input";
Menu.addMenuItem({
menuName: "Audio",
menuItemName: audioDeviceMenuString,
isCheckable: true,
isChecked: inputDevices[i] == AudioDevice.getInputDevice()
isChecked: inputDevices[i] == currentInputDevice
});
audioDevicesList.push(audioDeviceMenuString);
}
@ -78,13 +79,14 @@ function setupAudioMenus() {
// Setup audio output devices
Menu.addSeparator("Audio", "Output Audio Device");
var outputDevices = AudioDevice.getOutputDevices();
var currentOutputDevice = AudioDevice.getOutputDevice()
for (var i = 0; i < outputDevices.length; i++) {
var audioDeviceMenuString = "Use " + outputDevices[i] + " for Output";
Menu.addMenuItem({
menuName: "Audio",
menuItemName: audioDeviceMenuString,
isCheckable: true,
isChecked: outputDevices[i] == AudioDevice.getOutputDevice()
isChecked: outputDevices[i] == currentOutputDevice
});
audioDevicesList.push(audioDeviceMenuString);
}
@ -133,6 +135,11 @@ function onMenuEvent(audioDeviceMenuString) {
}
}
function onCurrentDeviceChanged() {
debug("System audio device switched. ");
setupAudioMenus()
}
function switchAudioDevice(audioDeviceMenuString) {
// if the device is not plugged in, short-circuit
if (!~audioDevicesList.indexOf(audioDeviceMenuString)) {
@ -254,7 +261,9 @@ function checkHMDAudio() {
// Wait for the C++ systems to fire up before trying to do anything with audio devices
Script.setTimeout(function () {
debug("Connecting deviceChanged(), displayModeChanged(), and switchAudioDevice()...");
AudioDevice.deviceChanged.connect(onDevicechanged);
// AudioDevice.deviceChanged.connect(onDevicechanged);
// AudioDevice.currentInputDeviceChanged.connect(onCurrentDeviceChanged);
// AudioDevice.currentOutputDeviceChanged.connect(onCurrentDeviceChanged);
HMD.displayModeChanged.connect(checkHMDAudio);
Menu.menuItemEvent.connect(onMenuEvent);
debug("Setting up Audio I/O menu for the first time...");