Commit f331943b authored by Alexandre Savard's avatar Alexandre Savard

#5607: Use same api for ALSA and PULSEAUDIO to manage audio device list

parent 14cf04ac
......@@ -78,7 +78,7 @@ AlsaLayer::AlsaLayer()
, ringtoneHandle_(NULL)
, captureHandle_(NULL)
, audioPlugin_(audioPref.getPlugin())
, IDSoundCards_()
// , IDSoundCards_()
, is_playback_prepared_(false)
, is_capture_prepared_(false)
, is_playback_running_(false)
......@@ -160,7 +160,7 @@ AlsaLayer::startStream()
if (not is_playback_open_)
Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE);
if (getIndexOut() != getIndexRing())
if (getIndexPlayback() != getIndexRingtone())
if (!openDevice(&ringtoneHandle_, pcmr, SND_PCM_STREAM_PLAYBACK))
Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE);
}
......@@ -432,7 +432,23 @@ AlsaLayer::buildDeviceTopo(const std::string &plugin, int card)
}
std::vector<std::string>
AlsaLayer::getSoundCardsInfo(int stream)
AlsaLayer::getAudioDeviceList(AudioStreamDirection dir) const
{
std::vector<HwIDPair> deviceMap;
std::vector<std::string> audioDeviceList;
deviceMap = getAudioDeviceIndexMap(dir);
for(std::vector<HwIDPair>::const_iterator iter = deviceMap.begin(); iter != deviceMap.end(); iter++) {
audioDeviceList.push_back(iter->second);
}
return audioDeviceList;
}
std::vector<HwIDPair>
AlsaLayer::getAudioDeviceIndexMap(AudioStreamDirection dir) const
{
snd_ctl_t* handle;
snd_ctl_card_info_t *info;
......@@ -442,10 +458,10 @@ AlsaLayer::getSoundCardsInfo(int stream)
int numCard = -1 ;
std::vector<std::string> cards_id;
std::vector<HwIDPair> audioDevice;
if (snd_card_next(&numCard) < 0 || numCard < 0)
return cards_id;
return audioDevice;
do {
std::stringstream ss;
......@@ -455,10 +471,11 @@ AlsaLayer::getSoundCardsInfo(int stream)
if (snd_ctl_open(&handle, name.c_str(), 0) == 0) {
if (snd_ctl_card_info(handle, info) == 0) {
snd_pcm_info_set_device(pcminfo , 0);
snd_pcm_info_set_stream(pcminfo, (stream == SFL_PCM_CAPTURE) ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK);
snd_pcm_info_set_stream(pcminfo, (dir == AUDIO_STREAM_CAPTURE) ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK);
if (snd_ctl_pcm_info(handle ,pcminfo) < 0)
if (snd_ctl_pcm_info(handle ,pcminfo) < 0) {
DEBUG(" Cannot get info");
}
else {
DEBUG("card %i : %s [%s]",
numCard,
......@@ -467,9 +484,9 @@ AlsaLayer::getSoundCardsInfo(int stream)
std::string description = snd_ctl_card_info_get_name(info);
description.append(" - ");
description.append(snd_pcm_info_get_name(pcminfo));
cards_id.push_back(description);
// The number of the sound card is associated with a string description
IDSoundCards_.push_back(HwIDPair(numCard , description));
audioDevice.push_back(HwIDPair(numCard , description));
}
}
......@@ -478,7 +495,7 @@ AlsaLayer::getSoundCardsInfo(int stream)
} while (snd_card_next(&numCard) >= 0 && numCard >= 0);
return cards_id;
return audioDevice;
}
......@@ -503,9 +520,17 @@ AlsaLayer::soundCardIndexExists(int card, int stream)
}
int
AlsaLayer::soundCardGetIndex(const std::string &description)
AlsaLayer::getAudioDeviceIndex(const std::string &description) const
{
for (std::vector<HwIDPair>::const_iterator iter = IDSoundCards_.begin(); iter != IDSoundCards_.end(); ++iter)
std::vector<HwIDPair> audioDeviceIndexMap;
std::vector<HwIDPair> captureDevice = getAudioDeviceIndexMap(AUDIO_STREAM_CAPTURE);
std::vector<HwIDPair> playbackDevice = getAudioDeviceIndexMap(AUDIO_STREAM_PLAYBACK);
audioDeviceIndexMap.insert(audioDeviceIndexMap.end(), captureDevice.begin(), captureDevice.end());
audioDeviceIndexMap.insert(audioDeviceIndexMap.end(), playbackDevice.begin(), playbackDevice.end());
for (std::vector<HwIDPair>::const_iterator iter = audioDeviceIndexMap.begin(); iter != audioDeviceIndexMap.end(); ++iter)
if (iter->second == description)
return iter->first;
......
......@@ -65,14 +65,14 @@ class AlsaLayer : public AudioLayer {
* The playback starts accordingly to its threshold
* ALSA Library API
*/
void startStream();
virtual void startStream();
/**
* Stop the playback and capture streams.
* Drops the pending frames and put the capture and playback handles to PREPARED state
* ALSA Library API
*/
void stopStream();
virtual void stopStream();
/**
* Concatenate two strings. Used to build a valid pcm device name.
......@@ -90,7 +90,12 @@ class AlsaLayer : public AudioLayer {
* SFL_PCM_BOTH
* @return std::vector<std::string> The vector containing the string description of the card
*/
std::vector<std::string> getSoundCardsInfo(int stream);
virtual std::vector<std::string> getAudioDeviceList(AudioStreamDirection dir) const;
/**
* Returns a map of audio device hardware description and index
*/
std::vector<HwIDPair> getAudioDeviceIndexMap(AudioStreamDirection dir) const;
/**
* Check if the given index corresponds to an existing sound card and supports the specified streaming mode
......@@ -109,7 +114,7 @@ class AlsaLayer : public AudioLayer {
* @param description The string description
* @return int Its index
*/
int soundCardGetIndex(const std::string &description);
int getAudioDeviceIndex(const std::string &description) const;
void playback(int maxSamples);
void capture();
......@@ -121,7 +126,7 @@ class AlsaLayer : public AudioLayer {
* @return int The index of the card used for capture
* 0 for the first available card on the system, 1 ...
*/
int getIndexIn() const {
int getIndexCapture() const {
return indexIn_;
}
......@@ -130,7 +135,7 @@ class AlsaLayer : public AudioLayer {
* @return int The index of the card used for playback
* 0 for the first available card on the system, 1 ...
*/
int getIndexOut() const {
int getIndexPlayback() const {
return indexOut_;
}
......@@ -139,7 +144,7 @@ class AlsaLayer : public AudioLayer {
* @return int The index of the card used for ringtone
* 0 for the first available card on the system, 1 ...
*/
int getIndexRing() const {
int getIndexRingtone() const {
return indexRing_;
}
......@@ -227,7 +232,7 @@ class AlsaLayer : public AudioLayer {
std::string audioPlugin_;
/** Vector to manage all soundcard index - description association of the system */
std::vector<HwIDPair> IDSoundCards_;
// std::vector<HwIDPair> IDSoundCards_;
bool is_playback_prepared_;
bool is_capture_prepared_;
......
......@@ -54,6 +54,8 @@ namespace ost {
class Time;
}
enum AudioStreamDirection { AUDIO_STREAM_CAPTURE, AUDIO_STREAM_PLAYBACK };
class AudioLayer {
private:
NON_COPYABLE(AudioLayer);
......@@ -62,6 +64,8 @@ class AudioLayer {
AudioLayer();
virtual ~AudioLayer();
virtual std::vector<std::string> getAudioDeviceList(AudioStreamDirection dir) const = 0;
/**
* Start the capture stream and prepare the playback stream.
* The playback starts accordingly to its threshold
......@@ -76,6 +80,9 @@ class AudioLayer {
*/
virtual void stopStream() = 0;
/**
* Determine wether or not the audio layer is active (i.e. stream opened)
*/
bool isStarted() const {
return isStarted_;
}
......@@ -88,11 +95,18 @@ class AudioLayer {
*/
void putUrgent(void* buffer, int toCopy);
/**
* Flush main buffer
*/
void flushMain();
/**
* Flush urgent buffer
*/
void flushUrgent();
/**
* Get the sample rate of the audio layer
* @return unsigned int The sample rate
......@@ -109,6 +123,9 @@ class AudioLayer {
return &mutex_;
}
/**
* Emit an audio notification on incoming calls
*/
void notifyincomingCall();
protected:
......
......@@ -31,7 +31,7 @@
#include <audiostream.h>
#include "pulselayer.h"
AudioStream::AudioStream(pa_context *c, pa_threaded_mainloop *m, const char *desc, int type, int smplrate, std::string *deviceName)
AudioStream::AudioStream(pa_context *c, pa_threaded_mainloop *m, const char *desc, int type, int smplrate, std::string& deviceName)
: audiostream_(0), mainloop_(m)
{
static const pa_channel_map channel_map = {
......@@ -62,14 +62,14 @@ AudioStream::AudioStream(pa_context *c, pa_threaded_mainloop *m, const char *des
attributes.fragsize = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec);
attributes.minreq = (uint32_t) -1;
const char *name = deviceName ? deviceName->c_str() : NULL;
pa_threaded_mainloop_lock(mainloop_);
if (type == PLAYBACK_STREAM || type == RINGTONE_STREAM)
pa_stream_connect_playback(audiostream_, name, &attributes, (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL);
pa_stream_connect_playback(audiostream_, deviceName == "" ? NULL : deviceName.c_str(), &attributes,
(pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL);
else if (type == CAPTURE_STREAM)
pa_stream_connect_record(audiostream_, name, &attributes, (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE));
pa_stream_connect_record(audiostream_, deviceName == "" ? NULL : deviceName.c_str(), &attributes,
(pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY|PA_STREAM_AUTO_TIMING_UPDATE));
pa_threaded_mainloop_unlock(mainloop_);
......
......@@ -55,7 +55,7 @@ class AudioStream {
* @param audio sampling rate
* @param device name
*/
AudioStream(pa_context *, pa_threaded_mainloop *, const char *, int, int, std::string *);
AudioStream(pa_context *, pa_threaded_mainloop *, const char *, int, int, std::string&);
~AudioStream();
......
......@@ -65,7 +65,6 @@ void stream_moved_callback(pa_stream *s, void *userdata UNUSED)
} // end anonymous namespace
PulseLayer::PulseLayer()
: playback_(0)
, record_(0)
......@@ -148,6 +147,7 @@ void PulseLayer::context_state_callback(pa_context* c, void* user_data)
PA_SUBSCRIPTION_MASK_SOURCE), NULL, pulse);
pa_context_set_subscribe_callback(c, context_changed_callback, pulse);
pulse->updateSinkList();
pulse->updateSourceList();
break;
case PA_CONTEXT_TERMINATED:
......@@ -187,30 +187,40 @@ bool PulseLayer::inSourceList(const std::string &deviceName) const
return std::find(sourceList_.begin(), sourceList_.end(), deviceName) != sourceList_.end();
}
std::vector<std::string> PulseLayer::getAudioDeviceList(AudioStreamDirection dir) const
{
if(AUDIO_STREAM_CAPTURE == dir) {
return sinkList_;
}
if(AUDIO_STREAM_PLAYBACK) {
return sourceList_;
}
}
void PulseLayer::createStreams(pa_context* c)
{
std::string playbackDevice(audioPref.getDevicePlayback());
std::string recordDevice(audioPref.getDeviceRecord());
std::string captureDevice(audioPref.getDeviceRecord());
std::string ringtoneDevice(audioPref.getDeviceRingtone());
std::string defaultDevice = "";
DEBUG("PulseAudio: Devices: playback %s , record %s , ringtone %s",
playbackDevice.c_str(), recordDevice.c_str(), ringtoneDevice.c_str());
DEBUG("PulseAudio: 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, audioSampleRate_,
inSinkList(playbackDevice) ? &playbackDevice : NULL);
inSourceList(playbackDevice) ? playbackDevice : defaultDevice);
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, audioSampleRate_,
inSourceList(recordDevice) ? &recordDevice : NULL);
inSinkList(captureDevice) ? captureDevice : defaultDevice);
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, audioSampleRate_,
inSourceList(ringtoneDevice) ? &ringtoneDevice : NULL);
inSourceList(ringtoneDevice) ? ringtoneDevice : defaultDevice);
pa_stream_set_write_callback(ringtone_->pulseStream(), ringtone_callback, this);
pa_stream_set_moved_callback(ringtone_->pulseStream(), stream_moved_callback, this);
......@@ -512,7 +522,7 @@ void PulseLayer::source_input_info_callback(pa_context *c UNUSED, const pa_sourc
{
char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
if (!eol)
if (eol)
return;
DEBUG("Sink %u\n"
......
......@@ -62,9 +62,11 @@ class PulseLayer : public AudioLayer {
bool inSourceList(const std::string &deviceName) const;
void startStream();
virtual std::vector<std::string> getAudioDeviceList(AudioStreamDirection dir) const;
void stopStream();
virtual void startStream();
virtual void stopStream();
private:
static void context_state_callback(pa_context* c, void* user_data);
......@@ -106,8 +108,15 @@ class PulseLayer : public AudioLayer {
*/
AudioStream* ringtone_;
std::list<std::string> sinkList_;
std::list<std::string> sourceList_;
/**
* Contain the list of playback devices
*/
std::vector<std::string> sinkList_;
/**
* Contain the list of capture devices
*/
std::vector<std::string> sourceList_;
/*
* Buffers used to avoid doing malloc/free in the audio thread
......
......@@ -1978,8 +1978,7 @@ std::vector<std::string> ManagerImpl::getAudioOutputDeviceList()
AlsaLayer *alsalayer = dynamic_cast<AlsaLayer*>(audiodriver_);
if (alsalayer)
devices = alsalayer->getSoundCardsInfo(SFL_PCM_PLAYBACK);
devices = alsalayer->getAudioDeviceList(AUDIO_STREAM_PLAYBACK);
audioLayerMutexUnlock();
return devices;
......@@ -1998,7 +1997,7 @@ std::vector<std::string> ManagerImpl::getAudioInputDeviceList()
AlsaLayer *alsalayer = dynamic_cast<AlsaLayer *>(audiodriver_);
if (alsalayer)
devices = alsalayer->getSoundCardsInfo(SFL_PCM_CAPTURE);
devices = alsalayer->getAudioDeviceList(AUDIO_STREAM_CAPTURE);
audioLayerMutexUnlock();
......@@ -2018,11 +2017,11 @@ std::vector<std::string> ManagerImpl::getCurrentAudioDevicesIndex()
if (alsa) {
std::stringstream ssi, sso, ssr;
sso << alsa->getIndexOut();
sso << alsa->getIndexPlayback();
v.push_back(sso.str());
ssi << alsa->getIndexIn();
ssi << alsa->getIndexCapture();
v.push_back(ssi.str());
ssr << alsa->getIndexRing();
ssr << alsa->getIndexRingtone();
v.push_back(ssr.str());
}
......@@ -2236,7 +2235,7 @@ int ManagerImpl::getAudioDeviceIndex(const std::string &name)
AlsaLayer *alsalayer = dynamic_cast<AlsaLayer *>(audiodriver_);
if (alsalayer)
soundCardIndex = alsalayer -> soundCardGetIndex(name);
soundCardIndex = alsalayer -> getAudioDeviceIndex(name);
audioLayerMutexUnlock();
......
......@@ -152,32 +152,37 @@ preferences_dialog_fill_ringtone_audio_device_list()
void
select_active_output_audio_device()
{
if (must_show_alsa_conf()) {
// Select active output device on server
gchar **devices = dbus_get_current_audio_devices_index();
int currentDeviceIndex = atoi(devices[0]);
DEBUG("audio device index for output = %d", currentDeviceIndex);
GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(output));
gboolean show_alsa = must_show_alsa_conf();
// Find the currently set output device
GtkTreeIter iter;
gtk_tree_model_get_iter_first(model, &iter);
if(!show_alsa)
return;
do {
int deviceIndex;
gtk_tree_model_get(model, &iter, 1, &deviceIndex, -1);
// Select active output device on server
gchar **devices = dbus_get_current_audio_devices_index();
if (deviceIndex == currentDeviceIndex) {
// Set current iteration the active one
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(output), &iter);
return;
}
} while (gtk_tree_model_iter_next(model, &iter));
int currentDeviceIndex = atoi(devices[0]);
DEBUG("audio device index for output = %d", currentDeviceIndex);
GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(output));
// No index was found, select first one
WARN("Warning : No active output device found");
gtk_combo_box_set_active(GTK_COMBO_BOX(output), 0);
}
// Find the currently set output device
GtkTreeIter iter;
gtk_tree_model_get_iter_first(model, &iter);
do {
int deviceIndex;
gtk_tree_model_get(model, &iter, 1, &deviceIndex, -1);
if (deviceIndex == currentDeviceIndex) {
// Set current iteration the active one
gtk_combo_box_set_active_iter(GTK_COMBO_BOX(output), &iter);
return;
}
} while (gtk_tree_model_iter_next(model, &iter));
// No index was found, select first one
WARN("Warning : No active output device found");
gtk_combo_box_set_active(GTK_COMBO_BOX(output), 0);
}
......
Markdown is supported
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