diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js index e133a30..e6f9bc8 100644 --- a/app/src/RoomClient.js +++ b/app/src/RoomClient.js @@ -230,6 +230,9 @@ export default class RoomClient // Local mic hark this._hark = null; + // Local MediaStream for hark + this._harkStream = null + // Local webcam mediasoup Producer. this._webcamProducer = null; @@ -278,8 +281,9 @@ export default class RoomClient _startKeyListener() { // Add keypress event listner on document - document.addEventListener('keypress', (event) => + document.addEventListener('keydown', (event) => { + if (event.repeat) return; const key = String.fromCharCode(event.which); const source = event.target; @@ -288,11 +292,11 @@ export default class RoomClient if (exclude.indexOf(source.tagName.toLowerCase()) === -1) { - logger.debug('keyPress() [key:"%s"]', key); + logger.debug('keyDown() [key:"%s"]', key); switch (key) { - case 'a': // Activate advanced mode + case 'A': // Activate advanced mode { store.dispatch(settingsActions.toggleAdvancedMode()); store.dispatch(requestActions.notify( @@ -331,8 +335,19 @@ export default class RoomClient break; } - case ' ': - case 'm': // Toggle microphone + case ' ': // Push To Talk start + { + if (this._micProducer) + { + if (this._micProducer.paused) + { + this.unmuteMic(); + } + } + + break; + } + case 'M': // Toggle microphone { if (this._micProducer) { @@ -377,7 +392,7 @@ export default class RoomClient break; } - case 'v': // Toggle video + case 'V': // Toggle video { if (this._webcamProducer) this.disableWebcam(); @@ -394,6 +409,41 @@ export default class RoomClient } } }); + document.addEventListener('keyup', (event) => + { + const key = String.fromCharCode(event.which); + + const source = event.target; + + const exclude = [ 'input', 'textarea' ]; + + if (exclude.indexOf(source.tagName.toLowerCase()) === -1) + { + logger.debug('keyUp() [key:"%s"]', key); + + switch (key) + { + case ' ': // Push To Talk stop + { + if (this._micProducer) + { + if (!this._micProducer.paused) + { + this.muteMic(); + } + } + + break; + } + default: + { + break; + } + } + } + event.preventDefault(); + }, true); + } _startDevicesListener() @@ -943,6 +993,16 @@ export default class RoomClient 'changeAudioDevice() | new selected webcam [device:%o]', device); + if (this._hark != null) + this._hark.stop(); + + if (this._harkStream != null) + { + logger.debug('Stopping hark.'); + this._harkStream.getAudioTracks()[0].stop(); + this._harkStream = null; + } + if (this._micProducer && this._micProducer.track) this._micProducer.track.stop(); @@ -964,17 +1024,15 @@ export default class RoomClient if (this._micProducer) this._micProducer.volume = 0; - const harkStream = new MediaStream(); + this._harkStream = new MediaStream(); - harkStream.addTrack(track); + this._harkStream.addTrack(track.clone()); + this._harkStream.getAudioTracks()[0].enabled = true; - if (!harkStream.getAudioTracks()[0]) + if (!this._harkStream.getAudioTracks()[0]) throw new Error('changeAudioDevice(): given stream has no audio track'); - if (this._hark != null) - this._hark.stop(); - - this._hark = hark(harkStream, { play: false }); + this._hark = hark(this._harkStream, { play: false }); // eslint-disable-next-line no-unused-vars this._hark.on('volume_change', (dBs, threshold) => @@ -998,6 +1056,14 @@ export default class RoomClient store.dispatch(peerVolumeActions.setPeerVolume(this._peerId, volume)); } }); + this._hark.on('speaking', function() + { + store.dispatch(meActions.setIsSpeaking(true)); + }); + this._hark.on('stopped_speaking', function() + { + store.dispatch(meActions.setIsSpeaking(false)); + }); if (this._micProducer && this._micProducer.id) store.dispatch( producerActions.setProducerTrack(this._micProducer.id, track)); @@ -2620,8 +2686,11 @@ export default class RoomClient track, codecOptions : { - opusStereo : 1, - opusDtx : 1 + opusStereo : false, + opusDtx : true, + opusFec : true, + opusPtime : '3', + opusMaxPlaybackRate : 48000 }, appData : { source: 'mic' } @@ -2663,17 +2732,20 @@ export default class RoomClient this._micProducer.volume = 0; - const harkStream = new MediaStream(); - - harkStream.addTrack(track); - - if (!harkStream.getAudioTracks()[0]) - throw new Error('enableMic(): given stream has no audio track'); - if (this._hark != null) this._hark.stop(); - this._hark = hark(harkStream, { play: false }); + if (this._harkStream != null) + this._harkStream.getAudioTracks()[0].stop(); + + this._harkStream = new MediaStream(); + + this._harkStream.addTrack(track.clone()); + + if (!this._harkStream.getAudioTracks()[0]) + throw new Error('enableMic(): given stream has no audio track'); + + this._hark = hark(this._harkStream, { play: false }); // eslint-disable-next-line no-unused-vars this._hark.on('volume_change', (dBs, threshold) => @@ -2697,6 +2769,14 @@ export default class RoomClient store.dispatch(peerVolumeActions.setPeerVolume(this._peerId, volume)); } }); + this._hark.on('speaking', function() + { + store.dispatch(meActions.setIsSpeaking(true)); + }); + this._hark.on('stopped_speaking', function() + { + store.dispatch(meActions.setIsSpeaking(false)); + }); } catch (error) { diff --git a/app/src/actions/meActions.js b/app/src/actions/meActions.js index 0afb9f7..6970a3f 100644 --- a/app/src/actions/meActions.js +++ b/app/src/actions/meActions.js @@ -91,3 +91,9 @@ export const setDisplayNameInProgress = (flag) => type : 'SET_DISPLAY_NAME_IN_PROGRESS', payload : { flag } }); + + export const setIsSpeaking = (flag) => + ({ + type : 'SET_IS_SPEAKING', + payload : { flag } + }); diff --git a/app/src/components/Containers/Me.js b/app/src/components/Containers/Me.js index 3107b27..433d34d 100644 --- a/app/src/components/Containers/Me.js +++ b/app/src/components/Containers/Me.js @@ -97,6 +97,26 @@ const styles = (theme) => fontSize : '7em', margin : 0 } + }, + ptt : + { + position : 'absolute', + float : 'left', + bottom : '10%', + left : '50%', + transform : 'translate(-50%, 0%)', + color : 'rgba(255, 255, 255, 0.7)', + fontSize : '2vs', + backgroundColor : 'rgba(255, 0, 0, 0.5)', + margin : '4px', + padding : '15px', + borderRadius : '20px', + textAlign : 'center', + opacity : 0, + '&.enabled' : + { + opacity : 1 + } } }); @@ -272,7 +292,7 @@ const Me = (props) => >
+