125std::vector<std::string>
131std::vector<std::string>
140 auto devices = pimpl_->getDevicesByType(type);
141 auto it = std::find_if(devices.cbegin(), devices.cend(), [&name](
const auto& deviceName) {
142 return deviceName == name;
144 return it != devices.end() ? std::distance(devices.cbegin(),
it) : -1;
177 if (!pimpl_->apiInitialised_) {
178 JAMI_WARN(
"PortAudioLayer API not initialised");
183 std::unique_lock lock(
mutex_);
188 ret = pimpl_->initFullDuplexStream(*
this);
190 ret = pimpl_->initOutputStream(*
this);
203 pimpl_->initInputStream(*
this);
208 pimpl_->initInputStream(*
this);
220 std::lock_guard lock(
mutex_);
227 if (pimpl_->hasFullDuplexStream()) {
229 JAMI_DBG(
"PortAudioLayer full-duplex stream stopped");
234 JAMI_DBG(
"PortAudioLayer output stream stopped");
239 JAMI_DBG(
"PortAudioLayer input stream stopped");
246 JAMI_DBG(
"PortAudioLayer input stream stopped");
255 JAMI_DBG(
"PortAudioLayer output stream stopped");
262 JAMI_DBG(
"PortAudioLayer streams stopped, flushing buffers");
271 auto deviceName = pimpl_->getDeviceNameByType(index, type);
274 preference.setPortAudioDevicePlayback(deviceName);
277 preference.setPortAudioDeviceRecord(deviceName);
280 preference.setPortAudioDeviceRingtone(deviceName);
291 : deviceRecord_ {
pref.getPortAudioDeviceRecord()}
292 , devicePlayback_ {
pref.getPortAudioDevicePlayback()}
293 , deviceRingtone_ {
pref.getPortAudioDeviceRingtone()}
299 JAMI_LOG(
"PortAudioLayer device event: {}, {}",
308 std::this_thread::sleep_for(std::chrono::milliseconds(300));
336 JAMI_WARN(
"PortAudioLayer was unable to initialize input");
337 deviceRecord_.clear();
338 inputInitialized_ =
true;
346 JAMI_WARN(
"PortAudioLayer was unable to initialize input, falling back to default device");
347 deviceRecord_.clear();
354 parent.hardwareInputFormatAvailable(
parent.audioInputFormat_);
355 JAMI_DBG(
"PortAudioLayer initialized input: %s {%d Hz, %d channels}",
357 parent.audioInputFormat_.sample_rate,
358 parent.audioInputFormat_.nb_channels);
359 inputInitialized_ =
true;
375 JAMI_WARN(
"PortAudioLayer was unable to initialize output");
376 devicePlayback_.clear();
377 outputInitialized_ =
true;
385 JAMI_WARN(
"PortAudioLayer was unable to initialize output, falling back to default device");
386 devicePlayback_.clear();
387 return initOutput(
parent);
394 JAMI_DBG(
"PortAudioLayer initialized output: %s {%d Hz, %d channels}",
396 parent.audioFormat_.sample_rate,
397 parent.audioFormat_.nb_channels);
398 outputInitialized_ =
true;
414 apiInitialised_ =
true;
420 std::lock_guard lock(streamsMutex_);
421 std::fill(std::begin(streams_), std::end(streams_),
nullptr);
424std::vector<std::string>
427 std::vector<std::string> devices;
441 if (!devices.empty()) {
453 auto devices = getDevicesByType(type);
454 if (!devices.size()) {
461 auto it = std::find_if(devices.cbegin(), devices.cend(), [&
toMatch](
const auto& deviceName) {
462 return deviceName == toMatch;
464 return it != devices.end() ? std::distance(devices.cbegin(),
it) : 0;
470 if (index == defaultIndex_)
473 auto devices = getDevicesByType(type);
474 if (!devices.size() || index >= devices.size())
477 return devices.at(index);
510 std::string deviceName {};
526 JAMI_DBG(
"PortAudioLayer terminate.");
548 params.hostApiSpecificStreamInfo =
nullptr;
604 JAMI_DBG(
"Open PortAudio Input Stream");
605 std::lock_guard lock(streamsMutex_);
629 JAMI_ERR(
"Error: No valid input device. There will be no mic.");
633 JAMI_DBG(
"Starting PortAudio Input Stream");
640 parent.recordChanged(
true);
647 JAMI_DBG(
"Open PortAudio Output Stream");
648 std::lock_guard lock(streamsMutex_);
663 return layer->pimpl_->paOutputCallback(*
layer,
672 JAMI_ERR(
"Error: No valid output device. There will be no sound.");
676 JAMI_DBG(
"Starting PortAudio Output Stream");
683 parent.playbackChanged(
true);
693 JAMI_ERR(
"Error: Invalid input/output devices. There will be no audio.");
697 JAMI_DBG(
"Open PortAudio Full-duplex input/output stream");
698 std::lock_guard lock(streamsMutex_);
720 JAMI_DBG(
"Start PortAudio I/O Streams");
727 parent.recordChanged(
true);
728 parent.playbackChanged(
true);
735 std::lock_guard lock(streamsMutex_);
743 }
else if (
ret < 0) {
764 std::lock_guard lock(streamsMutex_);
812 if (
parent.isCaptureMuted_)
std::unique_ptr< AudioDeviceNotificationClient, AudioDeviceNotificationClient_deleter > AudioDeviceNotificationClientPtr
void setDeviceEventCallback(DeviceEventCallback callback)
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 flushUrgent()
Flush urgent buffer.
void setHasNativeAEC(bool hasEAC)
void recordChanged(bool started)
void flushMain()
Flush main buffer.
static LIBJAMI_TEST_EXPORT Manager & instance()
std::string getAudioManager() const
Get the audio manager.
void setAudioPlugin(const std::string &audioPlugin)
Set input audio plugin.
int getIndexCapture() const override
void updatePreference(AudioPreference &pref, int index, AudioDeviceType type) override
int getIndexPlayback() const override
PortAudioLayer(const AudioPreference &pref)
void stopStream(AudioDeviceType stream=AudioDeviceType::ALL) override
Stop the playback and capture streams.
int getIndexRingtone() const override
std::vector< std::string > getPlaybackDeviceList() const override
int getAudioDeviceIndex(const std::string &name, AudioDeviceType type) const override
std::vector< std::string > getCaptureDeviceList() const override
void startStream(AudioDeviceType stream=AudioDeviceType::ALL) override
Start the capture stream and prepare the playback stream.
std::string getAudioDeviceName(int index, AudioDeviceType type) const override
direction
0: outgoing, 1: incoming
#define JAMI_LOG(formatstr,...)
void fillWithSilence(AVFrame *frame)
void emitSignal(Args... args)
static void openStreamDevice(PaStream **stream, PaDeviceIndex device, Direction direction, PaStreamCallback *callback, void *user_data)
std::string to_string(double value)
static void openFullDuplexStream(PaStream **stream, PaDeviceIndex inputDeviceIndex, PaDeviceIndex ouputDeviceIndex, PaStreamCallback *callback, void *user_data)
int paIOCallback(PortAudioLayer &parent, const int16_t *inputBuffer, int16_t *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags)
std::string devicePlayback_
void initInput(PortAudioLayer &)
bool initOutputStream(PortAudioLayer &)
int paInputCallback(PortAudioLayer &parent, const int16_t *inputBuffer, int16_t *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags)
int paOutputCallback(PortAudioLayer &parent, const int16_t *inputBuffer, int16_t *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags)
std::vector< std::string > getDevicesByType(AudioDeviceType type) const
bool hasFullDuplexStream() const
static constexpr const int defaultIndex_
bool initFullDuplexStream(PortAudioLayer &)
std::string deviceRecord_
std::string getDeviceNameByType(const int index, AudioDeviceType type)
PaDeviceIndex getApiIndexByType(AudioDeviceType type)
void initOutput(PortAudioLayer &)
bool paStopStream(Direction streamDirection)
PortAudioLayerImpl(PortAudioLayer &, const AudioPreference &)
std::string getApiDefaultDeviceName(AudioDeviceType type, bool commDevice) const
void init(PortAudioLayer &)
bool initInputStream(PortAudioLayer &)
std::string deviceRingtone_
AudioDeviceNotificationClientPtr audioDeviceNotificationClient_
std::atomic< bool > restartRequestPending_
int getIndexByType(AudioDeviceType type)
std::array< PaStream *, static_cast< int >(Direction::End)> streams_