Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Packages] AudioControl: Add AppVM names support #10

Merged
merged 1 commit into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions packages/ghaf-audio-control/src/app/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

#include <GhafAudioControl/AudioControl.hpp>
#include <GhafAudioControl/Backends/PulseAudio/AudioControlBackend.hpp>
#include <GhafAudioControl/utils/Debug.hpp>
#include <GhafAudioControl/utils/Logger.hpp>

#include <gtkmm/applicationwindow.h>

#include <glibmm/main.h>
#include <glibmm/optioncontext.h>
#include <gtkmm/applicationwindow.h>

#include <format>

Expand All @@ -18,13 +19,26 @@ using namespace ghaf::AudioControl;
namespace
{

int GtkClient(std::string pulseAudioServerAddress)
std::vector<std::string> GetAppVmsList(const std::string& appVms)
{
auto app = Gtk::Application::create();
std::vector<std::string> result;

AudioControl audioControl{std::make_unique<Backend::PulseAudio::AudioControlBackend>(std::move(pulseAudioServerAddress))};
std::istringstream iss(appVms);
std::string buf;

while (getline(iss, buf, ','))
result.push_back(buf);

return result;
}

int GtkClient(const std::string& pulseAudioServerAddress, const std::string& appVms)
{
auto app = Gtk::Application::create();
Gtk::ApplicationWindow window;

AudioControl audioControl{std::make_unique<Backend::PulseAudio::AudioControlBackend>(pulseAudioServerAddress), GetAppVmsList(appVms)};

window.add(audioControl);
window.show_all();

Expand All @@ -35,14 +49,21 @@ int GtkClient(std::string pulseAudioServerAddress)

int main(int argc, char** argv)
{
pthread_setname_np(pthread_self(), "main");

Glib::ustring pulseServerAddress;
Glib::OptionEntry pulseServerOption;

pulseServerOption.set_long_name("pulseaudio_server");
pulseServerOption.set_description("PulseAudio server address");

Glib::ustring appVms;
Glib::OptionEntry appVmsOption;
appVmsOption.set_long_name("app_vms");
appVmsOption.set_description("AppVMs list");

Glib::OptionGroup options("Main", "Main");
options.add_entry(pulseServerOption, pulseServerAddress);
options.add_entry(appVmsOption, appVms);

Glib::OptionContext context("Application Options");
context.set_main_group(options);
Expand All @@ -60,5 +81,5 @@ int main(int argc, char** argv)
return 1;
}

return GtkClient(pulseServerAddress);
return GtkClient(pulseServerAddress, appVms);
}
2 changes: 2 additions & 0 deletions packages/ghaf-audio-control/src/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ PRIVATE
src/models/DeviceModel.cpp

src/utils/ConnectionContainer.cpp
src/utils/Debug.cpp
src/utils/Logger.cpp

src/widgets/AppVmWidget.cpp
Expand Down Expand Up @@ -60,6 +61,7 @@ PUBLIC
include/GhafAudioControl/models/DeviceModel.hpp

include/GhafAudioControl/utils/ConnectionContainer.hpp
include/GhafAudioControl/utils/Debug.hpp
include/GhafAudioControl/utils/Logger.hpp
include/GhafAudioControl/utils/RaiiWrap.hpp
include/GhafAudioControl/utils/ScopeExit.hpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <GhafAudioControl/models/AppVmModel.hpp>

#include <gtkmm/box.h>
#include <gtkmm/cssprovider.h>
#include <gtkmm/listbox.h>
#include <gtkmm/separator.h>
#include <gtkmm/stack.h>
Expand All @@ -22,13 +23,15 @@ class AppList final : public Gtk::Box
public:
AppList();

void addVm(std::string appVmName);
void addDevice(IAudioControlBackend::ISinkInput::Ptr device);

void removeAllApps();

private:
Gtk::ListBox m_listBox;

Glib::RefPtr<Gtk::CssProvider> m_cssProvider;
Glib::RefPtr<Gio::ListStore<AppVmModel>> m_appsModel;
std::map<AppVmModel::AppIdType, std::vector<Glib::RefPtr<Glib::Binding>>> m_appsBindings;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace ghaf::AudioControl
class AudioControl final : public Gtk::Box
{
public:
explicit AudioControl(std::unique_ptr<IAudioControlBackend> backend);
AudioControl(std::unique_ptr<IAudioControlBackend> backend, const std::vector<std::string>& appVmsList);
~AudioControl() override = default;

AudioControl(AudioControl&) = delete;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class GeneralDeviceImpl final
[[nodiscard]] pa_volume_t getPulseVolume() const;
[[nodiscard]] pa_cvolume getPulseChannelVolume() const noexcept;

[[nodiscard]] std::optional<std::string> getAppVmName() const noexcept;

[[nodiscard]] std::string getName() const;
[[nodiscard]] std::string getDescription() const;

Expand Down Expand Up @@ -78,6 +80,9 @@ class GeneralDeviceImpl final

bool m_isDeleted = false;
bool m_isEnabled = false;

std::optional<std::string> m_appVmName;

std::string m_name;
std::string m_description;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ class SinkInput final : public IAudioControlBackend::ISinkInput
return m_device.getDescription();
}

std::optional<std::string> getAppVmName() const
{
return m_device.getAppVmName();
}

void update(const pa_sink_input_info& info);

void markDeleted();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

namespace ghaf::AudioControl
{

void MarkUiTreadStarted();
void CheckUiThread();

} // namespace ghaf::AudioControl
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,12 @@ namespace ghaf::AudioControl
class Logger
{
public:
static void debug(std::string_view message)
{
log(message);
}

static void error(std::string_view message)
{
log(message);
}

static void info(std::string_view message)
{
log(message);
}
static void debug(std::string_view message);
static void error(std::string_view message);
static void info(std::string_view message);

private:
static void log(std::string_view message);
static void log(std::string_view message, std::string_view logLevel);

Logger();
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,20 @@ class AppVmWidget final : public Gtk::Box

void reveal(bool reveal = true);

private:
void onDeviceChange(guint position, guint removed, guint added);

private:
Glib::RefPtr<AppVmModel> m_model;

Gtk::Box m_revealerBox;
Gtk::ListBox m_listBox;

Gtk::Label m_emptyListLabel;
Gtk::Button m_appNameButton;
Gtk::Revealer m_revealer;

sigc::connection m_connection;
ConnectionContainer m_connections;
};

} // namespace ghaf::AudioControl
26 changes: 22 additions & 4 deletions packages/ghaf-audio-control/src/lib/src/AppList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
*/

