service/pipewire: refactor defaults and metadata handling

This commit is contained in:
outfoxxed 2024-09-23 18:41:38 -07:00
parent 7f9762be53
commit f889f08901
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
11 changed files with 455 additions and 144 deletions

View file

@ -1,14 +1,15 @@
#include "metadata.hpp"
#include <array>
#include <cstring>
#include <pipewire/core.h>
#include <pipewire/extensions/metadata.h>
#include <qlogging.h>
#include <qloggingcategory.h>
#include <qobject.h>
#include <qstringview.h>
#include <qtmetamacros.h>
#include <qtypes.h>
#include <spa/utils/json.h>
#include <spa/param/param.h>
#include <spa/utils/dict.h>
#include "registry.hpp"
@ -22,6 +23,14 @@ void PwMetadata::bindHooks() {
void PwMetadata::unbindHooks() { this->listener.remove(); }
void PwMetadata::initProps(const spa_dict* props) {
if (const auto* name = spa_dict_lookup(props, PW_KEY_METADATA_NAME)) {
this->mName = name;
}
}
const QString& PwMetadata::name() const { return this->mName; }
const pw_metadata_events PwMetadata::EVENTS = {
.version = PW_VERSION_METADATA_EVENTS,
.property = &PwMetadata::onProperty,
@ -39,89 +48,26 @@ int PwMetadata::onProperty(
<< "key:" << QString(key) << "type:" << QString(type)
<< "value:" << QString(value);
emit self->registry->metadataUpdate(self, subject, key, type, value);
// ideally we'd dealloc metadata that wasn't picked up but there's no information
// available about if updates can come in later, so I assume they can.
emit self->propertyChanged(key, type, value);
return 0; // ??? - no docs and no reason for a callback to return an int
}
PwDefaultsMetadata::PwDefaultsMetadata(PwRegistry* registry) {
QObject::connect(
registry,
&PwRegistry::metadataUpdate,
this,
&PwDefaultsMetadata::onMetadataUpdate
);
bool PwMetadata::hasSetPermission() const {
return (this->perms & SPA_PARAM_INFO_WRITE) == SPA_PARAM_INFO_WRITE;
}
QString PwDefaultsMetadata::defaultSink() const { return this->mDefaultSink; }
QString PwDefaultsMetadata::defaultSource() const { return this->mDefaultSource; }
// we don't really care if the metadata objects are destroyed, but try to ref them so we get property updates
void PwDefaultsMetadata::onMetadataUpdate(
PwMetadata* metadata,
quint32 subject,
const char* key,
const char* /*type*/,
const char* value
) {
if (subject != 0) return;
if (strcmp(key, "default.audio.sink") == 0) {
this->defaultSinkHolder.setObject(metadata);
auto newSink = PwDefaultsMetadata::parseNameSpaJson(value);
qCInfo(logMeta) << "Got default sink" << newSink;
if (newSink == this->mDefaultSink) return;
this->mDefaultSink = newSink;
emit this->defaultSinkChanged();
void PwMetadata::setProperty(const char* key, const char* type, const char* value) {
if (this->proxy() == nullptr) {
qCCritical(logMeta) << "Tried to change property of" << this << "which is not bound.";
return;
}
if (strcmp(key, "default.audio.source") == 0) {
this->defaultSourceHolder.setObject(metadata);
auto newSource = PwDefaultsMetadata::parseNameSpaJson(value);
qCInfo(logMeta) << "Got default source" << newSource;
if (newSource == this->mDefaultSource) return;
this->mDefaultSource = newSource;
emit this->defaultSourceChanged();
return;
}
}
QString PwDefaultsMetadata::parseNameSpaJson(const char* spaJson) {
auto iter = std::array<spa_json, 2>();
spa_json_init(&iter[0], spaJson, strlen(spaJson));
if (spa_json_enter_object(&iter[0], &iter[1]) < 0) {
qCWarning(logMeta) << "Failed to parse source/sink SPA json - failed to enter object of"
<< QString(spaJson);
return "";
if (!this->hasSetPermission()) {
qCCritical(logMeta) << "Tried to change property of" << this << "which is read-only.";
}
auto buf = std::array<char, 512>();
while (spa_json_get_string(&iter[1], buf.data(), buf.size()) > 0) {
if (strcmp(buf.data(), "name") != 0) continue;
if (spa_json_get_string(&iter[1], buf.data(), buf.size()) < 0) {
qCWarning(logMeta
) << "Failed to parse source/sink SPA json - failed to read value of name property"
<< QString(spaJson);
return "";
}
return QString(buf.data());
}
qCWarning(logMeta) << "Failed to parse source/sink SPA json - failed to find name property of"
<< QString(spaJson);
return "";
pw_metadata_set_property(this->proxy(), PW_ID_CORE, key, type, value);
}
} // namespace qs::service::pipewire