From f68a364ffda271fb247ec57cb1e96690a116cf0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= Date: Mon, 25 Mar 2013 17:59:48 +1100 Subject: [PATCH] Use a dedicated structure to hold PA device infos instead of pa_sink_info and pa_source_info --- daemon/src/audio/pulseaudio/audiostream.cpp | 19 ++-- daemon/src/audio/pulseaudio/audiostream.h | 3 +- daemon/src/audio/pulseaudio/pulselayer.cpp | 100 +++++++++++--------- daemon/src/audio/pulseaudio/pulselayer.h | 65 +++++++------ daemon/src/logger.cpp | 2 +- 5 files changed, 97 insertions(+), 92 deletions(-) diff --git a/daemon/src/audio/pulseaudio/audiostream.cpp b/daemon/src/audio/pulseaudio/audiostream.cpp index 95215e4f1..b3b14c062 100644 --- a/daemon/src/audio/pulseaudio/audiostream.cpp +++ b/daemon/src/audio/pulseaudio/audiostream.cpp @@ -38,14 +38,10 @@ AudioStream::AudioStream(pa_context *c, const char *desc, int type, unsigned samplrate, - const void* infos) + const PaDeviceInfos* infos) : audiostream_(0), mainloop_(m) { - // assume pa_source_info and pa_sink_info are similar - const pa_source_info* const infos_source = static_cast(infos); - // assume infos->name is NULL-terminated - const std::string deviceName(infos_source->name); - const pa_channel_map channel_map = infos_source->channel_map; + const pa_channel_map channel_map = infos->channel_map; pa_sample_spec sample_spec = { PA_SAMPLE_S16LE, // PA_SAMPLE_FLOAT32LE, @@ -53,6 +49,8 @@ AudioStream::AudioStream(pa_context *c, channel_map.channels }; + DEBUG("%s: trying to create stream with device %s (%dHz, %d channels)", desc, infos->name.c_str(), samplrate, channel_map.channels); + assert(pa_sample_spec_valid(&sample_spec)); assert(pa_channel_map_valid(&channel_map)); @@ -71,18 +69,17 @@ AudioStream::AudioStream(pa_context *c, attributes.minreq = (uint32_t) -1; pa_threaded_mainloop_lock(mainloop_); - const pa_stream_flags_t flags = static_cast(PA_STREAM_ADJUST_LATENCY | - PA_STREAM_AUTO_TIMING_UPDATE); + const pa_stream_flags_t flags = static_cast(PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE); if (type == PLAYBACK_STREAM || type == RINGTONE_STREAM) { pa_stream_connect_playback(audiostream_, - deviceName.empty() ? NULL : deviceName.c_str(), + infos->name.empty() ? NULL : infos->name.c_str(), &attributes, flags, NULL, NULL); } else if (type == CAPTURE_STREAM) { pa_stream_connect_record(audiostream_, - deviceName.empty() ? NULL : deviceName.c_str(), + infos->name.empty() ? NULL : infos->name.c_str(), &attributes, flags); } @@ -139,7 +136,7 @@ AudioStream::stream_state_callback(pa_stream* s, void* /*user_data*/) case PA_STREAM_FAILED: default: - ERROR("Sink/Source doesn't exists: %s" , pa_strerror(pa_context_errno(pa_stream_get_context(s)))); + ERROR("Sink/Source doesn't exists: %s %s" , pa_strerror(pa_context_errno(pa_stream_get_context(s))), pa_stream_get_device_name(s)); break; } } diff --git a/daemon/src/audio/pulseaudio/audiostream.h b/daemon/src/audio/pulseaudio/audiostream.h index d34ab49a7..4db4bf195 100644 --- a/daemon/src/audio/pulseaudio/audiostream.h +++ b/daemon/src/audio/pulseaudio/audiostream.h @@ -34,6 +34,7 @@ #include #include #include "noncopyable.h" +#include "pulselayer.h" /** * This data structure contains the different king of audio streams available @@ -58,7 +59,7 @@ class AudioStream { * //@param channel number * //@param device name */ - AudioStream(pa_context *, pa_threaded_mainloop *, const char *, int, unsigned, const void*); + AudioStream(pa_context *, pa_threaded_mainloop *, const char *, int, unsigned, const PaDeviceInfos*); ~AudioStream(); diff --git a/daemon/src/audio/pulseaudio/pulselayer.cpp b/daemon/src/audio/pulseaudio/pulselayer.cpp index 3a6e0f132..86dd20864 100644 --- a/daemon/src/audio/pulseaudio/pulselayer.cpp +++ b/daemon/src/audio/pulseaudio/pulselayer.cpp @@ -3,6 +3,7 @@ * Author: Emmanuel Milou * Author: Alexandre Savard * Author: Андрей Лухнов + * Author: Adrien Beraud * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +33,7 @@ #include // for std::find #include + #include "audiostream.h" #include "pulselayer.h" #include "audio/samplerateconverter.h" @@ -193,7 +195,7 @@ void PulseLayer::updateSourceList() bool PulseLayer::inSinkList(const std::string &deviceName) { - const bool found = std::find_if(sinkList_.begin(), sinkList_.end(), sink_info_compare_name(deviceName)) != sinkList_.end(); + const bool found = std::find_if(sinkList_.begin(), sinkList_.end(), PaDeviceInfos::nameComparator(deviceName)) != sinkList_.end(); DEBUG("seeking for %s in sinks. %s found", deviceName.c_str(), found ? "" : "NOT"); return found; @@ -201,7 +203,7 @@ bool PulseLayer::inSinkList(const std::string &deviceName) bool PulseLayer::inSourceList(const std::string &deviceName) { - const bool found = std::find_if(sourceList_.begin(), sourceList_.end(), source_info_compare_name(deviceName)) != sourceList_.end(); + const bool found = std::find_if(sourceList_.begin(), sourceList_.end(), PaDeviceInfos::nameComparator(deviceName)) != sourceList_.end(); DEBUG("seeking for %s in sources. %s found", deviceName.c_str(), found ? "" : "NOT"); return found; @@ -227,29 +229,37 @@ std::vector PulseLayer::getPlaybackDeviceList() const int PulseLayer::getAudioDeviceIndex(const std::string& name) const { - int index = std::distance(sourceList_.begin(), std::find_if(sourceList_.begin(), sourceList_.end(), source_info_compare_name(name))); + int index = std::distance(sourceList_.begin(), std::find_if(sourceList_.begin(), sourceList_.end(), PaDeviceInfos::nameComparator(name))); if (index == std::distance(sourceList_.begin(), sourceList_.end())) { - index = std::distance(sinkList_.begin(), std::find_if(sinkList_.begin(), sinkList_.end(), sink_info_compare_name(name))); + index = std::distance(sinkList_.begin(), std::find_if(sinkList_.begin(), sinkList_.end(), PaDeviceInfos::nameComparator(name))); } return index; } -const pa_source_info* PulseLayer::getCaptureDevice(const std::string& name) const +const PaDeviceInfos* PulseLayer::getDeviceInfos(const std::vector& list, const std::string& name) const { - std::vector::const_iterator dev_info = std::find_if(sourceList_.begin(), sourceList_.end(), source_info_compare_name(name)); + std::vector::const_iterator dev_info = std::find_if(list.begin(), list.end(), PaDeviceInfos::nameComparator(name)); + if(dev_info == list.end()) return NULL; + return &(*dev_info); +} +/* +const PaDeviceInfos* PulseLayer::getCaptureDevice(const std::string& name) const +{ + std::vector::const_iterator dev_info = std::find_if(sourceList_.begin(), sourceList_.end(), PaEndpointInfos::nameComparator(name)); if(dev_info == sourceList_.end()) return NULL; return &(*dev_info); } -const pa_sink_info* PulseLayer::getPlaybackDevice(const std::string& name) const +const PaDeviceInfos* PulseLayer::getPlaybackDevice(const std::string& name) const { - std::vector::const_iterator dev_info = std::find_if(sinkList_.begin(), sinkList_.end(), sink_info_compare_name(name)); + std::vector::const_iterator dev_info = std::find_if(sinkList_.begin(), sinkList_.end(), PaEndpointInfos::nameComparator(name)); if(dev_info == sinkList_.end()) return NULL; return &(*dev_info); -} +}*/ std::string PulseLayer::getAudioDeviceName(int index, PCMType type) const { + switch (type) { case SFL_PCM_PLAYBACK: case SFL_PCM_RINGTONE: @@ -282,17 +292,17 @@ void PulseLayer::createStreams(pa_context* c) DEBUG("Devices:\n playback: %s\n record: %s\n ringtone: %s", playbackDevice.c_str(), captureDevice.c_str(), ringtoneDevice.c_str()); - playback_ = new AudioStream(c, mainloop_, "SFLphone playback", PLAYBACK_STREAM, sampleRate_, getPlaybackDevice(playbackDevice)); + playback_ = new AudioStream(c, mainloop_, "SFLphone playback", PLAYBACK_STREAM, sampleRate_, getDeviceInfos(sinkList_, playbackDevice)); pa_stream_set_write_callback(playback_->pulseStream(), playback_callback, this); pa_stream_set_moved_callback(playback_->pulseStream(), stream_moved_callback, this); - record_ = new AudioStream(c, mainloop_, "SFLphone capture", CAPTURE_STREAM, sampleRate_, getCaptureDevice(captureDevice)); + record_ = new AudioStream(c, mainloop_, "SFLphone capture", CAPTURE_STREAM, sampleRate_, getDeviceInfos(sourceList_, captureDevice)); pa_stream_set_read_callback(record_->pulseStream() , capture_callback, this); pa_stream_set_moved_callback(record_->pulseStream(), stream_moved_callback, this); - ringtone_ = new AudioStream(c, mainloop_, "SFLphone ringtone", RINGTONE_STREAM, sampleRate_, getPlaybackDevice(ringtoneDevice)); + ringtone_ = new AudioStream(c, mainloop_, "SFLphone ringtone", RINGTONE_STREAM, sampleRate_, getDeviceInfos(sinkList_, ringtoneDevice)); pa_stream_set_write_callback(ringtone_->pulseStream(), ringtone_callback, this); pa_stream_set_moved_callback(ringtone_->pulseStream(), stream_moved_callback, this); @@ -596,7 +606,7 @@ PulseLayer::context_changed_callback(pa_context* c, } -void PulseLayer::source_input_info_callback(pa_context *c UNUSED, const pa_source_info *info, int eol, void *userdata) +void PulseLayer::source_input_info_callback(pa_context *c UNUSED, const pa_source_info *i, int eol, void *userdata) { char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; PulseLayer *context = static_cast(userdata); @@ -606,8 +616,6 @@ void PulseLayer::source_input_info_callback(pa_context *c UNUSED, const pa_sourc return; } - const pa_source_info i = *info; - DEBUG("Source %u\n" " Name: %s\n" " Driver: %s\n" @@ -619,24 +627,25 @@ void PulseLayer::source_input_info_callback(pa_context *c UNUSED, const pa_sourc " Monitor if Sink: %u\n" " Latency: %0.0f usec\n" " Flags: %s%s%s\n", - i.index, - i.name, - i.driver, - i.description, - pa_sample_spec_snprint(s, sizeof(s), &i.sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i.channel_map), - i.owner_module, - i.mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i.volume), - i.monitor_of_sink, - (double) i.latency, - i.flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", - i.flags & PA_SOURCE_LATENCY ? "LATENCY " : "", - i.flags & PA_SOURCE_HARDWARE ? "HARDWARE" : ""); + i->index, + i->name, + i->driver, + i->description, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + i->owner_module, + i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + i->monitor_of_sink, + (double) i->latency, + i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", + i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "", + i->flags & PA_SOURCE_HARDWARE ? "HARDWARE" : ""); - context->sourceList_.push_back(i); + PaDeviceInfos ep_infos(i->index, i->name, i->sample_spec, i->channel_map); + context->sourceList_.push_back(ep_infos); } -void PulseLayer::sink_input_info_callback(pa_context *c UNUSED, const pa_sink_info *info, int eol, void *userdata) +void PulseLayer::sink_input_info_callback(pa_context *c UNUSED, const pa_sink_info *i, int eol, void *userdata) { char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; PulseLayer *context = static_cast(userdata); @@ -646,8 +655,6 @@ void PulseLayer::sink_input_info_callback(pa_context *c UNUSED, const pa_sink_in return; } - const pa_sink_info i = *info; - DEBUG("Sink %u\n" " Name: %s\n" " Driver: %s\n" @@ -659,21 +666,22 @@ void PulseLayer::sink_input_info_callback(pa_context *c UNUSED, const pa_sink_in " Monitor Source: %u\n" " Latency: %0.0f usec\n" " Flags: %s%s%s\n", - i.index, - i.name, - i.driver, - i.description, - pa_sample_spec_snprint(s, sizeof(s), &i.sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i.channel_map), - i.owner_module, - i.mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i.volume), - i.monitor_source, - static_cast(i.latency), - i.flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", - i.flags & PA_SINK_LATENCY ? "LATENCY " : "", - i.flags & PA_SINK_HARDWARE ? "HARDWARE" : ""); + i->index, + i->name, + i->driver, + i->description, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + i->owner_module, + i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + i->monitor_source, + static_cast(i->latency), + i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", + i->flags & PA_SINK_LATENCY ? "LATENCY " : "", + i->flags & PA_SINK_HARDWARE ? "HARDWARE" : ""); - context->sinkList_.push_back(i); + PaDeviceInfos ep_infos(i->index, i->name, i->sample_spec, i->channel_map); + context->sinkList_.push_back(ep_infos); } void PulseLayer::updatePreference(AudioPreference &preference, int index, PCMType type) diff --git a/daemon/src/audio/pulseaudio/pulselayer.h b/daemon/src/audio/pulseaudio/pulselayer.h index 38e63de62..cba5d1d2e 100644 --- a/daemon/src/audio/pulseaudio/pulselayer.h +++ b/daemon/src/audio/pulseaudio/pulselayer.h @@ -3,6 +3,7 @@ * Author: Emmanuel Milou * Author: Alexandre Savard * Author: Андрей Лухнов + * Author: Adrien Beraud * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,10 +40,37 @@ #include #include "audio/audiolayer.h" #include "noncopyable.h" +#include "logger.h" class AudioPreference; class AudioStream; +/** + * Convenience structure to hold PulseAudio device propreties such as supported channel number etc. + */ +typedef struct PaDeviceInfos { + unsigned index; // TODO: should use uint32_t (with C++11) since it's the PA type for indexes + std::string name; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + PaDeviceInfos(unsigned idx, const char* ep_name, pa_sample_spec samp_spec, pa_channel_map chan_map) + : index(idx), name(ep_name), sample_spec(samp_spec), channel_map(chan_map) + {} + + /** + * Unary function to search for a device by name in a list using std functions. + */ + struct nameComparator : public std::unary_function + { + explicit nameComparator(const std::string &baseline) : baseline(baseline) {} + bool operator() (const PaDeviceInfos &arg) { + return arg.name == baseline; + } + const std::string &baseline; + }; +} PaDeviceInfos; + class PulseLayer : public AudioLayer { public: PulseLayer(AudioPreference &pref); @@ -123,50 +151,21 @@ class PulseLayer : public AudioLayer { /** * Contain the list of playback devices */ - //std::vector sinkList_; - std::vector sinkList_; + std::vector sinkList_; /** * Contain the list of capture devices */ - //std::vector sourceList_; - std::vector sourceList_; - - /** Helper unary_function to search for a device name in a list of pa_source_info */ - struct source_info_compare_name : public std::unary_function - { - explicit source_info_compare_name(const std::string &baseline) : baseline(baseline) {} - bool operator() (const pa_source_info &arg) { - return std::strcmp(arg.name, baseline.c_str()) != 0; - } - std::string baseline; - }; - - /** Helper unary_function to search for a device name in a list of pa_sink_info */ - struct sink_info_compare_name : public std::unary_function - { - explicit sink_info_compare_name(const std::string &baseline) : baseline(baseline) {} - bool operator() (const pa_sink_info &arg) { - return std::strcmp(arg.name, baseline.c_str()) != 0; - } - std::string baseline; - }; + std::vector sourceList_; /** - * Returns a pointer to the pa_source_info with the given name in sourceList_, or NULL if not found. + * Returns a pointer to the PaEndpointInfos with the given name in sourceList_, or NULL if not found. */ - const pa_source_info* getCaptureDevice(const std::string& name) const; - - /** - * Returns a pointer to the pa_sink_info with the given name in sinkList_, or NULL if not found. - */ - const pa_sink_info* getPlaybackDevice(const std::string& name) const; + const PaDeviceInfos* getDeviceInfos(const std::vector&, const std::string& name) const; /* * Buffers used to avoid doing malloc/free in the audio thread */ - //SFLAudioSample *mic_buffer_; - //size_t mic_buf_size_; AudioBuffer mic_buffer_; /** PulseAudio context and asynchronous loop */ diff --git a/daemon/src/logger.cpp b/daemon/src/logger.cpp index 125bb87f6..0ec7d6534 100644 --- a/daemon/src/logger.cpp +++ b/daemon/src/logger.cpp @@ -36,7 +36,7 @@ namespace Logger { bool consoleLog = false; -bool debugMode = true; +bool debugMode = false; void log(const int level, const char* format, ...) {