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

* #6629 : simplify AudioLayer creation

Move ALSA specific options to alsalayer only
parent 073bfc05
......@@ -74,11 +74,14 @@ void AlsaThread::run (void)
// Constructor
AlsaLayer::AlsaLayer ()
: AudioLayer (ALSA)
, indexIn_ (audioPref.getCardin())
, indexOut_ (audioPref.getCardout())
, indexRing_ (audioPref.getCardring())
, playbackHandle_ (NULL)
, ringtoneHandle_ (NULL)
, captureHandle_ (NULL)
, periodSize_ (160)
, audioPlugin_ ("default")
, audioPlugin_ (audioPref.getPlugin())
, IDSoundCards_ ()
, is_playback_prepared_ (false)
, is_capture_prepared_ (false)
......@@ -88,85 +91,30 @@ AlsaLayer::AlsaLayer ()
, is_capture_open_ (false)
, trigger_request_ (false)
, audioThread_ (NULL)
, converter_ (0)
{
_debug ("Audio: Build ALSA layer");
urgentRingBuffer_.createReadPointer();
audioPlugin_ = audioPref.getPlugin();
}
// Destructor
AlsaLayer::~AlsaLayer (void)
{
_debug ("Audio: Destroy of ALSA layer");
closeLayer();
delete converter_;
}
void
AlsaLayer::closeLayer()
{
_debug ("Audio: Close ALSA streams");
try {
/* Stop the audio thread first */
if (audioThread_) {
_debug ("Audio: Stop Audio Thread");
delete audioThread_;
audioThread_ = NULL;
}
} catch (...) {
_debug ("Audio: Exception: when stopping audiortp");
throw;
}
delete audioThread_;
/* Then close the audio devices */
closeCaptureStream();
closePlaybackStream();
captureHandle_ = NULL;
playbackHandle_ = NULL;
ringtoneHandle_ = NULL;
}
void
AlsaLayer::openDevice (int indexIn, int indexOut, int indexRing, int sampleRate, int stream , const std::string &plugin)
void AlsaLayer::setPlugin(const std::string &plugin)
{
/* Close the devices before open it */
if (stream == SFL_PCM_BOTH and is_capture_open_ and is_playback_open_) {
closeCaptureStream();
closePlaybackStream();
} else if ( (stream == SFL_PCM_CAPTURE or stream == SFL_PCM_BOTH) and is_capture_open_)
closeCaptureStream ();
else if ( (stream == SFL_PCM_PLAYBACK or stream == SFL_PCM_BOTH) and is_playback_open_)
closePlaybackStream ();
indexIn_ = indexIn;
indexOut_ = indexOut;
indexRing_ = indexRing;
audioSampleRate_ = sampleRate;
audioPlugin_ = plugin;
_debug (" Setting AlsaLayer: device in=%2d, out=%2d, ring=%2d", indexIn_, indexOut_, indexRing_);
_debug (" : alsa plugin=%s", audioPlugin_.c_str());
_debug (" : sample rate=%5d, format=%s", audioSampleRate_, SFLDataFormatString);
audioThread_ = NULL;
// use 1 sec buffer for resampling
converter_ = new SamplerateConverter (audioSampleRate_);
delete audioThread_;
audioThread_ = NULL;
// FIXME : restart audio thread
}
void
AlsaLayer::startStream (void)
{
_debug ("Audio: Start stream");
dcblocker_.reset();
if (is_playback_running_ and is_capture_running_)
......@@ -190,12 +138,55 @@ AlsaLayer::startStream (void)
_debug ("pcmr: %s, index %d", pcmr.c_str(), indexRing_);
_debug ("pcmc: %s, index %d", pcmc.c_str(), indexIn_);
if (not is_capture_open_)
open_device (pcmp, pcmc, pcmr, SFL_PCM_CAPTURE);
if (not is_capture_open_) {
_debug ("Audio: Open capture device");
if (not is_playback_open_)
open_device (pcmp, pcmc, pcmr, SFL_PCM_PLAYBACK);
if (snd_pcm_open (&captureHandle_, pcmc.c_str(), SND_PCM_STREAM_CAPTURE, 0) < 0) {
_warn ("Audio: Error: Opening capture device %s", pcmc.c_str());
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());
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;
}
prepareCaptureStream ();
preparePlaybackStream ();
......@@ -225,17 +216,8 @@ AlsaLayer::stopStream (void)
isStarted_ = false;
try {
/* Stop the audio thread first */
if (audioThread_) {
_debug ("Audio: Stop audio thread");
delete audioThread_;
audioThread_ = NULL;
}
} catch (...) {
_debug ("Audio: Exception: when stopping audiortp");
throw;
}
delete audioThread_;
audioThread_ = NULL;
closeCaptureStream ();
closePlaybackStream ();
......@@ -268,6 +250,32 @@ 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_)
......@@ -427,7 +435,8 @@ bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle, int type)
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);
audioSampleRate_ = exact_ivalue;
//audioSampleRate_ = exact_ivalue;
// FIXME
}
/* Set the number of channels */
......@@ -493,68 +502,6 @@ bool AlsaLayer::alsa_set_params (snd_pcm_t *pcm_handle, int type)
return true;
}
bool
AlsaLayer::open_device (std::string pcm_p, std::string pcm_c, std::string pcm_r, int flag)
{
if (flag == SFL_PCM_BOTH or flag == SFL_PCM_PLAYBACK) {
_debug ("Audio: Open playback device (and ringtone)");
int err;
if ((err = snd_pcm_open (&playbackHandle_, pcm_p.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
_warn ("Audio: Error while opening playback device %s", pcm_p.c_str());
Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE);
is_playback_open_ = false;
return false;
}
if (!alsa_set_params (playbackHandle_, 1)) {
_warn ("Audio: Error: Playback failed");
snd_pcm_close (playbackHandle_);
is_playback_open_ = false;
return false;
}
if (getIndexOut() != getIndexRing()) {
if ((err = snd_pcm_open (&ringtoneHandle_, pcm_r.c_str(), SND_PCM_STREAM_PLAYBACK, 0)) < 0)
_warn ("Audio: Error: Opening ringtone device %s", pcm_r.c_str());
if (!alsa_set_params (ringtoneHandle_, 1)) {
_warn ("Audio: Error: Ringtone failed");
snd_pcm_close (ringtoneHandle_);
}
}
is_playback_open_ = true;
}
if (flag == SFL_PCM_BOTH or flag == SFL_PCM_CAPTURE) {
_debug ("Audio: Open capture device");
if (snd_pcm_open (&captureHandle_, pcm_c.c_str(), SND_PCM_STREAM_CAPTURE, 0) < 0) {
_warn ("Audio: Error: Opening capture device %s", pcm_c.c_str());
Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_CAPTURE_DEVICE);
is_capture_open_ = false;
return false;
}
if (!alsa_set_params (captureHandle_, 0)) {
_warn ("Audio: Error: Capture failed");
snd_pcm_close (captureHandle_);
is_capture_open_ = false;
return false;
}
is_capture_open_ = true;
}
return true;
}
//TODO first frame causes broken pipe (underrun) because not enough data are send --> make the handle wait to be ready
int
AlsaLayer::write (void* buffer, int length, snd_pcm_t * handle)
......
......@@ -35,7 +35,6 @@
#include "audio/audiolayer.h"
#include <alsa/asoundlib.h>
class SamplerateConverter;
class RingBuffer;
class ManagerImpl;
class AlsaThread;
......@@ -58,20 +57,6 @@ class AlsaLayer : public AudioLayer
*/
~AlsaLayer (void);
/**
* Check if no devices are opened, otherwise close them.
* Then open the specified devices by calling the private functions open_device
* @param indexIn The number of the card chosen for capture
* @param indexOut The number of the card chosen for playback
* @param sampleRate The sample rate
* @param stream To indicate which kind of stream you want to open
* SFL_PCM_CAPTURE
* SFL_PCM_PLAYBACK
* SFL_PCM_BOTH
* @param plugin The alsa plugin ( dmix , default , front , surround , ...)
*/
void openDevice (int indexIn, int indexOut, int indexRing, int sampleRate, int stream, const std::string &plugin);
/**
* Start the capture stream and prepare the playback stream.
* The playback starts accordingly to its threshold
......@@ -123,7 +108,7 @@ class AlsaLayer : public AudioLayer
* @return bool True if it exists and supports the mode
* false otherwise
*/
bool soundCardIndexExist (int card , int stream);
static bool soundCardIndexExist (int card , int stream);
/**
* An index is associated with its string description
......@@ -142,9 +127,55 @@ class AlsaLayer : public AudioLayer
void audioCallback (void);
/**
* Get the index of the audio card for capture
* @return int The index of the card used for capture
* 0 for the first available card on the system, 1 ...
*/
int getIndexIn() const {
return indexIn_;
}
void setIndexIn(int);
/**
* Get the index of the audio card for playback
* @return int The index of the card used for playback
* 0 for the first available card on the system, 1 ...
*/
int getIndexOut() const {
return indexOut_;
}
void setIndexOut(int);
/**
* Get the index of the audio card for ringtone (could be differnet from playback)
* @return int The index of the card used for ringtone
* 0 for the first available card on the system, 1 ...
*/
int getIndexRing() const {
return indexRing_;
}
void setIndexRing(int);
void setPlugin(const std::string &plugin);
private:
void closeLayer (void);
/**
* Number of audio cards on which capture stream has been opened
*/
int indexIn_;
/**
* Number of audio cards on which playback stream has been opened
*/
int indexOut_;
/**
* Number of audio cards on which ringtone stream has been opened
*/
int indexRing_;
/** Associate a sound card index to its string description */
typedef std::pair<int , std::string> HwIDPair;
......@@ -170,20 +201,6 @@ class AlsaLayer : public AudioLayer
void startPlaybackStream (void);
void preparePlaybackStream (void);
/**
* Open the specified device.
* ALSA Library API
* @param pcm_p The string name for the playback device
* @param pcm_c The string name for the capture device
* @param flag To indicate which kind of stream you want to open
* SFL_PCM_CAPTURE
* SFL_PCM_PLAYBACK
* SFL_PCM_BOTH
* @return true if successful
* false otherwise
*/
bool open_device (std::string pcm_p, std::string pcm_c, std::string pcm_r, int flag);
bool alsa_set_params (snd_pcm_t *pcm_handle, int type);
/**
......@@ -256,9 +273,6 @@ class AlsaLayer : public AudioLayer
bool trigger_request_;
AlsaThread* audioThread_;
/** Sample rate converter object */
SamplerateConverter* converter_;
};
#endif // _ALSA_LAYER_H_
......@@ -37,20 +37,20 @@
AudioLayer::AudioLayer (int type)
: isStarted_ (false)
, urgentRingBuffer_ (SIZEBUF, Call::DEFAULT_ID)
, recorder_ (0)
, indexIn_ (0)
, indexOut_ (0)
, indexRing_ (0)
, audioSampleRate_ (0)
, audioSampleRate_(Manager::instance().getMainBuffer()->getInternalSamplingRate())
, mutex_ ()
, audioPref(Manager::instance().audioPreference)
, converter_ (new SamplerateConverter(audioSampleRate_))
, layerType_ (type)
, lastNotificationTime_ (0)
{}
{
urgentRingBuffer_.createReadPointer();
}
AudioLayer::~AudioLayer ()
{
delete converter_;
}
void AudioLayer::flushMain (void)
......
......@@ -40,6 +40,7 @@
#include "manager.h"
#include "ringbuffer.h"
#include "dcblocker.h"
#include "samplerateconverter.h"
/**
* @file audiolayer.h
......@@ -72,20 +73,6 @@ class AudioLayer
*/
virtual ~AudioLayer (void);
/**
* Check if no devices are opened, otherwise close them.
* Then open the specified devices by calling the private functions open_device
* @param indexIn The number of the card chosen for capture
* @param indexOut The number of the card chosen for playback
* @param sampleRate The sample rate
* @param stream To indicate which kind of stream you want to open
* SFL_PCM_CAPTURE
* SFL_PCM_PLAYBACK
* SFL_PCM_BOTH
* @param plugin The alsa plugin ( dmix , default , front , surround , ...)
*/
virtual void openDevice (int indexIn, int indexOut, int indexRing, int sampleRate, int stream , const std::string &plugin) = 0;
/**
* Start the capture stream and prepare the playback stream.
* The playback starts accordingly to its threshold
......@@ -114,32 +101,6 @@ class AudioLayer
void flushUrgent (void);
/**
* Get the index of the audio card for capture
* @return int The index of the card used for capture
* 0 for the first available card on the system, 1 ...
*/
int getIndexIn() const {
return indexIn_;
}
/**
* Get the index of the audio card for playback
* @return int The index of the card used for playback
* 0 for the first available card on the system, 1 ...
*/
int getIndexOut() const {
return indexOut_;
}
/**
* Get the index of the audio card for ringtone (could be differnet from playback)
* @return int The index of the card used for ringtone
* 0 for the first available card on the system, 1 ...
*/
int getIndexRing() const {
return indexRing_;
}
/**
* Get the sample rate of the audio layer
......@@ -171,20 +132,6 @@ class AudioLayer
return Manager::instance().getMainBuffer();
}
/**
* Set the audio recorder
*/
void setRecorderInstance (Recordable* rec) {
recorder_ = rec;
}
/**
* Get the audio recorder
*/
Recordable* getRecorderInstance (void) const {
return recorder_;
}
/**
* Get the mutex lock for the entire audio layer
*/
......@@ -216,31 +163,11 @@ class AudioLayer
*/
RingBuffer urgentRingBuffer_;
/**
* A pointer to the recordable instance (may be a call or a conference)
*/
Recordable* recorder_;
/**
* Number of audio cards on which capture stream has been opened
*/
int indexIn_;
/**
* Number of audio cards on which playback stream has been opened
*/
int indexOut_;
/**
* Number of audio cards on which ringtone stream has been opened
*/
int indexRing_;
/**
* Sample Rate SFLphone should send sound data to the sound card
* The value can be set in the user config file- now: 44100HZ
*/
unsigned int audioSampleRate_;
const unsigned int audioSampleRate_;
/**
* Lock for the entire audio layer
......@@ -251,6 +178,8 @@ class AudioLayer
AudioPreference &audioPref;
SamplerateConverter *converter_;
private:
const int layerType_;
......
......@@ -219,45 +219,41 @@ void playback_overflow_callback (pa_stream* s UNUSED, void* userdata UNUSED)
PulseLayer::PulseLayer ()
: AudioLayer (PULSEAUDIO)
, context_(0)
, mainloop_(0)
, playback_(0)
, record_(0)
, ringtone_(0)
, converter_(0)
{
urgentRingBuffer_.createReadPointer();
setenv ("PULSE_PROP_media.role", "phone", 1);
openLayer();
}
mainloop_ = pa_threaded_mainloop_new();
if (!mainloop_)
_error("Couldn't create pulseaudio mainloop");
// Destructor
PulseLayer::~PulseLayer (void)
{
closeLayer ();
delete converter_;
}
context_ = pa_context_new (pa_threaded_mainloop_get_api (mainloop_) , "SFLphone");
if (!context_)
_error("Couldn't create pulseaudio context");
void
PulseLayer::openLayer (void)
{
if (isStarted_)
return;
pa_context_set_state_callback (context_, context_state_callback, this);
if (pa_context_connect (context_, NULL , PA_CONTEXT_NOAUTOSPAWN , NULL) < 0)
_error("Could not connect pulseaudio context to the server");
pa_threaded_mainloop_lock (mainloop_);
if (pa_threaded_mainloop_start (mainloop_) < 0)
_error("Failed to start pulseaudio mainloop");
pa_threaded_mainloop_wait (mainloop_);
_info ("Audio: Open Pulseaudio layer");
if (pa_context_get_state (context_) != PA_CONTEXT_READY)
_error("Couldn't connect to pulse audio server");
connectPulseAudioServer();