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

@ -121,7 +121,7 @@ set(SOURCES
engine/enginetype.cpp
engine/enginebase.cpp
engine/enginedevice.cpp
engine/devicefinders.cpp
engine/devicefinder.cpp
analyzer/fht.cpp
@ -315,7 +315,7 @@ set(HEADERS
core/mimedata.h
engine/enginebase.h
engine/enginedevice.h
engine/devicefinders.h
analyzer/analyzerbase.h
analyzer/analyzercontainer.h
@ -877,6 +877,7 @@ endif()
optional_source(WIN32
SOURCES
engine/directsounddevicefinder.cpp
engine/mmdevicefinder.cpp
widgets/osd_win.cpp
core/windows7thumbbar.cpp
HEADERS

View File

@ -51,7 +51,7 @@
#include "engine/engine_fwd.h"
#include "engine/enginebase.h"
#include "engine/enginetype.h"
#include "engine/enginedevice.h"
#include "engine/devicefinders.h"
#include "engine/devicefinder.h"
#include "collection/collection.h"
#include "collection/collectionbackend.h"
@ -341,7 +341,7 @@ void ContextView::SetSong(const Song &song) {
ui_->spacer_play_output->changeSize(20, 20, QSizePolicy::Fixed);
DeviceFinder::Device device;
for (DeviceFinder *f : app_->enginedevice()->device_finders_) {
for (DeviceFinder *f : app_->device_finders()->ListFinders()) {
for (const DeviceFinder::Device &d : f->ListDevices()) {
if (d.value != app_->player()->engine()->device()) continue;
device = d;

View File

@ -41,7 +41,7 @@
#include "player.h"
#include "appearance.h"
#include "engine/enginedevice.h"
#include "engine/devicefinders.h"
#ifndef Q_OS_WIN
# include "device/devicemanager.h"
#endif
@ -105,7 +105,7 @@ class ApplicationImpl {
appearance_([=]() { return new Appearance(app); }),
task_manager_([=]() { return new TaskManager(app); }),
player_([=]() { return new Player(app, app); }),
enginedevice_([=]() { return new EngineDevice(app); }),
device_finders_([=]() { return new DeviceFinders(app); }),
#ifndef Q_OS_WIN
device_manager_([=]() { return new DeviceManager(app, app); }),
#endif
@ -175,7 +175,7 @@ class ApplicationImpl {
Lazy<Appearance> appearance_;
Lazy<TaskManager> task_manager_;
Lazy<Player> player_;
Lazy<EngineDevice> enginedevice_;
Lazy<DeviceFinders> device_finders_;
#ifndef Q_OS_WIN
Lazy<DeviceManager> device_manager_;
#endif
@ -205,7 +205,7 @@ class ApplicationImpl {
Application::Application(QObject *parent)
: QObject(parent), p_(new ApplicationImpl(this)) {
enginedevice()->Init();
device_finders()->Init();
collection()->Init();
tag_reader_client();
@ -307,7 +307,7 @@ Appearance *Application::appearance() const { return p_->appearance_.get(); }
Database *Application::database() const { return p_->database_.get(); }
TaskManager *Application::task_manager() const { return p_->task_manager_.get(); }
Player *Application::player() const { return p_->player_.get(); }
EngineDevice *Application::enginedevice() const { return p_->enginedevice_.get(); }
DeviceFinders *Application::device_finders() const { return p_->device_finders_.get(); }
#ifndef Q_OS_WIN
DeviceManager *Application::device_manager() const { return p_->device_manager_.get(); }
#endif

View File

@ -41,7 +41,7 @@ class TaskManager;
class ApplicationImpl;
class TagReaderClient;
class Database;
class EngineDevice;
class DeviceFinders;
class Player;
class Appearance;
class SCollection;
@ -78,7 +78,7 @@ class Application : public QObject {
Appearance *appearance() const;
TaskManager *task_manager() const;
Player *player() const;
EngineDevice *enginedevice() const;
DeviceFinders *device_finders() const;
#ifndef Q_OS_WIN
DeviceManager *device_manager() const;
#endif

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

View File

@ -41,7 +41,7 @@
#include "core/logging.h"
#include "engine/engine_fwd.h"
#include "engine/enginebase.h"
#include "engine/enginedevice.h"
#include "engine/devicefinders.h"
#include "engine/enginetype.h"
#include "engine/devicefinder.h"
#include "widgets/lineedit.h"
@ -291,7 +291,7 @@ void BackendSettingsPage::Load_Device(QString output, QVariant device) {
#endif
ui_->combobox_device->addItem(IconLoader::Load("soundcard"), "Automatically select", QVariant());
for (DeviceFinder *f : dialog()->app()->enginedevice()->device_finders_) {
for (DeviceFinder *f : dialog()->app()->device_finders()->ListFinders()) {
if (!f->outputs().contains(output)) continue;
for (const DeviceFinder::Device &d : f->ListDevices()) {
devices++;