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;
150 return pimpl_->getDeviceNameByType(index, type);
175 if (!pimpl_->apiInitialised_) {
176 JAMI_WARN(
"PortAudioLayer API not initialised");
181 std::unique_lock lock(
mutex_);
186 ret = pimpl_->initFullDuplexStream(*
this);
188 ret = pimpl_->initOutputStream(*
this);
202 pimpl_->initInputStream(*
this);
207 pimpl_->initInputStream(*
this);
219 std::lock_guard lock(
mutex_);
227 if (pimpl_->hasFullDuplexStream()) {
229 JAMI_DBG(
"PortAudioLayer full-duplex stream stopped");
240 JAMI_DBG(
"PortAudioLayer output stream stopped");
245 JAMI_DBG(
"PortAudioLayer input stream stopped");
252 JAMI_DBG(
"PortAudioLayer input stream stopped");
262 JAMI_DBG(
"PortAudioLayer output stream stopped");
269 JAMI_DBG(
"PortAudioLayer streams stopped, flushing buffers");
282 auto deviceName = pimpl_->getDeviceNameByType(index, type);
285 preference.setPortAudioDevicePlayback(deviceName);
288 preference.setPortAudioDeviceRecord(deviceName);
291 preference.setPortAudioDeviceRingtone(deviceName);
301 : deviceRecord_ {
pref.getPortAudioDeviceRecord()}
302 , devicePlayback_ {
pref.getPortAudioDevicePlayback()}
303 , deviceRingtone_ {
pref.getPortAudioDeviceRingtone()}
316 std::this_thread::sleep_for(std::chrono::milliseconds(300));
344 JAMI_WARN(
"PortAudioLayer was unable to initialize input");
345 deviceRecord_.clear();
346 inputInitialized_ =
true;
354 JAMI_WARN(
"PortAudioLayer was unable to initialize input, falling back to default device");
355 deviceRecord_.clear();
363 parent.hardwareInputFormatAvailable(
parent.audioInputFormat_);
364 JAMI_DBG(
"PortAudio input device: %s (native: %.0f Hz, using: %d Hz, %d channels)",
367 parent.audioInputFormat_.sample_rate,
368 parent.audioInputFormat_.nb_channels);
369 inputInitialized_ =
true;
385 JAMI_WARN(
"PortAudioLayer was unable to initialize output");
386 devicePlayback_.clear();
387 outputInitialized_ =
true;
395 JAMI_WARN(
"PortAudioLayer was unable to initialize output, falling back to default device");
396 devicePlayback_.clear();
397 return initOutput(
parent);
405 JAMI_DBG(
"PortAudio output device: %s (native: %.0f Hz, using: %d Hz, %d channels)",
408 parent.audioFormat_.sample_rate,
409 parent.audioFormat_.nb_channels);
410 outputInitialized_ =
true;
426 apiInitialised_ =
true;
432 std::lock_guard lock(streamsMutex_);
433 std::fill(std::begin(streams_), std::end(streams_),
nullptr);
436std::vector<std::string>
439 std::vector<std::string> devices;
453 if (!devices.empty()) {
465 auto devices = getDevicesByType(type);
466 if (!devices.size()) {
472 auto it = std::find_if(devices.cbegin(), devices.cend(), [&
toMatch](
const auto& deviceName) {
473 return deviceName == toMatch;
475 return it != devices.end() ? std::distance(devices.cbegin(),
it) : 0;
481 if (index == defaultIndex_)
484 auto devices = getDevicesByType(type);
485 if (!devices.size() || index >= devices.size())
488 return devices.at(index);
518 std::string deviceName {};
534 JAMI_DBG(
"PortAudioLayer terminate.");
577 double sampleRate = 0.0;
581 sampleRate =
inputInfo->defaultSampleRate;
615 JAMI_DBG(
"Open PortAudio Input Stream");
616 std::lock_guard lock(streamsMutex_);
643 JAMI_ERR(
"Error: No valid input device. There will be no mic.");
647 JAMI_DBG(
"Starting PortAudio Input Stream");
651 parent.recordChanged(
true);
658 JAMI_DBG(
"Open PortAudio Output Stream");
659 std::lock_guard lock(streamsMutex_);
674 return layer->pimpl_->paOutputCallback(*
layer,
686 JAMI_ERR(
"Error: No valid output device. There will be no sound.");
690 JAMI_DBG(
"Starting PortAudio Output Stream");
694 parent.playbackChanged(
true);
704 JAMI_ERR(
"Error: Invalid input/output devices. There will be no audio.");
708 JAMI_DBG(
"Open PortAudio Full-duplex input/output stream");
709 std::lock_guard lock(streamsMutex_);
734 JAMI_DBG(
"Start PortAudio I/O Streams");
738 parent.recordChanged(
true);
739 parent.playbackChanged(
true);
746 std::lock_guard lock(streamsMutex_);
754 }
else if (
ret < 0) {
776 std::lock_guard lock(streamsMutex_);
797 for (
unsigned i = 0;
i <
parent.audioFormat_.nb_channels; ++
i) {
804 auto channels = std::min<size_t>(
parent.audioFormat_.nb_channels,
toPlay->pointer()->ch_layout.nb_channels);
806 for (
size_t i = 0;
i < channels; ++
i) {
834 auto channels =
parent.audioInputFormat_.nb_channels;
836 for (
size_t i = 0;
i < channels; ++
i) {
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.
std::condition_variable startedCv_
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
void startStream(AudioDeviceType stream) override
Start the capture stream and prepare the playback stream.
int getAudioDeviceIndex(const std::string &name, AudioDeviceType type) const override
std::vector< std::string > getCaptureDeviceList() const override
std::string getAudioDeviceName(int index, AudioDeviceType type) const override
#define JAMI_LOG(formatstr,...)
void fillWithSilence(AVFrame *frame)
void emitSignal(Args... args)
std::string to_string(double value)
static PaError openPaStream(PaStream **stream, PaDeviceIndex inputDeviceIndex, PaDeviceIndex outputDeviceIndex, PaStreamCallback *callback, void *user_data)
static bool startPaStream(PaStream *stream)
std::string devicePlayback_
void initInput(PortAudioLayer &)
bool initOutputStream(PortAudioLayer &)
std::vector< std::string > getDevicesByType(AudioDeviceType type) const
bool hasFullDuplexStream() const
static constexpr const int defaultIndex_
bool initFullDuplexStream(PortAudioLayer &)
std::string deviceRecord_
int paIOCallback(PortAudioLayer &parent, const float *inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags)
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_
int paOutputCallback(PortAudioLayer &parent, const float *inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags)
AudioDeviceNotificationClientPtr audioDeviceNotificationClient_
std::atomic< bool > restartRequestPending_
int getIndexByType(AudioDeviceType type)
std::array< PaStream *, static_cast< int >(Direction::End)> streams_
int paInputCallback(PortAudioLayer &parent, const float *inputBuffer, float *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags)