diff --git a/contrib/src/portaudio/0001-add-get-default-comm-devices-api.patch b/contrib/src/portaudio/0001-add-get-default-comm-devices-api.patch
new file mode 100644
index 0000000000000000000000000000000000000000..193606f29fd700330dc562833be3dd2c3ba908ef
--- /dev/null
+++ b/contrib/src/portaudio/0001-add-get-default-comm-devices-api.patch
@@ -0,0 +1,223 @@
+From 70ea89479fcff70982bb95ea82426320b8fe0845 Mon Sep 17 00:00:00 2001
+From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
+Date: Thu, 11 Mar 2021 19:19:54 -0500
+Subject: [PATCH] add get default comm devices api
+
+---
+ include/portaudio.h                | 11 +++++
+ src/common/pa_front.c              | 54 +++++++++++++++++++++++++
+ src/hostapi/wasapi/pa_win_wasapi.c | 65 ++++++++++++++++++++++++++++++
+ 3 files changed, 130 insertions(+)
+
+diff --git a/include/portaudio.h b/include/portaudio.h
+index 8a94aaf..0466a54 100644
+--- a/include/portaudio.h
++++ b/include/portaudio.h
+@@ -320,6 +320,13 @@ typedef struct PaHostApiInfo
+      if no default output device is available.
+     */
+     PaDeviceIndex defaultOutputDevice;
++
++    /** The default input/output devices for this host API(if supported).
++     The value will be a device index ranging from 0 to (Pa_GetDeviceCount()-1),
++     or paNoDevice if no default output device is available.
++    */
++    PaDeviceIndex defaultCommInputDevice;
++    PaDeviceIndex defaultCommOutputDevice;
+     
+ } PaHostApiInfo;
+ 
+@@ -449,6 +456,10 @@ PaDeviceIndex Pa_GetDefaultInputDevice( void );
+ PaDeviceIndex Pa_GetDefaultOutputDevice( void );
+ 
+ 
++PaDeviceIndex Pa_GetDefaultCommOutputDevice( void );
++PaDeviceIndex Pa_GetDefaultCommInputDevice( void );
++
++
+ /** The type used to represent monotonic time in seconds. PaTime is 
+  used for the fields of the PaStreamCallbackTimeInfo argument to the 
+  PaStreamCallback and as the result of Pa_GetStreamTime().
+diff --git a/src/common/pa_front.c b/src/common/pa_front.c
+index 188cee9..ea0c3da 100644
+--- a/src/common/pa_front.c
++++ b/src/common/pa_front.c
+@@ -234,6 +234,8 @@ static PaError InitializeHostApis( void )
+             PaUtilHostApiRepresentation* hostApi = hostApis_[hostApisCount_];
+             assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount );
+             assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount );
++            assert( hostApi->info.defaultCommInputDevice < hostApi->info.deviceCount );
++            assert( hostApi->info.defaultCommOutputDevice < hostApi->info.deviceCount );
+ 
+             /* the first successfully initialized host API with a default input *or*
+                output device is used as the default host API.
+@@ -253,6 +255,12 @@ static PaError InitializeHostApis( void )
+             if( hostApi->info.defaultOutputDevice != paNoDevice )
+                 hostApi->info.defaultOutputDevice += baseDeviceIndex;
+ 
++            if( hostApi->info.defaultCommInputDevice != paNoDevice )
++                hostApi->info.defaultCommInputDevice += baseDeviceIndex;
++
++            if( hostApi->info.defaultCommOutputDevice != paNoDevice )
++                hostApi->info.defaultCommOutputDevice += baseDeviceIndex;
++
+             baseDeviceIndex += hostApi->info.deviceCount;
+             deviceCount_ += hostApi->info.deviceCount;
+ 
+@@ -746,6 +754,52 @@ PaDeviceIndex Pa_GetDefaultOutputDevice( void )
+ }
+ 
+ 
++PaDeviceIndex Pa_GetDefaultCommInputDevice( void )
++{
++    PaHostApiIndex hostApi;
++    PaDeviceIndex result;
++
++    PA_LOGAPI_ENTER( "Pa_GetDefaultCommInputDevice" );
++
++    hostApi = Pa_GetDefaultHostApi();
++    if( hostApi < 0 )
++    {
++        result = paNoDevice;
++    }
++    else
++    {
++        result = hostApis_[hostApi]->info.defaultCommInputDevice;
++    }
++
++    PA_LOGAPI_EXIT_T( "Pa_GetDefaultCommInputDevice", "PaDeviceIndex: %d", result );
++
++    return result;
++}
++
++
++PaDeviceIndex Pa_GetDefaultCommOutputDevice( void )
++{
++    PaHostApiIndex hostApi;
++    PaDeviceIndex result;
++
++    PA_LOGAPI_ENTER( "Pa_GetDefaultCommOutputDevice" );
++
++    hostApi = Pa_GetDefaultHostApi();
++    if( hostApi < 0 )
++    {
++        result = paNoDevice;
++    }
++    else
++    {
++        result = hostApis_[hostApi]->info.defaultCommOutputDevice;
++    }
++
++    PA_LOGAPI_EXIT_T( "Pa_GetDefaultCommOutputDevice", "PaDeviceIndex: %d", result );
++
++    return result;
++}
++
++
+ const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
+ {
+     int hostSpecificDeviceIndex;
+diff --git a/src/hostapi/wasapi/pa_win_wasapi.c b/src/hostapi/wasapi/pa_win_wasapi.c
+index b12b91f..fb70eff 100644
+--- a/src/hostapi/wasapi/pa_win_wasapi.c
++++ b/src/hostapi/wasapi/pa_win_wasapi.c
+@@ -441,6 +441,9 @@ typedef struct
+     WCHAR defaultRenderer [MAX_STR_LEN];
+     WCHAR defaultCapturer [MAX_STR_LEN];
+ 
++    WCHAR defaultCommRenderer [MAX_STR_LEN];
++    WCHAR defaultCommCapturer [MAX_STR_LEN];
++
+     PaWasapiDeviceInfo *devInfo;
+ 
+ 	// Is true when WOW64 Vista/7 Workaround is needed
+@@ -1463,6 +1466,8 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
+     (*hostApi)->info.deviceCount		 = 0;
+     (*hostApi)->info.defaultInputDevice	 = paNoDevice;
+     (*hostApi)->info.defaultOutputDevice = paNoDevice;
++    (*hostApi)->info.defaultCommInputDevice = paNoDevice;
++    (*hostApi)->info.defaultCommOutputDevice = paNoDevice;
+ 
+ #ifndef PA_WINRT
+     paWasapi->enumerator = NULL;
+@@ -1524,6 +1529,57 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
+         }
+     }
+ 
++    // getting default device ids in the eCommunications "role"
++    {
++        {
++            IMMDevice *defaultCommRenderer = NULL;
++            hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eRender, eCommunications, &defaultCommRenderer);
++            if (hr != S_OK)
++			{
++				if (hr != E_NOTFOUND) {
++					// We need to set the result to a value otherwise we will return paNoError
++					// [IF_FAILED_JUMP(hResult, error);]
++					IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
++				}
++			}
++			else
++			{
++				WCHAR *pszDeviceId = NULL;
++				hr = IMMDevice_GetId(defaultCommRenderer, &pszDeviceId);
++				// We need to set the result to a value otherwise we will return paNoError
++				// [IF_FAILED_JUMP(hResult, error);]
++				IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
++				wcsncpy(paWasapi->defaultCommRenderer, pszDeviceId, MAX_STR_LEN-1);
++				CoTaskMemFree(pszDeviceId);
++				IMMDevice_Release(defaultCommRenderer);
++			}
++        }
++
++        {
++            IMMDevice *defaultCommCapturer = NULL;
++            hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(paWasapi->enumerator, eCapture, eCommunications, &defaultCommCapturer);
++            if (hr != S_OK)
++			{
++				if (hr != E_NOTFOUND) {
++					// We need to set the result to a value otherwise we will return paNoError
++					// [IF_FAILED_JUMP(hResult, error);]
++					IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
++				}
++			}
++			else
++			{
++				WCHAR *pszDeviceId = NULL;
++				hr = IMMDevice_GetId(defaultCommCapturer, &pszDeviceId);
++				// We need to set the result to a value otherwise we will return paNoError
++				// [IF_FAILED_JUMP(hResult, error);]
++				IF_FAILED_INTERNAL_ERROR_JUMP(hr, result, error);
++				wcsncpy(paWasapi->defaultCommCapturer, pszDeviceId, MAX_STR_LEN-1);
++				CoTaskMemFree(pszDeviceId);
++				IMMDevice_Release(defaultCommCapturer);
++			}
++        }
++    }
++
+     hr = IMMDeviceEnumerator_EnumAudioEndpoints(paWasapi->enumerator, eAll, DEVICE_STATE_ACTIVE, &pEndPoints);
+ 	// We need to set the result to a value otherwise we will return paNoError
+ 	// [IF_FAILED_JUMP(hResult, error);]
+@@ -1599,6 +1655,14 @@ PaError PaWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
+ 				{// we found the default output!
+                     (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
+                 }
++                if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCommCapturer) == 0)
++				{// we found the default input!
++                    (*hostApi)->info.defaultCommInputDevice = (*hostApi)->info.deviceCount;
++                }
++                if (lstrcmpW(paWasapi->devInfo[i].szDeviceID, paWasapi->defaultCommRenderer) == 0)
++				{// we found the default output!
++                    (*hostApi)->info.defaultCommOutputDevice = (*hostApi)->info.deviceCount;
++                }
+             }
+ 
+             hr = IMMDevice_GetState(paWasapi->devInfo[i].device, &paWasapi->devInfo[i].state);
+@@ -5736,3 +5800,4 @@ void PaWasapi_FreeMemory(void *ptr)
+ 				bFirst = FALSE;
+ 			}
+ #endif
++
+-- 
+2.17.1
+
diff --git a/contrib/src/portaudio/package.json b/contrib/src/portaudio/package.json
index 254b89fa1badc9efa1106b96296215de7d7da287..ff5fdf84ef84b864fc0bdcaacd166e99512892a5 100644
--- a/contrib/src/portaudio/package.json
+++ b/contrib/src/portaudio/package.json
@@ -9,5 +9,6 @@
         "PA_USE_DS=0",
         "PA_USE_WMME=0",
         "PA_USE_WDMKS=0"
-    ]
-}
\ No newline at end of file
+    ],
+    "patches": ["0001-add-get-default-comm-devices-api.patch"]
+}
diff --git a/src/media/audio/portaudio/portaudiolayer.cpp b/src/media/audio/portaudio/portaudiolayer.cpp
index 7a284ab6c2b7825b1c6d0522de546d73db2eb0db..d3fbdd5ad32afeb55a0b0e95013a58bc1a46415c 100644
--- a/src/media/audio/portaudio/portaudiolayer.cpp
+++ b/src/media/audio/portaudio/portaudiolayer.cpp
@@ -50,18 +50,21 @@ struct PortAudioLayer::PortAudioLayerImpl
     bool initFullDuplexStream(PortAudioLayer&);
     bool apiInitialised_ {false};
 
-    std::vector<std::string> getDeviceByType(AudioDeviceType type) const;
+    std::vector<std::string> getDevicesByType(AudioDeviceType type) const;
     int getIndexByType(AudioDeviceType type);
-    int getInternalIndexByType(const int index, AudioDeviceType type);
+    std::string getDeviceNameByType(const int index, AudioDeviceType type);
+    PaDeviceIndex getApiIndexByType(AudioDeviceType type);
+    std::string getApiDefaultDeviceName(AudioDeviceType type, bool commDevice) const;
+
+    std::string deviceRecord_ {};
+    std::string devicePlayback_ {};
+    std::string deviceRingtone_ {};
+
+    static constexpr const int defaultIndex_ {0};
 
-    PaDeviceIndex indexIn_;
     bool inputInitialized_ {false};
-    PaDeviceIndex indexOut_;
-    PaDeviceIndex indexRing_;
     bool outputInitialized_ {false};
 
-    AudioBuffer playbackBuff_;
-
     std::array<PaStream*, static_cast<int>(Direction::End)> streams_;
 
     int paOutputCallback(PortAudioLayer& parent,
@@ -114,42 +117,31 @@ PortAudioLayer::~PortAudioLayer()
 std::vector<std::string>
 PortAudioLayer::getCaptureDeviceList() const
 {
-    return pimpl_->getDeviceByType(AudioDeviceType::CAPTURE);
+    return pimpl_->getDevicesByType(AudioDeviceType::CAPTURE);
 }
 
 std::vector<std::string>
 PortAudioLayer::getPlaybackDeviceList() const
 {
-    return pimpl_->getDeviceByType(AudioDeviceType::PLAYBACK);
+    return pimpl_->getDevicesByType(AudioDeviceType::PLAYBACK);
 }
 
 int
 PortAudioLayer::getAudioDeviceIndex(const std::string& name, AudioDeviceType type) const
 {
-    auto deviceList = pimpl_->getDeviceByType(type);
-
-    int numDevices = 0;
-    numDevices = deviceList.size();
-    if (numDevices < 0) {
-        JAMI_ERR("PortAudioLayer error : %s", Pa_GetErrorText(numDevices));
-    } else {
-        int i = 0;
-        for (auto d = deviceList.cbegin(); d != deviceList.cend(); ++d, ++i) {
-            if (*d == name) {
-                return i;
-            }
-        }
-    }
-    return paNoDevice;
+    auto devices = pimpl_->getDevicesByType(type);
+    auto it = std::find_if(devices.cbegin(), devices.cend(), [&name](const auto& deviceName) {
+        return deviceName == name;
+    });
+    return it != devices.end() ? std::distance(devices.cbegin(), it) : -1;
 }
 
 std::string
 PortAudioLayer::getAudioDeviceName(int index, AudioDeviceType type) const
 {
+    (void) index;
     (void) type;
-    const PaDeviceInfo* deviceInfo;
-    deviceInfo = Pa_GetDeviceInfo(index);
-    return deviceInfo->name;
+    return {};
 }
 
 int
@@ -218,7 +210,7 @@ void
 PortAudioLayer::stopStream(AudioDeviceType stream)
 {
     auto stopPaStream = [](PaStream* stream) -> bool {
-        if (!stream)
+        if (!stream || Pa_IsStreamStopped(stream) != paNoError)
             return false;
         auto err = Pa_StopStream(stream);
         if (err != paNoError) {
@@ -287,16 +279,16 @@ PortAudioLayer::stopStream(AudioDeviceType stream)
 void
 PortAudioLayer::updatePreference(AudioPreference& preference, int index, AudioDeviceType type)
 {
-    auto internalIndex = pimpl_->getInternalIndexByType(index, type);
+    auto deviceName = pimpl_->getDeviceNameByType(index, type);
     switch (type) {
     case AudioDeviceType::PLAYBACK:
-        preference.setAlsaCardout(internalIndex);
+        preference.setPortAudioDevicePlayback(deviceName);
         break;
     case AudioDeviceType::CAPTURE:
-        preference.setAlsaCardin(internalIndex);
+        preference.setPortAudioDeviceRecord(deviceName);
         break;
     case AudioDeviceType::RINGTONE:
-        preference.setAlsaCardring(internalIndex);
+        preference.setPortAudioDeviceRingtone(deviceName);
         break;
     default:
         break;
@@ -307,10 +299,9 @@ PortAudioLayer::updatePreference(AudioPreference& preference, int index, AudioDe
 
 PortAudioLayer::PortAudioLayerImpl::PortAudioLayerImpl(PortAudioLayer& parent,
                                                        const AudioPreference& pref)
-    : indexIn_ {pref.getAlsaCardin()}
-    , indexOut_ {pref.getAlsaCardout()}
-    , indexRing_ {pref.getAlsaCardring()}
-    , playbackBuff_ {0, parent.audioFormat_}
+    : deviceRecord_ {pref.getPortAudioDeviceRecord()}
+    , devicePlayback_ {pref.getPortAudioDevicePlayback()}
+    , deviceRingtone_ {pref.getPortAudioDeviceRingtone()}
 {
     init(parent);
 }
@@ -323,91 +314,79 @@ PortAudioLayer::PortAudioLayerImpl::~PortAudioLayerImpl()
 void
 PortAudioLayer::PortAudioLayerImpl::initInput(PortAudioLayer& parent)
 {
-    auto numDevices = Pa_GetDeviceCount();
-    if (indexIn_ <= paNoDevice || indexIn_ >= numDevices) {
-        indexIn_ = Pa_GetDefaultInputDevice();
-    }
+    // convert out preference to an api index
+    auto apiIndex = getApiIndexByType(AudioDeviceType::CAPTURE);
 
-    // Pa_GetDefaultInputDevice returned paNoDevice or we already initialized the device
-    if (indexIn_ == paNoDevice || inputInitialized_)
+    // Pa_GetDefault[Comm]InputDevice returned paNoDevice or we already initialized the device
+    if (apiIndex == paNoDevice || inputInitialized_)
         return;
 
-    if (const auto inputDeviceInfo = Pa_GetDeviceInfo(indexIn_)) {
-        if (inputDeviceInfo->maxInputChannels <= 0) {
-            indexIn_ = paNoDevice;
-            return initInput(parent);
-        }
-        parent.audioInputFormat_.sample_rate = inputDeviceInfo->defaultSampleRate;
-        parent.audioInputFormat_.nb_channels = inputDeviceInfo->maxInputChannels;
-        parent.hardwareInputFormatAvailable(parent.audioInputFormat_);
-        JAMI_DBG("PortAudioLayer initialized input: %s {%d Hz, %d channels}",
-                 inputDeviceInfo->name,
-                 parent.audioInputFormat_.sample_rate,
-                 parent.audioInputFormat_.nb_channels);
-        inputInitialized_ = true;
-    } else {
+    const auto inputDeviceInfo = Pa_GetDeviceInfo(apiIndex);
+    if (!inputDeviceInfo) {
+        // this represents complete failure after attempting a fallback to default
         JAMI_WARN("PortAudioLayer could not initialize input");
-        indexIn_ = paNoDevice;
+        deviceRecord_.clear();
         inputInitialized_ = true;
+        return;
+    }
+
+    // if the device index is somehow no longer a device of the correct type, reset the
+    // internal index to paNoDevice and reenter in an attempt to set the default
+    // communications device
+    if (inputDeviceInfo->maxInputChannels <= 0) {
+        JAMI_WARN("PortAudioLayer could not initialize input, falling back to default device");
+        deviceRecord_.clear();
+        return initInput(parent);
     }
+
+    // at this point, the device is of the correct type and can be opened
+    parent.audioInputFormat_.sample_rate = inputDeviceInfo->defaultSampleRate;
+    parent.audioInputFormat_.nb_channels = inputDeviceInfo->maxInputChannels;
+    parent.hardwareInputFormatAvailable(parent.audioInputFormat_);
+    JAMI_DBG("PortAudioLayer initialized input: %s {%d Hz, %d channels}",
+             inputDeviceInfo->name,
+             parent.audioInputFormat_.sample_rate,
+             parent.audioInputFormat_.nb_channels);
+    inputInitialized_ = true;
 }
 
 void
 PortAudioLayer::PortAudioLayerImpl::initOutput(PortAudioLayer& parent)
 {
-    auto numDevices = Pa_GetDeviceCount();
-    if (indexOut_ <= paNoDevice || indexOut_ >= numDevices) {
-        indexRing_ = indexOut_ = Pa_GetDefaultOutputDevice();
-    } else {
-        indexRing_ = indexOut_;
-    }
+    // convert out preference to an api index
+    auto apiIndex = getApiIndexByType(AudioDeviceType::PLAYBACK);
 
-    // Pa_GetDefaultOutputDevice returned paNoDevice or we already initialized the device
-    if (indexOut_ == paNoDevice || outputInitialized_)
+    // Pa_GetDefault[Comm]OutputDevice returned paNoDevice or we already initialized the device
+    if (apiIndex == paNoDevice || outputInitialized_)
         return;
 
-    if (const auto outputDeviceInfo = Pa_GetDeviceInfo(indexOut_)) {
-        if (outputDeviceInfo->maxOutputChannels <= 0) {
-            indexOut_ = paNoDevice;
-            return initOutput(parent);
-        }
-        parent.audioFormat_.sample_rate = outputDeviceInfo->defaultSampleRate;
-        parent.audioFormat_.nb_channels = outputDeviceInfo->maxOutputChannels;
-        parent.hardwareFormatAvailable(parent.audioFormat_);
-        JAMI_DBG("PortAudioLayer initialized output: %s {%d Hz, %d channels}",
-                 outputDeviceInfo->name,
-                 parent.audioFormat_.sample_rate,
-                 parent.audioFormat_.nb_channels);
-        outputInitialized_ = true;
-    } else {
+    const auto outputDeviceInfo = Pa_GetDeviceInfo(apiIndex);
+    if (!outputDeviceInfo) {
+        // this represents complete failure after attempting a fallback to default
         JAMI_WARN("PortAudioLayer could not initialize output");
-        indexOut_ = paNoDevice;
+        devicePlayback_.clear();
         outputInitialized_ = true;
+        return;
     }
-}
 
-std::vector<std::string>
-PortAudioLayer::PortAudioLayerImpl::getDeviceByType(AudioDeviceType type) const
-{
-    std::vector<std::string> ret;
-    int numDevices = 0;
-
-    numDevices = Pa_GetDeviceCount();
-    if (numDevices < 0)
-        JAMI_ERR("PortAudioLayer error : %s", Pa_GetErrorText(numDevices));
-    else {
-        for (int i = 0; i < numDevices; i++) {
-            const auto deviceInfo = Pa_GetDeviceInfo(i);
-            if (type == AudioDeviceType::PLAYBACK) {
-                if (deviceInfo->maxOutputChannels > 0)
-                    ret.push_back(deviceInfo->name);
-            } else {
-                if (deviceInfo->maxInputChannels > 0)
-                    ret.push_back(deviceInfo->name);
-            }
-        }
+    // if the device index is somehow no longer a device of the correct type, reset the
+    // internal index to paNoDevice and reenter in an attempt to set the default
+    // communications device
+    if (outputDeviceInfo->maxOutputChannels <= 0) {
+        JAMI_WARN("PortAudioLayer could not initialize output, falling back to default device");
+        devicePlayback_.clear();
+        return initOutput(parent);
     }
-    return ret;
+
+    // at this point, the device is of the correct type and can be opened
+    parent.audioFormat_.sample_rate = outputDeviceInfo->defaultSampleRate;
+    parent.audioFormat_.nb_channels = outputDeviceInfo->maxOutputChannels;
+    parent.hardwareFormatAvailable(parent.audioFormat_);
+    JAMI_DBG("PortAudioLayer initialized output: %s {%d Hz, %d channels}",
+             outputDeviceInfo->name,
+             parent.audioFormat_.sample_rate,
+             parent.audioFormat_.nb_channels);
+    outputInitialized_ = true;
 }
 
 void
@@ -432,52 +411,101 @@ PortAudioLayer::PortAudioLayerImpl::init(PortAudioLayer& parent)
     std::fill(std::begin(streams_), std::end(streams_), nullptr);
 }
 
+std::vector<std::string>
+PortAudioLayer::PortAudioLayerImpl::getDevicesByType(AudioDeviceType type) const
+{
+    std::vector<std::string> devices;
+    auto numDevices = Pa_GetDeviceCount();
+    if (numDevices < 0)
+        JAMI_ERR("PortAudioLayer error : %s", Pa_GetErrorText(numDevices));
+    else {
+        for (int i = 0; i < numDevices; i++) {
+            const auto deviceInfo = Pa_GetDeviceInfo(i);
+            if (type == AudioDeviceType::CAPTURE) {
+                if (deviceInfo->maxInputChannels > 0)
+                    devices.push_back(deviceInfo->name);
+            } else if (deviceInfo->maxOutputChannels > 0)
+                devices.push_back(deviceInfo->name);
+        }
+        // add the default device aliases if requested and if there are any devices of this type
+        if (!devices.empty()) {
+            // default comm (index:0)
+            auto defaultDeviceName = getApiDefaultDeviceName(type, true);
+            devices.insert(devices.begin(), "{{Default}} - " + defaultDeviceName);
+        }
+    }
+    return devices;
+}
+
 int
 PortAudioLayer::PortAudioLayerImpl::getIndexByType(AudioDeviceType type)
 {
-    int index = indexRing_;
-    if (type == AudioDeviceType::PLAYBACK) {
-        index = indexOut_;
-    } else if (type == AudioDeviceType::CAPTURE) {
-        index = indexIn_;
+    auto devices = getDevicesByType(type);
+    if (!devices.size()) {
+        return 0;
     }
+    std::string_view toMatch = (type == AudioDeviceType::CAPTURE
+                                    ? deviceRecord_
+                                    : (type == AudioDeviceType::PLAYBACK ? devicePlayback_
+                                                                         : deviceRingtone_));
+    auto it = std::find_if(devices.cbegin(), devices.cend(), [&toMatch](const auto& deviceName) {
+        return deviceName == toMatch;
+    });
+    return it != devices.end() ? std::distance(devices.cbegin(), it) : 0;
+}
 
-    auto deviceList = getDeviceByType(type);
-    if (!deviceList.size()) {
-        return paNoDevice;
-    }
+std::string
+PortAudioLayer::PortAudioLayerImpl::getDeviceNameByType(const int index, AudioDeviceType type)
+{
+    if (index == defaultIndex_)
+        return {};
 
-    const PaDeviceInfo* indexedDeviceInfo;
-    indexedDeviceInfo = Pa_GetDeviceInfo(index);
-    if (!indexedDeviceInfo) {
-        return paNoDevice;
-    }
+    auto devices = getDevicesByType(type);
+    if (!devices.size() || index >= devices.size())
+        return {};
+
+    return devices.at(index);
+}
 
-    for (int i = 0; i < deviceList.size(); ++i) {
-        if (deviceList.at(i) == indexedDeviceInfo->name) {
-            return i;
+PaDeviceIndex
+PortAudioLayer::PortAudioLayerImpl::getApiIndexByType(AudioDeviceType type)
+{
+    auto numDevices = Pa_GetDeviceCount();
+    if (numDevices < 0)
+        JAMI_ERR("PortAudioLayer error : %s", Pa_GetErrorText(numDevices));
+    else {
+        std::string_view toMatch = (type == AudioDeviceType::CAPTURE
+                                        ? deviceRecord_
+                                        : (type == AudioDeviceType::PLAYBACK ? devicePlayback_
+                                                                             : deviceRingtone_));
+        if (toMatch.empty())
+            return type == AudioDeviceType::CAPTURE ? Pa_GetDefaultCommInputDevice()
+                                                    : Pa_GetDefaultCommOutputDevice();
+        for (int i = 0; i < numDevices; ++i) {
+            if (const auto deviceInfo = Pa_GetDeviceInfo(i)) {
+                if (deviceInfo->name == toMatch)
+                    return i;
+            }
         }
     }
-
     return paNoDevice;
 }
 
-int
-PortAudioLayer::PortAudioLayerImpl::getInternalIndexByType(const int index, AudioDeviceType type)
+std::string
+PortAudioLayer::PortAudioLayerImpl::getApiDefaultDeviceName(AudioDeviceType type,
+                                                            bool commDevice) const
 {
-    auto deviceList = getDeviceByType(type);
-    if (!deviceList.size() || index >= deviceList.size()) {
-        return paNoDevice;
+    std::string deviceName {};
+    PaDeviceIndex deviceIndex {paNoDevice};
+    if (type == AudioDeviceType::CAPTURE) {
+        deviceIndex = commDevice ? Pa_GetDefaultCommInputDevice() : Pa_GetDefaultInputDevice();
+    } else {
+        deviceIndex = commDevice ? Pa_GetDefaultCommOutputDevice() : Pa_GetDefaultOutputDevice();
     }
-
-    for (int i = 0; i < Pa_GetDeviceCount(); i++) {
-        const auto deviceInfo = Pa_GetDeviceInfo(i);
-        if (deviceList.at(index) == deviceInfo->name) {
-            return i;
-        }
+    if (const auto deviceInfo = Pa_GetDeviceInfo(deviceIndex)) {
+        deviceName = deviceInfo->name;
     }
-
-    return paNoDevice;
+    return deviceName;
 }
 
 void
@@ -563,10 +591,11 @@ PortAudioLayer::PortAudioLayerImpl::initInputStream(PortAudioLayer& parent)
 {
     JAMI_DBG("Open PortAudio Input Stream");
     auto& stream = streams_[Direction::Input];
-    if (indexIn_ != paNoDevice) {
+    auto apiIndex = getApiIndexByType(AudioDeviceType::CAPTURE);
+    if (apiIndex != paNoDevice) {
         openStreamDevice(
             &streams_[Direction::Input],
-            indexIn_,
+            apiIndex,
             Direction::Input,
             [](const void* inputBuffer,
                void* outputBuffer,
@@ -604,10 +633,11 @@ PortAudioLayer::PortAudioLayerImpl::initOutputStream(PortAudioLayer& parent)
 {
     JAMI_DBG("Open PortAudio Output Stream");
     auto& stream = streams_[Direction::Output];
-    if (indexOut_ != paNoDevice) {
+    auto apiIndex = getApiIndexByType(AudioDeviceType::PLAYBACK);
+    if (apiIndex != paNoDevice) {
         openStreamDevice(
             &stream,
-            indexOut_,
+            apiIndex,
             Direction::Output,
             [](const void* inputBuffer,
                void* outputBuffer,
@@ -643,7 +673,9 @@ PortAudioLayer::PortAudioLayerImpl::initOutputStream(PortAudioLayer& parent)
 bool
 PortAudioLayer::PortAudioLayerImpl::initFullDuplexStream(PortAudioLayer& parent)
 {
-    if (indexOut_ == paNoDevice || indexIn_ == paNoDevice) {
+    auto apiIndexRecord = getApiIndexByType(AudioDeviceType::CAPTURE);
+    auto apiIndexPlayback = getApiIndexByType(AudioDeviceType::PLAYBACK);
+    if (apiIndexRecord == paNoDevice || apiIndexPlayback == paNoDevice) {
         JAMI_ERR("Error: Invalid input/output devices. There will be no audio.");
         return false;
     }
@@ -654,8 +686,8 @@ PortAudioLayer::PortAudioLayerImpl::initFullDuplexStream(PortAudioLayer& parent)
     auto& stream = streams_[Direction::IO];
     openFullDuplexStream(
         &stream,
-        indexIn_,
-        indexOut_,
+        apiIndexRecord,
+        apiIndexPlayback,
         [](const void* inputBuffer,
            void* outputBuffer,
            unsigned long framesPerBuffer,
diff --git a/src/preferences.cpp b/src/preferences.cpp
index 975cd418d61d24225e16dade5493b6b905f42865..d122b1563a58bae7d2cedf75adb1a1a481a0fad0 100644
--- a/src/preferences.cpp
+++ b/src/preferences.cpp
@@ -104,6 +104,7 @@ static constexpr const char* ZID_FILE_KEY {"zidFile"};
 constexpr const char* const AudioPreference::CONFIG_LABEL;
 static constexpr const char* ALSAMAP_KEY {"alsa"};
 static constexpr const char* PULSEMAP_KEY {"pulse"};
+static constexpr const char* PORTAUDIO_KEY {"portaudio"};
 static constexpr const char* CARDIN_KEY {"cardIn"};
 static constexpr const char* CARDOUT_KEY {"cardOut"};
 static constexpr const char* CARDRING_KEY {"cardRing"};
@@ -446,6 +447,13 @@ AudioPreference::serialize(YAML::Emitter& out) const
     out << YAML::Key << DEVICE_RINGTONE_KEY << YAML::Value << pulseDeviceRingtone_;
     out << YAML::EndMap;
 
+    // portaudio submap
+    out << YAML::Key << PORTAUDIO_KEY << YAML::Value << YAML::BeginMap;
+    out << YAML::Key << DEVICE_PLAYBACK_KEY << YAML::Value << portaudioDevicePlayback_;
+    out << YAML::Key << DEVICE_RECORD_KEY << YAML::Value << portaudioDeviceRecord_;
+    out << YAML::Key << DEVICE_RINGTONE_KEY << YAML::Value << portaudioDeviceRingtone_;
+    out << YAML::EndMap;
+
     // more common options!
     out << YAML::Key << RECORDPATH_KEY << YAML::Value << recordpath_;
     out << YAML::Key << VOLUMEMIC_KEY << YAML::Value << volumemic_;
@@ -495,6 +503,12 @@ AudioPreference::unserialize(const YAML::Node& in)
     parseValue(pulse, DEVICE_RECORD_KEY, pulseDeviceRecord_);
     parseValue(pulse, DEVICE_RINGTONE_KEY, pulseDeviceRingtone_);
 
+    // portaudio submap
+    const auto& portaudio = node[PORTAUDIO_KEY];
+    parseValue(portaudio, DEVICE_PLAYBACK_KEY, portaudioDevicePlayback_);
+    parseValue(portaudio, DEVICE_RECORD_KEY, portaudioDeviceRecord_);
+    parseValue(portaudio, DEVICE_RINGTONE_KEY, portaudioDeviceRingtone_);
+
     // more common options!
     parseValue(node, RECORDPATH_KEY, recordpath_);
     parseValue(node, VOLUMEMIC_KEY, volumemic_);
diff --git a/src/preferences.h b/src/preferences.h
index afec033475eccf5da2e2551fec72c53eac6ba4d6..97da4e697b19e21e572f4d43b8eb1332683e1cad 100644
--- a/src/preferences.h
+++ b/src/preferences.h
@@ -152,7 +152,6 @@ class AudioPreference : public Serializable
 public:
     AudioPreference();
     AudioLayer* createAudioLayer();
-    AudioLayer* switchAndCreateAudioLayer();
 
     static std::vector<std::string> getSupportedAudioManagers();
 
@@ -161,10 +160,12 @@ public:
     void setAudioApi(const std::string& api) { audioApi_ = api; }
 
     void serialize(YAML::Emitter& out) const override;
+
     void unserialize(const YAML::Node& in) override;
 
     // alsa preference
     int getAlsaCardin() const { return alsaCardin_; }
+
     void setAlsaCardin(int c) { alsaCardin_ = c; }
 
     int getAlsaCardout() const { return alsaCardout_; }
@@ -180,6 +181,7 @@ public:
     void setAlsaPlugin(const std::string& p) { alsaPlugin_ = p; }
 
     int getAlsaSmplrate() const { return alsaSmplrate_; }
+
     void setAlsaSmplrate(int r) { alsaSmplrate_ = r; }
 
     // pulseaudio preference
@@ -194,6 +196,19 @@ public:
 
     void setPulseDeviceRingtone(const std::string& r) { pulseDeviceRingtone_ = r; }
 
+    // portaudio preference
+    const std::string& getPortAudioDevicePlayback() const { return portaudioDevicePlayback_; }
+
+    void setPortAudioDevicePlayback(const std::string& p) { portaudioDevicePlayback_ = p; }
+
+    const std::string& getPortAudioDeviceRecord() const { return portaudioDeviceRecord_; }
+
+    void setPortAudioDeviceRecord(const std::string& r) { portaudioDeviceRecord_ = r; }
+
+    const std::string& getPortAudioDeviceRingtone() const { return portaudioDeviceRingtone_; }
+
+    void setPortAudioDeviceRingtone(const std::string& r) { portaudioDeviceRingtone_ = r; }
+
     // general preference
     const std::string& getRecordPath() const { return recordpath_; }
 
@@ -245,6 +260,11 @@ private:
     std::string pulseDeviceRecord_;
     std::string pulseDeviceRingtone_;
 
+    // portaudio preference
+    std::string portaudioDevicePlayback_;
+    std::string portaudioDeviceRecord_;
+    std::string portaudioDeviceRingtone_;
+
     // general preference
     std::string recordpath_; //: /home/msavard/Bureau
     bool alwaysRecording_;