1 # ui-remote.tcl --
2 #
3 # FIXME: This file needs a description here.
4 #
5 # Copyright (c) 1993-2002 The Regents of the University of California.
6 # All rights reserved.
7 #
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions are met:
10 #
11 # A. Redistributions of source code must retain the above copyright notice,
12 # this list of conditions and the following disclaimer.
13 # B. Redistributions in binary form must reproduce the above copyright notice,
14 # this list of conditions and the following disclaimer in the documentation
15 # and/or other materials provided with the distribution.
16 # C. Neither the names of the copyright holders nor the names of its
17 # contributors may be used to endorse or promote products derived from this
18 # software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
21 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
24 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #
31 # @(#) $Header: /usr/mash/src/repository/mash/mash-1/tcl/rvic/ui-remote.tcl,v 1.33 2002/05/21 21:19:12 chema Exp $
32
33
34 #--------------#--------------#--------------#--------------
35 # ::TODO::
36 # - cl/srvr rendezvous
37 # - MUA agent
38 # -X use regex's for switching
39 # -X use cname if name not unique across members
40 # -X fix format change causing decoders to get confused
41 # -X fix race condition with shared memory writes to switching window
42 #--------------#--------------#--------------#--------------
43 # ::instance variable type info::
44 # - window_() ==> video widgets
45 # - attached_src_() ==> Source/RTPs
46 # - active_() ==> keys = Source/RTP ; attribs = SimpleActiveSource
47 # - allsrcs_ ==> Source/RTP
48 #--------------#--------------#--------------#--------------
49
50 import RTPAgent AudioMonitor VisualFrame Rendezvous RvicLayout
51
52
53 #-------------#-------------#-------------#-------------
54 # Class SimpleActiveSource
55 #-------------#-------------#-------------#-------------
56
57 # SimpleActiveSource has no tile thumbnails, no cmenu,
58 # and useHW hard-coded to 0.
59 Class SimpleActiveSource
60
61 #
62 SimpleActiveSource instproc init { parent src } {
63 $self next
64 $self instvar src_ parent_
65 set src_ $src
66 set parent_ $parent
67 }
68
69 # bind a source to a window so that the video stream from
70 # source $src appears in window $vw
71 SimpleActiveSource instproc attach-window vw {
72 $self instvar src_ parent_
73 # useHW set to 0 FIXME
74 $vw attach-decoder $src_ [[$parent_ set vframe_] set colorModel_] 0
75 }
76
77 #
78 SimpleActiveSource instproc detach-window vw {
79 $self instvar src_
80 $vw detach-decoder $src_
81 }
82
83 #
84 SimpleActiveSource instproc detach-windows {} {
85 #puts "SimpleActiveSource($self)::detach-windows"
86 $self instvar parent_
87
88 for {set i 1} {$i < 10} {incr i} {
89 set rtps [$parent_ attached_source $i]
90 set ss [$parent_ rtp2simple $rtps]
91 if {$ss == $self} {
92 set w [$parent_ window $i]
93 $self detach-window $w
94 #puts "detaching window [$parent_ window $i]"
95 $parent_ attached_source $i ""
96 }
97 }
98 }
99
100
101
102 #-------------#-------------#-------------#-------------
103 # Class RemoteVicUI
104 #-------------#-------------#-------------#-------------
105
106
107 import VicUI
108
109 #
110 # The main user interface for the rvic application.
111 #
112 Class RemoteVicUI -superclass VicUI
113
114 # returns SimpleActiveSource object for a given Source/RTP object
115 RemoteVicUI public rtp2simple {src} {
116 $self instvar active_
117 if {[info exists active_($src)]} {
118 return $active_($src)
119 } else {
120 return ""
121 }
122 }
123
124 # get or set attached_src_ instvar
125 RemoteVicUI public attached_source {i args} {
126 #puts "RemoteVicUI::attached_source $i $args"
127 $self instvar attached_src_
128
129 if {[llength $args] > 0} {
130 switch $args {
131 "" {unset attached_src_($i)}
132 "{}" {unset attached_src_($i)}
133 default {set attached_src_($i) $args}
134 }
135 } else {
136 if {[info exists attached_src_($i)]} {
137 return $attached_src_($i)
138 } else {
139 return ""
140 }
141 }
142 }
143
144 # window_ instvar accessor
145 #
146 RemoteVicUI public window {i} {
147 $self instvar window_
148 return $window_($i)
149 }
150
151 # resize & move window number `i' according to to `geom'
152 # <br> if `geom' == 0, delete (actually just hide) the window
153 #
154 RemoteVicUI public window_geom {i geom} {
155 $self instvar active_ path_
156 #puts "RemoteVicUI::window_geom $i => $geom"
157
158 if {$geom == 0} {
159 foreach {at val} "width 1 height 1 x 0 y 0" {
160 set $at $val
161 }
162 } else {
163 set gl [split $geom "x+"]
164 set width [expr int([lindex $gl 0]*640)]
165 set height [expr int([lindex $gl 1]*480)]
166 set x [lindex $gl 2]
167 set y [lindex $gl 3]
168 }
169 #puts "RemoteVicUI::window_geom $i => $width-by-$height at +$x+$y"
170
171 set w [$self window $i]
172 [$w window] resize $width $height
173 place configure $path_.top.vw$i -relx $x -rely $y
174
175 set att [$self attached_source $i]
176 if {$att != ""} {
177 if [info exists active_($att)] {
178 set as $active_($att)
179 $as detach-window $w
180 $as attach-window $w
181 }
182 }
183 after idle $w redraw
184 }
185
186 # toggle transmitting
187 RemoteVicUI public toggle_transmit {} {
188 $self instvar controlMenu_ xmit_
189 if $xmit_ {set xmit_ 0} else {set xmit_ 1}
190 #puts "RemoteVicUI::toggle_transmit (xmit_= $xmit_)"
191 $controlMenu_ invoke_transmit
192 }
193
194
195 #
196 # Build the "user-interface."
197 #
198 RemoteVicUI instproc build_gui { w } {
199 $self instvar videoAgent_ grid_ label_ controlMenu_ path_ vpipe_ \
200 vframe_ allsrcs_ window_ al_ voice_switched_ voice_sw_regex_ \
201 timer_switched_ timer_sw_regex_ layout_switched_ currLayout_ \
202 xmit_
203 set path_ $w
204 set vframe_ [new VisualFrame $w.top]
205 set allsrcs_ ""
206 set voice_switched_ "1" ; # defaults to vw 1
207 set voice_sw_regex_(1) "*"
208 set timer_switched_ "2" ; # defaults to vw 2
209 set timer_sw_regex_(2) "*"
210 set layout_switched_ 0
211 set xmit_ [$self yesno transmitOnStartup]
212
213 $self init_layouts
214
215 wm geometry . 640x480+0+0
216 place $w.top -x -5 -y -5 -width 640 -height 480
217 label $w.top.l -text "Waiting to finish configuring video windows..."
218 place $w.top.l -relx 0.5 -rely 0.5 -anchor c
219 set currLayout_ "none"
220 after idle "$self reconfig FocusPlusContext"
221 after idle "wm title . {rvic on [localaddr]:\
222 [$self get_option conferenceName]}"
223 after idle "$self match_layout_to_srcs"
224 after idle "$self start_timer_switching"
225
226 bind . <s> "$self print-active-sources"
227 bind . <q> "exit"
228 bind . <a> "$self switch_src all"
229 bind . <t> "$self toggle_transmit"
230 foreach {key configname} {y FocusPlusContext u Single i BradyBunch2x2 \
231 o BradyBunch3x3 p PictureInPicture} {
232 bind . <$key> "$self reconfig $configname"
233 }
234
235 foreach i {1 2 3 4 5 6 7 8 9} {
236 set p $w.top.vw$i
237 set window_($i) [new VideoWidget $p 320 240]
238 bind all <Key-$i> "$self switch_src $i"
239 }
240
241 # Note: sending {} for the ActiveSourceManager parameter
242 set controlMenu_ [new ControlMenu $self $videoAgent_ \
243 $vpipe_ $vframe_ {} [new UISrcListWindow $w $videoAgent_]]
244 $controlMenu_ build_window ;# never shows up
245
246 # start remote control interface
247 set ctrlAddr [$self get_option rvicCtrlSpec]
248 set al_ [new RvicCtrl $ctrlAddr $self]
249
250 # monitor the audio session for voice-switching
251 set aspec [$self get_option audioMonitorSpec]
252 if { $aspec != "" } {
253 set ab [new AddressBlock $aspec]
254 set monitor [new AudioMonitor $ab $self]
255 # audio doesn't want traffic looped back
256 #$audioAgent_ set-loopback 0
257 # send back-to-back packets spaced out at 128kb/s
258 #$audioAgent_ set-bandwidth 128
259 }
260 after 1000 "$self periodic_update"
261 }
262
263
264 # initialize to the set of "standard layouts", using the same syntax
265 # as messages on the wire
266 RemoteVicUI private init_layouts {} {
267 $self instvar layouts_
268 set layouts_ ""
269 lappend layouts_ [new RvicLayout Single \
270 "Set VideoWindowGeom\n\
271 1 1.0x1.0+0.0+0.0\n\
272 Set VoiceSwitchList\n\
273 1 *"]
274 lappend layouts_ [new RvicLayout PictureInPicture \
275 "Set VideoWindowGeom\n\
276 1 1.0x1.0+0.0+0.0\n\
277 2 0.25x0.25+0.7+0.05\n\
278 Set VoiceSwitchList\n\
279 1 *\n\
280 Set TimerSwitchList\n\
281 2 *"]
282 lappend layouts_ [new RvicLayout FocusPlusContext \
283 "Set VideoWindowGeom\n\
284 1 0.5x0.5+0.09375+0.09375\n\
285 2 0.25x0.25+0.6875+0.0625\n\
286 3 0.25x0.25+0.6875+0.3750\n\
287 4 0.25x0.25+0.0625+0.6875\n\
288 5 0.25x0.25+0.3750+0.6875\n\
289 6 0.25x0.25+0.6875+0.6875\n\
290 Set VoiceSwitchList\n\
291 1 *\n\
292 Set TimerSwitchList\n\
293 2 *"]
294 lappend layouts_ [new RvicLayout BradyBunch2x2 \
295 "Set VideoWindowGeom\n\
296 1 0.5x0.5+0.0+0.0\n\
297 2 0.5x0.5+0.5+0.0\n\
298 3 0.5x0.5+0.0+0.5\n\
299 4 0.5x0.5+0.5+0.5\n\
300 Set VoiceSwitchList\n\
301 1 *\n\
302 Set TimerSwitchList\n\
303 2 *"]
304 lappend layouts_ [new RvicLayout BradyBunch3x3 \
305 "Set VideoWindowGeom\n\
306 1 0.25x0.25+0.0625+0.0625\n\
307 2 0.25x0.25+0.375+0.0625\n\
308 3 0.25x0.25+0.6875+0.0625\n\
309 4 0.25x0.25+0.0625+0.375\n\
310 5 0.25x0.25+0.375+0.375\n\
311 6 0.25x0.25+0.6875+0.375\n\
312 7 0.25x0.25+0.0625+0.6875\n\
313 8 0.25x0.25+0.375+0.6875\n\
314 9 0.25x0.25+0.6875+0.6875\n\
315 Set VoiceSwitchList\n\
316 1 *\n\
317 Set TimerSwitchList\n\
318 2 *"]
319 }
320
321
322 #
323 # This reconfigures the video windows. <i>name</i> should be
324 # a string matching an RvicLayout::name of any of the existing
325 # RvicLayout objects listed in layouts_
326 #
327 RemoteVicUI instproc reconfig {name} {
328 $self instvar currLayout_ allsrcs_ path_ layouts_
329
330 # check for no sources
331 if {[llength $allsrcs_] == 0} {
332 if {[info commands $path_.top.l] == ""} {
333 label $path_.top.l -text "Waiting for video..."
334 place $path_.top.l -relx 0.5 -rely 0.5 -anchor c
335 } else {
336 $path_.top.l configure -text "Waiting for video..."
337 }
338 if {$currLayout_ == "none"} {after 6000 $self reconfig $name}
339 foreach i {1 2 3 4 5 6 7 8 9} {
340 $self window_geom $i 0
341 }
342 return
343 } else {
344 destroy $path_.top.l
345 }
346
347 set doneSwitch 0
348 # check `name' against each layout
349 foreach l $layouts_ {
350 if {$name == [$l name]} {
351 set doneSwitch 1
352 set n [$l num_windows]
353 for {set i 1} {$i <= $n} {incr i} {
354 $self window_geom $i [[$l get_window $i] geom]
355 }
356 for {set i [expr $n+1]} {$i <= 9} {incr i} {
357 $self window_geom $i 0
358 }
359 }
360 }
361 if !$doneSwitch {
362 puts "reconfig:: Bad layout: $name"
363 return
364 }
365 set currLayout_ $name
366 }
367
368
369 # Set up video widgets so that as many sources as possible are shown
370 # (a so-called "default view")
371 RemoteVicUI private default_vw_views {} {
372 $self instvar active_ allsrcs_ layout_switched_
373
374 set l [llength $allsrcs_]
375 if {$l == 0} {
376 after 5000 "$self default_vw_views"
377 return
378 }
379
380 foreach i {1 2 3 4 5 6 7 8 9} {
381 set idx [expr ($i-1) % $l]
382 set s [lindex $allsrcs_ $idx]
383 $self switch_src_to $i $s
384 }
385 }
386
387 # finds best match of configuration of windows
388 # to the number of sources by count of the number of windows.
389 # `Best' is defined as:
390 # <br><i> the minimum numwins s.t. numwins >= numsrcs </i> .
391 # <br> if <i> numsrcs > numwins </i> for all layouts, the layout
392 # with maximum numwins is used
393 #
394 RemoteVicUI public match_layout_to_srcs {} {
395 #puts "RemoteVicUI::match_layout_to_srcs"
396 $self instvar allsrcs_ layout_switched_ layouts_
397
398 if !$layout_switched_ {return}
399
400 set nsrcs [llength $allsrcs_]
401 set bestN 9999
402 set bestL ""
403 set maxN 0
404 set maxL ""
405 foreach l $layouts_ {
406 set nwins [$l num_windows]
407 if {$nwins > $maxN} {
408 set maxN $nwins
409 set maxL $l
410 }
411 #puts "$nsrcs <= $nwins && $nwins <= $bestN"
412 if {$nsrcs <= $nwins && $nwins < $bestN} {
413 set bestL $l
414 set bestN $nwins
415 }
416 }
417 if {$bestL == ""} {set bestL $maxL}
418 #puts "best layout: [$bestL name] for $nsrcs srcs"
419 $self reconfig [$bestL name]
420 $self default_vw_views
421 }
422
423 # Return a list of the active simpleactivesources.
424 RemoteVicUI instproc active-sources {} {
425 $self instvar active_
426 return [array names active_]
427 }
428
429 # prints active simpleactivesources.
430 RemoteVicUI instproc print-active-sources {} {
431 foreach i [$self active-sources] {puts "$i: [$i sdes cname] / [$i getid]"}
432 }
433
434
435 #
436 # Add the SimpleActiveSource, <i>ss</i>, to the <i>active_</i>
437 # array (indexed by Source/RTP, <i>src</i>).
438 # Also add the Source/RTP to the list, <i>allsrcs_</i>.
439 RemoteVicUI instproc add_active { ss src } {
440 $self instvar active_ allsrcs_
441 set active_($src) $ss
442 lappend allsrcs_ $src
443 $self match_layout_to_srcs
444 }
445
446 #
447 # Remove the Source, <i>src</i>, from the <i>active_</i> array and
448 # the <i>allsrcs_</i> list.
449 #
450 RemoteVicUI instproc rm_active src {
451 $self instvar active_ allsrcs_
452 unset active_($src)
453 set i [lsearch $allsrcs_ $src]
454 if {$i != -1} {
455 set allsrcs_ [lreplace $allsrcs_ $i $i]
456 }
457 $self match_layout_to_srcs
458 }
459
460 #
461 # Update the source descprtion by updating the element of the global
462 # arrays src_info(), src_nickname(), and src_name() indexed by the
463 # specified <i>src</i>. If the src_name() is changed, then this can
464 # be reflected via change_name
465 #
466 RemoteVicUI instproc trigger_sdes src {
467 global src_info src_nickname src_name
468 # Figure out best presentation from available information.
469 set name [$src sdes name]
470 set cname [$src sdes cname]
471 set addr [$src addr]
472 if { $name == "" } {
473 if { $cname == "" } {
474 set src_nickname($src) $addr
475 set info $addr/[$src format_name]
476
477 } else {
478 set src_nickname($src) $cname
479 set info "$addr/[$src format_name]"
480 }
481 } elseif [cname_redundant $name $cname] {
482 set src_nickname($src) $name
483 set info $addr/[$src format_name]
484 } else {
485 set src_nickname($src) $name
486 set info $cname/[$src format_name]
487 }
488 set src_info($src) $cname/[$src format_name]
489
490 set msg [$src sdes note]
491 if { $msg != "" } {
492 set info $msg
493 }
494 set src_info($src) $info
495
496 # only call change_name when name really changes
497 if { ![info exists src_name($src)] || "$src_name($src)" != "$name" } {
498 set src_name($src) $name
499 $self change_name $src
500 }
501 }
502
503 # noop
504 RemoteVicUI private change_name src {
505 #puts "RemoteVicUI::change_name $src ([$src sdes name]/[$src sdes cname])"
506 #Switcher rebuild_switch_list_menu
507 }
508
509
510 # Add a src to the active senders list. creates a
511 # SimpleActiveSource rather than an ActiveSource:
512 # i.e., no postage stamp window
513 RemoteVicUI instproc activate src {
514 #
515 # give the VideoAgent a chance to create and install
516 # a decoder and for that decoder to see a packet so it can
517 # determine the output geometry and color decimation.
518 # we shouldn't have to do this (e.g., resize will
519 # take care of a geometry change), but currently
520 # decoders can't trigger a renderer realloation
521 # when the decimation changes.FIXME fix this
522 #
523 after idle "$self really_activate $src"
524 }
525
526 #
527 RemoteVicUI instproc really_activate src {
528 set as [new SimpleActiveSource $self $src]
529 $self add_active $as $src
530 $self instvar allsrcs_ active_
531 # if any windows are empty, allocate this stream to them
532 foreach i {1 2 3 4 5 6 7 8 9} {
533 if {[$self attached_source $i] == ""} {
534 $as attach-window [$self window $i]
535 $self attached_source $i $src
536 }
537 }
538 }
539
540 # Remove a src from the active senders list.
541 #
542 RemoteVicUI instproc deactivate src {
543 #puts "RemoteVicUI::deactivate: $src"
544 $self instvar active_
545 if [info exists active_($src)] {
546 set as $active_($src)
547 $as detach-windows
548 $self rm_active $src
549 }
550
551 $src handler ""
552 }
553
554
555 # deal with format change <br>
556 # (only marginally tested: doesn't crash but the decoders can get confused)
557 RemoteVicUI instproc trigger_format src {
558 #puts "RemoteVicUI::trigger_format [$src getid]"
559 $self instvar active_ videoAgent_
560 if ![info exists active_($src)] {
561 return
562 }
563 set as $active_($src)
564 set L ""
565 for {set i 1} {$i < 10} {incr i} {
566 if {[$self attached_source $i] == $src} {
567 lappend L $i
568 }
569 }
570 $as detach-windows
571 #FIXME
572 set extoutList [extout_detach_src $src]
573
574 set d [$videoAgent_ reactivate $src]
575 ###set d [$videoAgent_ create_decoder $src]
576 $self update_decoder $src
577
578 foreach i $L {
579 set w [$self window $i]
580 $as attach-window $w
581 $w redraw
582 }
583 #FIXME
584 extout_attach_src $src $extoutList
585 }
586
587 #
588 # Called when the video stream state changes in a way that would
589 # affect the choice of renderer. For example, when a jpeg stream
590 # changes from type-0 to type-1 we might have to revert from
591 # hardware to software decoding, or we might have to reallocate
592 # a 422 renderer as a 420 renderer. This never needs to happen
593 # for most stream types (i.e., because the decimation factor is fixed).
594 # <br> FIXME - copied from hvic -- NEVER TESTED
595 RemoteVicUI instproc decoder_changed src {
596 $self instvar active_
597 if ![info exists active_($src)] {
598 return
599 }
600 #FIXME redundant with trigger_format
601 set as $active_($src)
602 $as detach-windows
603 #FIXME
604 set extoutList [extout_detach_src $src]
605 foreach w $iw {
606 $as attach-window $uw
607 $w redraw
608 }
609 #FIXME
610 extout_attach_src $src $extoutList
611 return
612 }
613
614
615
616 #-------------#-------------#-------------#-------------
617 # methods for dealing with switching window sources
618 #-------------#-------------#-------------#-------------
619
620
621 #
622 RemoteVicUI instproc switch_src_by_name {int name} {
623 $self instvar allsrcs_ active_
624
625 #puts "trying to switch $int to $name"
626 if { [llength $allsrcs_] > 0 } {
627 if {$name == ""} {
628 $self switch_src $int
629 return
630 }
631 set target ""
632 foreach s [array names active_] {
633 #puts "$name ?=? [$s getid]"
634 if {[string first $name [$s getid]] != -1} {
635 set target $s
636 }
637 }
638 if { $target == "" } {
639 foreach s [array names active_] {
640 if {[string first $name [$s sdes cname]] != -1} {
641 set target $s
642 }
643 }
644 }
645 if { $target == "" } {
646 foreach s [array names active_] {
647 if {[string first $name [$s sdes name]] != -1} {
648 set target $s
649 }
650 }
651 }
652 if { $target == "" } {
653 foreach s [array names active_] {
654 if {[string first $name [$s sdes note]] != -1} {
655 set target $s
656 }
657 }
658 }
659 if { $target == "" } {
660 puts stderr "no target - \"$name\""
661 if {[llength $name] > 1} {
662 puts "heuristic: trying [lindex $name 0]"
663 if {[regexp -nocase [lindex $name 0] [$s getid]]} {
664 set target $s
665 }
666 }
667 if { $target == "" } {
668 $self switch_src $int
669 return
670 }
671 }
672 $self switch_src_to $int $target
673 }
674 }
675
676 # for timer- or iterative- switching window `num': <br>
677 # returns the "next" source in the list of sources
678 # or "" if there are no sources
679 RemoteVicUI public next_src {num} {
680 $self instvar allsrcs_
681
682 set len [llength $allsrcs_]
683 if { $len > 0 } {
684 set curr_src [$self attached_source $num]
685 if {$curr_src != ""} {
686 set j [lsearch $allsrcs_ $curr_src]
687 set j [expr ($j+1) % $len]
688 return [lindex $allsrcs_ $j]
689 } else {
690 return [lindex $allsrcs_ 0]
691 }
692 } else {
693 return ""
694 }
695 }
696
697 # switch to next src in window `num' <br>
698 # if num == "all", switch all the windows
699 RemoteVicUI instproc switch_src {num} {
700 if {$num == "all"} {
701 for {set i 1} {$i < 10} {incr i} {
702 $self switch_src $i
703 }
704 return
705 }
706
707 $self instvar allsrcs_
708 set len [llength $allsrcs_]
709 if { $len > 0 } {
710 set nxt [$self next_src $num]
711 if {$nxt != ""} {
712 $self switch_src_to $num $nxt
713 }
714 }
715 }
716
717 # switch window number `num' to source object `src'
718 RemoteVicUI public switch_src_to {num src} {
719 $self instvar active_
720
721 set w [$self window $num]
722 if {[info exists active_($src)]} {
723 # detach old source
724 set curr_src [$self attached_source $num]
725 if {$curr_src != ""} {
726 if {[info exists active_($curr_src)]} {
727 set olds $active_($curr_src)
728 $olds detach-window $w
729 }
730 }
731 # attach new source
732 set as $active_($src)
733 $as attach-window $w
734 $self attached_source $num $src
735 $w redraw
736 }
737 }
738
739
740 #
741 # <i>audio_src</i> is an audio src. <br>
742 # <i>allsrcs_</i> are video sources <br>
743 # only voice-switches windows with indicies indicated
744 # in the list variable `voice_switched_'
745 #
746 RemoteVicUI instproc switch_to audio_src {
747 $self instvar allsrcs_ active_ voice_switched_
748
749 if { [string match *CoLab* [$audio_src getid]] } {
750 puts "Warning: ignoring CoLab audio sources..."
751 return
752 }
753 if { [llength $allsrcs_] > 0 } {
754 set target ""
755 foreach s $allsrcs_ {
756 if { "[$audio_src sdes cname]" == "[$s sdes cname]" } {
757 set target $s
758 }
759 }
760 if { $target == "" } {
761 puts stderr "no target: [$audio_src sdes cname]"
762 return
763 }
764 foreach i $voice_switched_ {
765 $self switch_src_to $i $target
766 }
767 }
768 }
769
770 #-----------------#-----------------#
771 # Timer switching
772 #-----------------#-----------------#
773
774
775 # initialize or re-initialize window timer switching
776 RemoteVicUI private start_timer_switching {} {
777 $self instvar timer_switched_ timer_sw_int_
778
779 # set default switch time
780 foreach i {1 2 3 4 5 6 7 8 9} {
781 set timer_sw_int_($i) 5
782 }
783 foreach i $timer_switched_ {
784 $self sched_timer $i
785 }
786 }
787
788 # schedule the next timer switching event for window `num'
789 # if it should be switched, canceling any existing scheduled switch
790 RemoteVicUI private sched_timer {num} {
791 $self instvar timer_switched_ timer_sw_regex_ timers_ timer_sw_int_
792 if [info exists timers_($num)] {
793 after cancel $timers_($num)
794 }
795
796 # check for reasons to stop switching this window
797 set idx [lsearch -exact $timer_switched_ $num]
798 if {$idx == -1} {return}
799 if {$timer_sw_int_($num) == 0} {
800 set timer_switched_ [lreplace $timer_switched_ $idx $idx]
801 return
802 }
803
804 set ms [expr $timer_sw_int_($num)*1000]
805 set timers_($num) [after $ms "$self timer_switch $num"]
806 }
807
808 # timer-switch window `num', and then schedule the next switch
809 RemoteVicUI private timer_switch {num} {
810 $self instvar timer_sw_int_ timer_sw_regex_ timers_
811 # FIXME ignoring regex for now...
812 $self switch_src $num
813 unset timers_($num)
814 $self sched_timer $num
815 }
816
817
818 #---------------#---------------#---------------#---------------
819 # RemoteVicUI methods that deal with messages of the form
820 # Set MethodName or Get MethodName
821 #---------------#---------------#---------------#---------------
822
823 #
824 RemoteVicUI private SourceList {data} {
825 $self instvar al_
826 set reply "SourceList"
827 foreach i [$self active-sources] {
828 append reply "\n" [$i getid]
829 #append reply "\n" [$i sdes cname]
830 }
831 $al_ announce $reply
832 }
833
834 #
835 RemoteVicUI private MonitorStyleList {data} {
836 $self instvar al_ layouts_
837 set reply "MonitorStyleList\n"
838 foreach layout $layouts_ {
839 append reply "[$layout name] {"
840 for {set i 1} {$i <= [$layout num_windows]} {incr i} {
841 append reply "[[$layout get_window $i] geom] "
842 }
843 append reply "}\n"
844 }
845 $al_ announce $reply
846 }
847
848 #
849 RemoteVicUI private MonitorStyle {data} {
850 $self instvar al_ currLayout_
851 if {[lrange $data 2 end] == ""} {
852 $al_ announce "MonitorStyle $currLayout_"
853 } else {
854 $self reconfig [lrange $data 2 end]
855 }
856 }
857
858 #
859 RemoteVicUI private VideoWindow {data} {
860 $self instvar al_
861 if {[llength $data] > 3} {
862 $self switch_src_by_name [lindex $data 2] [lrange $data 3 end]
863 } elseif {[llength $data] == 3} {
864 $self switch_src [lindex $data 2]
865 } else {
866 # blank argument: return update of vw-->cname mapping
867 set reply "VideoWindow\n"
868 append reply [$self build_sources_list]
869 $al_ announce $reply
870 }
871 }
872
873 #
874 RemoteVicUI private VideoWindowGeom {data} {
875 $self instvar al_
876 if {[llength $data] == 2} {
877 # FIXME respond with the geoms of the windows
878 #
879 #
880 return
881 }
882 set lines [split $data \n]
883 set lines [lrange $lines 1 end]
884 foreach line $lines {
885 if {$line == ""} {continue}
886 set idx [lindex $line 0]
887 set val [lrange $line 1 end]
888 $self window_geom $idx $val
889 }
890 }
891
892 #
893 RemoteVicUI private Autoswitchlayout {data} {
894 $self instvar al_ layout_switched_
895 switch [llength $data] {
896 2 {
897 if $layout_switched_ {set ls on} else {set ls off}
898 $al_ announce "Autoswitchlayout $ls"
899 }
900 3 {
901 set onoff [lindex $data 2]
902 $self set_autoswitching $onoff
903 }
904 default {
905 puts "Bad Autoswitchlayout msg: $data"
906 }
907 }
908 }
909
910 #
911 RemoteVicUI private VoiceSwitchList {data} {
912 $self instvar voice_switched_ voice_sw_regex_ al_
913 if {[llength $data] == 2} {
914 set reply [$self build_vswlist]
915 $al_ announce $reply
916 return
917 }
918 set lines [split $data \n]
919 set lines [lrange $lines 1 end]
920 foreach l $lines {
921 set idx [lindex $l 0]
922 set val [lrange $l 1 end]
923 if {$val == ""} {
924 # disable voice-switching
925 set lidx [lsearch -exact $voice_switched_ $idx]
926 if {$lidx != -1} {
927 set voice_switched_ \
928 [lreplace $voice_switched_ $lidx $lidx]
929 }
930 return
931 }
932 if {[lsearch -exact $voice_switched_ $idx] == -1} {
933 lappend voice_switched_ $idx
934 set voice_sw_regex_($idx) $val
935 }
936 }
937 }
938
939 #
940 RemoteVicUI private TimerSwitchList {data} {
941 $self instvar timer_switched_ timer_sw_regex_ al_
942 if {[llength $data] == 2} {
943 set reply [$self build_tswlist]
944 $al_ announce $reply
945 return
946 }
947 set lines [split $data \n]
948 set lines [lrange $lines 1 end]
949 foreach l $lines {
950 set idx [lindex $l 0]
951 set val [lrange $l 1 end]
952 if {$val == ""} {
953 # disable timer-switching
954 set lidx [lsearch -exact $timer_switched_ $idx]
955 if {$lidx != -1} {
956 set timer_switched_ \
957 [lreplace $timer_switched_ $lidx $lidx]
958 }
959 return
960 }
961 if {[lsearch -exact $timer_switched_ $idx] == -1} {
962 lappend timer_switched_ $idx
963 set timer_sw_regex_($idx) $val
964 $self sched_timer $idx
965 }
966 }
967 }
968
969 #
970 RemoteVicUI private SwitchInterval {data} {
971 $self instvar timer_sw_int_
972 set lines [split $data \n]
973 set lines [lrange $lines 1 end]
974 foreach l $lines {
975 set idx [lindex $l 0]
976 set val [lrange $l 1 end]
977 set timer_sw_int_($idx) $val
978 $self sched_timer $idx
979 }
980 }
981
982 # Set or Get TransmitVideo state
983 RemoteVicUI private TransmitVideo {data} {
984 $self instvar xmit_ al_
985 switch [llength $data] {
986 2 {}
987 3 {
988 set onoff [lindex $data 2]
989 if {$xmit_ != $onoff} {$self toggle_transmit}
990 }
991 default {puts "Bad TransmitVideo msg: $data"}
992 }
993 $al_ announce "TransmitVideo $xmit_"
994 }
995
996 #
997 # answer with the current session IP address (one line per
998 # layer). If the command is Set, set the session address
999 #
1000 RemoteVicUI private SessionAddress {data} {
1001 $self instvar al_
1002 $self instvar videoAgent_
1003
1004
1005 if {[lindex $data 0] == "Set"} {
1006 # set the new session address
1007 set spec [lindex $data 2]
1008 $videoAgent_ reset_spec $spec
1009 }
1010
1011 # answer with the current (or new) session address
1012 set reply "SessionAddress"
1013
1014 # get the network manager object from the VideoAgent
1015 set networkManager [$videoAgent_ set network_]
1016
1017 for {set i 0} {$i < [$networkManager set nchan_]} {incr i} {
1018 # get the ith network layer
1019 set networkLayer [$networkManager set net_($i)]
1020 # get the ith network layer's address and source
1021 append reply "\n" "[$networkLayer set addr_]/[$networkLayer set port_]"
1022 }
1023
1024 $al_ announce $reply
1025 }
1026
1027
1028 #-------------#-------------
1029 # helpers for message handlers
1030 #-------------#-------------
1031
1032 #
1033 RemoteVicUI private build_vswlist {} {
1034 $self instvar voice_switched_ voice_sw_regex_
1035 set reply "VoiceSwitchList"
1036 foreach i $voice_switched_ {
1037 append reply "\n$i $voice_sw_regex_($i)"
1038 }
1039 return $reply
1040 }
1041
1042 #
1043 RemoteVicUI private build_tswlist {} {
1044 $self instvar timer_switched_ timer_sw_regex_
1045 set reply "TimerSwitchList"
1046 foreach i $timer_switched_ {
1047 append reply "\n$i $timer_sw_regex_($i)"
1048 }
1049 return $reply
1050 }
1051
1052 # set whether to automatically match layout to the number of srcs
1053 RemoteVicUI private set_autoswitching {onoff} {
1054 $self instvar layout_switched_
1055 if {$onoff == "on"} {set onoff 1} else {set onoff 0}
1056 set layout_switched_ $onoff
1057 $self match_layout_to_srcs
1058 }
1059
1060 # return a textual list of the current window sources
1061 # (indexed, newline-separated lines)
1062 #
1063 # (TODO: also append sdes name if different, handle the two @ client)
1064 RemoteVicUI private build_sources_list {} {
1065 #puts "RemoteVicUI::build_sources_list"
1066 set reply ""
1067 foreach i {1 2 3 4 5 6 7 8 9} {
1068 #puts "$i: [$self attached_source $i]"
1069 append reply "$i "
1070 set as [$self attached_source $i]
1071 if {![string match *_o* $as] && ![string match "" $as]} {
1072 puts "Error: attached_source returned `$as'"
1073 }
1074 if {$as != ""} {
1075 append reply [$as getid]
1076 } else {
1077 append reply "(empty)"
1078 }
1079 append reply "\n"
1080 }
1081 ##puts " ... done."
1082 return [string trim $reply]
1083 }
1084
1085
1086
1087 #-------------#-------------#-------------#-------------
1088 # Class RvcCtrl
1089 #-------------#-------------#-------------#-------------
1090
1091 import UDPServer
1092
1093 # The remote-control interface to RVIC
1094 Class RvicCtrl -superclass UDPServer
1095
1096 #
1097 RvicCtrl public init {spec parent} {
1098 eval [list $self] next $spec
1099 $self instvar parent_
1100 set parent_ $parent
1101