2020-12-28 21:25:42 +01:00
|
|
|
|
class RemoteCamera extends this.OS.application.BaseApplication
|
|
|
|
|
constructor: ( args ) ->
|
|
|
|
|
super "RemoteCamera", args
|
|
|
|
|
|
|
|
|
|
main: () ->
|
2020-12-29 21:55:34 +01:00
|
|
|
|
|
|
|
|
|
@decoder = new Worker("pkg://RemoteCamera/decoder.js".asFileHandle().getlink())
|
|
|
|
|
|
|
|
|
|
@decoder.onmessage = (e) =>
|
|
|
|
|
@paint e.data
|
|
|
|
|
|
|
|
|
|
@decoder.postMessage {libjpeg: "pkg://libjpeg/jpg.js".asFileHandle().getlink()}
|
|
|
|
|
|
2020-12-28 21:25:42 +01:00
|
|
|
|
@mute = false
|
|
|
|
|
@player = @find "player"
|
|
|
|
|
|
|
|
|
|
@qctl = @find "qctl"
|
|
|
|
|
|
|
|
|
|
@fpsctl = @find "fpsctl"
|
|
|
|
|
|
2020-12-29 21:55:34 +01:00
|
|
|
|
|
|
|
|
|
|
2020-12-28 21:25:42 +01:00
|
|
|
|
@cam_setting = {
|
|
|
|
|
w: 640,
|
|
|
|
|
h: 480,
|
|
|
|
|
fps: 10,
|
|
|
|
|
quality: 60
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fps = []
|
|
|
|
|
for i in [5..30] by 5
|
|
|
|
|
fps.push {
|
|
|
|
|
text: "#{i}",
|
|
|
|
|
value: i
|
|
|
|
|
}
|
|
|
|
|
@fpsctl.data = fps
|
|
|
|
|
@fpsctl.selected = @cam_setting.fps/5 -1
|
|
|
|
|
|
|
|
|
|
@fpsctl.onlistselect = (e) =>
|
|
|
|
|
return if @mute
|
|
|
|
|
@cam_setting.fps = e.data.item.data.value
|
|
|
|
|
@setCameraSetting()
|
|
|
|
|
|
|
|
|
|
@qctl.value = @cam_setting.quality
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@resoctl = @find "resoctl"
|
|
|
|
|
|
|
|
|
|
@resoctl.data = [
|
|
|
|
|
{
|
|
|
|
|
text: __("320x240"),
|
|
|
|
|
mode: "qvga"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
text: __("640x480"),
|
|
|
|
|
selected: true,
|
|
|
|
|
mode: "vga"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
text: __("800x600"),
|
|
|
|
|
mode: "svga"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
text: __("1024x760"),
|
|
|
|
|
mode: "hd"
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
text: __("1920×1080"),
|
|
|
|
|
mode: "fhd"
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
@resoctl.onlistselect = (e) =>
|
|
|
|
|
return if @mute
|
|
|
|
|
switch e.data.item.data.mode
|
|
|
|
|
when "qvga"
|
|
|
|
|
@cam_setting.w = 320
|
|
|
|
|
@cam_setting.h = 240
|
|
|
|
|
when "vga"
|
|
|
|
|
@cam_setting.w = 640
|
|
|
|
|
@cam_setting.h = 480
|
|
|
|
|
when "svga"
|
|
|
|
|
@cam_setting.w = 800
|
|
|
|
|
@cam_setting.h = 600
|
|
|
|
|
when "hd"
|
|
|
|
|
@cam_setting.w = 1024
|
|
|
|
|
@cam_setting.h = 768
|
|
|
|
|
when "fhd"
|
|
|
|
|
@cam_setting.w = 1920
|
|
|
|
|
@cam_setting.h = 1080
|
|
|
|
|
@setCameraSetting()
|
|
|
|
|
|
|
|
|
|
@qctl.onvaluechange = (e) =>
|
|
|
|
|
return if @mute
|
|
|
|
|
@cam_setting.quality = e.data
|
|
|
|
|
@setCameraSetting()
|
|
|
|
|
|
|
|
|
|
return @notify __("Antunnel service is not available") unless Antunnel.tunnel
|
|
|
|
|
if not @setting.channel
|
|
|
|
|
@requestChannel()
|
|
|
|
|
else
|
|
|
|
|
@openSession()
|
|
|
|
|
|
|
|
|
|
requestChannel: () ->
|
|
|
|
|
@openDialog "PromptDialog", {
|
|
|
|
|
title: __("Enter camera channel"),
|
|
|
|
|
label: __("Please enter camera channel name")
|
|
|
|
|
}
|
|
|
|
|
.then (v) =>
|
|
|
|
|
@setting.channel = v
|
2020-12-29 21:55:34 +01:00
|
|
|
|
return @openSession() unless @sub
|
|
|
|
|
@sub.onclose = (e) =>
|
|
|
|
|
@openSession()
|
|
|
|
|
@sub.close()
|
|
|
|
|
|
|
|
|
|
paint: (msg) ->
|
|
|
|
|
# console.log msg
|
|
|
|
|
data = new Uint8Array msg.pixels
|
|
|
|
|
ctx = @player.getContext "2d", { alpha: false }
|
|
|
|
|
@player.width = msg.w
|
|
|
|
|
@player.height = msg.h
|
|
|
|
|
imgData = ctx.createImageData msg.w, msg.h
|
|
|
|
|
imgData.data.set data
|
|
|
|
|
ctx.putImageData imgData, 0, 0
|
2020-12-28 21:25:42 +01:00
|
|
|
|
|
|
|
|
|
menu: () ->
|
|
|
|
|
{
|
|
|
|
|
text: "__(Option)",
|
|
|
|
|
nodes: [
|
|
|
|
|
{ text: "__(Camera channel)" }
|
|
|
|
|
],
|
|
|
|
|
onchildselect: (e) => @requestChannel()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
openSession: () ->
|
|
|
|
|
return unless Antunnel
|
|
|
|
|
return unless @setting.channel
|
|
|
|
|
@tunnel = Antunnel.tunnel
|
|
|
|
|
@sub = new Antunnel.Subscriber(@setting.channel)
|
|
|
|
|
@sub.onopen = () =>
|
|
|
|
|
console.log("Subscribed to camera channel")
|
|
|
|
|
|
|
|
|
|
@sub.onerror = (e) =>
|
|
|
|
|
@error __("Error: {0}", new TextDecoder("utf-8").decode(e.data)), e
|
|
|
|
|
#@sub = undefined
|
|
|
|
|
@sub.onctrl = (e) =>
|
|
|
|
|
@cam_setting.w = Antunnel.Msg.int_from(e.data,0)
|
|
|
|
|
@cam_setting.h = Antunnel.Msg.int_from(e.data,2)
|
|
|
|
|
@cam_setting.fps = e.data[4]
|
|
|
|
|
@cam_setting.quality = e.data[5]
|
|
|
|
|
@mute = true
|
|
|
|
|
@qctl.value = @cam_setting.quality
|
|
|
|
|
res = "#{@cam_setting.w}x#{@cam_setting.h}"
|
|
|
|
|
switch res
|
|
|
|
|
when "320x240"
|
|
|
|
|
@resoctl.selected = 0
|
|
|
|
|
when "640x480"
|
|
|
|
|
@resoctl.selected = 1
|
|
|
|
|
when "800x600"
|
|
|
|
|
@resoctl.selected = 2
|
|
|
|
|
when "1024x768"
|
|
|
|
|
@resoctl.selected = 3
|
|
|
|
|
when "1920x1080"
|
|
|
|
|
@resoctl.selected = 4
|
|
|
|
|
@fpsctl.selected = @cam_setting.fps/5 -1
|
|
|
|
|
@mute = false
|
|
|
|
|
|
|
|
|
|
@sub.onmessage = (e) =>
|
2020-12-29 21:55:34 +01:00
|
|
|
|
return unless @decoder
|
|
|
|
|
@decoder.postMessage e.data.buffer, [e.data.buffer]
|
2020-12-28 21:25:42 +01:00
|
|
|
|
|
|
|
|
|
@sub.onclose = () =>
|
|
|
|
|
@sub = undefined
|
|
|
|
|
@notify __("Unsubscribed to the camera service")
|
2020-12-29 21:55:34 +01:00
|
|
|
|
return @quit()
|
2020-12-28 21:25:42 +01:00
|
|
|
|
Antunnel.tunnel.subscribe @sub
|
|
|
|
|
|
|
|
|
|
cleanup: () ->
|
|
|
|
|
@sub.close() if @sub
|
2020-12-29 21:55:34 +01:00
|
|
|
|
@decoder.terminate() if @decoder
|
2020-12-28 21:25:42 +01:00
|
|
|
|
|
|
|
|
|
setCameraSetting: () ->
|
|
|
|
|
return unless @sub
|
|
|
|
|
arr = new Uint8Array(6)
|
|
|
|
|
arr.set Antunnel.Msg.bytes_of(@cam_setting.w), 0
|
|
|
|
|
arr.set Antunnel.Msg.bytes_of(@cam_setting.h), 2
|
|
|
|
|
arr[4] = @cam_setting.fps
|
|
|
|
|
arr[5] = @cam_setting.quality
|
|
|
|
|
@sub.send Antunnel.Msg.CTRL, arr
|
|
|
|
|
|
|
|
|
|
RemoteCamera.singleton = true
|
2020-12-29 21:55:34 +01:00
|
|
|
|
|
2020-12-28 21:25:42 +01:00
|
|
|
|
this.OS.register "RemoteCamera", RemoteCamera
|