1 # ui-audio.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/src/mash/repository/mash/mash-1/tcl/vat/ui-audio.tcl,v 1.13 1997/12/23 05:31:51 mccanne Exp $
32
33
34 import Observable Configuration CoordinationBus
35
36 #
37 # The AudioArbiter is used to negotiate with other processes for control
38 # over the host's audio device. Multiple applications might want to
39 # simultaneously access the underlying audio hardware, but many such
40 # devices cannot be shared because of the operating system's contraints
41 # on the API. Thus, we have explicit methods for obtaining and
42 # releasing the underlying hardware resources.
43 # <p>
44 #
45 # The AudioArbiter is also an Observable so an Observer, e.g. a UI, can watch
46 # its status (i.e. Do we have the device? Did we just get it so we
47 # should raise the window?, etc.)
48 #
49 Class AudioArbiter -superclass {CoordinationBus Observable} -configuration {
50 idleDropTime 20
51 defaultPriority 100
52 }
53
54 #
55 # Create an arbiter to represent the given AudioAgent, <i>agent</i>.
56 # Register CoordinationBus messages to suit the following device bus API: <br>
57 # <dd> $cb send audio-demand $pid
58 # <dd> $cb send audio-request $pid $pri
59 # <dd> $cb send audio-release $pid
60 #
61 AudioArbiter public init agent {
62 # the default coordbus channel is 0
63 # so, we get the base channel for the global stuff
64 $self next
65 $self instvar agent_ activity_ id_ priority_ hold_
66 set agent_ $agent
67 set hold_ 0
68
69 $self register audio-demand someone_demands
70 $self register audio-request someone_requests
71 $self register audio-release someone_released
72
73 set activity_ 0
74 set priority_ [$self get_option defaultPriority]
75 set id_ [after 5000 "$self timeout"]
76 }
77
78 #
79 # Cancel the "timeout".
80 #
81 AudioArbiter instproc destroy {} {
82 $self instvar id_
83 after cancel $id_
84 $self next
85 }
86
87 #
88 # Set the priority, <i>p</i>, that this arbiter has over the control of the audio device.
89 #
90 AudioArbiter instproc set-pri p {
91 $self instvar priority_
92 set priority_ $p
93 }
94
95 #
96 # Close the audio device.
97 #
98 AudioArbiter public release {} {
99 $self instvar agent_
100 $agent_ release
101 $self indicator_update
102 }
103
104 #
105 # Callback when someone requests the audio. If we have the audio, it's
106 # not pinned, and it's unmuted, we must relinquish it to anyone with higher
107 # priority. #
108 #
109 AudioArbiter public someone_requests { pid pri } {
110 $self instvar agent_ priority_ hold_
111 global unmuted outputMutebutton
112 if { [$agent_ have_audio] && !$hold_ && ($pri > $priority_) } {
113
114 #FIXME FIX unmuted ref
115 # || !$unmuted($outputMutebutton))} {
116 #
117 # we have the audio, it's not pinned, and someone
118 # with a high priority wants it or we have it muted.
119 # give it up to them.
120 #
121 $self give_it_up $pid
122 }
123 }
124
125 #
126 # Close the audio device, and advertise that it's
127 # been released to the conference bus.
128 #
129 AudioArbiter private give_it_up pid {
130 $self release
131 $self send audio-release $pid
132 }
133
134 #
135 # Callback when someone demands the audio
136 # If we have it, honor request.
137 #
138 AudioArbiter public someone_demands pid {
139 $self instvar agent_
140 if { [$agent_ have_audio] } {
141 #
142 # we have the audio and someone demanded it.
143 # give it up.
144 #
145 $self give_it_up $pid
146 }
147 }
148
149 #
150 # Callback when someone releases the audio to process <i>pid</i>. If
151 # the audio was released to us, i.e. if the pid matches, try to grab it.
152 #
153 AudioArbiter public someone_released pid {
154 if { $pid == [pid] } {
155 #
156 # someone released the audio to us.
157 # try to grab it -- if we fail, somebody else
158 # got it and give up (shouldn't happen because
159 # pids are unique).
160 #
161 $self grab
162 $self notify_observers arbiter_snatch
163 }
164 }
165
166 #
167 # Update the title bar indicator to show whether or
168 # not we have the device open.
169 #
170 AudioArbiter instproc indicator_update { } {
171 $self instvar agent_ activity_ hold_
172 if [$agent_ have_audio] {
173 $self notify_observers arbiter_have 1
174 #
175 # when we're not running off the audio clock, our time base
176 # can shift pretty badly (especially on PC's where gettimeofday
177 # accuracy is low). so we reset all our clock offsets whenever
178 # we recover the audio device.
179 #
180 $agent_ reset_source_offsets
181 } else {
182 $self notify_observers arbiter_have 0
183 set hold_ 0
184 }
185 set activity_ [$agent_ unix_time]
186 }
187
188 #
189 # Attempt to open and intialize the underlying audio hardware. After
190 # <i>grab</i> is called, the AudioAgent <i>haveaudio</i> method can be
191 # queried to see if the device was successfully opened. Once obtained,
192 # the device can be released with the AudioAgent <i>release</i> method.
193 #
194 AudioArbiter public grab {} {
195 $self instvar agent_
196 $agent_ obtain
197 $self indicator_update
198 }
199
200 #
201 # Ask for the audio, but don't demand it, because it
202 # might be in use for more important things. First,
203 # just try to open the device directly. If that fails,
204 # ask the vat that has it to give it up via the conference bus.
205 #
206 AudioArbiter public request {} {
207 # first just try to see if we can get it
208 $self instvar agent_ priority_
209 $agent_ obtain
210 if [$agent_ have_audio] {
211 $self indicator_update
212 } else {
213 $self send audio-request [pid] $priority_
214 }
215 }
216
217 #
218 # Demand the audio. Whoever has it will hear us, close the
219 # device, and eventually notify us back over the conference bus.
220 #
221 AudioArbiter public demand {} {
222 $self instvar agent_
223 $agent_ obtain
224 if [$agent_ have_audio] {
225 $self indicator_update
226 } else {
227 $self send audio-demand [pid]
228 }
229 }
230
231 #
232 # Demand the audio device if <i>v</i> is true and the AudioAgent does not have_audio.
233 #
234 AudioArbiter public hold v {
235 $self instvar hold_ agent_
236 set hold_ $v
237 if { $hold_ && ![$agent_ have_audio] } {
238 $self demand
239 }
240 }
241
242 #
243 # Periodically check the status of the AudioAgent, releasing the audio
244 # device if the AudioAgent has been inactive for given amount of time.
245 #
246 AudioArbiter private timeout {} {
247 $self instvar activity_ agent_ id_ hold_
248
249 if { [$agent_ have_audio] && !$hold_ } {
250 if [$agent_ is_active] {
251 $agent_ clear_active
252 set activity_ [$agent_ unix_time]
253 } else {
254 set r [$self get_option idleDropTime]
255 if { $r && [$agent_ unix_time] - $activity_ > \
256 $r } {
257 $self give_it_up 0
258 }
259 }
260 }
261 set id_ [after 5000 "$self timeout"]
262 }
263
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.