Rename EngineDevice --> DeviceFinders, Add MMDeviceFinder

This commit is contained in:
Jonas Kvinge
2019-11-03 19:53:08 +01:00
parent 62b8521cbe
commit 7b977ea839
12 changed files with 192 additions and 35 deletions

View File

@@ -26,8 +26,8 @@
#include <QtDebug>
#include "core/logging.h"
#include "devicefinders.h"
#include "devicefinder.h"
#include "enginedevice.h"
#ifdef HAVE_ALSA
# include "alsadevicefinder.h"
@@ -43,16 +43,16 @@
#ifdef Q_OS_WIN32
# include "directsounddevicefinder.h"
# include "mmdevicefinder.h"
#endif
EngineDevice::EngineDevice(QObject *parent) : QObject(parent) {
}
DeviceFinders::DeviceFinders(QObject *parent) : QObject(parent) {}
EngineDevice::~EngineDevice() {
DeviceFinders::~DeviceFinders() {
qDeleteAll(device_finders_);
}
void EngineDevice::Init() {
void DeviceFinders::Init() {
QList<DeviceFinder*> device_finders;
@@ -67,6 +67,7 @@ void EngineDevice::Init() {
#endif
#ifdef Q_OS_WIN32
device_finders.append(new DirectSoundDeviceFinder);
device_finders.append(new MMDeviceFinder);
#endif
for (DeviceFinder *finder : device_finders) {

View File

@@ -17,8 +17,8 @@
*
*/
#ifndef ENGINEDEVICE_H
#define ENGINEDEVICE_H
#ifndef DEVICEFINDERS_H
#define DEVICEFINDERS_H
#include "config.h"
@@ -28,21 +28,19 @@
class DeviceFinder;
class EngineDevice : public QObject {
class DeviceFinders : public QObject {
Q_OBJECT
public:
explicit EngineDevice(QObject *parent = nullptr);
~EngineDevice();
explicit DeviceFinders(QObject *parent = nullptr);
~DeviceFinders();
void Init();
QList<DeviceFinder*> device_finders_;
QList<DeviceFinder*> ListFinders() { return device_finders_; }
private:
QString output_;
QList<DeviceFinder*> device_finders_;
};
#endif // ENGINEDEVICE_H
#endif // DEVICEFINDERS_H

View File

@@ -35,7 +35,7 @@
#include "core/logging.h"
DirectSoundDeviceFinder::DirectSoundDeviceFinder()
: DeviceFinder("directsound", { "directsound", "dsound", "directsoundsink", "directx", "directx2", "wasapisink" }) {
: DeviceFinder("directsound", { "directsound", "dsound", "directsoundsink", "directx", "directx2" }) {
}
QList<DeviceFinder::Device> DirectSoundDeviceFinder::ListDevices() {
@@ -52,9 +52,7 @@ BOOL DirectSoundDeviceFinder::EnumerateCallback(LPGUID guid, LPCSTR description,
Device dev;
dev.description = QString::fromLatin1(description);
//if (guid) dev.value = QUuid(*guid).toByteArray();
if (guid) dev.value = QUuid(*guid).toString();
else dev.value = QVariant();
dev.iconname = GuessIconName(dev.description);
state->devices.append(dev);

View File

@@ -41,7 +41,7 @@
#include "engine_fwd.h"
#include "enginetype.h"
#include "enginedevice.h"
#include "devicefinders.h"
#include "core/song.h"
namespace Engine {

View File

@@ -40,6 +40,7 @@
#include <QTimeLine>
#include <QMetaObject>
#include <QtDebug>
#include <QUuid>
#include "core/concurrentrun.h"
#include "core/logging.h"
@@ -197,11 +198,11 @@ bool GstEnginePipeline::InitAudioBin() {
if (device_.isValid() && g_object_class_find_property(G_OBJECT_GET_CLASS(audiosink), "device")) {
switch (device_.type()) {
case QVariant::String:
if (device_.toString().isEmpty()) break;
g_object_set(G_OBJECT(audiosink), "device", device_.toString().toUtf8().constData(), nullptr);
if (device_.toString().isEmpty()) break;
g_object_set(G_OBJECT(audiosink), "device", device_.toString().toUtf8().constData(), nullptr);
break;
case QVariant::ByteArray:
g_object_set(G_OBJECT(audiosink), "device", device_.toByteArray().constData(), nullptr);
g_object_set(G_OBJECT(audiosink), "device", device_.toByteArray().constData(), nullptr);
break;
case QVariant::LongLong:
g_object_set(G_OBJECT(audiosink), "device", device_.toLongLong(), nullptr);
@@ -209,12 +210,20 @@ bool GstEnginePipeline::InitAudioBin() {
case QVariant::Int:
g_object_set(G_OBJECT(audiosink), "device", device_.toInt(), nullptr);
break;
case QVariant::Uuid:
g_object_set(G_OBJECT(audiosink), "device", device_.toUuid(), nullptr);
break;
default:
qLog(Warning) << "Unknown device type" << device_;
break;
}
}
if (output_ == "wasapisink") {
g_object_set(G_OBJECT(audiosink), "exclusive", true, nullptr);
g_object_set(G_OBJECT(audiosink), "low-latency", true, nullptr);
}
// Create all the other elements
audioqueue_ = engine_->CreateElement("queue2", audiobin_);
@@ -901,6 +910,7 @@ void GstEnginePipeline::SourceSetupCallback(GstPlayBin *bin, GParamSpec *, gpoin
if (g_object_class_find_property(G_OBJECT_GET_CLASS(element), "device") && !instance->source_device().isEmpty()) {
// Gstreamer is not able to handle device in URL (referring to Gstreamer documentation, this might be added in the future).
// Despite that, for now we include device inside URL: we decompose it during Init and set device here, when this callback is called.
qLog(Info) << instance->source_device().toLocal8Bit().constData();
g_object_set(element, "device", instance->source_device().toLocal8Bit().constData(), nullptr);
}

View File

@@ -0,0 +1,115 @@
/*
* Strawberry Music Player
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <initguid.h>
#include <devpkey.h>
#include <functiondiscoverykeys_devpkey.h>
#include <mmdeviceapi.h>
#include <QList>
#include <QVariant>
#include <QString>
#include "mmdevicefinder.h"
#include "core/logging.h"
MMDeviceFinder::MMDeviceFinder() : DeviceFinder("mmdevice", { "wasapisink" }) {}
QList<DeviceFinder::Device> MMDeviceFinder::ListDevices() {
HRESULT hr = S_OK;
IMMDeviceEnumerator *enumerator = nullptr;
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void**)&enumerator);
if (FAILED(hr)) {
return QList<Device>();
}
IMMDeviceCollection *collection = nullptr;
hr = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &collection);
if (FAILED(hr)) {
enumerator->Release();
return QList<Device>();
}
UINT count;
hr = collection->GetCount(&count);
if (FAILED(hr)) {
collection->Release();
enumerator->Release();
return QList<Device>();
}
QList<Device> devices;
Device default_device;
default_device.description = "Default device";
default_device.iconname = GuessIconName(default_device.description);
devices.append(default_device);
for (ULONG i = 0 ; i < count ; i++) {
IMMDevice *endpoint = nullptr;
hr = collection->Item(i, &endpoint);
if (FAILED(hr)) { return devices; }
LPWSTR pwszid = nullptr;
hr = endpoint->GetId(&pwszid);
if (FAILED(hr)) {
endpoint->Release();
continue;
}
IPropertyStore *props = nullptr;
hr = endpoint->OpenPropertyStore(STGM_READ, &props);
if (FAILED(hr)) {
CoTaskMemFree(pwszid);
endpoint->Release();
continue;
}
PROPVARIANT var_name;
PropVariantInit(&var_name);
hr = props->GetValue(PKEY_Device_FriendlyName, &var_name);
if (FAILED(hr)) {
props->Release();
CoTaskMemFree(pwszid);
endpoint->Release();
continue;
}
Device device;
device.description = QString::fromWCharArray(var_name.pwszVal);
device.iconname = GuessIconName(device.description);
device.value = QString::fromStdWString(pwszid);
devices.append(device);
PropVariantClear(&var_name);
props->Release();
CoTaskMemFree(pwszid);
endpoint->Release();
}
collection->Release();
enumerator->Release();
return devices;
}

View File

@@ -0,0 +1,34 @@
/*
* Strawberry Music Player
* Copyright 2019, Jonas Kvinge <jonas@jkvinge.net>
*
* Strawberry is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Strawberry is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef MMDEVICEFINDER_H
#define MMDEVICEFINDER_H
#include "config.h"
#include "devicefinder.h"
class MMDeviceFinder : public DeviceFinder {
public:
MMDeviceFinder();
virtual bool Initialise() { return true; }
virtual QList<Device> ListDevices();
};
#endif // MMDEVICEFINDER_H