diff --git a/src/call.h b/src/call.h index 10c897c947f25e9ce558753db129dc74077e1645..a306144933fd462af808210c28daf9f4bb40be91 100644 --- a/src/call.h +++ b/src/call.h @@ -49,6 +49,7 @@ namespace jami { class VoIPLink; class Account; struct AccountVideoCodecInfo; +class AudioDeviceGuard; template<class T> using CallMap = std::map<std::string, std::shared_ptr<T>>; @@ -331,6 +332,8 @@ public: // media management return confInfo_.toVectorMapStringString(); } + std::unique_ptr<AudioDeviceGuard> audioGuard; + protected: virtual void merge(Call& scall); diff --git a/src/client/configurationmanager.cpp b/src/client/configurationmanager.cpp index 20faedc73088a301b149281a6846597b8e538329..b9155df1b5457b189627b71eb62c79910d4ef9d0 100644 --- a/src/client/configurationmanager.cpp +++ b/src/client/configurationmanager.cpp @@ -70,7 +70,7 @@ using jami::SIPAccount; using jami::JamiAccount; using jami::tls::TlsValidator; using jami::tls::CertificateStore; -using jami::DeviceType; +using jami::AudioDeviceType; using jami::HookPreference; void @@ -641,25 +641,25 @@ getAudioInputDeviceList() void setAudioOutputDevice(int32_t index) { - return jami::Manager::instance().setAudioDevice(index, DeviceType::PLAYBACK); + return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::PLAYBACK); } void setAudioInputDevice(int32_t index) { - return jami::Manager::instance().setAudioDevice(index, DeviceType::CAPTURE); + return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::CAPTURE); } void startAudio() { - jami::Manager::instance().restartAudioDriverStream(); + jami::Manager::instance().startAudio(); } void setAudioRingtoneDevice(int32_t index) { - return jami::Manager::instance().setAudioDevice(index, DeviceType::RINGTONE); + return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::RINGTONE); } std::vector<std::string> diff --git a/src/client/videomanager.cpp b/src/client/videomanager.cpp index 881a6cd07fcaefebd5769615c68041b5a8476c28..55dd4c6ddce7c685133474f594ee8e732578de09 100644 --- a/src/client/videomanager.cpp +++ b/src/client/videomanager.cpp @@ -465,12 +465,6 @@ stopCamera() void startAudioDevice() { - // Don't start audio layer if already done - auto audioLayer = jami::Manager::instance().getAudioDriver(); - if (!audioLayer) - jami::Manager::instance().initAudioDriver(); - if (!audioLayer->isStarted()) - jami::Manager::instance().startAudioDriverStream(); jami::Manager::instance().getVideoManager().audioPreview = jami::getAudioInput( jami::RingBufferPool::DEFAULT_ID); } @@ -479,7 +473,6 @@ void stopAudioDevice() { jami::Manager::instance().getVideoManager().audioPreview.reset(); - jami::Manager::instance().checkAudio(); // stops audio layer if no calls } std::string @@ -787,21 +780,19 @@ getMediaPlayer(const std::string& id) std::string createMediaPlayer(const std::string& path) { - auto& vmgr = Manager::instance().getVideoManager(); auto player = std::make_shared<MediaPlayer>(path); if (!player->isInputValid()) { return ""; } auto playerId = player.get()->getId(); - vmgr.mediaPlayers[playerId] = player; + Manager::instance().getVideoManager().mediaPlayers[playerId] = player; return playerId; } bool pausePlayer(const std::string& id, bool pause) { - auto player = getMediaPlayer(id); - if (player) { + if (auto player = getMediaPlayer(id)) { player->pause(pause); return true; } @@ -811,24 +802,13 @@ pausePlayer(const std::string& id, bool pause) bool closePlayer(const std::string& id) { - auto& vmgr = Manager::instance().getVideoManager(); - auto player = getMediaPlayer(id); - if (player) { - vmgr.mediaPlayers.erase(id); - if (vmgr.mediaPlayers.empty()) { - jami::Manager::instance().checkAudio(); - } - return true; - } - return false; + return Manager::instance().getVideoManager().mediaPlayers.erase(id) > 0; } bool mutePlayerAudio(const std::string& id, bool mute) { - auto& vmgr = Manager::instance().getVideoManager(); - auto player = getMediaPlayer(id); - if (player) { + if (auto player = getMediaPlayer(id)) { player->muteAudio(mute); return true; } @@ -838,22 +818,16 @@ mutePlayerAudio(const std::string& id, bool mute) bool playerSeekToTime(const std::string& id, int time) { - auto& vmgr = Manager::instance().getVideoManager(); - auto player = getMediaPlayer(id); - if (player) { + if (auto player = getMediaPlayer(id)) return player->seekToTime(time); - } return false; } int64_t getPlayerPosition(const std::string& id) { - auto& vmgr = Manager::instance().getVideoManager(); - auto player = getMediaPlayer(id); - if (player) { + if (auto player = getMediaPlayer(id)) return player->getPlayerPosition(); - } return -1; } diff --git a/src/manager.cpp b/src/manager.cpp index d456e07572fcbc4a64f4ec183a6d38d4a3627fc8..0f90d65c3de09b3e1eb0440916f085f6d2be570e 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -300,7 +300,7 @@ struct Manager::ManagerPimpl */ void playATone(Tone::ToneId toneId); - int getCurrentDeviceIndex(DeviceType type); + int getCurrentDeviceIndex(AudioDeviceType type); /** * Process remaining participant given a conference and the current call id. @@ -345,6 +345,8 @@ struct Manager::ManagerPimpl template<class T> std::shared_ptr<T> findAccount(const std::function<bool(const std::shared_ptr<T>&)>&); + void initAudioDriver(); + Manager& base_; // pimpl back-pointer std::shared_ptr<asio::io_context> ioContext_; @@ -357,6 +359,7 @@ struct Manager::ManagerPimpl /** Application wide tone controller */ ToneControl toneCtrl_; + std::unique_ptr<AudioDeviceGuard> toneDeviceGuard_; /** Current Call ID */ std::string currentCall_; @@ -366,6 +369,7 @@ struct Manager::ManagerPimpl /** Audio layer */ std::shared_ptr<AudioLayer> audiodriver_ {nullptr}; + std::array<std::atomic_uint, 3> audioStreamUsers_ {}; // Main thread std::unique_ptr<DTMF> dtmfKey_; @@ -487,32 +491,29 @@ Manager::ManagerPimpl::playATone(Tone::ToneId toneId) if (not base_.voipPreferences.getPlayTones()) return; - { - std::lock_guard<std::mutex> lock(audioLayerMutex_); - - if (not audiodriver_) { - JAMI_ERR("Audio layer not initialized"); - return; - } - - audiodriver_->flushUrgent(); - audiodriver_->startStream(); + std::lock_guard<std::mutex> lock(audioLayerMutex_); + if (not audiodriver_) { + JAMI_ERR("Audio layer not initialized"); + return; } + auto oldGuard = std::move(toneDeviceGuard_); + toneDeviceGuard_ = base_.startAudioStream(AudioDeviceType::PLAYBACK); + audiodriver_->flushUrgent(); toneCtrl_.play(toneId); } int -Manager::ManagerPimpl::getCurrentDeviceIndex(DeviceType type) +Manager::ManagerPimpl::getCurrentDeviceIndex(AudioDeviceType type) { if (not audiodriver_) return -1; switch (type) { - case DeviceType::PLAYBACK: + case AudioDeviceType::PLAYBACK: return audiodriver_->getIndexPlayback(); - case DeviceType::RINGTONE: + case AudioDeviceType::RINGTONE: return audiodriver_->getIndexRingtone(); - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: return audiodriver_->getIndexCapture(); default: return -1; @@ -817,17 +818,14 @@ Manager::init(const std::string& config_file) } } - initAudioDriver(); - { std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - + pimpl_->initAudioDriver(); if (pimpl_->audiodriver_) { pimpl_->toneCtrl_.setSampleRate(pimpl_->audiodriver_->getSampleRate()); pimpl_->dtmfKey_.reset(new DTMF(getRingBufferPool().getInternalSamplingRate())); } } - registerAccounts(); } @@ -861,7 +859,6 @@ Manager::finish() noexcept { std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - pimpl_->audiodriver_.reset(); } @@ -1025,22 +1022,6 @@ Manager::answerCall(const std::string& call_id) return result; } -void -Manager::checkAudio() -{ - // FIXME dirty, the manager should not need to be aware of local recorders - if (getCallList().empty() -#ifdef ENABLE_VIDEO - and not getVideoManager().audioPreview -#endif - and not getVideoManager().hasRunningPlayers() - and not jami::LocalRecorderManager::instance().hasRunningRecorders()) { - std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - if (pimpl_->audiodriver_) - pimpl_->audiodriver_->stopStream(); - } -} - // THREAD=Main bool Manager::hangupCall(const std::string& callId) @@ -1054,7 +1035,6 @@ Manager::hangupCall(const std::string& callId) auto call = getCallFromCallID(callId); if (not call) { JAMI_WARN("Could not hang up non-existant call %s", callId.c_str()); - checkAudio(); return false; } @@ -1631,7 +1611,6 @@ Manager::addAudio(Call& call) JAMI_INFO("Add audio to call %s", call.getCallId().c_str()); const auto& call_id = call.getCallId(); - if (isConferenceParticipant(call_id)) { JAMI_DBG("[conf:%s] Attach local audio", call_id.c_str()); @@ -1646,6 +1625,8 @@ Manager::addAudio(Call& call) // bind to main getRingBufferPool().bindCallID(call_id, RingBufferPool::DEFAULT_ID); + auto oldGuard = std::move(call.audioGuard); + call.audioGuard = startAudioStream(AudioDeviceType::PLAYBACK); std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); if (!pimpl_->audiodriver_) { @@ -1655,7 +1636,6 @@ Manager::addAudio(Call& call) pimpl_->audiodriver_->flushUrgent(); getRingBufferPool().flushAllBuffers(); } - startAudioDriverStream(); } void @@ -1664,6 +1644,7 @@ Manager::removeAudio(Call& call) const auto& call_id = call.getCallId(); JAMI_DBG("[call:%s] Remove local audio", call_id.c_str()); getRingBufferPool().unBindAll(call_id); + call.audioGuard.reset(); } ScheduledExecutor& @@ -1788,7 +1769,7 @@ Manager::playDtmf(char code) return; } - pimpl_->audiodriver_->startStream(); + std::shared_ptr<AudioDeviceGuard> audioGuard = startAudioStream(AudioDeviceType::PLAYBACK); if (not pimpl_->audiodriver_->waitForStart(std::chrono::seconds(1))) { JAMI_ERR("Failed to start audio layer..."); return; @@ -1814,6 +1795,9 @@ Manager::playDtmf(char code) pimpl_->audiodriver_->putUrgent(pimpl_->dtmfBuf_); } + scheduler().scheduleIn([audioGuard] { JAMI_WARN("End of dtmf"); }, + std::chrono::milliseconds(pulselen)); + // TODO Cache the DTMF } @@ -2048,7 +2032,6 @@ Manager::peerHungupCall(Call& call) call.peerHungup(); - checkAudio(); pimpl_->removeWaitingCall(call_id); if (not incomingCallsWaiting()) stopTone(); @@ -2066,7 +2049,6 @@ Manager::callBusy(Call& call) pimpl_->unsetCurrentCall(); } - checkAudio(); pimpl_->removeWaitingCall(call.getCallId()); if (not incomingCallsWaiting()) stopTone(); @@ -2089,7 +2071,6 @@ Manager::callFailure(Call& call) removeParticipant(call_id); } - checkAudio(); pimpl_->removeWaitingCall(call_id); if (not incomingCallsWaiting()) stopTone(); @@ -2106,6 +2087,7 @@ Manager::stopTone() return; pimpl_->toneCtrl_.stop(); + pimpl_->toneDeviceGuard_.reset(); } /** @@ -2151,7 +2133,6 @@ void Manager::playRingtone(const std::string& accountID) { const auto account = getAccount(accountID); - if (!account) { JAMI_WARN("Invalid account in ringtone"); return; @@ -2163,15 +2144,7 @@ Manager::playRingtone(const std::string& accountID) } std::string ringchoice = account->getRingtonePath(); -#if (defined(TARGET_OS_IOS) && TARGET_OS_IOS) - // for ios file located in main buindle - CFBundleRef bundle = CFBundleGetMainBundle(); - CFURLRef bundleURL = CFBundleCopyBundleURL(bundle); - CFStringRef stringPath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle); - CFStringEncoding encodingMethod = CFStringGetSystemEncoding(); - const char* buindlePath = CFStringGetCStringPtr(stringPath, encodingMethod); - ringchoice = std::string(buindlePath) + DIR_SEPARATOR_STR + ringchoice; -#elif !defined(_WIN32) +#if !defined(_WIN32) if (ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos) { // check inside global share directory static const char* const RINGDIR = "ringtones"; @@ -2188,7 +2161,8 @@ Manager::playRingtone(const std::string& accountID) return; } // start audio if not started AND flush all buffers (main and urgent) - pimpl_->audiodriver_->startStream(); + auto oldGuard = std::move(pimpl_->toneDeviceGuard_); + pimpl_->toneDeviceGuard_ = startAudioStream(AudioDeviceType::RINGTONE); pimpl_->toneCtrl_.setSampleRate(pimpl_->audiodriver_->getSampleRate()); } @@ -2214,21 +2188,13 @@ Manager::getTelephoneFile() void Manager::setAudioPlugin(const std::string& audioPlugin) { - std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - - audioPreference.setAlsaPlugin(audioPlugin); - - bool wasStarted = pimpl_->audiodriver_->isStarted(); - + { + std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); + audioPreference.setAlsaPlugin(audioPlugin); + pimpl_->audiodriver_.reset(); + pimpl_->initAudioDriver(); + } // Recreate audio driver with new settings - pimpl_->audiodriver_.reset(); - pimpl_->audiodriver_.reset(audioPreference.createAudioLayer()); - - if (pimpl_->audiodriver_ and wasStarted) - pimpl_->audiodriver_->startStream(); - else - JAMI_ERR("No audio layer created, possibly built without audio support"); - saveConfig(); } @@ -2236,7 +2202,7 @@ Manager::setAudioPlugin(const std::string& audioPlugin) * Set audio output device */ void -Manager::setAudioDevice(int index, DeviceType type) +Manager::setAudioDevice(int index, AudioDeviceType type) { std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); @@ -2249,15 +2215,11 @@ Manager::setAudioDevice(int index, DeviceType type) return; } - const bool wasStarted = pimpl_->audiodriver_->isStarted(); pimpl_->audiodriver_->updatePreference(audioPreference, index, type); // Recreate audio driver with new settings - pimpl_->audiodriver_.reset(audioPreference.createAudioLayer()); - - if (pimpl_->audiodriver_ and wasStarted) - pimpl_->audiodriver_->startStream(); - + pimpl_->audiodriver_.reset(); + pimpl_->initAudioDriver(); saveConfig(); } @@ -2300,23 +2262,50 @@ std::vector<std::string> Manager::getCurrentAudioDevicesIndex() { std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - if (not pimpl_->audiodriver_) { JAMI_ERR("Audio layer not initialized"); return {}; } - std::vector<std::string> v; + return {std::to_string(pimpl_->audiodriver_->getIndexPlayback()), + std::to_string(pimpl_->audiodriver_->getIndexCapture()), + std::to_string(pimpl_->audiodriver_->getIndexRingtone())}; +} - std::stringstream ssi, sso, ssr; - sso << pimpl_->audiodriver_->getIndexPlayback(); - v.push_back(sso.str()); - ssi << pimpl_->audiodriver_->getIndexCapture(); - v.push_back(ssi.str()); - ssr << pimpl_->audiodriver_->getIndexRingtone(); - v.push_back(ssr.str()); +void +Manager::startAudio() +{ + if (!pimpl_->audiodriver_) + pimpl_->audiodriver_.reset(pimpl_->base_.audioPreference.createAudioLayer()); + constexpr std::array<AudioDeviceType, 3> TYPES {AudioDeviceType::CAPTURE, + AudioDeviceType::PLAYBACK, + AudioDeviceType::RINGTONE}; + for (const auto& type : TYPES) + if (pimpl_->audioStreamUsers_[(unsigned) type]) + pimpl_->audiodriver_->startStream(type); - return v; +} + +AudioDeviceGuard::AudioDeviceGuard(Manager& manager, AudioDeviceType type) + : manager_(manager) + , type_(type) +{ + auto streamId = (unsigned) type; + if (streamId >= manager_.pimpl_->audioStreamUsers_.size()) + throw std::invalid_argument("Invalid audio device type"); + if (manager_.pimpl_->audioStreamUsers_[(unsigned) type]++ == 0) { + if (auto layer = manager_.getAudioDriver()) + layer->startStream(type); + } +} + +AudioDeviceGuard::~AudioDeviceGuard() +{ + auto streamId = (unsigned) type_; + if (--manager_.pimpl_->audioStreamUsers_[streamId] == 0) { + if (auto layer = manager_.getAudioDriver()) + layer->stopStream(type_); + } } bool @@ -2416,29 +2405,14 @@ Manager::startRecordedFilePlayback(const std::string& filepath) return false; } - pimpl_->audiodriver_->startStream(); + auto oldGuard = std::move(pimpl_->toneDeviceGuard_); + pimpl_->toneDeviceGuard_ = startAudioStream(AudioDeviceType::RINGTONE); pimpl_->toneCtrl_.setSampleRate(pimpl_->audiodriver_->getSampleRate()); } return pimpl_->toneCtrl_.setAudioFile(filepath); } -bool -Manager::startAudioPlayback() -{ - if (not pimpl_->audiodriver_) { - JAMI_ERR("No audio layer"); - return false; - } - - if (pimpl_->audiodriver_->isStarted()) { - JAMI_DBG("Audio is running"); - return true; - } - pimpl_->audiodriver_->startStream(AudioStreamType::PLAYBACK); - return true; -} - void Manager::recordingPlaybackSeek(const double value) { @@ -2450,8 +2424,8 @@ Manager::stopRecordedFilePlayback() { JAMI_DBG("Stop recorded file playback"); - checkAudio(); pimpl_->toneCtrl_.stopAudioFile(); + pimpl_->toneDeviceGuard_.reset(); } void @@ -2499,13 +2473,9 @@ Manager::setAudioManager(const std::string& api) { std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - - bool wasStarted = pimpl_->audiodriver_->isStarted(); audioPreference.setAudioApi(api); - pimpl_->audiodriver_.reset(audioPreference.createAudioLayer()); - - if (pimpl_->audiodriver_ and wasStarted) - pimpl_->audiodriver_->startStream(); + pimpl_->audiodriver_.reset(); + pimpl_->initAudioDriver(); } saveConfig(); @@ -2530,7 +2500,7 @@ Manager::getAudioInputDeviceIndex(const std::string& name) return 0; } - return pimpl_->audiodriver_->getAudioDeviceIndex(name, DeviceType::CAPTURE); + return pimpl_->audiodriver_->getAudioDeviceIndex(name, AudioDeviceType::CAPTURE); } int @@ -2543,7 +2513,7 @@ Manager::getAudioOutputDeviceIndex(const std::string& name) return 0; } - return pimpl_->audiodriver_->getAudioDeviceIndex(name, DeviceType::PLAYBACK); + return pimpl_->audiodriver_->getAudioDeviceIndex(name, AudioDeviceType::PLAYBACK); } std::string @@ -2580,10 +2550,15 @@ Manager::setAGCState(bool state) * Initialization: Main Thread */ void -Manager::initAudioDriver() +Manager::ManagerPimpl::initAudioDriver() { - std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - pimpl_->audiodriver_.reset(audioPreference.createAudioLayer()); + audiodriver_.reset(base_.audioPreference.createAudioLayer()); + constexpr std::array<AudioDeviceType, 3> TYPES {AudioDeviceType::CAPTURE, + AudioDeviceType::PLAYBACK, + AudioDeviceType::RINGTONE}; + for (const auto& type : TYPES) + if (audioStreamUsers_[(unsigned) type]) + audiodriver_->startStream(type); } AudioFormat @@ -2991,29 +2966,6 @@ Manager::getConferenceId(const std::string& callID) return ""; } -void -Manager::startAudioDriverStream() -{ - std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - if (!pimpl_->audiodriver_) { - JAMI_ERR("Audio driver not initialized"); - return; - } - pimpl_->audiodriver_->startStream(); -} - -void -Manager::restartAudioDriverStream() -{ - std::lock_guard<std::mutex> lock(pimpl_->audioLayerMutex_); - if (!pimpl_->audiodriver_) { - JAMI_ERR("Audio driver not initialized"); - return; - } - pimpl_->audiodriver_->stopStream(); - pimpl_->audiodriver_->startStream(); -} - void Manager::registerAccounts() { diff --git a/src/manager.h b/src/manager.h index bb37c79458c689385b8faccf5195224ad60736b1..24414b362aa7c36c28d542e8b09738e7466fafd6 100644 --- a/src/manager.h +++ b/src/manager.h @@ -137,8 +137,10 @@ public: */ std::shared_ptr<AudioLayer> getAudioDriver(); - void startAudioDriverStream(); - void restartAudioDriverStream(); + inline std::unique_ptr<AudioDeviceGuard> startAudioStream(AudioDeviceType stream) + { + return std::make_unique<AudioDeviceGuard>(*this, stream); + } /** * Functions which occur with a user's action @@ -546,7 +548,9 @@ public: * @param index The index of the soundcard * @param the type of stream, either PLAYBACK, CAPTURE, RINGTONE */ - void setAudioDevice(int index, DeviceType streamType); + void setAudioDevice(int index, AudioDeviceType streamType); + + void startAudio(); /** * Get list of supported audio output device @@ -641,11 +645,6 @@ public: */ bool startRecordedFilePlayback(const std::string&); - /** - * Start audio playback - */ - bool startAudioPlayback(); - void recordingPlaybackSeek(const double value); /** @@ -782,8 +781,6 @@ public: */ bool isCurrentCall(const Call& call) const; - void initAudioDriver(); - /** * Load the accounts order set by the user from the dringrc config file * @return std::vector<std::string> A vector containing the account ID's @@ -874,14 +871,6 @@ public: */ void unregisterAccounts(); - /** - * Suspends audio processing if no calls remain, allowing - * other applications to resume audio. - * See: - * https://projects.savoirfairelinux.com/issues/7037 - */ - void checkAudio(); - /** * Call periodically to poll for VoIP events */ void pollEvents(); @@ -951,11 +940,23 @@ public: private: Manager(); ~Manager(); + friend class AudioDeviceGuard; struct ManagerPimpl; std::unique_ptr<ManagerPimpl> pimpl_; }; +class AudioDeviceGuard +{ +public: + AudioDeviceGuard(Manager& manager, AudioDeviceType type); + ~AudioDeviceGuard(); + +private: + Manager& manager_; + const AudioDeviceType type_; +}; + // Helper to install a callback to be called once by the main event loop template<typename Callback> static void diff --git a/src/media/audio/alsa/alsalayer.cpp b/src/media/audio/alsa/alsalayer.cpp index 749f5a13c2d3ec69373761a45b446a477ed373b6..a0d1d4c031505d575f53b30898e200d9a490f56f 100644 --- a/src/media/audio/alsa/alsalayer.cpp +++ b/src/media/audio/alsa/alsalayer.cpp @@ -231,7 +231,7 @@ AlsaLayer::openDevice(snd_pcm_t** pcm, return true; } -void AlsaLayer::startStream(AudioStreamType) +void AlsaLayer::startStream(AudioDeviceType) { { std::lock_guard<std::mutex> lock(mutex_); @@ -254,7 +254,7 @@ void AlsaLayer::startStream(AudioStreamType) } void -AlsaLayer::stopStream() +AlsaLayer::stopStream(AudioDeviceType stream) { audioThread_.reset(); @@ -674,7 +674,7 @@ AlsaLayer::getAudioDeviceIndexMap(bool getCapture) const } bool -AlsaLayer::soundCardIndexExists(int card, DeviceType stream) +AlsaLayer::soundCardIndexExists(int card, AudioDeviceType stream) { const std::string name("hw:" + std::to_string(card)); @@ -685,17 +685,17 @@ AlsaLayer::soundCardIndexExists(int card, DeviceType stream) snd_pcm_info_t* pcminfo; snd_pcm_info_alloca(&pcminfo); snd_pcm_info_set_stream(pcminfo, - stream == DeviceType::PLAYBACK ? SND_PCM_STREAM_PLAYBACK - : SND_PCM_STREAM_CAPTURE); + stream == AudioDeviceType::PLAYBACK ? SND_PCM_STREAM_PLAYBACK + : SND_PCM_STREAM_CAPTURE); bool ret = snd_ctl_pcm_info(handle, pcminfo) >= 0; snd_ctl_close(handle); return ret; } int -AlsaLayer::getAudioDeviceIndex(const std::string& description, DeviceType type) const +AlsaLayer::getAudioDeviceIndex(const std::string& description, AudioDeviceType type) const { - std::vector<HwIDPair> devices = getAudioDeviceIndexMap(type == DeviceType::CAPTURE); + std::vector<HwIDPair> devices = getAudioDeviceIndexMap(type == AudioDeviceType::CAPTURE); for (const auto& dev : devices) if (dev.second == description) @@ -706,17 +706,17 @@ AlsaLayer::getAudioDeviceIndex(const std::string& description, DeviceType type) } std::string -AlsaLayer::getAudioDeviceName(int index, DeviceType type) const +AlsaLayer::getAudioDeviceName(int index, AudioDeviceType type) const { // a bit ugly and wrong.. i do not know how to implement it better in alsalayer. // in addition, for now it is used in pulselayer only due to alsa and pulse layers api // differences. but after some tweaking in alsalayer, it could be used in it too. switch (type) { - case DeviceType::PLAYBACK: - case DeviceType::RINGTONE: + case AudioDeviceType::PLAYBACK: + case AudioDeviceType::RINGTONE: return getPlaybackDeviceList().at(index); - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: return getCaptureDeviceList().at(index); default: // Should never happen @@ -778,18 +778,18 @@ AlsaLayer::ringtone() } void -AlsaLayer::updatePreference(AudioPreference& preference, int index, DeviceType type) +AlsaLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type) { switch (type) { - case DeviceType::PLAYBACK: + case AudioDeviceType::PLAYBACK: preference.setAlsaCardout(index); break; - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: preference.setAlsaCardin(index); break; - case DeviceType::RINGTONE: + case AudioDeviceType::RINGTONE: preference.setAlsaCardring(index); break; diff --git a/src/media/audio/alsa/alsalayer.h b/src/media/audio/alsa/alsalayer.h index 346c5eda69f4db16623fa6f13e3b197568ac6588..6c468af79d7f0716bddbb9211e56d72b9e6bf9c9 100644 --- a/src/media/audio/alsa/alsalayer.h +++ b/src/media/audio/alsa/alsalayer.h @@ -20,11 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef ALSA_LAYER_H_ -#define ALSA_LAYER_H_ +#pragma once #include "audio/audiolayer.h" #include "noncopyable.h" + #include <alsa/asoundlib.h> #include <memory> @@ -67,14 +67,14 @@ public: * The playback starts accordingly to its threshold * ALSA Library API */ - virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT); + virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL); /** * Stop the playback and capture streams. * Drops the pending frames and put the capture and playback handles to PREPARED state * ALSA Library API */ - virtual void stopStream(); + virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL); /** * Concatenate two strings. Used to build a valid pcm device name. @@ -96,21 +96,21 @@ public: *streaming mode * @param card An index * @param stream The stream mode - * DeviceType::CAPTURE - * DeviceType::PLAYBACK - * DeviceType::RINGTONE + * AudioDeviceType::CAPTURE + * AudioDeviceType::PLAYBACK + * AudioDeviceType::RINGTONE * @return bool True if it exists and supports the mode * false otherwise */ - static bool soundCardIndexExists(int card, DeviceType stream); + static bool soundCardIndexExists(int card, AudioDeviceType stream); /** * An index is associated with its string description * @param description The string description * @return int Its index */ - int getAudioDeviceIndex(const std::string& description, DeviceType type) const; - std::string getAudioDeviceName(int index, DeviceType type) const; + int getAudioDeviceIndex(const std::string& description, AudioDeviceType type) const; + std::string getAudioDeviceName(int index, AudioDeviceType type) const; void playback(); void ringtone(); @@ -206,7 +206,7 @@ private: */ std::unique_ptr<AudioFrame> read(unsigned frames); - virtual void updatePreference(AudioPreference& pref, int index, DeviceType type); + virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type); /** * Handles to manipulate playback stream @@ -250,5 +250,3 @@ private: }; } // namespace jami - -#endif // ALSA_LAYER_H_ diff --git a/src/media/audio/audio_input.cpp b/src/media/audio/audio_input.cpp index 1ff1e682572ff68c52dc7bbc1f16f6645fbb4b67..c5b427342a917b8970d91c53590a422c2b7aeaec 100644 --- a/src/media/audio/audio_input.cpp +++ b/src/media/audio/audio_input.cpp @@ -48,11 +48,16 @@ AudioInput::AudioInput(const std::string& id) frameResized(std::move(f)); })) , fileId_(id + "_file") + , deviceGuard_() , loop_([] { return true; }, [this] { process(); }, [] {}) { JAMI_DBG() << "Creating audio input with id: " << id; - wakeUp_ = std::chrono::high_resolution_clock::now() + MS_PER_PACKET; - loop_.start(); +} + +AudioInput::AudioInput(const std::string& id, const std::string& resource) + : AudioInput(id) +{ + switchInput(resource); } AudioInput::~AudioInput() @@ -66,9 +71,6 @@ AudioInput::~AudioInput() void AudioInput::process() { - // NOTE This is only useful if the device params weren't yet found in switchInput - // For both files and audio devices, this is already done - // foundDevOpts(devOpts_); if (switchPending_.exchange(false)) { if (devOpts_.input.empty()) JAMI_DBG() << "Switching to default audio input"; @@ -108,9 +110,6 @@ AudioInput::setSeekTime(int64_t time) void AudioInput::readFromDevice() { - auto& mainBuffer = Manager::instance().getRingBufferPool(); - auto bufferFormat = mainBuffer.getInternalAudioFormat(); - if (decodingFile_) while (fileBuf_->isEmpty()) readFromFile(); @@ -128,6 +127,7 @@ AudioInput::readFromDevice() std::this_thread::sleep_until(wakeUp_); wakeUp_ += MS_PER_PACKET; + auto& mainBuffer = Manager::instance().getRingBufferPool(); auto samples = mainBuffer.getData(id_); if (not samples) return; @@ -136,7 +136,7 @@ AudioInput::readFromDevice() libav_utils::fillWithSilence(samples->pointer()); std::lock_guard<std::mutex> lk(fmtMutex_); - if (bufferFormat != format_) + if (mainBuffer.getInternalAudioFormat() != format_) samples = resampler_->resample(std::move(samples), format_); resizer_->enqueue(std::move(samples)); } @@ -179,10 +179,13 @@ AudioInput::readFromFile() bool AudioInput::initDevice(const std::string& device) { + JAMI_WARN("AudioInput::initDevice %s", device.c_str()); devOpts_ = {}; devOpts_.input = device; devOpts_.channel = format_.nb_channels; devOpts_.framerate = format_.sample_rate; + deviceGuard_ = Manager::instance().startAudioStream(AudioDeviceType::CAPTURE); + playingDevice_ = true; return true; } @@ -217,8 +220,10 @@ AudioInput::setPaused(bool paused) { if (paused) { Manager::instance().getRingBufferPool().unBindHalfDuplexOut(RingBufferPool::DEFAULT_ID, id_); + deviceGuard_.reset(); } else { Manager::instance().getRingBufferPool().bindHalfDuplexOut(RingBufferPool::DEFAULT_ID, id_); + deviceGuard_ = Manager::instance().startAudioStream(AudioDeviceType::PLAYBACK); } paused_ = paused; } @@ -254,6 +259,7 @@ AudioInput::initFile(const std::string& path) // have file audio mixed into the local buffer so it gets played Manager::instance().getRingBufferPool().bindHalfDuplexOut(RingBufferPool::DEFAULT_ID, fileId_); decodingFile_ = true; + deviceGuard_ = Manager::instance().startAudioStream(AudioDeviceType::PLAYBACK); return true; } @@ -261,7 +267,6 @@ std::shared_future<DeviceParams> AudioInput::switchInput(const std::string& resource) { // Always switch inputs, even if it's the same resource, so audio will be in sync with video - if (switchPending_) { JAMI_ERR() << "Audio switch already requested"; return {}; @@ -269,12 +274,18 @@ AudioInput::switchInput(const std::string& resource) JAMI_DBG() << "Switching audio source to match '" << resource << "'"; + auto oldGuard = std::move(deviceGuard_); + decoder_.reset(); - decodingFile_ = false; - Manager::instance().getRingBufferPool().unBindHalfDuplexOut(id_, fileId_); - Manager::instance().getRingBufferPool().unBindHalfDuplexOut(RingBufferPool::DEFAULT_ID, fileId_); + if (decodingFile_) { + decodingFile_ = false; + Manager::instance().getRingBufferPool().unBindHalfDuplexOut(id_, fileId_); + Manager::instance().getRingBufferPool().unBindHalfDuplexOut(RingBufferPool::DEFAULT_ID, + fileId_); + } fileBuf_.reset(); + playingDevice_ = false; currentResource_ = resource; devOptsFound_ = false; @@ -284,33 +295,31 @@ AudioInput::switchInput(const std::string& resource) if (resource.empty()) { if (initDevice("")) foundDevOpts(devOpts_); - switchPending_ = true; - futureDevOpts_ = foundDevOpts_.get_future(); - return futureDevOpts_; - } - - static const std::string& sep = DRing::Media::VideoProtocolPrefix::SEPARATOR; - - const auto pos = resource.find(sep); - if (pos == std::string::npos) - return {}; - - const auto prefix = resource.substr(0, pos); - if ((pos + sep.size()) >= resource.size()) - return {}; - - const auto suffix = resource.substr(pos + sep.size()); - bool ready = false; - if (prefix == DRing::Media::VideoProtocolPrefix::FILE) - ready = initFile(suffix); - else - ready = initDevice(suffix); + } else { + static const std::string& sep = DRing::Media::VideoProtocolPrefix::SEPARATOR; + const auto pos = resource.find(sep); + if (pos == std::string::npos) + return {}; + + const auto prefix = resource.substr(0, pos); + if ((pos + sep.size()) >= resource.size()) + return {}; + + const auto suffix = resource.substr(pos + sep.size()); + bool ready = false; + if (prefix == DRing::Media::VideoProtocolPrefix::FILE) + ready = initFile(suffix); + else + ready = initDevice(suffix); - if (ready) - foundDevOpts(devOpts_); + if (ready) + foundDevOpts(devOpts_); + } switchPending_ = true; futureDevOpts_ = foundDevOpts_.get_future().share(); + wakeUp_ = std::chrono::high_resolution_clock::now() + MS_PER_PACKET; + loop_.start(); return futureDevOpts_; } @@ -381,8 +390,7 @@ MediaStream AudioInput::getInfo() const { std::lock_guard<std::mutex> lk(fmtMutex_); - auto ms = MediaStream("a:local", format_, sent_samples); - return ms; + return MediaStream("a:local", format_, sent_samples); } MediaStream diff --git a/src/media/audio/audio_input.h b/src/media/audio/audio_input.h index 9fc2170c9a0a1a97eafcdf87ad7a14e257916854..6928213ee201ed45c7a511639a15610cddc69147 100644 --- a/src/media/audio/audio_input.h +++ b/src/media/audio/audio_input.h @@ -33,12 +33,9 @@ #include "threadloop.h" namespace jami { -class MediaDecoder; -class MediaDemuxer; -} // namespace jami -namespace jami { - +class AudioDeviceGuard; class AudioFrameResizer; +class MediaDemuxer; class MediaDecoder; class MediaRecorder; struct MediaStream; @@ -49,9 +46,11 @@ class AudioInput : public Observable<std::shared_ptr<MediaFrame>> { public: AudioInput(const std::string& id); + AudioInput(const std::string& id, const std::string& resource); ~AudioInput(); std::shared_future<DeviceParams> switchInput(const std::string& resource); + void start() { loop_.start(); }; bool isCapturing() const { return loop_.isRunning(); } void setFormat(const AudioFormat& fmt); @@ -76,7 +75,6 @@ private: void frameResized(std::shared_ptr<AudioFrame>&& ptr); std::string id_; - AudioBuffer micData_; bool muteState_ = false; uint64_t sent_samples = 0; mutable std::mutex fmtMutex_ {}; @@ -98,8 +96,11 @@ private: std::shared_future<DeviceParams> futureDevOpts_; std::atomic_bool devOptsFound_ {false}; void foundDevOpts(const DeviceParams& params); + + std::atomic_bool playingDevice_ {false}; std::atomic_bool decodingFile_ {false}; std::atomic_bool playingFile_ {false}; + std::unique_ptr<AudioDeviceGuard> deviceGuard_; ThreadLoop loop_; void process(); diff --git a/src/media/audio/audio_rtp_session.cpp b/src/media/audio/audio_rtp_session.cpp index 7466bc1eb0a830c77e8be92b11f72d13711c53a3..596762c58db829454e9341cfbe0135ef11280491 100644 --- a/src/media/audio/audio_rtp_session.cpp +++ b/src/media/audio/audio_rtp_session.cpp @@ -184,7 +184,9 @@ AudioRtpSession::stop() receiveThread_.reset(); sender_.reset(); socketPair_.reset(); + audioInput_.reset(); } + void AudioRtpSession::setMuted(bool isMuted) { diff --git a/src/media/audio/audio_sender.cpp b/src/media/audio/audio_sender.cpp index fe97eb687a495c53ef27793c950c5cf8a78db428..ffe0735db053be3be20dbd1ee1c891d931bbc158 100644 --- a/src/media/audio/audio_sender.cpp +++ b/src/media/audio/audio_sender.cpp @@ -94,7 +94,6 @@ AudioSender::setup(SocketPair& socketPair) audioInput_ = jami::getAudioInput(id_); audioInput_->setFormat(codec->audioformat); audioInput_->attach(this); - return true; } @@ -103,16 +102,8 @@ AudioSender::update(Observable<std::shared_ptr<jami::MediaFrame>>* /*obs*/, const std::shared_ptr<jami::MediaFrame>& framePtr) { auto frame = framePtr->pointer(); - auto ms = MediaStream("a:local", - frame->format, - rational<int>(1, frame->sample_rate), - frame->sample_rate, - frame->channels, - frame->nb_samples); frame->pts = sent_samples; - ms.firstTimestamp = frame->pts; sent_samples += frame->nb_samples; - if (audioEncoder_->encodeAudio(*std::static_pointer_cast<AudioFrame>(framePtr)) < 0) JAMI_ERR("encoding failed"); } diff --git a/src/media/audio/audiolayer.cpp b/src/media/audio/audiolayer.cpp index b312db227aba926cbac114edf6c750338dcb6e9e..b4ed1e4eb8681512e0afcfc990bab6e5cc0ee365 100644 --- a/src/media/audio/audiolayer.cpp +++ b/src/media/audio/audiolayer.cpp @@ -69,9 +69,11 @@ struct AudioLayer::EchoState { if (playbackQueue.samples() < playbackQueue.frameSize() or recordQueue.samples() < recordQueue.frameSize()) { - /* JAMI_DBG("getRecorded underflow %d / %d, %d / %d", - playbackQueue.samples(), playbackQueue.frameSize(), - recordQueue.samples(), recordQueue.frameSize()); */ + JAMI_DBG("getRecorded underflow %d / %d, %d / %d", + playbackQueue.samples(), + playbackQueue.frameSize(), + recordQueue.samples(), + recordQueue.frameSize()); return {}; } if (recordQueue.samples() > 2 * recordQueue.frameSize() && playbackQueue.samples() == 0) { @@ -79,11 +81,11 @@ struct AudioLayer::EchoState return recordQueue.dequeue(); } while (playbackQueue.samples() > 10 * playbackQueue.frameSize()) { - JAMI_DBG("getRecorded playback underflow"); + JAMI_DBG("getRecorded record underflow"); playbackQueue.dequeue(); } while (recordQueue.samples() > 4 * recordQueue.frameSize()) { - JAMI_DBG("getRecorded record underflow"); + JAMI_DBG("getRecorded playback underflow"); recordQueue.dequeue(); } auto playback = playbackQueue.dequeue(); diff --git a/src/media/audio/audiolayer.h b/src/media/audio/audiolayer.h index 0b37db6921c391f15d081df92651bceb75728ab6..6c34840af2b3f159d8716222394b7362955cb5c1 100644 --- a/src/media/audio/audiolayer.h +++ b/src/media/audio/audiolayer.h @@ -32,6 +32,7 @@ #include <vector> #include <atomic> #include <condition_variable> +#include <array> extern "C" { struct SpeexEchoState_; @@ -60,17 +61,7 @@ namespace jami { class AudioPreference; class Resampler; -enum class DeviceType { - PLAYBACK, /** To open playback device only */ - CAPTURE, /** To open capture device only */ - RINGTONE /** To open the ringtone device only */ -}; - -enum class AudioStreamType { - PLAYBACK, /** To start playback stream only */ - CAPTURE, /** To start capture stream only */ - DEFAULT /** To start both playback and capture streams */ -}; +enum class AudioDeviceType { ALL = -1, PLAYBACK = 0, CAPTURE, RINGTONE }; class AudioLayer { @@ -84,28 +75,26 @@ public: AudioLayer(const AudioPreference&); virtual ~AudioLayer(); - virtual std::vector<std::string> getCaptureDeviceList() const = 0; - virtual std::vector<std::string> getPlaybackDeviceList() const = 0; - - virtual int getAudioDeviceIndex(const std::string& name, DeviceType type) const = 0; - virtual std::string getAudioDeviceName(int index, DeviceType type) const = 0; - virtual int getIndexCapture() const = 0; - virtual int getIndexPlayback() const = 0; - virtual int getIndexRingtone() const = 0; - /** * Start the capture stream and prepare the playback stream. * The playback starts accordingly to its threshold - * ALSA Library API */ - virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT) = 0; + virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL) = 0; /** * Stop the playback and capture streams. * Drops the pending frames and put the capture and playback handles to PREPARED state - * ALSA Library API */ - virtual void stopStream() = 0; + virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL) = 0; + + virtual std::vector<std::string> getCaptureDeviceList() const = 0; + virtual std::vector<std::string> getPlaybackDeviceList() const = 0; + + virtual int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const = 0; + virtual std::string getAudioDeviceName(int index, AudioDeviceType type) const = 0; + virtual int getIndexCapture() const = 0; + virtual int getIndexPlayback() const = 0; + virtual int getIndexRingtone() const = 0; /** * Determine wether or not the audio layer is active (i.e. stream opened) @@ -193,7 +182,7 @@ public: */ void notifyIncomingCall(); - virtual void updatePreference(AudioPreference& pref, int index, DeviceType type) = 0; + virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type) = 0; protected: /** @@ -213,9 +202,7 @@ protected: void setHasNativeAEC(bool hasEAC); std::shared_ptr<AudioFrame> getToPlay(AudioFormat format, size_t writableSamples); - std::shared_ptr<AudioFrame> getToRing(AudioFormat format, size_t writableSamples); - std::shared_ptr<AudioFrame> getPlayback(AudioFormat format, size_t samples) { const auto& ringBuff = getToRing(format, samples); diff --git a/src/media/audio/coreaudio/ios/corelayer.h b/src/media/audio/coreaudio/ios/corelayer.h index 291e2cd1ef358f9a9a5437075d916870f46cedd3..1155f9426181e57eb840ce16dee4c94d2a67d00b 100644 --- a/src/media/audio/coreaudio/ios/corelayer.h +++ b/src/media/audio/coreaudio/ios/corelayer.h @@ -53,8 +53,8 @@ public: virtual std::vector<std::string> getCaptureDeviceList() const; virtual std::vector<std::string> getPlaybackDeviceList() const; - virtual int getAudioDeviceIndex(const std::string& name, DeviceType type) const; - virtual std::string getAudioDeviceName(int index, DeviceType type) const; + virtual int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const; + virtual std::string getAudioDeviceName(int index, AudioDeviceType type) const; /** * Get the index of the audio card for capture @@ -77,7 +77,7 @@ public: /** * Configure the AudioUnit */ - void initAudioLayerIO(AudioStreamType stream); + bool initAudioLayerIO(AudioDeviceType stream); void setupOutputBus(); void setupInputBus(); void bindCallbacks(); @@ -90,7 +90,7 @@ public: * CoreAudio Library API */ - virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT); + virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL); void destroyAudioLayer(); @@ -99,7 +99,7 @@ public: * Drops the pending frames and put the capture and playback handles to PREPARED state * CoreAudio Library API */ - virtual void stopStream(); + virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL); private: NON_COPYABLE(CoreLayer); @@ -132,7 +132,7 @@ private: UInt32 inNumberFrames, AudioBufferList* ioData); - virtual void updatePreference(AudioPreference& pref, int index, DeviceType type); + virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type); /** * Number of audio cards on which capture stream has been opened @@ -160,6 +160,8 @@ private: UInt32 inChannelsPerFrame_; Float64 outSampleRate_; UInt32 outChannelsPerFrame_; + + std::condition_variable readyCv_ {}; }; } // namespace jami diff --git a/src/media/audio/coreaudio/ios/corelayer.mm b/src/media/audio/coreaudio/ios/corelayer.mm index 2188f27e64784935a904dfb81e1afe64ba2fcada..54640bc66da6201ce1642eea7fce4b7207e10ac0 100644 --- a/src/media/audio/coreaudio/ios/corelayer.mm +++ b/src/media/audio/coreaudio/ios/corelayer.mm @@ -71,7 +71,7 @@ CoreLayer::getPlaybackDeviceList() const } int -CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const +CoreLayer::getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const { (void) name; (void) index; @@ -80,15 +80,15 @@ CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const } std::string -CoreLayer::getAudioDeviceName(int index, DeviceType type) const +CoreLayer::getAudioDeviceName(int index, AudioDeviceType type) const { (void) index; (void) type; return ""; } -void -CoreLayer::initAudioLayerIO(AudioStreamType stream) +bool +CoreLayer::initAudioLayerIO(AudioDeviceType stream) { JAMI_DBG("iOS CoreLayer - initializing audio session"); @@ -102,22 +102,25 @@ CoreLayer::initAudioLayerIO(AudioStreamType stream) auto comp = AudioComponentFindNext(nullptr, &outputUnitDescription); if (comp == nullptr) { JAMI_ERR("Can't find default output audio component."); - return; + return false; } checkErr(AudioComponentInstanceNew(comp, &ioUnit_)); - bool setUpOutput = stream == AudioStreamType::DEFAULT || stream == AudioStreamType::PLAYBACK; - bool setUpInput = stream == AudioStreamType::DEFAULT || stream == AudioStreamType::CAPTURE; + + bool setUpInput = stream == AudioDeviceType::ALL || stream == AudioDeviceType::CAPTURE; NSError* error = nil; AVAudioSessionCategory audioCategory = setUpInput ? AVAudioSessionCategoryPlayAndRecord : AVAudioSessionCategoryPlayback; AVAudioSessionMode mode = setUpInput ? AVAudioSessionModeVoiceChat : AVAudioSessionModeMoviePlayback; - [[AVAudioSession sharedInstance] setCategory:audioCategory mode: mode options:AVAudioSessionCategoryOptionAllowBluetooth error:&error]; + AVAudioSessionCategoryOptions options = setUpInput ? AVAudioSessionCategoryOptionAllowBluetooth : AVAudioSessionCategoryOptionMixWithOthers; + [[AVAudioSession sharedInstance] setCategory:audioCategory mode: mode options:options error:&error]; if (error) { - JAMI_DBG("***Initializing audio session failed"); + NSLog(@"Initializing audio session failed, %@",[error localizedDescription]); + return false; } [[AVAudioSession sharedInstance] setActive: true withOptions: AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error: &error]; if (error) { - JAMI_DBG("***set active audio session failed"); + NSLog(@"Set active audio session failed, %@",[error localizedDescription]); + return false; } auto playBackDeviceList = getPlaybackDeviceList(); JAMI_DBG("Setting playback device: %s", playBackDeviceList[indexOut_].c_str()); @@ -135,13 +138,12 @@ CoreLayer::initAudioLayerIO(AudioStreamType stream) break; } - if (setUpOutput) { - setupOutputBus(); - } + setupOutputBus(); if (setUpInput) { setupInputBus(); } bindCallbacks(); + return true; } void @@ -309,32 +311,35 @@ CoreLayer::bindCallbacks() { inputBus, &inputCall, sizeof(AURenderCallbackStruct))); + } void -CoreLayer::startStream(AudioStreamType stream) +CoreLayer::startStream(AudioDeviceType stream) { + std::lock_guard<std::mutex> lock(mutex_); JAMI_DBG("iOS CoreLayer - Start Stream"); + auto currentCategoty = [[AVAudioSession sharedInstance] category]; - { - std::lock_guard<std::mutex> lock(mutex_); - if (status_ != Status::Idle) + bool updateStream = currentCategoty == AVAudioSessionCategoryPlayback && (stream == AudioDeviceType::CAPTURE || stream == AudioDeviceType::ALL); + if (status_ == Status::Started) { + if (updateStream) + destroyAudioLayer(); + else return; - status_ = Status::Started; } + status_ = Status::Started; dcblocker_.reset(); - - initAudioLayerIO(stream); - - // Run - auto inputRes = AudioUnitInitialize(ioUnit_); - auto outputRes = AudioOutputUnitStart(ioUnit_); - if(inputRes || outputRes) { - stopStream(); - checkErr(inputRes); - checkErr(outputRes); + if (initAudioLayerIO(stream)) { + auto inputRes = AudioUnitInitialize(ioUnit_); + auto outputRes = AudioOutputUnitStart(ioUnit_); + if (!inputRes && !outputRes) { + return; + } } + destroyAudioLayer(); + status_ = Status::Idle; } void @@ -347,19 +352,17 @@ CoreLayer::destroyAudioLayer() } void -CoreLayer::stopStream() +CoreLayer::stopStream(AudioDeviceType stream) { JAMI_DBG("iOS CoreLayer - Stop Stream"); - { std::lock_guard<std::mutex> lock(mutex_); if (status_ != Status::Started) return; status_ = Status::Idle; + destroyAudioLayer(); } - destroyAudioLayer(); - /* Flush the ring buffers */ flushUrgent(); flushMain(); @@ -450,18 +453,19 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags, putRecorded(std::move(inBuff)); } -void CoreLayer::updatePreference(AudioPreference &preference, int index, DeviceType type) +void CoreLayer::updatePreference(AudioPreference &preference, int index, AudioDeviceType type) { switch (type) { - case DeviceType::PLAYBACK: + case AudioDeviceType::ALL: + case AudioDeviceType::PLAYBACK: preference.setAlsaCardout(index); break; - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: preference.setAlsaCardin(index); break; - case DeviceType::RINGTONE: + case AudioDeviceType::RINGTONE: preference.setAlsaCardring(index); break; diff --git a/src/media/audio/coreaudio/osx/corelayer.cpp b/src/media/audio/coreaudio/osx/corelayer.cpp index 4e917285a30724ac692e0fdf268d8bad5e1a83b9..823f516ec07ff59dc836fb2f4de77cc3bde00599 100644 --- a/src/media/audio/coreaudio/osx/corelayer.cpp +++ b/src/media/audio/coreaudio/osx/corelayer.cpp @@ -68,10 +68,10 @@ CoreLayer::getPlaybackDeviceList() const } int -CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const +CoreLayer::getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const { int i = 0; - for (const auto& device : getDeviceList(type == DeviceType::CAPTURE)) { + for (const auto& device : getDeviceList(type == AudioDeviceType::CAPTURE)) { if (device.name_ == name) return i; i++; @@ -80,13 +80,13 @@ CoreLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const } std::string -CoreLayer::getAudioDeviceName(int index, DeviceType type) const +CoreLayer::getAudioDeviceName(int index, AudioDeviceType type) const { return ""; } void -CoreLayer::initAudioLayerIO() +CoreLayer::initAudioLayerIO(AudioDeviceType stream) { // OS X uses Audio Units for output. Steps: // 1) Create a description. @@ -120,7 +120,11 @@ CoreLayer::initAudioLayerIO() return; } - checkErr(AudioComponentInstanceNew(comp, &ioUnit_)); + auto initError = AudioComponentInstanceNew(comp, &ioUnit_); + if (initError) { + checkErr(initError); + return; + } // set capture device UInt32 size = sizeof(inputDeviceID); @@ -288,7 +292,7 @@ CoreLayer::initAudioLayerIO() } void -CoreLayer::startStream(AudioStreamType stream) +CoreLayer::startStream(AudioDeviceType stream) { JAMI_DBG("START STREAM"); @@ -297,15 +301,18 @@ CoreLayer::startStream(AudioStreamType stream) if (status_ != Status::Idle) return; status_ = Status::Started; - } - dcblocker_.reset(); + dcblocker_.reset(); - initAudioLayerIO(); + initAudioLayerIO(stream); - // Run - checkErr(AudioUnitInitialize(ioUnit_)); - checkErr(AudioOutputUnitStart(ioUnit_)); + auto inputRes = AudioUnitInitialize(ioUnit_); + auto outputRes = AudioOutputUnitStart(ioUnit_); + if (!inputRes && !outputRes) { + return; + } + } + stopStream(); } void @@ -317,19 +324,17 @@ CoreLayer::destroyAudioLayer() } void -CoreLayer::stopStream() +CoreLayer::stopStream(AudioDeviceType stream) { JAMI_DBG("STOP STREAM"); - { std::lock_guard<std::mutex> lock(mutex_); if (status_ != Status::Started) return; status_ = Status::Idle; + destroyAudioLayer(); } - destroyAudioLayer(); - /* Flush the ring buffers */ flushUrgent(); flushMain(); @@ -441,18 +446,19 @@ CoreLayer::read(AudioUnitRenderActionFlags* ioActionFlags, } void -CoreLayer::updatePreference(AudioPreference& preference, int index, DeviceType type) +CoreLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type) { switch (type) { - case DeviceType::PLAYBACK: + case AudioDeviceType::ALL: + case AudioDeviceType::PLAYBACK: preference.setAlsaCardout(index); break; - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: preference.setAlsaCardin(index); break; - case DeviceType::RINGTONE: + case AudioDeviceType::RINGTONE: preference.setAlsaCardring(index); break; diff --git a/src/media/audio/coreaudio/osx/corelayer.h b/src/media/audio/coreaudio/osx/corelayer.h index d3668ab42f8fff735c7462d1f82b25b7de612d6c..8409a49f1d61622bf9da860858be2ee50301ea48 100644 --- a/src/media/audio/coreaudio/osx/corelayer.h +++ b/src/media/audio/coreaudio/osx/corelayer.h @@ -57,8 +57,8 @@ public: virtual std::vector<std::string> getCaptureDeviceList() const; virtual std::vector<std::string> getPlaybackDeviceList() const; - virtual int getAudioDeviceIndex(const std::string& name, DeviceType type) const; - virtual std::string getAudioDeviceName(int index, DeviceType type) const; + virtual int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const; + virtual std::string getAudioDeviceName(int index, AudioDeviceType type) const; /** * Get the index of the audio card for capture @@ -81,7 +81,7 @@ public: /** * Configure the AudioUnit */ - void initAudioLayerIO(); + void initAudioLayerIO(AudioDeviceType stream); /** * Start the capture stream and prepare the playback stream. @@ -89,7 +89,7 @@ public: * CoreAudio Library API */ - virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT); + virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL); void destroyAudioLayer(); @@ -98,7 +98,7 @@ public: * Drops the pending frames and put the capture and playback handles to PREPARED state * CoreAudio Library API */ - virtual void stopStream(); + virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL); private: NON_COPYABLE(CoreLayer); @@ -135,7 +135,7 @@ private: UInt32 inNumberFrames, AudioBufferList* ioData); - virtual void updatePreference(AudioPreference& pref, int index, DeviceType type); + virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type); /** * Number of audio cards on which capture stream has been opened diff --git a/src/media/audio/jack/jacklayer.cpp b/src/media/audio/jack/jacklayer.cpp index 03735a04bde9a65445d8fe96d4756f3dad8e43e0..5225afff5ef22b97aa401d7af7f8b07f4368c88d 100644 --- a/src/media/audio/jack/jacklayer.cpp +++ b/src/media/audio/jack/jacklayer.cpp @@ -269,7 +269,7 @@ JackLayer::~JackLayer() } void -JackLayer::updatePreference(AudioPreference& /*pref*/, int /*index*/, DeviceType /*type*/) +JackLayer::updatePreference(AudioPreference& /*pref*/, int /*index*/, AudioDeviceType /*type*/) {} std::vector<std::string> @@ -285,13 +285,13 @@ JackLayer::getPlaybackDeviceList() const } int -JackLayer::getAudioDeviceIndex(const std::string& /*name*/, DeviceType /*type*/) const +JackLayer::getAudioDeviceIndex(const std::string& /*name*/, AudioDeviceType /*type*/) const { return 0; } std::string -JackLayer::getAudioDeviceName(int /*index*/, DeviceType /*type*/) const +JackLayer::getAudioDeviceName(int /*index*/, AudioDeviceType /*type*/) const { return ""; } @@ -377,7 +377,7 @@ JackLayer::process_playback(jack_nframes_t frames, void* arg) /** * Start the capture and playback. */ -void JackLayer::startStream(AudioStreamType) +void JackLayer::startStream(AudioDeviceType) { { std::lock_guard<std::mutex> lock(mutex_); @@ -406,8 +406,7 @@ JackLayer::onShutdown(void* /* data */) /** * Stop playback and capture. */ -void -JackLayer::stopStream() +void JackLayer::stopStream(AudioDeviceType) { { std::lock_guard<std::mutex> lock(mutex_); diff --git a/src/media/audio/jack/jacklayer.h b/src/media/audio/jack/jacklayer.h index 1eef9123fc6ba61ed9b14494e905c29aea8640ab..30ee9ae48b524d3dbd3539e7ab3b3a552757aa87 100644 --- a/src/media/audio/jack/jacklayer.h +++ b/src/media/audio/jack/jacklayer.h @@ -65,22 +65,22 @@ private: std::vector<std::string> getCaptureDeviceList() const; std::vector<std::string> getPlaybackDeviceList() const; - int getAudioDeviceIndex(const std::string& name, DeviceType type) const; - std::string getAudioDeviceName(int index, DeviceType type) const; + int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const; + std::string getAudioDeviceName(int index, AudioDeviceType type) const; int getIndexCapture() const; int getIndexPlayback() const; int getIndexRingtone() const; - void updatePreference(AudioPreference& pref, int index, DeviceType type); + void updatePreference(AudioPreference& pref, int index, AudioDeviceType type); /** * Start the capture and playback. */ - void startStream(AudioStreamType stream = AudioStreamType::DEFAULT); + void startStream(AudioDeviceType stream = AudioDeviceType::ALL); /** * Stop playback and capture. */ - void stopStream(); + void stopStream(AudioDeviceType stream = AudioDeviceType::ALL); static void onShutdown(void* data); diff --git a/src/media/audio/opensl/opensllayer.cpp b/src/media/audio/opensl/opensllayer.cpp index 5ee20853313114da33a231f8cfa5c8e3e5c27dde..efb2fb040fd5b7eb135852430c70216d7836cd06 100644 --- a/src/media/audio/opensl/opensllayer.cpp +++ b/src/media/audio/opensl/opensllayer.cpp @@ -43,7 +43,9 @@ namespace jami { // Constructor OpenSLLayer::OpenSLLayer(const AudioPreference& pref) : AudioLayer(pref) -{} +{ + initAudioEngine(); +} // Destructor OpenSLLayer::~OpenSLLayer() @@ -52,61 +54,84 @@ OpenSLLayer::~OpenSLLayer() } void -OpenSLLayer::init() -{ - initAudioEngine(); - initAudioPlayback(); - initAudioCapture(); - - flush(); -} - -void -OpenSLLayer::startStream(AudioStreamType stream) +OpenSLLayer::startStream(AudioDeviceType stream) { + using namespace std::placeholders; std::lock_guard<std::mutex> lock(mutex_); - if (status_ != Status::Idle) - return; - status_ = Status::Starting; JAMI_WARN("Start OpenSL audio layer"); - - init(); - startAudioPlayback(); - startAudioCapture(); + if (stream == AudioDeviceType::PLAYBACK) { + if (not player_) { + try { + player_.reset(new opensl::AudioPlayer(hardwareFormat_, + hardwareBuffSize_, + engineInterface_, + SL_ANDROID_STREAM_VOICE)); + player_->setBufQueue(&playBufQueue_, &freePlayBufQueue_); + player_->registerCallback(std::bind(&OpenSLLayer::engineServicePlay, this)); + player_->start(); + } catch (const std::exception& e) { + JAMI_ERR("Error initializing audio playback: %s", e.what()); + } + if (recorder_) + startAudioCapture(); + } + } else if (stream == AudioDeviceType::RINGTONE) { + if (not ringtone_) { + try { + ringtone_.reset(new opensl::AudioPlayer(hardwareFormat_, + hardwareBuffSize_, + engineInterface_, + SL_ANDROID_STREAM_VOICE)); + ringtone_->setBufQueue(&ringBufQueue_, &freeRingBufQueue_); + ringtone_->registerCallback(std::bind(&OpenSLLayer::engineServiceRing, this)); + ringtone_->start(); + } catch (const std::exception& e) { + JAMI_ERR("Error initializing ringtone playback: %s", e.what()); + } + } + } else if (stream == AudioDeviceType::CAPTURE) { + if (not recorder_) { + std::lock_guard<std::mutex> lck(recMtx); + try { + recorder_.reset(new opensl::AudioRecorder(hardwareFormat_, engineInterface_)); + recorder_->setBufQueues(&freeRecBufQueue_, &recBufQueue_); + recorder_->registerCallback(std::bind(&OpenSLLayer::engineServiceRec, this)); + setHasNativeAEC(recorder_->hasNativeAEC()); + } catch (const std::exception& e) { + JAMI_ERR("Error initializing audio capture: %s", e.what()); + } + if (player_) + startAudioCapture(); + } + } JAMI_WARN("OpenSL audio layer started"); status_ = Status::Started; - startedCv_.notify_all(); } void -OpenSLLayer::stopStream() +OpenSLLayer::stopStream(AudioDeviceType stream) { std::unique_lock<std::mutex> lock(mutex_); - startedCv_.wait(lock, [this] { return status_ != Status::Starting; }); - if (status_ != Status::Started) - return; - status_ = Status::Idle; - JAMI_WARN("Stopping OpenSL audio layer"); - - stopAudioPlayback(); - stopAudioCapture(); - flush(); + JAMI_WARN("Stopping OpenSL audio layer for type %u", (unsigned) stream); - if (engineObject_ != nullptr) { - (*engineObject_)->Destroy(engineObject_); - engineObject_ = nullptr; - engineInterface_ = nullptr; + if (stream == AudioDeviceType::PLAYBACK) { + if (player_) { + player_->stop(); + player_.reset(); + } + } else if (stream == AudioDeviceType::RINGTONE) { + if (ringtone_) { + ringtone_->stop(); + ringtone_.reset(); + } + } else if (stream == AudioDeviceType::CAPTURE) { + stopAudioCapture(); } - freePlayBufQueue_.clear(); - freeRingBufQueue_.clear(); - playBufQueue_.clear(); - ringBufQueue_.clear(); - freeRecBufQueue_.clear(); - recBufQueue_.clear(); - bufs_.clear(); - dcblocker_.reset(); - startedCv_.notify_all(); + if (not player_ and not ringtone_ and not recorder_) + status_ = Status::Idle; + + flush(); } std::vector<sample_buf> @@ -149,9 +174,33 @@ OpenSLLayer::initAudioEngine() void OpenSLLayer::shutdownAudioEngine() { + stopAudioCapture(); + freeRecBufQueue_.clear(); + recBufQueue_.clear(); + + if (player_) { + player_->stop(); + player_.reset(); + } + if (ringtone_) { + ringtone_->stop(); + ringtone_.reset(); + } + freePlayBufQueue_.clear(); + playBufQueue_.clear(); + freeRingBufQueue_.clear(); + ringBufQueue_.clear(); + // destroy engine object, and invalidate all associated interfaces JAMI_DBG("Shutdown audio engine"); - stopStream(); + if (engineObject_ != nullptr) { + (*engineObject_)->Destroy(engineObject_); + engineObject_ = nullptr; + engineInterface_ = nullptr; + } + + startedCv_.notify_all(); + bufs_.clear(); } uint32_t @@ -235,34 +284,6 @@ OpenSLLayer::engineServiceRec() return; } -void -OpenSLLayer::initAudioPlayback() -{ - using namespace std::placeholders; - try { - player_.reset(new opensl::AudioPlayer(hardwareFormat_, - hardwareBuffSize_, - engineInterface_, - SL_ANDROID_STREAM_VOICE)); - player_->setBufQueue(&playBufQueue_, &freePlayBufQueue_); - player_->registerCallback(std::bind(&OpenSLLayer::engineServicePlay, this)); - } catch (const std::exception& e) { - JAMI_ERR("Error initializing audio playback: %s", e.what()); - return; - } - - try { - ringtone_.reset(new opensl::AudioPlayer(hardwareFormat_, - hardwareBuffSize_, - engineInterface_, - SL_ANDROID_STREAM_VOICE)); - ringtone_->setBufQueue(&ringBufQueue_, &freeRingBufQueue_); - ringtone_->registerCallback(std::bind(&OpenSLLayer::engineServiceRing, this)); - } catch (const std::exception& e) { - JAMI_ERR("Error initializing ringtone playback: %s", e.what()); - } -} - void OpenSLLayer::initAudioCapture() { @@ -278,20 +299,6 @@ OpenSLLayer::initAudioCapture() } } -void -OpenSLLayer::startAudioPlayback() -{ - if (not player_ and not ringtone_) - return; - JAMI_WARN("Start audio playback"); - playbackChanged(true); - if (player_) - player_->start(); - if (ringtone_) - ringtone_->start(); - JAMI_WARN("Audio playback started"); -} - void OpenSLLayer::startAudioCapture() { @@ -299,10 +306,13 @@ OpenSLLayer::startAudioCapture() return; JAMI_DBG("Start audio capture"); - recorder_->start(); + if (recThread.joinable()) + return; recThread = std::thread([&]() { - recordChanged(true); std::unique_lock<std::mutex> lck(recMtx); + if (recorder_) + recorder_->start(); + recordChanged(true); while (recorder_) { recCv.wait_for(lck, std::chrono::seconds(1)); if (not recorder_) @@ -331,23 +341,6 @@ OpenSLLayer::startAudioCapture() JAMI_DBG("Audio capture started"); } -void -OpenSLLayer::stopAudioPlayback() -{ - JAMI_DBG("Stop audio playback"); - playbackChanged(false); - if (player_) { - player_->stop(); - player_.reset(); - } - if (ringtone_) { - ringtone_->stop(); - ringtone_.reset(); - } - - JAMI_DBG("Audio playback stopped"); -} - void OpenSLLayer::stopAudioCapture() { @@ -360,8 +353,8 @@ OpenSLLayer::stopAudioCapture() recorder_.reset(); } } - recCv.notify_all(); if (recThread.joinable()) { + recCv.notify_all(); recThread.join(); } @@ -442,7 +435,9 @@ OpenSLLayer::getPlaybackDeviceList() const } void -OpenSLLayer::updatePreference(AudioPreference& /*preference*/, int /*index*/, DeviceType /*type*/) +OpenSLLayer::updatePreference(AudioPreference& /*preference*/, + int /*index*/, + AudioDeviceType /*type*/) {} void diff --git a/src/media/audio/opensl/opensllayer.h b/src/media/audio/opensl/opensllayer.h index 6c1a2d5bb58a924358ee78287207210a30376ca6..71a3579cca4728608af58fdf4913d4e3a19ca245 100644 --- a/src/media/audio/opensl/opensllayer.h +++ b/src/media/audio/opensl/opensllayer.h @@ -68,47 +68,38 @@ public: * Start the capture stream and prepare the playback stream. * The playback starts accordingly to its threshold */ - virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT); + void startStream(AudioDeviceType stream = AudioDeviceType::ALL) override; /** * Stop the playback and capture streams. * Drops the pending frames and put the capture and playback handles to PREPARED state */ - virtual void stopStream(); + void stopStream(AudioDeviceType stream = AudioDeviceType::ALL) override; /** * Scan the sound card available for capture on the system * @return std::vector<std::string> The vector containing the string description of the card */ - virtual std::vector<std::string> getCaptureDeviceList() const; + std::vector<std::string> getCaptureDeviceList() const override; /** * Scan the sound card available for capture on the system * @return std::vector<std::string> The vector containing the string description of the card */ - virtual std::vector<std::string> getPlaybackDeviceList() const; + std::vector<std::string> getPlaybackDeviceList() const override; void init(); void initAudioEngine(); - void shutdownAudioEngine(); - void initAudioPlayback(); - void initAudioCapture(); - - void startAudioPlayback(); - void startAudioCapture(); - - void stopAudioPlayback(); - void stopAudioCapture(); - virtual int getAudioDeviceIndex(const std::string&, DeviceType) const { return 0; } + virtual int getAudioDeviceIndex(const std::string&, AudioDeviceType) const { return 0; } - virtual std::string getAudioDeviceName(int, DeviceType) const { return ""; } + virtual std::string getAudioDeviceName(int, AudioDeviceType) const { return ""; } void engineServicePlay(); void engineServiceRing(); @@ -142,7 +133,10 @@ private: NON_COPYABLE(OpenSLLayer); - virtual void updatePreference(AudioPreference& pref, int index, DeviceType type); + virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type); + + std::mutex recMtx {}; + std::condition_variable recCv {}; /** * OpenSL standard object interface @@ -154,9 +148,8 @@ private: */ SLEngineItf engineInterface_ {nullptr}; - std::unique_ptr<opensl::AudioPlayer> player_ {}; - std::unique_ptr<opensl::AudioPlayer> ringtone_ {}; - std::unique_ptr<opensl::AudioRecorder> recorder_ {}; + AudioFormat hardwareFormat_ {AudioFormat::MONO()}; + size_t hardwareBuffSize_ {BUFFER_SIZE}; AudioQueue freePlayBufQueue_ {BUF_COUNT}; AudioQueue playBufQueue_ {BUF_COUNT}; @@ -167,14 +160,13 @@ private: AudioQueue freeRecBufQueue_ {BUF_COUNT}; // Owner of the queue AudioQueue recBufQueue_ {BUF_COUNT}; // Owner of the queue - std::mutex recMtx {}; - std::condition_variable recCv {}; - std::thread recThread {}; - std::vector<sample_buf> bufs_ {}; - AudioFormat hardwareFormat_ {AudioFormat::MONO()}; - size_t hardwareBuffSize_ {BUFFER_SIZE}; + std::unique_ptr<opensl::AudioPlayer> player_ {}; + std::unique_ptr<opensl::AudioPlayer> ringtone_ {}; + std::unique_ptr<opensl::AudioRecorder> recorder_ {}; + + std::thread recThread {}; }; } // namespace jami diff --git a/src/media/audio/portaudio/portaudiolayer.cpp b/src/media/audio/portaudio/portaudiolayer.cpp index e2b44c78920e935c6efbce4651e3b0d16a7ac278..8b61f2455330b9bac575197043dfa6f8f16fd54e 100644 --- a/src/media/audio/portaudio/portaudiolayer.cpp +++ b/src/media/audio/portaudio/portaudiolayer.cpp @@ -45,9 +45,9 @@ struct PortAudioLayer::PortAudioLayerImpl void terminate() const; void initStream(PortAudioLayer&); - std::vector<std::string> getDeviceByType(DeviceType type) const; - int getIndexByType(DeviceType type); - int getInternalIndexByType(const int index, DeviceType type); + std::vector<std::string> getDeviceByType(AudioDeviceType type) const; + int getIndexByType(AudioDeviceType type); + int getInternalIndexByType(const int index, AudioDeviceType type); PaDeviceIndex indexIn_; PaDeviceIndex indexOut_; @@ -94,17 +94,17 @@ PortAudioLayer::~PortAudioLayer() std::vector<std::string> PortAudioLayer::getCaptureDeviceList() const { - return pimpl_->getDeviceByType(DeviceType::CAPTURE); + return pimpl_->getDeviceByType(AudioDeviceType::CAPTURE); } std::vector<std::string> PortAudioLayer::getPlaybackDeviceList() const { - return pimpl_->getDeviceByType(DeviceType::PLAYBACK); + return pimpl_->getDeviceByType(AudioDeviceType::PLAYBACK); } int -PortAudioLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) const +PortAudioLayer::getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const { auto deviceList = pimpl_->getDeviceByType(type); @@ -124,7 +124,7 @@ PortAudioLayer::getAudioDeviceIndex(const std::string& name, DeviceType type) co } std::string -PortAudioLayer::getAudioDeviceName(int index, DeviceType type) const +PortAudioLayer::getAudioDeviceName(int index, AudioDeviceType type) const { (void) type; const PaDeviceInfo* deviceInfo; @@ -135,24 +135,24 @@ PortAudioLayer::getAudioDeviceName(int index, DeviceType type) const int PortAudioLayer::getIndexCapture() const { - return pimpl_->getIndexByType(DeviceType::CAPTURE); + return pimpl_->getIndexByType(AudioDeviceType::CAPTURE); } int PortAudioLayer::getIndexPlayback() const { - auto index = pimpl_->getIndexByType(DeviceType::PLAYBACK); + auto index = pimpl_->getIndexByType(AudioDeviceType::PLAYBACK); return index; } int PortAudioLayer::getIndexRingtone() const { - return pimpl_->getIndexByType(DeviceType::RINGTONE); + return pimpl_->getIndexByType(AudioDeviceType::RINGTONE); } void -PortAudioLayer::startStream(AudioStreamType stream) +PortAudioLayer::startStream(AudioDeviceType stream) { { std::lock_guard<std::mutex> lock(mutex_); @@ -167,7 +167,7 @@ PortAudioLayer::startStream(AudioStreamType stream) } void -PortAudioLayer::stopStream() +PortAudioLayer::stopStream(AudioDeviceType stream) { if (status_ != Status::Started) return; @@ -198,17 +198,17 @@ PortAudioLayer::stopStream() } void -PortAudioLayer::updatePreference(AudioPreference& preference, int index, DeviceType type) +PortAudioLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type) { auto internalIndex = pimpl_->getInternalIndexByType(index, type); switch (type) { - case DeviceType::PLAYBACK: + case AudioDeviceType::PLAYBACK: preference.setAlsaCardout(internalIndex); break; - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: preference.setAlsaCardin(internalIndex); break; - case DeviceType::RINGTONE: + case AudioDeviceType::RINGTONE: preference.setAlsaCardring(internalIndex); break; default: @@ -234,7 +234,7 @@ PortAudioLayer::PortAudioLayerImpl::~PortAudioLayerImpl() } std::vector<std::string> -PortAudioLayer::PortAudioLayerImpl::getDeviceByType(DeviceType type) const +PortAudioLayer::PortAudioLayerImpl::getDeviceByType(AudioDeviceType type) const { std::vector<std::string> ret; int numDevices = 0; @@ -245,7 +245,7 @@ PortAudioLayer::PortAudioLayerImpl::getDeviceByType(DeviceType type) const else { for (int i = 0; i < numDevices; i++) { const auto deviceInfo = Pa_GetDeviceInfo(i); - if (type == DeviceType::PLAYBACK) { + if (type == AudioDeviceType::PLAYBACK) { if (deviceInfo->maxOutputChannels > 0) ret.push_back(deviceInfo->name); } else { @@ -304,12 +304,12 @@ PortAudioLayer::PortAudioLayerImpl::init(PortAudioLayer& parent) } int -PortAudioLayer::PortAudioLayerImpl::getIndexByType(DeviceType type) +PortAudioLayer::PortAudioLayerImpl::getIndexByType(AudioDeviceType type) { int index = indexRing_; - if (type == DeviceType::PLAYBACK) { + if (type == AudioDeviceType::PLAYBACK) { index = indexOut_; - } else if (type == DeviceType::CAPTURE) { + } else if (type == AudioDeviceType::CAPTURE) { index = indexIn_; } @@ -334,7 +334,7 @@ PortAudioLayer::PortAudioLayerImpl::getIndexByType(DeviceType type) } int -PortAudioLayer::PortAudioLayerImpl::getInternalIndexByType(const int index, DeviceType type) +PortAudioLayer::PortAudioLayerImpl::getInternalIndexByType(const int index, AudioDeviceType type) { auto deviceList = getDeviceByType(type); if (!deviceList.size() || index >= deviceList.size()) { diff --git a/src/media/audio/portaudio/portaudiolayer.h b/src/media/audio/portaudio/portaudiolayer.h index 78eb0cf7b8d63238f475ed25c62d620cbed419a1..6a24a9dfff082b5e816057cfde53ea83cca0638c 100644 --- a/src/media/audio/portaudio/portaudiolayer.h +++ b/src/media/audio/portaudio/portaudiolayer.h @@ -29,7 +29,7 @@ namespace jami { -class PortAudioLayer : public AudioLayer +class PortAudioLayer final : public AudioLayer { public: PortAudioLayer(const AudioPreference& pref); @@ -37,8 +37,8 @@ public: std::vector<std::string> getCaptureDeviceList() const override; std::vector<std::string> getPlaybackDeviceList() const override; - int getAudioDeviceIndex(const std::string& name, DeviceType type) const override; - std::string getAudioDeviceName(int index, DeviceType type) const override; + int getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const override; + std::string getAudioDeviceName(int index, AudioDeviceType type) const override; int getIndexCapture() const override; int getIndexPlayback() const override; int getIndexRingtone() const override; @@ -47,15 +47,15 @@ public: * Start the capture stream and prepare the playback stream. * The playback starts accordingly to its threshold */ - void startStream(AudioStreamType stream = AudioStreamType::DEFAULT) override; + void startStream(AudioDeviceType stream = AudioDeviceType::ALL) override; /** * Stop the playback and capture streams. * Drops the pending frames and put the capture and playback handles to PREPARED state */ - void stopStream() override; + void stopStream(AudioDeviceType stream = AudioDeviceType::ALL) override; - void updatePreference(AudioPreference& pref, int index, DeviceType type) override; + void updatePreference(AudioPreference& pref, int index, AudioDeviceType type) override; private: NON_COPYABLE(PortAudioLayer); diff --git a/src/media/audio/pulseaudio/pulselayer.cpp b/src/media/audio/pulseaudio/pulselayer.cpp index 35a8cc5cdd67d65891bcc8ef0f4f5abb9765b277..b54fa3113077e27eab9a324f0161ec8bd519a667 100644 --- a/src/media/audio/pulseaudio/pulselayer.cpp +++ b/src/media/audio/pulseaudio/pulselayer.cpp @@ -254,16 +254,16 @@ PulseLayer::getPlaybackDeviceList() const } int -PulseLayer::getAudioDeviceIndex(const std::string& descr, DeviceType type) const +PulseLayer::getAudioDeviceIndex(const std::string& descr, AudioDeviceType type) const { switch (type) { - case DeviceType::PLAYBACK: - case DeviceType::RINGTONE: + case AudioDeviceType::PLAYBACK: + case AudioDeviceType::RINGTONE: return std::distance(sinkList_.begin(), std::find_if(sinkList_.begin(), sinkList_.end(), PaDeviceInfos::DescriptionComparator(descr))); - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: return std::distance(sourceList_.begin(), std::find_if(sourceList_.begin(), sourceList_.end(), @@ -275,18 +275,18 @@ PulseLayer::getAudioDeviceIndex(const std::string& descr, DeviceType type) const } int -PulseLayer::getAudioDeviceIndexByName(const std::string& name, DeviceType type) const +PulseLayer::getAudioDeviceIndexByName(const std::string& name, AudioDeviceType type) const { if (name.empty()) return 0; switch (type) { - case DeviceType::PLAYBACK: - case DeviceType::RINGTONE: + case AudioDeviceType::PLAYBACK: + case AudioDeviceType::RINGTONE: return std::distance(sinkList_.begin(), std::find_if(sinkList_.begin(), sinkList_.end(), PaDeviceInfos::NameComparator(name))); - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: return std::distance(sourceList_.begin(), std::find_if(sourceList_.begin(), sourceList_.end(), @@ -333,18 +333,18 @@ PulseLayer::getDeviceInfos(const std::vector<PaDeviceInfos>& list, const std::st } std::string -PulseLayer::getAudioDeviceName(int index, DeviceType type) const +PulseLayer::getAudioDeviceName(int index, AudioDeviceType type) const { switch (type) { - case DeviceType::PLAYBACK: - case DeviceType::RINGTONE: + case AudioDeviceType::PLAYBACK: + case AudioDeviceType::RINGTONE: if (index < 0 or static_cast<size_t>(index) >= sinkList_.size()) { JAMI_ERR("Index %d out of range", index); return ""; } return sinkList_[index].name; - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: if (index < 0 or static_cast<size_t>(index) >= sourceList_.size()) { JAMI_ERR("Index %d out of range", index); return ""; @@ -449,7 +449,7 @@ PulseLayer::disconnectAudioStream() record_.reset(); } -void PulseLayer::startStream(AudioStreamType) +void PulseLayer::startStream(AudioDeviceType) { std::unique_lock<std::mutex> lk(readyMtx_); readyCv_.wait(lk, [this] { @@ -473,7 +473,7 @@ void PulseLayer::startStream(AudioStreamType) } void -PulseLayer::stopStream() +PulseLayer::stopStream(AudioDeviceType stream) { std::unique_lock<std::mutex> lk(readyMtx_); readyCv_.wait(lk, [this] { @@ -810,44 +810,49 @@ PulseLayer::sink_input_info_callback(pa_context* c UNUSED, } void -PulseLayer::updatePreference(AudioPreference& preference, int index, DeviceType type) +PulseLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type) { const std::string devName(getAudioDeviceName(index, type)); switch (type) { - case DeviceType::PLAYBACK: + case AudioDeviceType::PLAYBACK: JAMI_DBG("setting %s for playback", devName.c_str()); preference.setPulseDevicePlayback(devName); break; - case DeviceType::CAPTURE: + case AudioDeviceType::CAPTURE: JAMI_DBG("setting %s for capture", devName.c_str()); preference.setPulseDeviceRecord(devName); break; - case DeviceType::RINGTONE: + case AudioDeviceType::RINGTONE: JAMI_DBG("setting %s for ringer", devName.c_str()); preference.setPulseDeviceRingtone(devName); break; + + default: + break; } } int PulseLayer::getIndexCapture() const { - return getAudioDeviceIndexByName(preference_.getPulseDeviceRecord(), DeviceType::CAPTURE); + return getAudioDeviceIndexByName(preference_.getPulseDeviceRecord(), AudioDeviceType::CAPTURE); } int PulseLayer::getIndexPlayback() const { - return getAudioDeviceIndexByName(preference_.getPulseDevicePlayback(), DeviceType::PLAYBACK); + return getAudioDeviceIndexByName(preference_.getPulseDevicePlayback(), + AudioDeviceType::PLAYBACK); } int PulseLayer::getIndexRingtone() const { - return getAudioDeviceIndexByName(preference_.getPulseDeviceRingtone(), DeviceType::RINGTONE); + return getAudioDeviceIndexByName(preference_.getPulseDeviceRingtone(), + AudioDeviceType::RINGTONE); } std::string diff --git a/src/media/audio/pulseaudio/pulselayer.h b/src/media/audio/pulseaudio/pulselayer.h index 3b04065c9549dd40b4880abe45d8277e968f31bf..903b8a2fa10037bdeea5dcb78d93442cda8b9c6a 100644 --- a/src/media/audio/pulseaudio/pulselayer.h +++ b/src/media/audio/pulseaudio/pulselayer.h @@ -134,13 +134,13 @@ public: virtual std::vector<std::string> getCaptureDeviceList() const; virtual std::vector<std::string> getPlaybackDeviceList() const; - int getAudioDeviceIndex(const std::string& descr, DeviceType type) const; - int getAudioDeviceIndexByName(const std::string& name, DeviceType type) const; + int getAudioDeviceIndex(const std::string& descr, AudioDeviceType type) const; + int getAudioDeviceIndexByName(const std::string& name, AudioDeviceType type) const; - std::string getAudioDeviceName(int index, DeviceType type) const; + std::string getAudioDeviceName(int index, AudioDeviceType type) const; - virtual void startStream(AudioStreamType stream = AudioStreamType::DEFAULT); - virtual void stopStream(); + virtual void startStream(AudioDeviceType stream = AudioDeviceType::ALL); + virtual void stopStream(AudioDeviceType stream = AudioDeviceType::ALL); private: static void context_state_callback(pa_context* c, void* user_data); @@ -161,7 +161,7 @@ private: void* userdata); static void server_info_callback(pa_context*, const pa_server_info* i, void* userdata); - virtual void updatePreference(AudioPreference& pref, int index, DeviceType type); + virtual void updatePreference(AudioPreference& pref, int index, AudioDeviceType type); virtual int getIndexCapture() const; virtual int getIndexPlayback() const; diff --git a/src/media/audio/ringbuffer.h b/src/media/audio/ringbuffer.h index 11cdc3fe0018a2c9f45dae4ac0574f0f7447c34b..0f1af3ed7a999550ec194dc2b135a4aa2c6e5794 100644 --- a/src/media/audio/ringbuffer.h +++ b/src/media/audio/ringbuffer.h @@ -136,12 +136,10 @@ public: * Blocks until min_data_length samples of data is available, or until deadline has passed. * * @param call_id The read offset for which data should be available. - * @param min_data_length Minimum number of samples that should be available for the call to - * return - * @param deadline The call is guaranteed to end after this time point. If no deadline is - * provided, the call blocks indefinitely. - * @return available data for call_id after the call returned (same as calling - * getLength(call_id) ). + * @param min_data_length Minimum number of samples that should be available for the call to return + * @param deadline The call is guaranteed to end after this time point. If no deadline is provided, + * the call blocks indefinitely. + * @return available data for call_id after the call returned (same as calling getLength(call_id) ). */ size_t waitForDataAvailable(const std::string& call_id, const time_point& deadline = time_point::max()) const; diff --git a/src/media/localrecorder.cpp b/src/media/localrecorder.cpp index f5fa003f4585bc812dd7180fc6307c8c14371659..33d0186e9b2d26e9e1943e71dbaf9ba2e814f2b3 100644 --- a/src/media/localrecorder.cpp +++ b/src/media/localrecorder.cpp @@ -75,11 +75,11 @@ LocalRecorder::startRecording() // audio recording // create read offset in RingBuffer Manager::instance().getRingBufferPool().bindHalfDuplexOut(path_, RingBufferPool::DEFAULT_ID); - Manager::instance().startAudioDriverStream(); audioInput_ = jami::getAudioInput(path_); audioInput_->setFormat(AudioFormat::STEREO()); audioInput_->attach(recorder_->addStream(audioInput_->getInfo())); + audioInput_->switchInput(""); #ifdef ENABLE_VIDEO // video recording diff --git a/src/media/media_player.cpp b/src/media/media_player.cpp index dbf51ac369ed1350e2f22744dca2a8b44526ed86..bc5f76ad4fdc02705258267d70212df7fe6fa5c2 100644 --- a/src/media/media_player.cpp +++ b/src/media/media_player.cpp @@ -44,7 +44,6 @@ MediaPlayer::MediaPlayer(const std::string& path) path_ = path; id_ = std::to_string(rand()); - Manager::instance().startAudioPlayback(); audioInput_ = jami::getAudioInput(id_); audioInput_->setPaused(paused_); videoInput_ = jami::getVideoInput(id_, video::VideoInputMode::ManagedByDaemon); @@ -82,6 +81,7 @@ MediaPlayer::configureMediaInputs() if (hasAudio()) { audioInput_->configureFilePlayback(path_, demuxer_, audioStream_); audioInput_->updateStartTime(startTime_); + audioInput_->start(); } } catch (const std::exception& e) { JAMI_ERR("media player: %s open audio input failed: %s", path_.c_str(), e.what()); diff --git a/src/preferences.cpp b/src/preferences.cpp index 319b1b249eacc820d6e1596d30d9eaa24e4390db..1d5f42ed23f0ad473a97c73bc1d6894e21897a37 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -372,7 +372,7 @@ AudioPreference::AudioPreference() static const int ALSA_DFT_CARD_ID = 0; // Index of the default soundcard static void -checkSoundCard(int& card, DeviceType type) +checkSoundCard(int& card, AudioDeviceType type) { if (not AlsaLayer::soundCardIndexExists(card, type)) { JAMI_WARN(" Card with index %d doesn't exist or is unusable.", card); @@ -426,9 +426,9 @@ AudioPreference::createAudioLayer() #if HAVE_ALSA audioApi_ = ALSA_API_STR; - checkSoundCard(alsaCardin_, DeviceType::CAPTURE); - checkSoundCard(alsaCardout_, DeviceType::PLAYBACK); - checkSoundCard(alsaCardring_, DeviceType::RINGTONE); + checkSoundCard(alsaCardin_, AudioDeviceType::CAPTURE); + checkSoundCard(alsaCardout_, AudioDeviceType::PLAYBACK); + checkSoundCard(alsaCardring_, AudioDeviceType::RINGTONE); return new AlsaLayer(*this); #endif diff --git a/src/security/tlsvalidator.cpp b/src/security/tlsvalidator.cpp index 15a05fc683b366e3d87a2b4dbc94046b96de6965..9a8394cc2d5786b5648944625ca2e8a76ac5628a 100644 --- a/src/security/tlsvalidator.cpp +++ b/src/security/tlsvalidator.cpp @@ -863,23 +863,15 @@ TlsValidator::privateKeyStoragePermissions() if (err) return TlsValidator::CheckResult(CheckValues::UNSUPPORTED, ""); - return TlsValidator::CheckResult((statbuf.st_mode & S_IFREG) - && /* Regular file only */ - /* READ WRITE EXECUTE */ - /* Owner */ ((statbuf.st_mode - & S_IRUSR) /* write is not relevant */ - && !(statbuf.st_mode & S_IXUSR)) - /* Group */ - && (!(statbuf.st_mode & S_IRGRP) - && !(statbuf.st_mode & S_IWGRP) - && !(statbuf.st_mode & S_IXGRP)) - /* Other */ - && (!(statbuf.st_mode & S_IROTH) - && !(statbuf.st_mode & S_IWOTH) - && !(statbuf.st_mode & S_IXOTH)) - ? CheckValues::PASSED - : CheckValues::FAILED, - ""); +// clang-format off + return TlsValidator::CheckResult( + (statbuf.st_mode & S_IFREG) && /* Regular file only */ + /* READ WRITE EXECUTE */ + /* Owner */ ( (statbuf.st_mode & S_IRUSR) /* write is not relevant */ && !(statbuf.st_mode & S_IXUSR)) + /* Group */ && (!(statbuf.st_mode & S_IRGRP) && !(statbuf.st_mode & S_IWGRP) && !(statbuf.st_mode & S_IXGRP)) + /* Other */ && (!(statbuf.st_mode & S_IROTH) && !(statbuf.st_mode & S_IWOTH) && !(statbuf.st_mode & S_IXOTH)) + ? CheckValues::PASSED:CheckValues::FAILED, ""); +// clang-format on } TlsValidator::CheckResult @@ -890,21 +882,15 @@ TlsValidator::publicKeyStoragePermissions() if (err) return TlsValidator::CheckResult(CheckValues::UNSUPPORTED, ""); +// clang-format off return TlsValidator::CheckResult( - (statbuf.st_mode & S_IFREG) - && /* Regular file only */ - /* READ WRITE EXECUTE */ - /* Owner */ ((statbuf.st_mode & S_IRUSR) /* write is not relevant */ - && !(statbuf.st_mode & S_IXUSR)) - /* Group */ - && (/* read is not relevant */ !(statbuf.st_mode & S_IWGRP) - && !(statbuf.st_mode & S_IXGRP)) - /* Other */ - && (/* read is not relevant */ !(statbuf.st_mode & S_IWOTH) - && !(statbuf.st_mode & S_IXOTH)) - ? CheckValues::PASSED - : CheckValues::FAILED, - ""); + (statbuf.st_mode & S_IFREG) && /* Regular file only */ + /* READ WRITE EXECUTE */ + /* Owner */ ( (statbuf.st_mode & S_IRUSR) /* write is not relevant */ && !(statbuf.st_mode & S_IXUSR)) + /* Group */ && ( /* read is not relevant */ !(statbuf.st_mode & S_IWGRP) && !(statbuf.st_mode & S_IXGRP)) + /* Other */ && ( /* read is not relevant */ !(statbuf.st_mode & S_IWOTH) && !(statbuf.st_mode & S_IXOTH)) + ? CheckValues::PASSED:CheckValues::FAILED, ""); +// clang-format on } TlsValidator::CheckResult diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index 49526896be37b9de5d75514b352f8cc07569d748..9b3e0e4c77ffd07fe478fb6585dbcc841939c974 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -879,15 +879,12 @@ SIPCall::sendTextMessage(const std::map<std::string, std::string>& messages, con void SIPCall::removeCall() { - { - std::lock_guard<std::recursive_mutex> lk {callMutex_}; - JAMI_WARN("[call:%s] removeCall()", getCallId().c_str()); - Call::removeCall(); - mediaTransport_.reset(); - inv.reset(); - setTransport({}); - } - Manager::instance().checkAudio(); + std::lock_guard<std::recursive_mutex> lk {callMutex_}; + JAMI_WARN("[call:%s] removeCall()", getCallId().c_str()); + Call::removeCall(); + mediaTransport_.reset(); + inv.reset(); + setTransport({}); } void @@ -929,7 +926,6 @@ SIPCall::onClosed() auto& call = *shared; Manager::instance().peerHungupCall(call); call.removeCall(); - Manager::instance().checkAudio(); } }); } diff --git a/src/upnp/protocol/mapping.cpp b/src/upnp/protocol/mapping.cpp index 9c71a20c2230ea548af3b1aa79200de39d125c8a..a172a4eb234fb468b933ae9522a0f60c373aeed6 100644 --- a/src/upnp/protocol/mapping.cpp +++ b/src/upnp/protocol/mapping.cpp @@ -161,4 +161,4 @@ Mapping::isValid() const }; } // namespace upnp -} // namespace jami \ No newline at end of file +} // namespace jami diff --git a/src/upnp/protocol/natpmp/nat_pmp.cpp b/src/upnp/protocol/natpmp/nat_pmp.cpp index 6edb102023030fdb48df6c5a7e5acae24511ccff..60a7df18e639cb0704d39b150a6128d0335a0107 100644 --- a/src/upnp/protocol/natpmp/nat_pmp.cpp +++ b/src/upnp/protocol/natpmp/nat_pmp.cpp @@ -494,4 +494,4 @@ NatPmp::getNatPmpErrorStr(int errorCode) } } // namespace upnp -} // namespace jami \ No newline at end of file +} // namespace jami diff --git a/src/upnp/protocol/natpmp/pmp_igd.cpp b/src/upnp/protocol/natpmp/pmp_igd.cpp index 2ad3ea9453dd5f2eb1895755c91e125e1c15cec1..5c1988715a25de669f57fc31dcb4d8d6f08aee1d 100644 --- a/src/upnp/protocol/natpmp/pmp_igd.cpp +++ b/src/upnp/protocol/natpmp/pmp_igd.cpp @@ -128,4 +128,4 @@ PMPIGD::getRenewalTime() return nextTime; } } // namespace upnp -} // namespace jami \ No newline at end of file +} // namespace jami diff --git a/src/upnp/protocol/natpmp/pmp_igd.h b/src/upnp/protocol/natpmp/pmp_igd.h index efc7dd9bef9bd6478f54882a8965144596c8fd53..bf09c2ad06cba9e196c02952a6fcc73d94767116 100644 --- a/src/upnp/protocol/natpmp/pmp_igd.h +++ b/src/upnp/protocol/natpmp/pmp_igd.h @@ -88,4 +88,4 @@ public: std::atomic_bool clearAll_ {true}; }; } // namespace upnp -} // namespace jami \ No newline at end of file +} // namespace jami