~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Open Mash Cross Reference
mash/tcl/net/agent-rtp.tcl

Component: ~ [ mash ] ~ [ apps ] ~ [ gsm ] ~ [ lib ] ~ [ otcl ] ~ [ srm ] ~ [ tcl8.3 ] ~ [ tclcl ] ~ [ tk8.3 ] ~ [ tutorials ] ~

  1 # agent-rtp.tcl --
  2 #
  3 #       Source/RTP, MediaAgent and RTPAgent object definitions.
  4 #
  5 # Copyright (c) 1996-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/net/agent-rtp.tcl,v 1.79 2004/01/12 22:18:59 aswan Exp $
 32 
 33 
 34 # make sure we have network utilities
 35 import SessionAddress NetworkManager Observable mashutils Configuration
 36 
 37 #
 38 # Default value for C++ instance variables.
 39 #
 40 Source/RTP set reportLoss_ 0
 41 Session/RTP set nb_ 0
 42 Session/RTP set nf_ 0
 43 Session/RTP set np_ 0
 44 Session/RTP set loopback_ 1
 45 
 46 Source/RTP set badsesslen_ 0
 47 Source/RTP set badsessver_ 0
 48 Source/RTP set badsessopt_ 0
 49 Source/RTP set badsdes_ 0
 50 Source/RTP set badbye_ 0
 51 SourceLayer/RTP set nchan_ 1
 52 
 53 Session/RTP set badversion_ 0
 54 Session/RTP set badoptions_ 0
 55 Session/RTP set badfmt_ 0
 56 Session/RTP set badext_ 0
 57 Session/RTP set nrunt_ 0
 58 
 59 #FIXME
 60 Session/RTP set loopbackLayer_ 1000
 61 
 62 Source/RTP public layer-stat which {
 63         $self instvar layers_
 64         set s 0
 65         foreach l $layers_ {
 66                 set s [expr $s + [$l set $which]]
 67         }
 68         return $s
 69 }
 70 
 71 Source/RTP public ns {} {
 72         $self instvar layers_
 73         set s 0
 74         foreach l $layers_ {
 75                 set s [expr $s + [$l set cs_] - [$l set fs_]]
 76         }
 77         return $s
 78 }
 79 
 80 Source/RTP public missing {} {
 81         $self instvar layers_
 82         set s 0
 83         foreach l $layers_ {
 84                 set nm [expr [$l set cs_] - [$l set fs_] - [$l set np_]]
 85                 if { $nm > 0 } {
 86                         set s [expr $s + $nm]
 87                 }
 88         }
 89         return $s
 90 }
 91 
 92 # FIXME
 93 Source/RTP instproc is_mixer {} {
 94         return [expr [$self srcid] != [$self ssrc]]
 95 }
 96 
 97 SourceLayer/RTP set nrunt_ 0
 98 SourceLayer/RTP set ndup_ 0
 99 SourceLayer/RTP set fs_ 0
