1 # synch-switch.tcl --
2 #
3 # FIXME: This file needs a description here.
4 #
5 # Copyright (c) 1999-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 import Observer
32 import SynchSrcVideoAgent
33 import VideoAgent
34
35 Class SynchSwitch;
36
37 SynchSwitch instproc init {app} {
38 $self next;
39
40 $self instvar sources_ synch_transmitters_ source_sessions_
41 $self instvar master_lts_;
42 $self instvar app_;
43 $self instvar new_source_cmd_;
44
45 set app_ $app;
46
47 set sources_ "";
48 set source_sessions_ "";
49 set synch_transmitters_ "";
50
51 set master_lts_ [new SynchLTS];
52 $master_lts_ speed 1.0;
53 $master_lts_ set_reference 0 0;
54
55 set new_source_cmd_ "";
56
57 $self instvar expansion_speed_ compression_speed_;
58
59 set expansion_speed_ 0.9;
60 set compression_speed_ 1.1;
61 }
62
63 SynchSwitch instproc register_source {sess src} {
64 $self instvar sources_ master_lts_
65
66 set new_src [new SynchSource $sess $src $master_lts_];
67 lappend sources_ $new_src;
68
69 $self instvar new_source_cmd_;
70
71 if {$new_source_cmd_ != ""} {
72 eval $new_source_cmd_ $new_src
73 }
74
75 return $new_src
76 }
77
78 SynchSwitch instproc unregister_source {src} {
79 $self instvar sources_;
80
81 set k [lsearch -exact $sources_ $src];
82 set sources_ [lreplace $sources_ $k $k];
83
84 delete $src;
85 }
86
87 Class SynchTransmitAgent -superclass VideoAgent
88
89 SynchTransmitAgent instproc create_decoder {src} {
90 set decoder [new Module/VideoDecoder/Null];
91 $decoder set src_ $src;
92 $decoder set agent_ $self;
93 return $decoder;
94 }
95
96 SynchTransmitter instproc init {switch spec} {
97 $self instvar sess_ switch_ src_ srcid_ cur_src_ spec_;
98
99 set spec_ $spec;
100 set sess_ [new SynchTransmitAgent [$switch set app_] $spec];
101
102 # This is a call to RTPAgent::get_transmitter{}. It returns a handler to
103 # the Session/RTP/Video object handler created by
104 # VideoAgent::create_session{}
105 [$sess_ get_transmitter] set loopback_ 0;
106
107 # SynchTransmitAgent::local_ is the Source/RTP object that contains the
108 # information of our own Source object
109 set src_ [$sess_ set local_];
110 set srcid_ [$sess_ get_local_srcid];
111 set cur_src_ "";
112
113 $self target [$sess_ get_transmitter];
114 $self reset;
115 }
116
117 Class SynchSource -superclass Observer
118
119 SynchSource instproc init {sess src master} {
120 $self next;
121
122 $self instvar sess_ src_ master_;
123
124 set sess_ $sess;
125 set src_ $src;
126 set master_ $master;
127
128 $self instvar synch_buffer_ lts_;
129
130 set synch_buffer_ [new SynchBuffer];
131 $synch_buffer_ set synch_src_ $self;
132
133 set lts_ [new SynchLTS];
134
135 $synch_buffer_ lts $lts_;
136 $lts_ lts $master;
137 $lts_ speed 1.0;
138 $synch_buffer_ reset_reference;
139 $sess_ attach $self
140 }
141
142 SynchSource public trigger_sr {src} {
143 $self instvar src_;
144
145 if {$src == $src_} {
146 $self instvar synch_buffer_;
147
148 $synch_buffer_ synch_to_source $src_;
149 }
150 }
151
152 SynchSource instproc synch_buffer {} {
153 $self instvar synch_buffer_;
154
155 return $synch_buffer_;
156 }
157
158 SynchSource instproc buffer_latency {} {
159 $self instvar synch_buffer_;
160 return [$synch_buffer_ buffer_latency];
161 }
162
163 SynchSource instproc num_frames {} {
164 $self instvar synch_buffer_;
165 return [$synch_buffer_ num_frames];
166 }
167
168 SynchSource instproc destroy {} {
169 $self instvar synch_buffer_ lts_;
170 $lts_ lts "";
171 $synch_buffer_ lts "";
172 delete $lts_;
173 delete $synch_buffer_;
174
175 $self instvar sess_;
176 $sess_ detach $self;
177
178 $self next;
179 }
180
181 #################
182 # Below is API for Synch Switch although
183 # this is not strictly enforced (i.e.,
184 # procedures defined above are accessible).
185 ################
186
187 # add_source_session
188 # Add session for possible sources
189
190 SynchSwitch instproc add_source_session {spec} {
191 $self instvar app_ source_sessions_;
192
193 set new_sess [new SynchSrcVideoAgent $app_ $self $spec];
194 lappend source_sessions_ $new_sess;
195 }
196
197 # new_source_command
198 # Set callback for when new source is heard
199
200 SynchSwitch instproc new_source_command {args} {
201 $self instvar new_source_cmd_;
202
203 if {[llength $args] == 0} {
204 return $new_source_cmd_;
205 } else {
206 set new_source_cmd_ [lindex $args 0];
207 }
208 }
209
210 # sources
211 # Return list of sources we know about.
212
213 SynchSwitch instproc sources {} {
214 $self instvar sources_;
215
216 return $sources_;
217 }
218
219 # create_synch_transmitter
220 # Create a new source for transmission
221
222 SynchSwitch instproc create_synch_transmitter {spec} {
223 $self instvar synch_transmitters_
224
225 set tsrc [new SynchTransmitter $self $spec];
226
227 lappend synch_transmitters_ $tsrc;
228 return $tsrc;
229 }
230
231 # buffer_latency
232 # Query current estimated buffer latency for a source.
233 # If <src> is "", returns a list of source/latency pairs
234 # for all known sources.
235
236 SynchSwitch instproc buffer_latency {{src ""}} {
237 if {$src != ""} {
238 return [$src buffer_latency];
239 } else {
240 $self instvar sources_;
241 set res "";
242 foreach s $sources_ {
243 lappend res [list $s [$s buffer_latency]];
244 }
245 return $res;
246 }
247 }
248
249 # master_speed
250 # Set/query master LTS speed
251
252 SynchSwitch instproc master_speed {{speed ""}} {
253 $self instvar master_lts_;
254
255 if {$speed == ""} {
256 return [$master_lts_ speed];
257 } else {
258 $master_lts_ speed $speed;
259 }
260 }
261
262 # master_offset_adjust
263 # Adjust master logical offset by <delta>
264
265 SynchSwitch instproc master_offset_adjust {delta} {
266 $self instvar master_lts_;
267
268 $master_lts_ adjust $delta;
269 }
270
271 # master_time_expansion_speed
272 # Set/query speed used for time expansion
273
274 SynchSwitch instproc master_time_expansion_speed {{speed ""}} {
275 $self instvar expansion_speed_;
276
277 if {$speed == ""} {
278 return $expansion_speed_;
279 } else {
280 set expansion_speed_ $speed;
281 }
282 }
283
284 # master_time_compression_speed
285 # Set/query speed used for time compression
286
287 SynchSwitch instproc master_time_compression_speed {{speed ""}} {
288 $self instvar compression_speed_;
289
290 if {$speed == ""} {
291 return $compression_speed_;
292 } else {
293 set compression_speed_ $speed;
294 }
295 }
296
297 # prep_switch
298 # Switch transmission to specified source after
299 # eliminating negative latency. Positive latencies
300 # eliminated after switch only if <no_positive> flag
301 # set.
302
303 SynchSwitch instproc prep_switch {src transmitter {no_positive 0}} {
304 $self instvar pending_action_ expansion_speed_ compression_speed_;
305
306 if {[info exists pending_action_]} {
307 after cancel $pending_action_;
308 unset pending_action_;
309 $self master_speed 1.0;
310 }
311
312 set sb [$src set synch_buffer_];
313 set lat [$sb buffer_latency];
314 if {$lat < -0.030} {
315 $self master_speed $expansion_speed_;
316 set delta [expr int((($lat * -1.0)/(1.0 - $expansion_speed_)) * 1000.0)];
317
318 set pending_action_ [after $delta "$self straight_switch $src $transmitter"];
319 } else {
320 $self straight_switch $src $transmitter;
321 if {($lat > 0.030) && $no_positive} {
322 $self master_speed $compression_speed_;
323 set delta [expr int(($lat / ($compression_speed_ - 1.0)) * 1000.0)];
324 set pending_action_ [after $delta "$self straight_switch $src $transmitter"];
325 }
326 }
327 }
328
329 # switch_prep
330 # Switch transmission to specified source immediately,
331 # eliminate negative latency after switch. Positive
332 # latencies eliminated after switch only if <no_positive>
333 # flag set.
334
335 SynchSwitch instproc switch_prep {src transmitter {no_positive 0}} {
336 $self instvar pending_action_ expansion_speed_ compression_speed_;
337
338 if {[info exists pending_action_]} {
339 after cancel $pending_action_;
340 unset pending_action_;
341 $self master_speed 1.0;
342 }
343
344 $self straight_switch $src $transmitter;
345
346 set sb [$src set synch_buffer_];
347 set lat [$sb buffer_latency];
348 if {$lat < -0.030} {
349 $self master_speed $expansion_speed_;
350 set delta [expr int((($lat * -1.0)/(1.0 - $expansion_speed_)) * 1000.0)];
351 set pending_action_ [after $delta "$self straight_switch $src $transmitter"];
352 } else {
353 if {($lat > 0.030) && $no_positive} {
354 $self master_speed $compression_speed_;
355 set delta [expr int(($lat / ($compression_speed_ - 1.0)) * 1000.0)];
356 set pending_action_ [after $delta "$self straight_switch $src $transmitter"];
357 }
358 }
359 }
360
361 # straight_switch
362 # Switch transmission without adjusting for latencies
363
364 SynchSwitch instproc straight_switch {src transmitter} {
365 $self instvar sources_ pending_action_;
366
367 if {[info exists pending_action_]} {
368 after cancel $pending_action_;
369 unset pending_action_;
370 $self master_speed 1.0;
371 }
372
373 if {[$transmitter set cur_src_] == $src} {
374 return;
375 }
376
377 set sb [$src set synch_buffer_];
378
379 if {[lsearch -exact $sources_ [$transmitter set cur_src_]] != -1} {
380 set old_sb [[$transmitter set cur_src_] set synch_buffer_];
381 if {[$old_sb target] == $transmitter} {
382 $old_sb target "";
383 }
384 $transmitter set cur_src_ "";
385 }
386 $transmitter reset;
387 $transmitter set cur_src_ $src;
388 $sb target $transmitter;
389 }
390
391
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.