Commit f68a364f authored by Adrien Béraud's avatar Adrien Béraud
Browse files

Use a dedicated structure to hold PA device infos instead of pa_sink_info and pa_source_info

parent e1f1e0df
......@@ -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<const pa_source_info*>(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_flags_t>(PA_STREAM_ADJUST_LATENCY |
PA_STREAM_AUTO_TIMING_UPDATE);
const pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(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;
}
}
......
......@@ -34,6 +34,7 @@
#include <pulse/pulseaudio.h>
#include <string>
#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();
......
......@@ -3,6 +3,7 @@
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
* Author: Андрей Лухнов <aol.nnov@gmail.com>
* Author: Adrien Beraud <adrien.beraud@gmail.com>
*
* 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 <algorithm> // for std::find
#include <stdexcept>
#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<std::string> 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<PaDeviceInfos>& list, const std::string& name) const
{
std::vector<PaDeviceInfos>::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<pa_source_info>::const_iterator dev_info = std::find_if(sourceList_.begin(), sourceList_.end(), source_info_compare_name(name));
std::vector<PaEndpointInfos>::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<pa_sink_info>::const_iterator dev_info = std::find_if(sinkList_.begin(), sinkList_.end(), sink_info_compare_name(name));
std::vector<PaEndpointInfos>::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<PulseLayer*>(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" : "");
context->sourceList_.push_back(i);
}
void PulseLayer::sink_input_info_callback(pa_context *c UNUSED, const pa_sink_info *info, int eol, void *userdata)
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" : "");
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 *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<PulseLayer*>(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<double>(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);
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<double>(i->latency),
i->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
i->flags & PA_SINK_LATENCY ? "LATENCY " : "",
i->flags & PA_SINK_HARDWARE ? "HARDWARE" : "");
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)
......
......@@ -3,6 +3,7 @@
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
* Author: Андрей Лухнов <aol.nnov@gmail.com>
* Author: Adrien Beraud <adrien.beraud@gmail.com>
*
* 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 <pulse/stream.h>
#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<const PaDeviceInfos, bool>
{
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<std::string> sinkList_;
std::vector<pa_sink_info> sinkList_;
std::vector<PaDeviceInfos> sinkList_;
/**
* Contain the list of capture devices
*/
//std::vector<std::string> sourceList_;
std::vector<pa_source_info> 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<const pa_source_info, bool>
{
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<const pa_sink_info, bool>
{
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;
};
/**
* Returns a pointer to the pa_source_info with the given name in sourceList_, or NULL if not found.
*/
const pa_source_info* getCaptureDevice(const std::string& name) const;
std::vector<PaDeviceInfos> sourceList_;
/**
* Returns a pointer to the pa_sink_info with the given name in sinkList_, or NULL if not found.
* Returns a pointer to the PaEndpointInfos with the given name in sourceList_, or NULL if not found.
*/
const pa_sink_info* getPlaybackDevice(const std::string& name) const;
const PaDeviceInfos* getDeviceInfos(const std::vector<PaDeviceInfos>&, 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 */
......
......@@ -36,7 +36,7 @@
namespace Logger {
bool consoleLog = false;
bool debugMode = true;
bool debugMode = false;
void log(const int level, const char* format, ...)
{
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment