38 , indexIn_(
pref.getAlsaCardin())
39 , indexOut_(
pref.getAlsaCardout())
40 , indexRing_(
pref.getAlsaCardRingtone())
41 , audioPlugin_(
pref.getAlsaPlugin())
54 closePlaybackStream();
55 closeRingtoneStream();
82 const std::string&
dev,
86 JAMI_DBG(
"Alsa: Opening %s device '%s'",
90 static const int MAX_RETRIES = 10;
98 std::this_thread::sleep_for(std::chrono::milliseconds(100));
103 JAMI_ERR(
"Alsa: Unable to open %s device %s : %s",
112 if (!alsa_set_params(*
pcm, format)) {
130 is_playback_open_ = openDevice(&playbackHandle_,
134 if (
not is_playback_open_)
138 startPlaybackStream();
142 and not ringtoneHandle_) {
143 if (!openDevice(&ringtoneHandle_,
151 is_capture_open_ = openDevice(&captureHandle_,
156 if (
not is_capture_open_)
158 prepareCaptureStream();
159 startCaptureStream();
173 closeCaptureStream();
177 closePlaybackStream();
183 closeRingtoneStream();
186 if (is_capture_open_
or is_playback_open_
or ringtoneHandle_) {
194AlsaLayer::startThread()
201AlsaLayer::stopThread()
204 if (audioThread_.joinable())
216#define ALSA_CALL(call, error) \
218 int err_code = call; \
220 JAMI_ERR(error ": %s", snd_strerror(err_code)); \
225AlsaLayer::stopCaptureStream()
228 is_capture_running_ =
false;
229 is_capture_prepared_ =
false;
234AlsaLayer::closeCaptureStream()
236 if (is_capture_prepared_
and is_capture_running_)
239 JAMI_DBG(
"Alsa: Closing capture stream");
242 is_capture_open_ =
false;
243 captureHandle_ =
nullptr;
248AlsaLayer::startCaptureStream()
250 if (captureHandle_
and not is_capture_running_)
252 is_capture_running_ =
true;
256AlsaLayer::stopPlaybackStream()
258 if (playbackHandle_
and is_playback_running_) {
260 is_playback_running_ =
false;
266AlsaLayer::closePlaybackStream()
268 if (is_playback_running_)
269 stopPlaybackStream();
271 if (is_playback_open_) {
272 JAMI_DBG(
"Alsa: Closing playback stream");
274 is_playback_open_ =
false;
275 playbackHandle_ =
nullptr;
280AlsaLayer::closeRingtoneStream()
282 if (ringtoneHandle_) {
285 ringtoneHandle_ =
nullptr;
290AlsaLayer::startPlaybackStream()
292 is_playback_running_ =
true;
296AlsaLayer::prepareCaptureStream()
298 if (is_capture_open_
and not is_capture_prepared_)
300 is_capture_prepared_ =
true;
306#define TRY(call, error) \
308 if (ALSA_CALL(call, error) < 0) \
328#define HW pcm_handle, hwparams
335 "hardware sample rate");
340 format.nb_channels = 2;
355 "Unable to set buffer size for playback");
357 "Unable to set period size for playback");
359 "Unable to set number of periods for playback");
370 JAMI_ERR(
"buffer to small, unable to use");
383#define SW pcm_handle, swparams
400 (
const void*)
buffer.pointer()->data[0],
401 buffer.pointer()->nb_samples);
418 stopPlaybackStream();
419 startPlaybackStream();
423 (
const void*)
buffer.pointer()->data[0],
424 buffer.pointer()->nb_samples),
425 "XRUN handling failed");
435 JAMI_ERR(
"Writing in state SND_PCM_STATE_SETUP, should be "
436 "SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING");
441 stopPlaybackStream();
451 stopPlaybackStream();
456std::unique_ptr<AudioFrame>
457AlsaLayer::read(
unsigned frames)
460 prepareCaptureStream();
461 startCaptureStream();
468 ret->pointer()->nb_samples =
err;
482 prepareCaptureStream();
483 startCaptureStream();
492 prepareCaptureStream();
493 startCaptureStream();
526static std::vector<std::string>
538std::vector<std::string>
541 return getValues(getAudioDeviceIndexMap(
true));
544std::vector<std::string>
547 return getValues(getAudioDeviceIndexMap(
false));
551AlsaLayer::getAudioDeviceIndexMap(
bool getCapture)
const
567 std::string name = fmt::format(
"hw:{}",
numCard);
578 JAMI_WARN(
"Unable to get info for %s %s: %s",
579 getCapture ?
"capture device" :
"playback device",
588 description.append(
" - ");
606 std::string name = fmt::format(
"hw:{}",
card);
627 for (
const auto&
dev : devices)
628 if (
dev.second == description)
658 if (!captureHandle_
or !is_capture_running_)
674 JAMI_ERR(
"ALSA MIC : Unable to read!");
680 if (!playbackHandle_)
690 write(*
toPlay, playbackHandle_);
697 if (!ringtoneHandle_)
705 write(*
toRing, ringtoneHandle_);
#define ALSA_CALL(call, error)
#define ALSA_CAPTURE_DEVICE
#define ALSA_PLAYBACK_DEVICE
virtual int getIndexPlayback() const
Get the index of the audio card for playback.
std::string getAudioDeviceName(int index, AudioDeviceType type) const
AlsaLayer(const AudioPreference &pref)
Constructor.
std::string buildDeviceTopo(const std::string &plugin, int card)
Concatenate two strings.
int getAudioDeviceIndex(const std::string &description, AudioDeviceType type) const
An index is associated with its string description.
virtual std::vector< std::string > getCaptureDeviceList() const
Scan the sound card available on the system.
virtual std::vector< std::string > getPlaybackDeviceList() const
virtual int getIndexRingtone() const
Get the index of the audio card for ringtone (could be differnet from playback)
void run()
Reimplementation of run()
static bool soundCardIndexExists(int card, AudioDeviceType stream)
Check if the given index corresponds to an existing sound card and supports the specified streaming m...
virtual void startStream(AudioDeviceType stream=AudioDeviceType::ALL)
Start the capture stream and prepare the playback stream.
virtual void stopStream(AudioDeviceType stream=AudioDeviceType::ALL)
Stop the playback and capture streams.
std::mutex mutex_
Lock for the entire audio layer.
std::atomic< Status > status_
Whether or not the audio layer's playback stream is started.
void playbackChanged(bool started)
void setHasNativeNS(bool hasNS)
void hardwareFormatAvailable(AudioFormat playback, size_t bufSize=0)
Callback to be called by derived classes when the audio output is opened.
std::shared_ptr< AudioFrame > getToRing(AudioFormat format, size_t writableSamples)
void flushUrgent()
Flush urgent buffer.
void setHasNativeAEC(bool hasEAC)
std::shared_ptr< AudioFrame > getToPlay(AudioFormat format, size_t writableSamples)
void recordChanged(bool started)
AudioFormat audioFormat_
Sample Rate that should be sent to the sound card.
void flushMain()
Flush main buffer.
AudioFormat audioInputFormat_
Sample Rate for input.
void putRecorded(std::shared_ptr< AudioFrame > &&frame)
AudioFormat getFormat() const
Get the audio format of the layer (sample rate & channel number).
static constexpr std::string_view toString(AuthDecodingState state)
void emitSignal(Args... args)
static bool safeUpdate(snd_pcm_t *handle, long &samples)
libjami::AudioFrame AudioFrame
static std::vector< std::string > getValues(const std::vector< HwIDPair > &deviceMap)
Simple macro to hide class' copy constructor and assignment operator.