Commit 6fedd707 authored by Rafaël Carré's avatar Rafaël Carré
Browse files

* #6629: Always restart audio driver when changing parameters (ALSA only)

parent b4558a88
......@@ -104,12 +104,20 @@ AlsaLayer::~AlsaLayer (void)
closePlaybackStream();
}
void AlsaLayer::setPlugin(const std::string &plugin)
bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stream_t stream)
{
audioPlugin_ = plugin;
delete audioThread_;
audioThread_ = NULL;
// FIXME : restart audio thread
int err = snd_pcm_open(pcm, dev.c_str(),stream, 0);
if (err < 0) {
_error("Alsa: couldn't open device %s : %s", dev.c_str(), snd_strerror(err));
return false;
}
if (!alsa_set_params(*pcm)) {
snd_pcm_close(*pcm);
return false;
}
return true;
}
void
......@@ -125,13 +133,13 @@ AlsaLayer::startStream (void)
std::string pcmc;
if (audioPlugin_ == PCM_DMIX_DSNOOP) {
pcmp = buildDeviceTopo (PCM_DMIX, indexOut_, 0);
pcmr = buildDeviceTopo (PCM_DMIX, indexRing_, 0);
pcmc = buildDeviceTopo (PCM_DSNOOP, indexIn_, 0);
pcmp = buildDeviceTopo (PCM_DMIX, indexOut_);
pcmr = buildDeviceTopo (PCM_DMIX, indexRing_);
pcmc = buildDeviceTopo (PCM_DSNOOP, indexIn_);
} else {
pcmp = buildDeviceTopo (audioPlugin_, indexOut_, 0);
pcmr = buildDeviceTopo (audioPlugin_, indexRing_, 0);
pcmc = buildDeviceTopo (audioPlugin_, indexIn_, 0);
pcmp = buildDeviceTopo (audioPlugin_, indexOut_);
pcmr = buildDeviceTopo (audioPlugin_, indexRing_);
pcmc = buildDeviceTopo (audioPlugin_, indexIn_);
}
_debug ("pcmp: %s, index %d", pcmp.c_str(), indexOut_);
......@@ -139,54 +147,22 @@ AlsaLayer::startStream (void)
_debug ("pcmc: %s, index %d", pcmc.c_str(), indexIn_);
if (not is_capture_open_) {
_debug ("Audio: Open capture device");
if (snd_pcm_open (&captureHandle_, pcmc.c_str(), SND_PCM_STREAM_CAPTURE, 0) < 0) {
_warn ("Audio: Error: Opening capture device %s", pcmc.c_str());
is_capture_open_ = openDevice(&captureHandle_, pcmc, SND_PCM_STREAM_CAPTURE);
if (not is_capture_open_) {
Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_CAPTURE_DEVICE);
is_capture_open_ = false;
}
if (!alsa_set_params (captureHandle_, 0)) {
_warn ("Audio: Error: Capture failed");
snd_pcm_close (captureHandle_);
is_capture_open_ = false;
}
is_capture_open_ = true;
}
}
if (not is_playback_open_) {
_debug ("Audio: Open playback device (and ringtone)");
int err;
if ((err = snd_pcm_open (&playbackHandle_, pcmp.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
_warn ("Audio: Error while opening playback device %s", pcmp.c_str());
is_playback_open_ = openDevice(&playbackHandle_, pcmp, SND_PCM_STREAM_PLAYBACK);
if (not is_playback_open_)
Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE);
is_playback_open_ = false;
}
if (!alsa_set_params (playbackHandle_, 1)) {
_warn ("Audio: Error: Playback failed");
snd_pcm_close (playbackHandle_);
is_playback_open_ = false;
}
if (getIndexOut() != getIndexRing()) {
if ((err = snd_pcm_open (&ringtoneHandle_, pcmr.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0)
_warn ("Audio: Error: Opening ringtone device %s", pcmr.c_str());
if (!alsa_set_params (ringtoneHandle_, 1)) {
_warn ("Audio: Error: Ringtone failed");
snd_pcm_close (ringtoneHandle_);
}
}
is_playback_open_ = true;
if (getIndexOut() != getIndexRing())
if (!openDevice(&ringtoneHandle_, pcmr, SND_PCM_STREAM_PLAYBACK))
Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE);
}
prepareCaptureStream ();
preparePlaybackStream ();
......@@ -197,13 +173,8 @@ AlsaLayer::startStream (void)
flushUrgent();
if (audioThread_ == NULL) {
try {
_debug ("Audio: Start Audio Thread");
audioThread_ = new AlsaThread (this);
audioThread_->start();
} catch (...) {
_debug ("Fail to start audio thread");
}
audioThread_ = new AlsaThread (this);
audioThread_->start();
}
isStarted_ = true;
......@@ -250,32 +221,6 @@ void AlsaLayer::stopCaptureStream (void)
}
}
void AlsaLayer::setIndexRing(int index)
{
indexRing_ = index;
delete audioThread_;
audioThread_ = NULL;
}
void AlsaLayer::setIndexOut(int index)
{
indexOut_ = index;
if (is_playback_open_)
closePlaybackStream ();
delete audioThread_;
audioThread_ = NULL;
}
void AlsaLayer::setIndexIn(int index)
{
indexIn_ = index;
if (is_capture_open_)
closeCaptureStream ();
delete audioThread_;
audioThread_ = NULL;
}
void AlsaLayer::closeCaptureStream (void)
{
if (is_capture_prepared_ and is_capture_running_)
......@@ -389,7 +334,7 @@ void AlsaLayer::preparePlaybackStream (void)
}
}
bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle, int type)
bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle)
{
snd_pcm_hw_params_t *hwparams = NULL;
snd_pcm_sw_params_t *swparams = NULL;
......@@ -428,13 +373,13 @@ bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle, int type)
unsigned int exact_ivalue = audioSampleRate_;
if ((err = snd_pcm_hw_params_set_rate_near (pcm_handle, hwparams, &exact_ivalue, &dir) < 0)) {
_debug ("Audio: Error: Cannot set sample rate (%s)", snd_strerror (err));
_error("Alsa: Cannot set sample rate (%s)", snd_strerror (err));
return false;
} else
_debug ("Audio: Set audio rate to %d", audioSampleRate_);
_debug ("Alsa: Set audio rate to %d", audioSampleRate_);
if (dir != 0) {
_debug ("Audio: Error: (%i) The chosen rate %d Hz is not supported by your hardware.Using %d Hz instead. ", type , audioSampleRate_, exact_ivalue);
_error("Alsa: The chosen rate %d Hz is not supported by your hardware.Using %d Hz instead. ", audioSampleRate_, exact_ivalue);
//audioSampleRate_ = exact_ivalue;
// FIXME
}
......@@ -456,7 +401,7 @@ bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle, int type)
}
if (dir != 0)
_debug ("Audio: Warning: (%i) The chosen period size %lu bytes is not supported by your hardware.Using %lu instead. ", type, periodsize, exact_lvalue);
_warn("Alsa: The chosen period size %lu bytes is not supported by your hardware.Using %lu instead. ", periodsize, exact_lvalue);
periodSize_ = exact_lvalue;
/* Set the number of fragments */
......@@ -619,36 +564,22 @@ AlsaLayer::handle_xrun_playback (snd_pcm_t *handle)
}
std::string
AlsaLayer::buildDeviceTopo (const std::string &plugin, int card, int subdevice)
AlsaLayer::buildDeviceTopo (const std::string &plugin, int card)
{
std::stringstream ss, ss1;
std::stringstream ss;
std::string pcm(plugin);
if (pcm == PCM_DEFAULT)
return pcm;
ss << card;
ss << ":" << card;
pcm.append (":");
pcm.append (ss.str());
if (subdevice != 0) {
pcm.append (",");
ss1 << subdevice;
pcm.append (ss1.str());
}
_debug ("Audio: Device topo: %s", pcm.c_str());
return pcm;
return pcm + ss.str();
}
std::vector<std::string>
AlsaLayer::getSoundCardsInfo (int stream)
{
_debug ("Audio: Get sound cards info: ");
snd_ctl_t* handle;
snd_ctl_card_info_t *info;
snd_pcm_info_t* pcminfo;
......@@ -656,7 +587,6 @@ AlsaLayer::getSoundCardsInfo (int stream)
snd_pcm_info_alloca (&pcminfo);
int numCard = -1 ;
std::string description;
std::vector<std::string> cards_id;
if (snd_card_next (&numCard) < 0 || numCard < 0)
......@@ -679,7 +609,7 @@ AlsaLayer::getSoundCardsInfo (int stream)
numCard,
snd_ctl_card_info_get_id (info),
snd_ctl_card_info_get_name (info));
description = snd_ctl_card_info_get_name (info);
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);
......
......@@ -83,10 +83,9 @@ class AlsaLayer : public AudioLayer
* Concatenate two strings. Used to build a valid pcm device name.
* @param plugin the alsa PCM name
* @param card the sound card number
* @param subdevice the subdevice number
* @return std::string the concatenated string
*/
std::string buildDeviceTopo (const std::string &plugin, int card, int subdevice);
std::string buildDeviceTopo (const std::string &plugin, int card);
/**
* Scan the sound card available on the system
......@@ -135,7 +134,6 @@ class AlsaLayer : public AudioLayer
int getIndexIn() const {
return indexIn_;
}
void setIndexIn(int);
/**
* Get the index of the audio card for playback
......@@ -145,7 +143,6 @@ class AlsaLayer : public AudioLayer
int getIndexOut() const {
return indexOut_;
}
void setIndexOut(int);
/**
* Get the index of the audio card for ringtone (could be differnet from playback)
......@@ -155,13 +152,12 @@ class AlsaLayer : public AudioLayer
int getIndexRing() const {
return indexRing_;
}
void setIndexRing(int);
void setPlugin(const std::string &plugin);
private:
bool openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stream_t stream);
/**
* Number of audio cards on which capture stream has been opened
*/
......@@ -201,7 +197,7 @@ class AlsaLayer : public AudioLayer
void startPlaybackStream (void);
void preparePlaybackStream (void);
bool alsa_set_params (snd_pcm_t *pcm_handle, int type);
bool alsa_set_params (snd_pcm_t *pcm_handle);
/**
* Copy a data buffer in the internal ring buffer
......
......@@ -142,19 +142,9 @@ class AudioLayer
void notifyincomingCall (void);
protected:
/**
* Drop the pending frames and close the capture device
*/
virtual void closeCaptureStream (void) = 0;
/**
* Drop the pending frames and close the playback device
*/
virtual void closePlaybackStream (void) = 0;
/**
* Wether or not the audio layer stream is started
* Wether or not the audio layer stream is started
*/
bool isStarted_;
......
......@@ -310,21 +310,14 @@ void PulseLayer::context_state_callback (pa_context* c, void* user_data)
void PulseLayer::updateSinkList (void)
{
_debug ("Audio: Update sink list");
getSinkList()->clear();
pa_context_get_sink_info_list (context_, sink_input_info_callback, this);
}
void PulseLayer::updateSourceList (void)
{
_debug ("Audio: Update source list");
getSourceList()->clear();
pa_context_get_source_info_list (context_, source_input_info_callback, this);
}
bool PulseLayer::inSinkList (const std::string &deviceName) const
......@@ -341,22 +334,15 @@ bool PulseLayer::inSourceList (const std::string &deviceName) const
void PulseLayer::createStreams (pa_context* c)
{
_info ("Audio: Create streams");
playback_ = new AudioStream (c, mainloop_, PLAYBACK_STREAM_NAME, PLAYBACK_STREAM, audioSampleRate_);
std::string playbackDevice(audioPref.getDevicePlayback());
std::string recordDevice(audioPref.getDeviceRecord());
std::string ringtoneDevice(audioPref.getDeviceRingtone());
_debug ("Audio: Device for playback: %s", playbackDevice.c_str());
_debug ("Audio: Device for record: %s", recordDevice.c_str());
_debug ("Audio: Device for ringtone: %s", ringtoneDevice.c_str());
_debug ("PulseAudio: Devices: playback %s , record %s , ringtone %s",
playbackDevice.c_str(), recordDevice.c_str(), ringtoneDevice.c_str());
if (inSinkList (playbackDevice))
playback_->connectStream (&playbackDevice);
else
playback_->connectStream (NULL);
playback_ = new AudioStream (c, mainloop_, PLAYBACK_STREAM_NAME, PLAYBACK_STREAM, audioSampleRate_);
playback_->connectStream(inSinkList(playbackDevice) ? &playbackDevice : NULL);
pa_stream_set_write_callback (playback_->pulseStream(), playback_callback, this);
pa_stream_set_overflow_callback (playback_->pulseStream(), playback_overflow_callback, this);
......@@ -365,22 +351,14 @@ void PulseLayer::createStreams (pa_context* c)
pa_stream_set_latency_update_callback (playback_->pulseStream(), latency_update_callback, this);
record_ = new AudioStream (c, mainloop_, CAPTURE_STREAM_NAME, CAPTURE_STREAM, audioSampleRate_);
if (inSourceList (recordDevice))
record_->connectStream (&recordDevice);
else
record_->connectStream (NULL);
record_->connectStream (inSourceList(recordDevice) ? &recordDevice : NULL);
pa_stream_set_read_callback (record_->pulseStream() , capture_callback, this);
pa_stream_set_moved_callback (record_->pulseStream(), stream_moved_callback, this);
pa_stream_set_latency_update_callback (record_->pulseStream(), latency_update_callback, this);
ringtone_ = new AudioStream (c, mainloop_, RINGTONE_STREAM_NAME, RINGTONE_STREAM, audioSampleRate_);
if (inSourceList (ringtoneDevice))
ringtone_->connectStream (&ringtoneDevice);
else
ringtone_->connectStream (NULL);
ringtone_->connectStream(inSourceList(ringtoneDevice) ? &ringtoneDevice : NULL);
pa_stream_set_write_callback (ringtone_->pulseStream(), ringtone_callback, this);
pa_stream_set_moved_callback (ringtone_->pulseStream(), stream_moved_callback, this);
......@@ -393,43 +371,13 @@ void PulseLayer::createStreams (pa_context* c)
void PulseLayer::disconnectAudioStream (void)
{
_info ("Audio: Disconnect audio stream");
closePlaybackStream();
closeCaptureStream();
}
void PulseLayer::closeCaptureStream (void)
{
if (record_) {
if (record_->pulseStream()) {
const char *name = pa_stream_get_device_name (record_->pulseStream());
if (name && strlen (name)) {
_debug ("Audio: record device to be stored in config: %s", name);
audioPref.setDeviceRecord (name);
}
}
delete record_;
record_ = NULL;
}
}
void PulseLayer::closePlaybackStream (void)
{
if (playback_) {
if (playback_->pulseStream()) {
const char *name = pa_stream_get_device_name (playback_->pulseStream());
if (name && strlen (name)) {
_debug ("Audio: playback device to be stored in config: %s", name);
if (name && *name)
audioPref.setDevicePlayback (name);
}
}
delete playback_;
......@@ -437,21 +385,28 @@ void PulseLayer::closePlaybackStream (void)
}
if (ringtone_) {
if (ringtone_->pulseStream()) {
const char *name = pa_stream_get_device_name (ringtone_->pulseStream());
if (ringtone_->pulseStream()) {
const char *name = pa_stream_get_device_name (ringtone_->pulseStream());
if (name && *name)
audioPref.setDeviceRingtone (name);
}
if (name && strlen (name)) {
_debug ("Audio: ringtone device to be stored in config: %s", name);
audioPref.setDeviceRingtone (name);
}
}
delete ringtone_;
ringtone_ = NULL;
}
delete ringtone_;
ringtone_ = NULL;
if (record_) {
if (record_->pulseStream()) {
const char *name = pa_stream_get_device_name (record_->pulseStream());
if (name && *name)
audioPref.setDeviceRecord (name);
}
delete record_;
record_ = NULL;
}
}
void PulseLayer::startStream (void)
{
// Create Streams
......
......@@ -166,12 +166,6 @@ class PulseLayer : public AudioLayer
// Assignment Operator
PulseLayer& operator= (const PulseLayer& rh);
/**
* Drop the pending frames and close the capture device
*/
void closeCaptureStream (void);
/**
* Write data from the ring buffer to the harware and read data from the hardware
*/
......@@ -185,11 +179,6 @@ class PulseLayer : public AudioLayer
*/
void createStreams (pa_context* c);
/**
* Drop the pending frames and close the playback device
*/
void closePlaybackStream (void);
/**
* Close the connection with the local pulseaudio server
*/
......
......@@ -2053,8 +2053,19 @@ void ManagerImpl::setAudioPlugin (const std::string& audioPlugin)
audioPreference.setPlugin (audioPlugin);
AlsaLayer *alsa = dynamic_cast<AlsaLayer*>(_audiodriver);
if (alsa)
alsa->setPlugin(audioPlugin);
if (!alsa) {
_error("Can't find alsa device");
audioLayerMutexUnlock();
return ;
}
bool wasStarted = _audiodriver->isStarted();
// Recreate audio driver with new settings
delete _audiodriver;
_audiodriver = new AlsaLayer;
if (wasStarted)
_audiodriver->startStream();
audioLayerMutexUnlock();
}
......@@ -2073,23 +2084,29 @@ void ManagerImpl::setAudioDevice (const int index, int streamType)
return ;
}
bool wasStarted = _audiodriver->isStarted();
switch (streamType) {
case SFL_PCM_PLAYBACK:
alsaLayer->setIndexOut(index);
audioPreference.setCardout (index);
break;
case SFL_PCM_CAPTURE:
alsaLayer->setIndexIn(index);
audioPreference.setCardin (index);
break;
case SFL_PCM_RINGTONE:
alsaLayer->setIndexRing(index);
audioPreference.setCardring (index);
break;
default:
break;
}
// Recreate audio driver with new settings
delete _audiodriver;
_audiodriver = new AlsaLayer;
if (wasStarted)
_audiodriver->startStream();
audioLayerMutexUnlock();
}
......
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