From 6fedd70771ed5359772791c6a68ea9c3e6fa716d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= <rafael.carre@savoirfairelinux.com> Date: Tue, 30 Aug 2011 14:46:05 -0400 Subject: [PATCH] * #6629: Always restart audio driver when changing parameters (ALSA only) --- daemon/src/audio/alsa/alsalayer.cpp | 150 ++++++--------------- daemon/src/audio/alsa/alsalayer.h | 12 +- daemon/src/audio/audiolayer.h | 12 +- daemon/src/audio/pulseaudio/pulselayer.cpp | 93 ++++--------- daemon/src/audio/pulseaudio/pulselayer.h | 11 -- daemon/src/managerimpl.cpp | 27 +++- 6 files changed, 91 insertions(+), 214 deletions(-) diff --git a/daemon/src/audio/alsa/alsalayer.cpp b/daemon/src/audio/alsa/alsalayer.cpp index 1ab1574e4c..7076cc7822 100644 --- a/daemon/src/audio/alsa/alsalayer.cpp +++ b/daemon/src/audio/alsa/alsalayer.cpp @@ -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); diff --git a/daemon/src/audio/alsa/alsalayer.h b/daemon/src/audio/alsa/alsalayer.h index c29ccda940..a8a8629c8e 100644 --- a/daemon/src/audio/alsa/alsalayer.h +++ b/daemon/src/audio/alsa/alsalayer.h @@ -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 diff --git a/daemon/src/audio/audiolayer.h b/daemon/src/audio/audiolayer.h index 56b47e2a8c..f6e348b0d4 100644 --- a/daemon/src/audio/audiolayer.h +++ b/daemon/src/audio/audiolayer.h @@ -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_; diff --git a/daemon/src/audio/pulseaudio/pulselayer.cpp b/daemon/src/audio/pulseaudio/pulselayer.cpp index 90f09b3e19..42d29b3909 100644 --- a/daemon/src/audio/pulseaudio/pulselayer.cpp +++ b/daemon/src/audio/pulseaudio/pulselayer.cpp @@ -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 diff --git a/daemon/src/audio/pulseaudio/pulselayer.h b/daemon/src/audio/pulseaudio/pulselayer.h index f06ce86539..8c4baf6b45 100644 --- a/daemon/src/audio/pulseaudio/pulselayer.h +++ b/daemon/src/audio/pulseaudio/pulselayer.h @@ -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 */ diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 9ad7b54b9c..2aae49f0bd 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -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(); } -- GitLab