/* $Id$ */ /*** This file is part of paman. paman 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 2 of the License, or (at your option) any later version. paman 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 paman; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. ***/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "ServerInfoManager.hh" #include "paman.hh" SinkInfo::SinkInfo(const pa_sink_info &i) : driver(i.driver), name(i.name), index(i.index), sample_spec(i.sample_spec), channel_map(i.channel_map), monitor_source(i.monitor_source), owner_module(i.owner_module), volume(i.volume), hw_volume_supported(!!(i.flags & PA_SINK_HW_VOLUME_CTRL)), latency(i.latency), monitor_source_name(i.monitor_source_name), window(NULL) { if (i.description) description = i.description; } SinkInfo::~SinkInfo() { if (window) delete window; } void SinkInfo::update(const pa_sink_info &i) { driver = Glib::ustring(i.driver); name = Glib::ustring(i.name); index = i.index; sample_spec = i.sample_spec; channel_map = i.channel_map; monitor_source = i.monitor_source; owner_module = i.owner_module; volume = i.volume; hw_volume_supported = !!(i.flags & PA_SINK_HW_VOLUME_CTRL), latency = i.latency; monitor_source_name = i.monitor_source_name; description = i.description ? i.description : ""; if (window) window->updateInfo(*this); g_assert(mainWindow); mainWindow->updateInfo(*this); } void SinkInfo::showWindow() { if (window) window->present(); else { window = SinkWindow::create(); window->updateInfo(*this); window->show(); } } SourceInfo::SourceInfo(const pa_source_info &i) : driver(i.driver), name(i.name), index(i.index), sample_spec(i.sample_spec), channel_map(i.channel_map), owner_module(i.owner_module), monitor_of_sink(i.monitor_of_sink), volume(i.volume), hw_volume_supported(!!(i.flags & PA_SINK_HW_VOLUME_CTRL)), latency(i.latency), window(NULL) { if (i.description) description = i.description; } SourceInfo::~SourceInfo() { if (window) delete window; } void SourceInfo::update(const struct pa_source_info &i) { driver = i.driver; name = i.name; index = i.index; sample_spec = i.sample_spec; channel_map = i.channel_map; owner_module = i.owner_module; monitor_of_sink = i.monitor_of_sink; volume = i.volume; hw_volume_supported = !!(i.flags & PA_SOURCE_HW_VOLUME_CTRL), latency = i.latency; description = i.description ? i.description : ""; if (window) window->updateInfo(*this); g_assert(mainWindow); mainWindow->updateInfo(*this); } void SourceInfo::showWindow() { if (window) window->present(); else { window = SourceWindow::create(); window->updateInfo(*this); window->show(); } } ClientInfo::ClientInfo(const struct pa_client_info &i) : index(i.index), driver(i.driver), name(i.name), owner_module(i.owner_module), window(NULL) { } ClientInfo::~ClientInfo() { if (window) delete window; } void ClientInfo::update(const struct pa_client_info &i) { driver = i.driver; name = i.name; index = i.index; owner_module = i.owner_module; if (window) window->updateInfo(*this); g_assert(mainWindow); mainWindow->updateInfo(*this); } void ClientInfo::showWindow() { if (window) window->present(); else { window = ClientWindow::create(); window->updateInfo(*this); window->show(); } } ModuleInfo::ModuleInfo(const struct pa_module_info &i) : index(i.index), name(i.name), autoloaded(i.auto_unload), used(i.n_used), window(NULL) { if (i.argument) argument = i.argument; } ModuleInfo::~ModuleInfo() { if (window) delete window; } void ModuleInfo::update(const struct pa_module_info &i) { name = i.name; index = i.index; autoloaded = i.auto_unload; used = i.n_used; argument = i.argument ? i.argument : ""; if (window) window->updateInfo(*this); g_assert(mainWindow); mainWindow->updateInfo(*this); } void ModuleInfo::showWindow() { if (window) window->present(); else { window = ModuleWindow::create(); window->updateInfo(*this); window->show(); } } SinkInputInfo::SinkInputInfo(const struct pa_sink_input_info &i) : driver(i.driver), name(i.name), index(i.index), sample_spec(i.sample_spec), channel_map(i.channel_map), sink(i.sink), client(i.client), owner_module(i.owner_module), volume(i.volume), buffer_usec(i.buffer_usec), sink_usec(i.sink_usec), resample_method(i.resample_method ? i.resample_method : "n/a"), window(NULL) { } SinkInputInfo::~SinkInputInfo() { if (window) delete window; } void SinkInputInfo::update(const struct pa_sink_input_info &i) { driver = i.driver; name = i.name; index = i.index; sample_spec = i.sample_spec; channel_map = i.channel_map; sink = i.sink; client = i.client; owner_module = i.owner_module; volume = i.volume; buffer_usec = i.buffer_usec; sink_usec = i.sink_usec; resample_method = i.resample_method ? i.resample_method : "n/a"; if (window) window->updateInfo(*this); g_assert(mainWindow); mainWindow->updateInfo(*this); } void SinkInputInfo::showWindow() { if (window) window->present(); else { window = SinkInputWindow::create(); window->updateInfo(*this); window->show(); } } SourceOutputInfo::SourceOutputInfo(const struct pa_source_output_info &i) : driver(i.driver), name(i.name), index(i.index), sample_spec(i.sample_spec), channel_map(i.channel_map), source(i.source), client(i.client), owner_module(i.owner_module), buffer_usec(i.buffer_usec), source_usec(i.source_usec), resample_method(i.resample_method ? i.resample_method : "n/a"), window(NULL) { } SourceOutputInfo::~SourceOutputInfo() { if (window) delete window; } void SourceOutputInfo::update(const struct pa_source_output_info &i) { driver = i.driver; name = i.name; index = i.index; sample_spec = i.sample_spec; channel_map = i.channel_map; source = i.source; client = i.client; owner_module = i.owner_module; buffer_usec = i.buffer_usec; source_usec = i.source_usec; resample_method = i.resample_method ? i.resample_method : "n/a"; if (window) window->updateInfo(*this); g_assert(mainWindow); mainWindow->updateInfo(*this); } void SourceOutputInfo::showWindow() { if (window) window->present(); else { window = SourceOutputWindow::create(); window->updateInfo(*this); window->show(); } } SampleInfo::SampleInfo(const struct pa_sample_info &i) : index(i.index), name(i.name), sample_spec(i.sample_spec), duration(i.duration), bytes(i.bytes), volume(i.volume), lazy(!!i.lazy), filename_valid(false), window(NULL) { if (i.filename) { filename = i.filename; filename_valid = true; } } SampleInfo::~SampleInfo() { if (window) delete window; } void SampleInfo::update(const struct pa_sample_info &i) { index = i.index; name = i.name; sample_spec = i.sample_spec; duration = i.duration; bytes = i.bytes; volume = i.volume; lazy = !!i.lazy; filename_valid = !!i.filename; if (i.filename) filename = i.filename; if (window) window->updateInfo(*this); g_assert(mainWindow); mainWindow->updateInfo(*this); } void SampleInfo::showWindow() { if (window) window->present(); else { window = SampleWindow::create(); window->updateInfo(*this); window->show(); } } extern "C" { static void server_info_callback(struct pa_context *c, const struct pa_server_info *i, void *userdata); static void sink_info_callback(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata); static void source_info_callback(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata); static void client_info_callback(struct pa_context *c, const struct pa_client_info *i, int is_last, void *userdata); static void module_info_callback(struct pa_context *c, const struct pa_module_info *i, int is_last, void *userdata); static void sink_input_info_callback(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata); static void source_output_info_callback(struct pa_context *c, const struct pa_source_output_info *i, int is_last, void *userdata); static void sample_info_callback(struct pa_context *c, const struct pa_sample_info *i, int is_last, void *userdata); static void subscribe_callback(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata); }; static void server_info_callback(struct pa_context *c, const struct pa_server_info *i, void *) { if (!i) { mainWindow->showFailure(pa_strerror(pa_context_errno(c))); return; } mainWindow->updateInfo(*i); } static void sink_info_callback(struct pa_context *, const struct pa_sink_info *i, int, void *userdata) { ServerInfoManager *si = (ServerInfoManager*) userdata; if (i) si->updateInfo(*i); } static void source_info_callback(struct pa_context *, const struct pa_source_info *i, int, void *userdata) { ServerInfoManager *si = (ServerInfoManager*) userdata; if (i) si->updateInfo(*i); } static void client_info_callback(struct pa_context *, const struct pa_client_info *i, int, void *userdata) { ServerInfoManager *si = (ServerInfoManager*) userdata; if (i) si->updateInfo(*i); } static void module_info_callback(struct pa_context *, const struct pa_module_info *i, int, void *userdata) { ServerInfoManager *si = (ServerInfoManager*) userdata; if (i) si->updateInfo(*i); } static void sink_input_info_callback(struct pa_context *, const struct pa_sink_input_info *i, int, void *userdata) { ServerInfoManager *si = (ServerInfoManager*) userdata; if (i) si->updateInfo(*i); } static void source_output_info_callback(struct pa_context *, const struct pa_source_output_info *i, int, void *userdata) { ServerInfoManager *si = (ServerInfoManager*) userdata; if (i) si->updateInfo(*i); } static void sample_info_callback(struct pa_context *, const struct pa_sample_info *i, int, void *userdata) { ServerInfoManager *si = (ServerInfoManager*) userdata; if (i) si->updateInfo(*i); } static void subscribe_callback(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) { ServerInfoManager *si = (ServerInfoManager*) userdata; // fprintf(stderr, "EV: %u %u\n", t, index); switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { case PA_SUBSCRIPTION_EVENT_SINK: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) si->removeSinkInfo(index); else pa_operation_unref(pa_context_get_sink_info_by_index(c, index, sink_info_callback, si)); break; case PA_SUBSCRIPTION_EVENT_SOURCE: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) si->removeSourceInfo(index); else pa_operation_unref(pa_context_get_source_info_by_index(c, index, source_info_callback, si)); break; case PA_SUBSCRIPTION_EVENT_MODULE: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) si->removeModuleInfo(index); else pa_operation_unref(pa_context_get_module_info(c, index, module_info_callback, si)); break; case PA_SUBSCRIPTION_EVENT_CLIENT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) si->removeClientInfo(index); else pa_operation_unref(pa_context_get_client_info(c, index, client_info_callback, si)); break; case PA_SUBSCRIPTION_EVENT_SINK_INPUT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) si->removeSinkInputInfo(index); else pa_operation_unref(pa_context_get_sink_input_info(c, index, sink_input_info_callback, si)); break; case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) si->removeSourceOutputInfo(index); else pa_operation_unref(pa_context_get_source_output_info(c, index, source_output_info_callback, si)); break; case PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE: if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) si->removeSampleInfo(index); else pa_operation_unref(pa_context_get_sample_info_by_index(c, index, sample_info_callback, si)); break; case PA_SUBSCRIPTION_EVENT_SERVER: pa_operation_unref(pa_context_get_server_info(c, server_info_callback, si)); break; default: fprintf(stderr, "OTHER EVENT\n"); break; } } ServerInfoManager::ServerInfoManager(struct pa_context &c) : context(c), statWindow(NULL) { pa_operation_unref(pa_context_get_server_info(&c, server_info_callback, this)); pa_operation_unref(pa_context_get_sink_info_list(&c, sink_info_callback, this)); pa_operation_unref(pa_context_get_source_info_list(&c, source_info_callback, this)); pa_operation_unref(pa_context_get_module_info_list(&c, module_info_callback, this)); pa_operation_unref(pa_context_get_client_info_list(&c, client_info_callback, this)); pa_operation_unref(pa_context_get_sink_input_info_list(&c, sink_input_info_callback, this)); pa_operation_unref(pa_context_get_source_output_info_list(&c, source_output_info_callback, this)); pa_operation_unref(pa_context_get_sample_info_list(&c, sample_info_callback, this)); pa_context_set_subscribe_callback(&c, subscribe_callback, this); pa_operation_unref(pa_context_subscribe(&c, (enum pa_subscription_mask) (PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_MODULE| PA_SUBSCRIPTION_MASK_SINK_INPUT| PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| PA_SUBSCRIPTION_MASK_CLIENT| PA_SUBSCRIPTION_MASK_SAMPLE_CACHE| PA_SUBSCRIPTION_MASK_SERVER), NULL, NULL)); } ServerInfoManager::~ServerInfoManager() { for (std::map::iterator i = sinks.begin(); i != sinks.end(); i++) delete i->second; for (std::map::iterator i = sources.begin(); i != sources.end(); i++) delete i->second; for (std::map::iterator i = clients.begin(); i != clients.end(); i++) delete i->second; for (std::map::iterator i = modules.begin(); i != modules.end(); i++) delete i->second; for (std::map::iterator i = sinkInputs.begin(); i != sinkInputs.end(); i++) delete i->second; for (std::map::iterator i = sourceOutputs.begin(); i != sourceOutputs.end(); i++) delete i->second; for (std::map::iterator i = samples.begin(); i != samples.end(); i++) delete i->second; if (statWindow) delete statWindow; } void ServerInfoManager::updateInfo(const struct pa_sink_info &i) { SinkInfo *si; if ((si = sinks[i.index])) si->update(i); else { SinkInfo *n = new SinkInfo(i); sinks[i.index] = n; mainWindow->updateInfo(*n); } } void ServerInfoManager::updateInfo(const struct pa_source_info &i) { SourceInfo *si; if ((si = sources[i.index])) si->update(i); else { SourceInfo *n = new SourceInfo(i); sources[i.index] = n; mainWindow->updateInfo(*n); } } void ServerInfoManager::updateInfo(const struct pa_client_info &i) { ClientInfo *ci; if ((ci = clients[i.index])) ci->update(i); else { ClientInfo *n = new ClientInfo(i); clients[i.index] = n; mainWindow->updateInfo(*n); } } void ServerInfoManager::updateInfo(const struct pa_module_info &i) { ModuleInfo *si; if ((si = modules[i.index])) si->update(i); else { ModuleInfo *n = new ModuleInfo(i); modules[i.index] = n; mainWindow->updateInfo(*n); } } void ServerInfoManager::updateInfo(const struct pa_sink_input_info &i) { SinkInputInfo *si; if ((si = sinkInputs[i.index])) si->update(i); else { SinkInputInfo *n = new SinkInputInfo(i); sinkInputs[i.index] = n; mainWindow->updateInfo(*n); } } void ServerInfoManager::updateInfo(const struct pa_source_output_info &i) { SourceOutputInfo *si; if ((si = sourceOutputs[i.index])) si->update(i); else { SourceOutputInfo *n = new SourceOutputInfo(i); sourceOutputs[i.index] = n; mainWindow->updateInfo(*n); } } void ServerInfoManager::updateInfo(const struct pa_sample_info &i) { SampleInfo *si; if ((si = samples[i.index])) si->update(i); else { SampleInfo *n = new SampleInfo(i); samples[i.index] = n; mainWindow->updateInfo(*n); } } void ServerInfoManager::showSinkWindow(uint32_t index) { SinkInfo *i; if ((i = sinks[index])) i->showWindow(); } void ServerInfoManager::showSourceWindow(uint32_t index) { SourceInfo *i; if ((i = sources[index])) i->showWindow(); } void ServerInfoManager::showClientWindow(uint32_t index) { ClientInfo *i; if ((i = clients[index])) i->showWindow(); } void ServerInfoManager::showModuleWindow(uint32_t index) { ModuleInfo *i; if ((i = modules[index])) i->showWindow(); } void ServerInfoManager::showSinkInputWindow(uint32_t index) { SinkInputInfo *i; if ((i = sinkInputs[index])) i->showWindow(); } void ServerInfoManager::showSourceOutputWindow(uint32_t index) { SourceOutputInfo *i; if ((i = sourceOutputs[index])) i->showWindow(); } void ServerInfoManager::showSampleWindow(uint32_t index) { SampleInfo *i; if ((i = samples[index])) i->showWindow(); } SourceInfo* ServerInfoManager::getSourceInfo(uint32_t index) { return sources[index]; } SinkInfo* ServerInfoManager::getSinkInfo(uint32_t index) { return sinks[index]; } ClientInfo* ServerInfoManager::getClientInfo(uint32_t index) { return clients[index]; } ModuleInfo* ServerInfoManager::getModuleInfo(uint32_t index) { return modules[index]; } SampleInfo* ServerInfoManager::getSampleInfo(uint32_t index) { return samples[index]; } void ServerInfoManager::removeSinkInfo(uint32_t index) { SinkInfo *i; if ((i = sinks[index])) { sinks.erase(index); mainWindow->removeInfo(*i); delete i; } } void ServerInfoManager::removeSourceInfo(uint32_t index) { SourceInfo *i; if ((i = sources[index])) { sources.erase(index); mainWindow->removeInfo(*i); delete i; } } void ServerInfoManager::removeClientInfo(uint32_t index) { ClientInfo *i; if ((i = clients[index])) { clients.erase(index); mainWindow->removeInfo(*i); delete i; } } void ServerInfoManager::removeModuleInfo(uint32_t index) { ModuleInfo *i; if ((i = modules[index])) { modules.erase(index); mainWindow->removeInfo(*i); delete i; } } void ServerInfoManager::removeSinkInputInfo(uint32_t index) { SinkInputInfo *i; if ((i = sinkInputs[index])) { sinkInputs.erase(index); mainWindow->removeInfo(*i); delete i; } } void ServerInfoManager::removeSourceOutputInfo(uint32_t index) { SourceOutputInfo *i; if ((i = sourceOutputs[index])) { sourceOutputs.erase(index); mainWindow->removeInfo(*i); delete i; } } void ServerInfoManager::removeSampleInfo(uint32_t index) { SampleInfo *i; if ((i = samples[index])) { samples.erase(index); mainWindow->removeInfo(*i); delete i; } } /* FIXME: Handle all channels separately. */ void ServerInfoManager::setSinkVolume(uint32_t index, pa_volume_t volume) { pa_cvolume cvol; pa_cvolume_set(&cvol, sinks[index]->volume.channels, volume); pa_operation_unref(pa_context_set_sink_volume_by_index(&context, index, &cvol, NULL, NULL)); } /* FIXME: Handle all channels separately. */ void ServerInfoManager::setSourceVolume(uint32_t index, pa_volume_t volume) { pa_cvolume cvol; pa_cvolume_set(&cvol, sources[index]->volume.channels, volume); pa_operation_unref(pa_context_set_source_volume_by_index(&context, index, &cvol, NULL, NULL)); } /* FIXME: Handle all channels separately. */ void ServerInfoManager::setSinkInputVolume(uint32_t index, pa_volume_t volume) { pa_cvolume cvol; pa_cvolume_set(&cvol, sinkInputs[index]->volume.channels, volume); pa_operation_unref(pa_context_set_sink_input_volume(&context, index, &cvol, NULL, NULL)); } void ServerInfoManager::showStatWindow() { if (statWindow) statWindow->present(); else { statWindow = StatWindow::create(); statWindow->show(); } } void ServerInfoManager::playSample(uint32_t sample, uint32_t sink) { SinkInfo *sinki = getSinkInfo(sink); SampleInfo *samplei = getSampleInfo(sample); if (!sinki || !samplei) return; pa_operation_unref(pa_context_play_sample(&context, samplei->name.c_str(), sinki->name.c_str(), PA_VOLUME_NORM, NULL, NULL)); } #ifndef PAVUMETER_PATH #define PAVUMETER_PATH "pavumeter" #endif void ServerInfoManager::runVolumeMeter(const Glib::ustring &source) { char t[256]; snprintf(t, sizeof(t), "%s --record %s", PAVUMETER_PATH, source.c_str()); Glib::spawn_command_line_async(t); } bool ServerInfoManager::volumeMeterSupported() { gchar *c; c = g_find_program_in_path(PAVUMETER_PATH); g_free(c); return !!c; } void ServerInfoManager::killClient(uint32_t index) { pa_operation_unref(pa_context_kill_client(&context, index, NULL, NULL)); } void ServerInfoManager::killSourceOutput(uint32_t index) { pa_operation_unref(pa_context_kill_source_output(&context, index, NULL, NULL)); } void ServerInfoManager::killSinkInput(uint32_t index) { pa_operation_unref(pa_context_kill_sink_input(&context, index, NULL, NULL)); }