100 SourceLayer/RTP set cs_ 0
101 SourceLayer/RTP set np_ 0
102 SourceLayer/RTP set nf_ 0
103 SourceLayer/RTP set nb_ 0
104 SourceLayer/RTP set nm_ 0
105 SourceLayer/RTP set ntp_ts_sec_ 0
106 SourceLayer/RTP set ntp_ts_fsec_ 0
107 SourceLayer/RTP set mts_ 0
108 SourceLayer/RTP set ref_ntp_sec_ 0
109 SourceLayer/RTP set ref_ntp_fsec_ 0
110 SourceLayer/RTP set ref_mts_ 0
111 
112 
113 Source/RTP public init { sm srcid ssrc addr } {
114         $self next $srcid $ssrc $addr
115         $self set sm_ $sm
116         $self instvar layers_
117         set k 0
118         set report 0
119         if { [$sm info vars network_] != "" } {
120                 set net [$sm set network_]
121                 set n [$net set nchan_]
122                 set report [$net usingRLM]
123         } else {
124                 set n [SourceLayer/RTP set nchan_]
125         }
126         while { $k < $n } {
127                 set l [new SourceLayer/RTP]
128                 lappend layers_ $l
129                 $self layer $k $l
130                 incr k
131         }
132 
133         $self set reportLoss_ $report
134 }
135 
136 
137 Source/RTP public destroy {} {
138         $self instvar sm_
139 
140         # delete all the layers associated to this source (SourceLayer/RTP objects)
141         foreach layer [$self set layers_] {
142                 $layer destroy
143         }
144 
145         # if the Source/RTP object is associated to a data handler (i.e., if the 
146         # source to which the object is associated is sending data), deactivate 
147         # the corresponding decoder
148         if {[$self data-handler] != ""} {
149                 $self deactivate
150         }
151 
152         # unregister and delete the source in the SourceManager
153         $self unregister
154         $sm_ delete $self;
155 
156         # destroy the object
157         $self next
158 }
159 
160 
161 
162 #
163 # Return the best name for the given source, based on
164 # the possibly limited information we have.
165 #
166 Source/RTP public getid {} {
167         set name [$self sdes name]
168         if { $name == "" } {
169                 set name [$self sdes cname]
170                 if { $name == "" } {
171                         set name [$self addr]
172                 }
173         }
174         return $name
175 }
176 
177 #
178 # Return a the RTP format name as a string for the RTP
179 # payload format of the media stream underlying this source
180 # object.
181 #
182 Source/RTP public format_name {} {
183         $self instvar sm_
184         return [$sm_ rtp_type [$self format]]
185 }
186 
187 #
188 # The <u>MediaAgent</u> class is the core programming layer
189 # for all ``media agents'' that manipulate media over the network.
190 # These agents are relatively large and complex objects,
191 # but are used by most applications in a fairly straightforward
192 # manner.  The idea is to give the MASH programmer
193 # a fairly course-grained programming object that relieves the
194 # burden of managing video capture devices, multicast sockets,
195 # audio processing code, etc. into a high-level, easy-to-use API.
196 # The effort can then be spent figuring out how to cleanly
197 # integrate video, audio, or whiteboard objects into the
198 # application under design.
199 # <p>
200 # MediaAgents are ``bare processing engines''.  They do not create
201 # or rely upon a user-interface.  Instead, the script that creates
202 # the object manipulates it directly and if a user-interface is desired,
203 # that script must create and bind the UI to the agent.
204 # The protocol for communicating between the agent and the UI
205 # follows the MASH Observer model.
206 # In fact, since the observer abstraction is completely general,
207 # any object can attach itself to a MediaAgent as
208 # an observer, not just UIs.
209 #
210 # <p>
211 # <i>Note: This is an abstract base class. Do not create objects directly
212 # of this class</i>
213 #
214 Class MediaAgent -superclass {SourceManager Observable}
215 
216 #
217 # Arrange for each of the methods on an RTP source object to be
218 # re-directed to the source-manager and in turn dispatched
219 # to each of the observers.  This arrangement allows subclasses
220 # to override this default behavior (e.g., the VideoAgent class
221 # catches activate so it can create a decoder).
222 #
223 foreach method "unregister activate deactivate \
224                 trigger_media \
225                 trigger_format \
226                 trigger_sdes \
227                 trigger_idle \
228                 trigger_sr \
229                 notify" {
230         Source/RTP public $method {args} \
231                 "\$self instvar sm_ ; eval \$sm_ $method \$self \$args"
232         MediaAgent public $method src "\$self notify_observers $method \$src"
233 }
234 
235 MediaAgent public init {} {
236         $self next
237         $self set sources_ ""
238 }
239 
240 MediaAgent public destroy {} {
241         $self instvar sources_
242 
243         # destroy all the Source/RTP objects
244         foreach src $sources_ {
245                 $src destroy;
246         }
247 
248         $self next
249 }
250 
251 
252 MediaAgent public active_list {} {
253         $self instvar active_
254         if ![info exists active_] {
255                 return ""
256         }
257         return [array names active_]
258 }
259 
260 #
261 # Override some of the above SourceManager methods...
262 #
263 
264 MediaAgent public activate src {
265         $self instvar active_
266         set active_($src) 1
267         $self notify_observers activate $src
268 }
269 
270 MediaAgent public deactivate src {
271         $self instvar active_
272         unset active_($src)
273         $self notify_observers deactivate $src
274 }
275 
276 MediaAgent public unregister src {
277         $self notify_observers unregister $src
278         $self instvar sources_
279         set k [lsearch -exact $sources_ $src]
280         set sources_ [lreplace $sources_ $k $k]
281 }
282 
283 #
284 # Attach an observer to this agent.
285 #
286 MediaAgent public attach o {
287         $self attach_observer $o
288 #
289 # FIXME local_ is in sources_ list
290 #       $o register $local_
291         $self instvar sources_ active_
292         foreach s $sources_ {
293                 $o update register $s
294                 if [info exists active_($s)] {
295                         $o update activate $s
296                         $s enable_trigger
297                 }
298         }
299 }
300 
301 #
302 # Detach an observer from this agent.
303 #
304 MediaAgent public detach o {
305         $self detach_observer $o
306         $self instvar sources_ active_
307         foreach s $sources_ {
308                 if [info exists active_($s)] {
309                         $o update deactivate $s
310                 }
311                 $o update unregister $s
312         }
313 }
314 
315 #
316 # Called from C++ when a new RTP source is seen (and validated).
317 #
318 MediaAgent public create-source { srcid ssrc addr srcsess } {
319         set s [new Source/RTP $self $srcid $ssrc $addr]
320         $s set session_ $srcsess
321         $self instvar sources_
322         lappend sources_ $s
323         return $s
324 }
325 
326 #
327 # This class implements the machinery of an RTP session.
328 # It is pure mechanism; no user-interface etc.
329 # Instead it is manipulated by user interfaces or
330 # other agents that define policy.
331 #
332 Class RTPAgent -superclass MediaAgent -configuration {
333         mtu 1024
334         loopback 0
335         siteDropTime "300"
336 }
337 
338 RTPAgent public init {ab {callback {}} } {
339         $self next
340         $self instvar session_ mtu_ callback_
341         if { $callback!={} } { set callback_ $callback }
342         set session_ [$self create_session]
343         $session_ sm $self
344         $session_ buffer-pool [new BufferPool]
345 
346         if { $ab != "" } {
347                 $self reset $ab
348         }
349         set mtu_ [$self get_option mtu]
350 
351         #FIXME
352         global V
353         set V(sm) $self
354 }
355 
356 RTPAgent public destroy {} {
357         $self instvar session_ network_
358 
359         # exit the M/C session so all the other sources realize we're leaving
360         $session_ exit;
361         delete $session_
362 
363         # clean up the network infrastructure
364         delete $network_
365 
366         $self next
367 }
368 
369 RTPAgent public reset_spec spec {
370         set ab [SessionAddress parse $spec]
371         $self reset $ab
372         delete $ab
373 }
374 
375 #
376 # Reset the address specifier of the underlying session in question.
377 # This allows the network objects to be dynamically reconfigured to
378 # facilitate higher-level control protocols that might instruct an
379 # application to switch multicast sessions or speak to a different
380 # unicast destination. FIXME should only reset the piece that matters.
381 #
382 RTPAgent public reset ab {
383         $self instvar network_ session_ sources_
384 
385         if [catch {
386                 set c [$ab info class]
387                 if { [lsearch [$c info heritage] "SessionAddress"] == -1 } {
388                         error "ab is a $c, which is not a SessionAddress"
389                 }
390         } err] {
391                 error "Got bogus argument to RTPAgent::reset: $err"
392         }
393 
394 
395         # It is important to create the new objects before destroying the 
396         # old ones (NetworkManager and Source/RTP) so that, in the case 
397         # the agent is transmitting, the encoder has a place to deliver 
398         # its packets
399 
400 
401         # copy all the old object handlers to destroy them at the end
402         if [info exists network_] {
403                 set old_network $network_
404         }
405         set old_sources $sources_
406 
407         # inform the other session members that we're leaving
408         # (send RTP BYE message)
409         $session_ exit
410 
411         # create the new network object
412         set class [$ab net-class]
413         set network_ [new $class $ab $session_ $self]
414 
415         #FIXME
416         $self app_loopback 1
417         $self net_loopback [$self get_option loopback]
418 
419         set key [$self get_option sessionKey]
420         if { $key != "" } {
421                 $network_ install-key $key
422         }
423 
424         # create the local rtp-source object
425         $self mk_local_source
426 
427         #FIXME currently session object understands only one bandwidth limit
428         # FIXME get this into b/s eventually.
429         $session_ max-bandwidth [expr [$ab maxbw]/1000.]
430 
431 
432         # FIXME Eventually use 'attach' mechanism.
433         $self instvar callback_
434         if [info exists callback_] {
435             eval $callback_ [list $ab]
436         } else {
437             catch {
438                     set a [Application instance]
439                     if [catch {$a reset $ab rtp $self}] {
440                         $a reset $ab
441                     }
442                 }
443         }
444 
445         # clean up the old object
446 
447         # destroy all the Source/RTP objects
448         foreach src $old_sources {
449                 $src destroy
450         }
451 
452         # destroy the old NetworkManager object
453         if [info exists old_network] {
454                 delete $old_network
455         }
456 
457 }
458 
459 RTPAgent private notify {src layer} {
460         $self instvar network_
461         if ![$network_ usingRLM] { return }
462         $network_ notify-loss $src $layer
463 }
464 
465 #
466 # Return a list of names and values of the statistics
467 # for the RTP session as a whole.
468 #
469 RTPAgent public stats {} {
470         set s [$self set session_]
471         return " \
472                 Bad-RTP-version [$s set badversion_] \
473                 Bad-RTPv1-options [$s set badoptions_] \
474                 Bad-Payload-Format [$s set badfmt_] \
475                 Bad-RTP-Extension [$s set badext_] \
476                 Runts [$s set nrunt_]"
477         #FIXME should report counters with bad crypt operations
478 }
479 
480 #
481 # Create the local source object and do proper initialization
482 # of its various parameters and fields like sdes info.
483 #
484 RTPAgent private mk_local_source {} {
485         $self instvar network_ session_ local_
486 
487         set net [$network_ data-net 0]
488 
489         # choose the initial RTP srcid
490         set a [$net addr]
491         set srcid [$session_ random-srcid $a]
492         # create the local source object
493         set src [$self create-local $srcid [$net interface]]
494         set local_ $src
495         $self notify_observers register $local_
496 
497         set cname [$self get_option cname]
498         if { $cname == "" } {
499                 set interface [$net interface]
500                 if { $interface == "0.0.0.0" } {
501                         # this happens under solaris
502                         set interface [$session_ local-addr-heuristic]
503                 }
504                 set cname [user_heuristic]@$interface
505         }
506         $src sdes name [$self get_option rtpName]
507         $src sdes email [$self get_option rtpEmail]
508         # We use the loc field for distributed recording, setting it to
509         # be the closest local AS1 platform
510         $src sdes loc [$self get_option rtpLoc]
511         $src sdes cname $cname
512 
513         set tool [Application name]\-[version]
514 
515         global tcl_platform
516         if {[info exists tcl_platform(os)] && $tcl_platform(os) != "" && \
517                         $tcl_platform(os) != "unix"} {
518                 set p $tcl_platform(os)
519                 if {$tcl_platform(osVersion) != ""} {
520                         set p $p-$tcl_platform(osVersion)
521                 }
522                 if {$tcl_platform(machine) != ""} {
523                         set p $p-$tcl_platform(machine)
524                 }
525                 set tool "$tool/$p"
526         }
527         $src sdes tool $tool
528 
529         return $src
530 }
531 
532 #
533 # Return true iff an underlying network object has been
534 # created and attached to this RTP agent.
535 #
536 RTPAgent public have_network {} {
537         $self instvar network_
538         return [info exists network_]
539 }
540 
541 #
542 # Return true iff the underlying object that represents
543 # the local source has been created and attached to this RTP agent.
544 #
545 RTPAgent public have_localsrc {} {
546         $self instvar local_
547         return [info exists local_]
548 }
549 
550 #
551 # Instruct the media-agent to perform encryption and decryption of all
552 # data sent to or received from the network.  The format of the key is
553 # as specified by the SDP specification.  FIXME put format here.
554 #
555 RTPAgent public install-key key {
556         $self instvar network_
557         if [info exists network_] {
558                 $network_ install-key $key
559         }
560 }
561 
562 #
563 # Return the network object that underlies the RTP session,
564 # or return "none" if it does not yet exist.
565 #
566 RTPAgent public network {} {
567         $self instvar network_
568         if ![info exists network_] {
569                 return none
570         }
571         return [$network_ data-net 0]
572 }
573 
574 #
575 # Returns a string that describes the network session
576 #
577 RTPAgent public session-info {} {
578         $self instvar network_
579         if ![info exists network_] {
580                 return "No network"
581         }
582         return [$network_ session-info]
583 }
584 
585 #
586 # Return the network address of the underlying
587 # communication session, or the string "none"
588 # if the underlying network object hasn't yet
589 # been created.
590 #
591 RTPAgent public session-addr {} {
592         $self instvar network_
593         if ![info exists network_] {
594                 return none
595         }
596         return [[$self network] addr]
597 }
598 
599 #
600 # Return the network port number of the underlying
601 # communication session, or the string "none"
602 # if the underlying network object hasn't yet
603 # been created.  FIXME why do we have three port methods?
604 #
605 RTPAgent public session-port {} {
606         $self instvar network_
607         if ![info exists network_] {
608                 return none
609         }
610         return [[$self network] port]
611 }
612 
613 #
614 # Return the inbound port number of the underlying
615 # communication session, or the string "none"
616 # if the underlying network object hasn't yet
617 # been created.
618 #
619 RTPAgent public session-rport {} {
620         $self instvar network_
621         if ![info exists network_] {
622                 return none
623         }
624         return [[$self network] rport]
625 }
626 
627 #
628 # Return the outbound port number of the underlying
629 # communication session, or the string "none"
630 # if the underlying network object hasn't yet
631 # been created.
632 #
633 RTPAgent public session-sport {} {
634         $self instvar network_
635         if ![info exists network_] {
636                 return none
637         }
638         return [[$self network] sport]
639 }
640 
641 #
642 # Return the RTP SRCID of the object that represents
643 # the local source, or the string "none"
644 # if the underlying network object hasn't yet
645 # been created.
646 #
647 RTPAgent public get_local_srcid {} {
648         $self instvar network_
649         if ![info exists network_] {
650                 return none
651         }
652         $self instvar local_
653         return [$local_ srcid]
654 }
655 
656 #
657 # Return the RTP SDES element of the object that represents
658 # the local source, or the string "none" if the underlying 
659 # network object hasn't yet been created.
660 #
661 RTPAgent public get_local_sdes {which} {
662         $self instvar network_
663         if ![info exists network_] {
664                 return none
665         }
666         $self instvar local_
667         return [$local_ sdes $which]
668 }
669 
670 
671 #
672 # Return the name of an object that sinks the locally generated
673 # RTP packet stream and in turns sends it out over the network.
674 #
675 RTPAgent public get_transmitter {} {
676         return [$self set session_]
677 }
678 
679 #
680 # Return the time-to-live values used by the underlying
681 # communication session, or the string "none"
682 # if the underlying network object hasn't yet
683 # been created.  This value is undefined if the
684 # underlying session is not a multicast address.
685 #
686 RTPAgent public session-ttl {} {
687         $self instvar network_
688         if ![info exists network_] {
689                 return none
690         }
691         return [[$self network] ttl]
692 }
693 
694 #
695 # Return the time-to-live values used by the underlying
696 # communication session, or the string "none"
697 # if the underlying network object hasn't yet
698 # been created.  This value is undefined if the
699 # underlying session is not a multicast address.
700 #
701 # Deprecated by "$self get_local_sdes name"
702 #
703 RTPAgent public local-name {} {
704         $self instvar network_
705         if ![info exists network_] {
706                 return none
707         }
708         $self instvar local_
709         return [$local_ sdes name]
710 }
711 
712 #
713 # Set an RTP SDES string for the local source
714 # to the indicate value.  <i>which</i> is the SDES
715 # string type and <i>value</i> is the desired string.
716 # Example usage:
717 # <pre>
718 #       $o set_local_sdes email mccanne@cs.berkeley.edu
719 # </pre>
720 #
721 RTPAgent public set_local_sdes { which value } {
722         $self instvar local_
723         $local_ sdes $which $value
724 }
725 
726 #
727 # Turn off encryption.
728 #
729 RTPAgent public crypt_clear {} {
730         if [info exists network_] {
731                 $network_ crypt_clear
732         }
733 }
734 
735 #
736 # Gracefully tear down the underlying session. Set or query the media
737 # associated with this session. Please note that the media is
738 # automatically set by the init method of this class. Programmers
739 # should not invoke this method directly to set the media.
740 #
741 RTPAgent public shutdown {} {
742         $self instvar session_
743         $session_ exit
744 }
745 
746 #
747 # Set the maximum number of network channels used by the
748 # session to <i>n</i>.  Multiple channels are used
749 # when transmitting layered media streams (e.g., the PVH
750 # video coding format).  See
751 # <a href=http://www.cs.berkeley.edu/~mccanne/phd-work>McCanne's
752 # PhD work</a> for more info on layered video transmission.
753 #
754 RTPAgent public set_maxchannel n {}
755 
756 #
757 # Set the network bandwidth used by the underlying media transmission
758 # protocols to <i>bps</i> bits per second.  This rate constraint is
759 # met in a media-specific fashion.  Currently, most all of the video
760 # codecs simply adjust the inter-frame spacing to meet the bit-rate
761 # budget.
762 #
763 RTPAgent public set-bandwidth bps {
764         [$self set session_] data-bandwidth $bps
765 }
766 
767 #
768 # Set the multicast loopback flag on the underlying session
769 # according to the <i>sense</i> argument.  If true, then
770 # packets are looped back according to the semantics of
771 # the underlying operating system's loopback flag.
772 # This can have unpredictable results if you don't know
773 # exactly what you're doing.  Most of the mash applications
774 # assume that packets are not looped back and will take
775 # unpredictable action if they see their own traffic looped back.
776 # However, unless you set filter_own to 0, the app will never
777 # see the traffic.
778 #
779 RTPAgent public net_loopback enable {
780         $self instvar network_
781         $network_ loopback $enable
782 }
783 
784 RTPAgent public app_loopback enable {
785         $self instvar session_
786         $session_ set loopback_ $enable
787 }
788 
789 RTPAgent public set-bandwidth bps {
790         [$self set session_] data-bandwidth $bps
791 }
792 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.