diff --git a/bigbluebutton-html5/imports/api/2.0/audio/client/bridge/sip.js b/bigbluebutton-html5/imports/api/2.0/audio/client/bridge/sip.js
index 11d4d1269cd44c3303b272b88f0fa5c08c26ec00..8b1ec01a05ad540cb6bbd133cfe80bead76bfb7a 100644
--- a/bigbluebutton-html5/imports/api/2.0/audio/client/bridge/sip.js
+++ b/bigbluebutton-html5/imports/api/2.0/audio/client/bridge/sip.js
@@ -1,4 +1,6 @@
 import BaseAudioBridge from './base';
+import { Tracker } from 'meteor/tracker';
+import VoiceUsers from '/imports/api/2.0/voice-users';
 
 const STUN_TURN_FETCH_URL = Meteor.settings.public.media.stunTurnServersFetchAddress;
 const MEDIA_TAG = Meteor.settings.public.media.mediaTag;
@@ -66,7 +68,7 @@ export default class SIPBridge extends BaseAudioBridge {
 
   joinAudio({ isListenOnly, extension, inputStream }, managerCallback) {
     return new Promise((resolve, reject) => {
-      const callExtension = extension || this.userData.voiceBridge;
+      const callExtension = extension + this.userData.voiceBridge || this.userData.voiceBridge;
 
       const callback = (message) => {
         managerCallback(message).then(resolve);
@@ -82,6 +84,32 @@ export default class SIPBridge extends BaseAudioBridge {
     });
   }
 
+  transferCall(onTransferStart, onTransferSuccess) {
+    return new Promise((resolve) => {
+      onTransferStart();
+      this.currentSession.dtmf(1);
+
+      Tracker.autorun((c) => {
+        const selector = { meetingId: this.userData.meetingId, intId: this.userData.userId };
+        const query = VoiceUsers.find(selector);
+        console.log(selector);
+        window.Kappa = query;
+
+        query.observeChanges({
+          changed: (id, fields) => {
+            console.log('changed', fields);
+            if (fields.joined) {
+              console.log('LUL', fields.joined);
+              onTransferSuccess();
+              c.stop();
+              resolve();
+            }
+          },
+        });
+      });
+    })
+  }
+
   exitAudio() {
     return new Promise((resolve) => {
       this.currentSession.on('bye', () => {
@@ -119,6 +147,9 @@ export default class SIPBridge extends BaseAudioBridge {
       this.userAgent = new window.SIP.UA({
         uri: `sip:${encodeURIComponent(username)}@${server}`,
         wsServers: `${(protocol === 'https:' ? 'wss://' : 'ws://')}${server}/ws`,
+        log: {
+          builtinEnabled: false,
+        },
         displayName: username,
         register: false,
         traceSip: true,
diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-modal/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-modal/container.jsx
index bb0f6df2bd75e6ac77ee8511ab31550a0da01f6f..71829e62cbb32bc9422f45c50c4b31c51a8825ed 100644
--- a/bigbluebutton-html5/imports/ui/components/audio/audio-modal/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/audio/audio-modal/container.jsx
@@ -13,8 +13,7 @@ export default withModalMounter(createContainer(({ mountModal }) =>
      },
      joinMicrophone: () => {
        console.log('JOIN MIC FROM CONTAINER');
-       Service.exitAudio().then(() => Service.joinMicrophone())
-                          .then(() => mountModal(null));
+       Service.transferCall().then(() => mountModal(null));
      },
      joinListenOnly: () => {
        Service.joinListenOnly().then(() => mountModal(null))
diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-test/container.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-test/container.jsx
index 088fa1c7b31bda2895e68dfaafe4c0c2eb560792..4db17c5389a3e1993e4e1ccbc90fc8de45c39e73 100644
--- a/bigbluebutton-html5/imports/ui/components/audio/audio-test/container.jsx
+++ b/bigbluebutton-html5/imports/ui/components/audio/audio-test/container.jsx
@@ -14,7 +14,7 @@ export default createContainer(() => ({
   handlePlayAudioSample: (deviceId) => {
     console.log('handle play audio sample', deviceId);
     const sound = new Audio('resources/sounds/audioSample.mp3');
-    sound.setSinkId(deviceId);
+    if (deviceId) sound.setSinkId(deviceId);
     sound.play();
   },
 }), AudioTestContainer);
diff --git a/bigbluebutton-html5/imports/ui/components/audio/service.js b/bigbluebutton-html5/imports/ui/components/audio/service.js
index 007682bab33eda7fc23cd8ddd1732f0a014ecfb6..9c5f76a79ad0d3c4762f2f46e053f19737e2a172 100644
--- a/bigbluebutton-html5/imports/ui/components/audio/service.js
+++ b/bigbluebutton-html5/imports/ui/components/audio/service.js
@@ -5,6 +5,7 @@ import Meetings from '/imports/api/2.0/meetings';
 
 const init = () => {
   console.log('Running audio service init.');
+  const meetingId = Auth.meetingID;
   const userId = Auth.userID;
   const sessionToken = Auth.sessionToken;
   const User = Users.findOne({ userId });
@@ -16,6 +17,7 @@ const init = () => {
   const microphoneLockEnforced = false;
 
   const userData = {
+    meetingId,
     userId,
     sessionToken,
     username,
@@ -29,6 +31,7 @@ const init = () => {
 export default {
   init,
   exitAudio: () => AudioManager.exitAudio(),
+  transferCall: () => AudioManager.transferCall(),
   joinListenOnly: () => AudioManager.joinAudio({ isListenOnly: true }),
   joinMicrophone: () => AudioManager.joinAudio(),
   joinEchoTest: () => AudioManager.joinAudio({ isEchoTest: true }),
diff --git a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js
index eb60fa0f12775b3df965b973760f9f0dc6f81f27..3a7c20e558bd9f883612c032fb86a216abad4e8c 100644
--- a/bigbluebutton-html5/imports/ui/services/audio-manager/index.js
+++ b/bigbluebutton-html5/imports/ui/services/audio-manager/index.js
@@ -110,6 +110,10 @@ class AudioManager {
     return this.bridge.exitAudio()
   }
 
+  transferCall() {
+    return this.bridge.transferCall(this.onTransferStart.bind(this), this.onAudioJoin.bind(this));
+  }
+
   toggleMuteMicrophone() {
     console.log('toggleMuteMicrophone', this);
     makeCall('toggleSelfVoice').then((res) => {
@@ -137,6 +141,11 @@ class AudioManager {
     console.log('onAudioJoin', this);
   }
 
+  onTransferStart() {
+    this.isEchoTest = false;
+    this.isConnecting = true;
+  }
+
   onAudioExit() {
     this.isConnected = false;
     this.isConnecting = false;