387 lines
12 KiB
CoffeeScript
387 lines
12 KiB
CoffeeScript
context = window
|
|
logger = context.JK.logger
|
|
|
|
reactContext = if window.opener? then window.opener else window
|
|
# make sure this is actually us opening the window, not someone else (by checking for MixerStore)
|
|
if window.opener?
|
|
try
|
|
m = window.opener.MixerStore
|
|
catch e
|
|
reactContext = window
|
|
|
|
userAgent = window.navigator.userAgent;
|
|
if /iPhone|iPad|iPod|android/i.test(navigator.userAgent)
|
|
# iPad or iPhone
|
|
reactContext = window
|
|
|
|
|
|
VideoStore = reactContext.VideoStore
|
|
VideoActions = reactContext.VideoActions
|
|
PlatformStore = reactContext.PlatformStore
|
|
|
|
ALERT_NAMES = context.JK.ALERT_NAMES;
|
|
|
|
BackendNumericToBackendString = {
|
|
1 : "CIF (352X288)",
|
|
2 : "VGA (640X480)",
|
|
3 : "4CIF (704X576)",
|
|
4 : "1/2WHD (640X360)",
|
|
5 : "WHD (1280X720)",
|
|
6 : "FHD (1920x1080)"
|
|
}
|
|
|
|
|
|
BackendToFrontendFPS = {
|
|
1: 30,
|
|
2: 24,
|
|
3: 20,
|
|
4: 15,
|
|
5: 10
|
|
}
|
|
|
|
mixins = []
|
|
mixins.push(Reflux.listenTo(VideoStore, 'onVideoStateChanged'))
|
|
|
|
@WebcamViewer = React.createClass({
|
|
|
|
mixins: mixins
|
|
logger: context.JK.logger
|
|
visible: false
|
|
|
|
getInitialState: () ->
|
|
{
|
|
currentDevice: null
|
|
deviceNames: {}
|
|
deviceCaps: null
|
|
currentCaptureResolution: 0
|
|
captureResolutions: {}
|
|
frameRates: {}
|
|
rescanning: false
|
|
}
|
|
|
|
onVideoStateChanged: (changes) ->
|
|
@setState(changes)
|
|
|
|
render: () ->
|
|
|
|
if @props.showBackBtn
|
|
backBtn = `<a className="hidden button-grey back-btn" onClick={this.back}>BACK</a>`
|
|
|
|
selectedDevice = this.selectedDeviceName(@state)
|
|
|
|
# build list of webcams
|
|
|
|
webcams = []
|
|
noneSelected = selectedDevice == null || selectedDevice.length == 0
|
|
|
|
# the backend does not allow setting no video camera. So if a webcam is selected, prevent un-selecting
|
|
if noneSelected
|
|
webcams.push `<option key="none" value="" selected={noneSelected}>None Selected</option>`
|
|
|
|
context._.each @state.deviceNames, (deviceName, deviceGuid) ->
|
|
selected = deviceGuid == selectedDevice
|
|
webcams.push `<option key={deviceGuid} value={deviceGuid} selected={selected}>{deviceName}</option>`
|
|
|
|
noWebcams = Object.keys(@state.deviceNames).length == 0
|
|
|
|
# build list of capture resolutions
|
|
|
|
captureResolutions = []
|
|
# load current settings from backend
|
|
captureResolution = @state.currentCaptureResolution
|
|
|
|
resolutions = @state.captureResolutions
|
|
context._.each resolutions, (resolution, resolutionKey, obj) =>
|
|
|
|
value = resolutionKey
|
|
text = resolution
|
|
|
|
selected = captureResolution.toString() == value.toString()
|
|
|
|
captureResolutions.push `<option key={value} value={value} selected={selected}>{text}</option>`
|
|
|
|
|
|
testBtnClassNames = {'button-orange' : true, 'webcam-test-btn' : true}
|
|
if noWebcams
|
|
if PlatformStore.isWindows()
|
|
testBtnClassNames.disabled = !@state.videoEnabled
|
|
testBtnClasses = classNames(testBtnClassNames)
|
|
testBtn = `<a className={testBtnClasses} onClick={this.toggleWebcam}>TEST VIDEO</a>`
|
|
else
|
|
testBtn = null
|
|
else if @state.videoShared
|
|
testBtnClassNames.disabled = !@state.videoEnabled
|
|
testBtnClasses = classNames(testBtnClassNames)
|
|
testBtn = `<a className={testBtnClasses} onClick={this.toggleWebcam}>STOP WEBCAM</a>`
|
|
else
|
|
testBtnClassNames.disabled = !@state.videoEnabled || noneSelected
|
|
testBtnClasses = classNames(testBtnClassNames)
|
|
testBtn = `<a className={testBtnClasses} onClick={this.toggleWebcam}>TEST WEBCAM</a>`
|
|
|
|
if @state.rescanning
|
|
rescanning =
|
|
`<span className="rescanning-notice">
|
|
<span className="spinner-small" />
|
|
CHECKING GEAR
|
|
</span>`
|
|
|
|
if @props.show_header
|
|
if noWebcams
|
|
if PlatformStore.isWindows()
|
|
testVideoHelpText = `<span>The TEST VIDEO button will open the JamKazam video window to verify that receiving video works on your system.</span>`
|
|
header = `<div className="video-header">
|
|
<h2 className="subcaption">video gear:</h2>
|
|
<div className="subcaption">
|
|
JamKazam does not detect any webcams. You will not be able to send video, but you can still receive it from others. {testVideoHelpText}
|
|
</div>
|
|
</div>`
|
|
else
|
|
header =
|
|
`<div className="video-header">
|
|
<h2 className="subcaption">video gear:</h2>
|
|
<div className="subcaption">
|
|
Select webcam to use for video in sessions. Verify that you see video from webcam in the external application window (it may be behind this window).
|
|
</div>
|
|
</div>`
|
|
|
|
if @state.videoEnabled
|
|
disableVideoBtnText = "DISABLE VIDEO"
|
|
else
|
|
disableVideoBtnText = "ENABLE VIDEO"
|
|
|
|
if @props.show_disable || !@state.videoEnabled || @state.everDisabled
|
|
|
|
if @state.videoEnabled
|
|
disableHelpBtn = `<a className="ftue-video-disable-help">[?]</a>`
|
|
|
|
disableBtnClasses = classNames({'button-grey' : true, 'disable-video' : true, 'disabled' : @state.videoShared})
|
|
disableVideo =
|
|
`<div className="webcam-select-container wizard_control">
|
|
<a className={disableBtnClasses} onClick={this.disableVideo}>{disableVideoBtnText}</a>
|
|
{disableHelpBtn}
|
|
</div>`
|
|
|
|
`<div className="webcam-viewer">
|
|
{header}
|
|
<form className="video">
|
|
<h2 className="sub-header select-webcam">select webcam:</h2>
|
|
<div className="webcam-select-container wizard_control">
|
|
<select onChange={this.selectWebcam} disabled={noWebcams || !this.state.videoEnabled}>
|
|
{webcams}
|
|
</select>
|
|
</div>
|
|
<h2 className="sub-header select-resolution">select video capture resolution:</h2>
|
|
<div className="webcam-resolution-select-container wizard_control">
|
|
<select onChange={this.selectResolution} disabled={noWebcams || !this.state.videoEnabled}>
|
|
{captureResolutions}
|
|
</select>
|
|
<a className="ftue-video-settings-help">[?]</a>
|
|
</div>
|
|
<div className="configure-webcam wizard_control">
|
|
{backBtn}
|
|
{testBtn}
|
|
</div>
|
|
{rescanning}
|
|
</form>
|
|
{disableVideo}
|
|
</div>`
|
|
|
|
componentDidMount: () ->
|
|
|
|
if @props.isVisible
|
|
@beforeShow()
|
|
|
|
$root = $(@getDOMNode())
|
|
|
|
$videoSettingsHelp = $root.find('.ftue-video-settings-help')
|
|
context.JK.helpBubble($videoSettingsHelp, 'ftue-video-settings', {}, {width:300}) if $videoSettingsHelp.length > 0
|
|
$videoSettingsHelp.click(false)
|
|
|
|
$videoDisableHelp = $root.find('.ftue-video-disable-help')
|
|
context.JK.helpBubble($videoDisableHelp, 'ftue-video-disable', {}, {width:300}) if $videoDisableHelp.length > 0
|
|
$videoDisableHelp.click(false)
|
|
|
|
|
|
componentWillUpdate: (nextProps, nextState) ->
|
|
# protect against non-video clients pointed at video-enabled server from getting into a session
|
|
|
|
#@logger.debug("webcam devices", nextState.deviceNames, @state.deviceNames)
|
|
|
|
if !@initialScan?
|
|
@initialScan = true
|
|
else if @visible
|
|
@findChangedWebcams(nextState.deviceNames, @state.deviceNames)
|
|
|
|
componentWillReceiveProps:(nextProps) ->
|
|
if nextProps.isVisible
|
|
@beforeShow()
|
|
else
|
|
@beforeHide()
|
|
|
|
beforeShow:() ->
|
|
|
|
@visible = true
|
|
VideoActions.refresh()
|
|
VideoActions.stopVideo()
|
|
|
|
context.JK.onBackendEvent(ALERT_NAMES.USB_CONNECTED, 'webcam-viewer', @onUsbDeviceConnected);
|
|
context.JK.onBackendEvent(ALERT_NAMES.USB_DISCONNECTED, 'webcam-viewer', @onUsbDeviceDisconnected);
|
|
|
|
beforeHide: () ->
|
|
|
|
@visible = false
|
|
context.JK.offBackendEvent(ALERT_NAMES.USB_CONNECTED, 'webcam-viewer', @onUsbDeviceConnected);
|
|
context.JK.offBackendEvent(ALERT_NAMES.USB_DISCONNECTED, 'webcam-viewer', @onUsbDeviceDisconnected);
|
|
|
|
if @rescanTimeout?
|
|
clearTimeout(@rescanTimeout)
|
|
@rescanTimeout = null
|
|
|
|
@setVideoOff()
|
|
|
|
|
|
onUsbDeviceConnected: () ->
|
|
# don't handle USB events when minimized
|
|
#return if !context.jamClient.IsFrontendVisible()
|
|
|
|
logger.debug("USB device connected")
|
|
|
|
@scheduleRescanSystem(3000)
|
|
|
|
onUsbDeviceDisconnected:() ->
|
|
# don't handle USB events when minimized
|
|
#return if !context.jamClient.IsFrontendVisible()
|
|
|
|
logger.debug("USB device disconnected")
|
|
|
|
@scheduleRescanSystem(3000)
|
|
|
|
scheduleRescanSystem: (time) ->
|
|
if @rescanTimeout?
|
|
clearTimeout(@rescanTimeout)
|
|
@rescanTimeout = null
|
|
|
|
@setState({rescanning: true})
|
|
@rescanTimeout = setTimeout(() =>
|
|
@setState({rescanning: false})
|
|
VideoActions.refresh()
|
|
, time)
|
|
|
|
selectWebcam:(e) ->
|
|
e.preventDefault()
|
|
|
|
device = $(e.target).val()
|
|
|
|
VideoActions.selectDevice(device, {})
|
|
|
|
disableVideo: (e) ->
|
|
e.preventDefault()
|
|
|
|
return if @state.videoShared
|
|
|
|
if @state.videoEnabled
|
|
context.JK.Banner.showYesNo({
|
|
title: "Disable Video?",
|
|
html: "You will not be able to send or receive video.",
|
|
yes: =>
|
|
VideoActions.setVideoEnabled(false)
|
|
})
|
|
else
|
|
VideoActions.setVideoEnabled(true)
|
|
|
|
|
|
updateBackend: (captureResolution) ->
|
|
@logger.debug 'Selecting capture resolution: ', captureResolution
|
|
|
|
VideoActions.setCaptureResolution(captureResolution)
|
|
|
|
selectResolution:(e) ->
|
|
e.preventDefault()
|
|
|
|
resolution = $(e.target).val()
|
|
@logger.debug 'new capture resolution selected: ' + resolution
|
|
|
|
if resolution?
|
|
@updateBackend(resolution)
|
|
|
|
setVideoOff:() ->
|
|
VideoActions.stopVideo()
|
|
|
|
back: () =>
|
|
window.location = '/client#/account'
|
|
|
|
toggleWebcam:(e) ->
|
|
e.preventDefault()
|
|
|
|
return unless this.state.videoEnabled
|
|
|
|
$toggleBtn = $(e.target)
|
|
|
|
# we should only do this if no device is currently selected
|
|
$root = $(@getDOMNode())
|
|
$select = $root.find('.webcam-select-container select')
|
|
if Object.keys(@state.deviceNames).length == 0
|
|
|
|
context.JK.Banner.showYesNo({
|
|
yes_text: 'RUN TEST',
|
|
title: "Run Video Test?",
|
|
html: "A video window will show up with changing colors and shapes for 10 seconds. The test was successful if you were able to see the changing colors. Close the window once the colors and shapes stop changing.",
|
|
yes: =>
|
|
VideoActions.testVideo()
|
|
})
|
|
|
|
else
|
|
device = $select.val()
|
|
#VideoActions.selectDevice(device, {})
|
|
if VideoStore.videoShared
|
|
VideoActions.stopVideo()
|
|
else
|
|
VideoActions.toggleVideo()
|
|
|
|
|
|
#if this.isVideoShared()
|
|
# $toggleBtn.removeClass("selected")
|
|
# VideoActions.stopVideo()
|
|
# @setState({videoShared: false})
|
|
#else
|
|
# $toggleBtn.addClass("selected")
|
|
# VideoActions.startVideo()
|
|
# @setState({videoShared: true})
|
|
|
|
selectedDeviceName:(state) ->
|
|
webcamName = null
|
|
# protect against non-video clients pointed at video-enabled server from getting into a session
|
|
webcam = state.currentDevice
|
|
#@logger.debug("currently selected video device", webcam)
|
|
if (webcam? && Object.keys(webcam).length>0)
|
|
webcamName = Object.keys(webcam)[0]
|
|
|
|
webcamName
|
|
|
|
findChangedWebcams: (newList, oldList) ->
|
|
newKeys = Object.keys(newList)
|
|
oldKeys = Object.keys(oldList)
|
|
|
|
webcamSelect = $(@getDOMNode()).find('.webcam-select-container select')
|
|
|
|
if newKeys.length > oldKeys.length
|
|
for newKey in newKeys
|
|
if oldKeys.indexOf(newKey) == -1
|
|
newWebcam = newList[newKey]
|
|
@logger.debug("new webcam found: " + newWebcam, newKey)
|
|
context.JK.prodBubble(webcamSelect, 'new-webcam-found', {name: newWebcam}, {positions:['right']})
|
|
break
|
|
else if newKeys.length < oldKeys.length
|
|
for oldKey in oldKeys
|
|
if newKeys.indexOf(oldKey) == -1
|
|
oldWebcam = oldList[oldKey]
|
|
@logger.debug("webcam no longer found: " + oldWebcam)
|
|
context.JK.prodBubble(webcamSelect, 'old-webcam-lost', {name: oldWebcam}, {positions:['right']})
|
|
break
|
|
|
|
|
|
}
|
|
)
|
|
|
|
|