#include <GhafAudioControl/AppList.hpp>
#include <GhafAudioControl/widgets/AppVmWidget.hpp>

#include <GhafAudioControl/Backends/PulseAudio/SinkInput.hpp>
#include <GhafAudioControl/utils/Debug.hpp>
#include <GhafAudioControl/utils/Logger.hpp>
#include <GhafAudioControl/widgets/AppVmWidget.hpp>

#include <gtkmm/adjustment.h>
#include <gtkmm/button.h>
Expand Down Expand Up @@ -36,6 +37,12 @@ std::optional<size_t> GetIndexByAppId(const Glib::RefPtr<Gio::ListStore<AppVmMod

std::string GetAppNameFromSinkInput(const IAudioControlBackend::ISinkInput::Ptr& device)
{
if (auto sinkInput = std::dynamic_pointer_cast<Backend::PulseAudio::SinkInput>(device))
{
if (const auto appVmName = sinkInput->getAppVmName())
return *appVmName;
}

return "Other";
}

Expand All @@ -61,6 +68,7 @@ Gtk::Widget* CreateWidgetsForApp(const Glib::RefPtr<Glib::Object>& appVmModelPtr

AppList::AppList()
: Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)
, m_cssProvider(Gtk::CssProvider::create())
, m_appsModel(Gio::ListStore<AppVmModel>::create())
{
m_listBox.bind_model(m_appsModel, &CreateWidgetsForApp);
Expand All @@ -70,6 +78,14 @@ AppList::AppList()
pack_start(m_listBox, Gtk::PACK_EXPAND_WIDGET);
}

void AppList::addVm(std::string appVmName)
{
if (const auto index = GetIndexByAppId(m_appsModel, appVmName))
return;

m_appsModel->append(AppVmModel::create(std::move(appVmName)));
}

void AppList::addDevice(IAudioControlBackend::ISinkInput::Ptr device)
{
const std::string appName = GetAppNameFromSinkInput(device);
Expand All @@ -81,10 +97,12 @@ void AppList::addDevice(IAudioControlBackend::ISinkInput::Ptr device)
Logger::error(std::format("AppList::addDevice: add new app with name: {}", appName));

auto appVmModel = AppVmModel::create(appName);
appVmModel->addSinkInput(std::move(device));

m_appsModel->append(appVmModel);

appVmModel->addSinkInput(std::move(device));
}

show_all_children(true);
}

void AppList::removeAllApps()
Expand Down
20 changes: 15 additions & 5 deletions packages/ghaf-audio-control/src/lib/src/AudioControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
namespace ghaf::AudioControl
{

constexpr auto CssStyle = "button#AppVmNameButton { background-color: transparent; border: none; font-weight: bold; }"
"box#DeviceWidget { background: #e6e6e6; border-radius: 15px; }"
"label#EmptyListName { background: #e6e6e6; border-radius: 15px; min-height: 40px; }"
"*:selected { background-color: transparent; color: inherit; box-shadow: none; outline: none; }";

template<class IndexT, class DevicePtrT>
void OnPulseDeviceChanged(IAudioControlBackend::EventType eventType, IndexT index, DevicePtrT device, AppList& appList)
{
Expand Down Expand Up @@ -64,10 +69,13 @@ void OnPulseDeviceChanged(IAudioControlBackend::EventType eventType, IndexT inde
}
}

AudioControl::AudioControl(std::unique_ptr<IAudioControlBackend> backend)
AudioControl::AudioControl(std::unique_ptr<IAudioControlBackend> backend, const std::vector<std::string>& appVmsList)
: Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)
, m_audioControl(std::move(backend))
{
for (const auto& appVm : appVmsList)
m_appList.addVm(appVm);

init();
}

Expand All @@ -91,34 +99,36 @@ void AudioControl::init()
{
onPulseError("No audio backend");
}

auto cssProvider = Gtk::CssProvider::create();
cssProvider->load_from_data(CssStyle);

auto style_context = Gtk::StyleContext::create();
style_context->add_provider_for_screen(Gdk::Screen::get_default(), cssProvider, GTK_STYLE_PROVIDER_PRIORITY_USER);
}

void AudioControl::onPulseSinksChanged(IAudioControlBackend::EventType eventType, IAudioControlBackend::Sinks::IndexT extIndex,
IAudioControlBackend::Sinks::PtrT sink)
{
OnPulseDeviceChanged(eventType, extIndex, std::move(sink), m_appList);
show_all_children();
}

void AudioControl::onPulseSourcesChanged(IAudioControlBackend::EventType eventType, IAudioControlBackend::Sources::IndexT extIndex,
IAudioControlBackend::Sources::PtrT source)
{
OnPulseDeviceChanged(eventType, extIndex, std::move(source), m_appList);
show_all_children();
}

void AudioControl::onPulseSinkInputsChanged(IAudioControlBackend::EventType eventType, IAudioControlBackend::SinkInputs::IndexT extIndex,
IAudioControlBackend::SinkInputs::PtrT sinkInput)
{
OnPulseDeviceChanged(eventType, extIndex, std::move(sinkInput), m_appList);
show_all_children();
}

void AudioControl::onPulseSourcesOutputsChanged(IAudioControlBackend::EventType eventType, IAudioControlBackend::SourceOutputs::IndexT extIndex,
IAudioControlBackend::SourceOutputs::PtrT sourceOutput)
{
OnPulseDeviceChanged(eventType, extIndex, std::move(sourceOutput), m_appList);
show_all_children();
}

void AudioControl::onPulseError(std::string_view error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ void OnPulseDeviceInfo(const InfoT& info, IAudioControlBackend::SignalMap<IDevic
{
const IDeviceT& device = *deviceIt.value()->second;

Logger::debug(std::format("Updating... Before: {}", device.toString()));
map.update(*deviceIt, [&info](IDeviceT& device) { dynamic_cast<DeviceT&>(device).update(info); });
Logger::debug(std::format("Updating... After: {}", device.toString()));
Logger::debug(std::format("Updating... {}", device.toString()));
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
namespace ghaf::AudioControl::Backend::PulseAudio
{

constexpr auto PropertyAppVmName = "application.process.host";

GeneralDeviceImpl::GeneralDeviceImpl(const pa_sink_info& info, pa_context& context)
: m_index(info.index)
, m_cardIndex(info.card)
Expand Down Expand Up @@ -39,6 +41,7 @@ GeneralDeviceImpl::GeneralDeviceImpl(const pa_source_info& info, pa_context& con
GeneralDeviceImpl::GeneralDeviceImpl(const pa_sink_input_info& info, pa_context& context)
: m_index(info.index)
, m_cardIndex(0)
, m_appVmName(pa_proplist_gets(info.proplist, PropertyAppVmName))
, m_name(info.name)
, m_context(context)
, m_channel_map(info.channel_map)
Expand Down Expand Up @@ -99,6 +102,12 @@ GeneralDeviceImpl::GeneralDeviceImpl(const pa_source_output_info& info, pa_conte
return m_volume;
}

std::optional<std::string> GeneralDeviceImpl::getAppVmName() const noexcept
{
const std::lock_guard l{m_mutex};
return m_appVmName;
}

[[nodiscard]] std::string GeneralDeviceImpl::getName() const
{
const std::lock_guard l{m_mutex};
Expand Down
Loading