mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-07 22:02:12 +08:00
Use a dedicated structure to hold PA device infos instead of pa_sink_info and pa_source_info
This commit is contained in:
@ -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<pa_source_info>::const_iterator dev_info = std::find_if(sourceList_.begin(), sourceList_.end(), source_info_compare_name(name));
|
||||
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<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" : "");
|
||||
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<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" : "");
|
||||
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);
|
||||
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;
|
||||
};
|
||||
std::vector<PaDeviceInfos> 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<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, ...)
|
||||
{
|
||||
|
Reference in New Issue
Block a user