Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
latoilescoute-dev
mumble-web
Commits
fd4f2ecc
Commit
fd4f2ecc
authored
Sep 19, 2017
by
Jonas Herzig
Browse files
Factor out voice input handling into own file
parent
6f22419a
Changes
2
Hide whitespace changes
Inline
Side-by-side
app/index.js
View file @
fd4f2ecc
...
...
@@ -3,14 +3,13 @@ import url from 'url'
import
mumbleConnect
from
'
mumble-client-websocket
'
import
CodecsBrowser
from
'
mumble-client-codecs-browser
'
import
BufferQueueNode
from
'
web-audio-buffer-queue
'
import
MicrophoneStream
from
'
microphone-stream
'
import
audioContext
from
'
audio-context
'
import
chunker
from
'
stream-chunker
'
import
Resampler
from
'
libsamplerate.js
'
import
getUserMedia
from
'
getusermedia
'
import
ko
from
'
knockout
'
import
_dompurify
from
'
dompurify
'
import
{
ContinuousVoiceHandler
,
initVoice
}
from
'
./voice
'
const
dompurify
=
_dompurify
(
window
)
function
sanitize
(
html
)
{
...
...
@@ -53,16 +52,27 @@ function CommentDialog () {
}
}
function
SettingsDialog
()
{
var
self
=
this
self
.
visible
=
ko
.
observable
(
false
)
self
.
show
=
function
()
{
self
.
visible
(
true
)
class
SettingsDialog
{
constructor
()
{
this
.
visible
=
ko
.
observable
(
false
)
this
.
voiceMode
=
ko
.
observable
()
}
show
()
{
this
.
visible
(
true
)
}
}
class
Settings
{
constructor
()
{
const
load
=
key
=>
window
.
localStorage
.
getItem
(
'
mumble.
'
+
key
)
this
.
voiceMode
=
load
(
'
voiceMode
'
)
||
'
cont
'
}
}
class
GlobalBindings
{
constructor
()
{
this
.
settings
=
new
Settings
()
this
.
client
=
null
this
.
connectDialog
=
new
ConnectDialog
()
this
.
connectionInfo
=
new
ConnectionInfo
()
...
...
@@ -140,6 +150,9 @@ class GlobalBindings {
message
:
sanitize
(
client
.
welcomeMessage
)
})
}
// Startup audio input processing
this
.
_updateVoiceHandler
()
},
err
=>
{
if
(
err
.
type
==
4
)
{
log
(
'
Connection error: invalid server password
'
)
...
...
@@ -284,6 +297,22 @@ class GlobalBindings {
this
.
connected
=
()
=>
this
.
thisUser
()
!=
null
this
.
_updateVoiceHandler
=
()
=>
{
if
(
!
this
.
client
)
{
return
}
let
mode
=
this
.
settings
.
voiceMode
if
(
mode
===
'
cont
'
)
{
voiceHandler
=
new
ContinuousVoiceHandler
(
this
.
client
)
}
else
if
(
mode
===
'
ptt
'
)
{
}
else
if
(
mode
===
'
vad
'
)
{
}
else
{
log
(
'
Unknown voice mode:
'
,
mode
)
}
}
this
.
messageBoxHint
=
ko
.
pureComputed
(()
=>
{
if
(
!
this
.
thisUser
())
{
return
''
// Not yet connected
...
...
@@ -492,34 +521,14 @@ function userToState () {
return
flags
.
join
(
'
,
'
)
}
// Audio input
var
resampler
=
new
Resampler
({
unsafe
:
true
,
type
:
Resampler
.
Type
.
SINC_FASTEST
,
ratio
:
48000
/
audioContext
.
sampleRate
})
var
voiceHandler
var
voiceStream
resampler
.
pipe
(
chunker
(
4
*
480
)).
on
(
'
data
'
,
function
(
data
)
{
initVoice
(
data
=>
{
if
(
!
ui
.
client
)
{
voiceStream
=
null
}
if
(
!
voiceStream
&&
ui
.
client
)
{
voiceStream
=
ui
.
client
.
createVoiceStream
()
}
if
(
voiceStream
)
{
voiceStream
.
write
(
new
Float32Array
(
data
.
buffer
,
data
.
byteOffset
,
data
.
byteLength
/
4
))
}
})
getUserMedia
({
audio
:
true
},
function
(
err
,
userMedia
)
{
if
(
err
)
{
log
(
'
Cannot initialize user media. Microphone will not work:
'
,
err
)
}
else
{
var
micStream
=
new
MicrophoneStream
(
userMedia
,
{
objectMode
:
true
})
micStream
.
on
(
'
data
'
,
function
(
data
)
{
resampler
.
write
(
Buffer
.
from
(
data
.
getChannelData
(
0
).
buffer
))
})
voiceHandler
=
null
}
else
if
(
voiceHandler
)
{
voiceHandler
.
write
(
new
Float32Array
(
data
.
buffer
,
data
.
byteOffset
,
data
.
byteLength
/
4
))
}
},
err
=>
{
log
(
'
Cannot initialize user media. Microphone will not work:
'
,
err
)
})
app/voice.js
0 → 100644
View file @
fd4f2ecc
import
{
Writable
}
from
'
stream
'
import
MicrophoneStream
from
'
microphone-stream
'
import
audioContext
from
'
audio-context
'
import
chunker
from
'
stream-chunker
'
import
Resampler
from
'
libsamplerate.js
'
import
getUserMedia
from
'
getusermedia
'
class
VoiceHandler
extends
Writable
{
constructor
(
client
)
{
super
({
objectMode
:
true
})
this
.
_client
=
client
this
.
_outbound
=
null
}
_getOrCreateOutbound
()
{
if
(
!
this
.
_outbound
)
{
this
.
_outbound
=
this
.
_client
.
createVoiceStream
()
}
return
this
.
_outbound
}
}
export
class
ContinuousVoiceHandler
extends
VoiceHandler
{
constructor
(
client
)
{
super
(
client
)
}
_write
(
data
,
_
,
callback
)
{
this
.
_getOrCreateOutbound
().
write
(
data
,
callback
)
}
}
export
function
initVoice
(
onData
,
onUserMediaError
)
{
var
resampler
=
new
Resampler
({
unsafe
:
true
,
type
:
Resampler
.
Type
.
SINC_FASTEST
,
ratio
:
48000
/
audioContext
.
sampleRate
})
resampler
.
pipe
(
chunker
(
4
*
480
)).
on
(
'
data
'
,
data
=>
{
onData
(
data
)
})
getUserMedia
({
audio
:
true
},
(
err
,
userMedia
)
=>
{
if
(
err
)
{
onUserMediaError
(
err
)
}
else
{
var
micStream
=
new
MicrophoneStream
(
userMedia
,
{
objectMode
:
true
})
micStream
.
on
(
'
data
'
,
data
=>
{
resampler
.
write
(
Buffer
.
from
(
data
.
getChannelData
(
0
).
buffer
))
})
}
})
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment