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

Open Mash Cross Reference
mash/audio/audio.cc

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

  1 /*
  2  * audio.cc --
  3  *
  4  *      FIXME: This file needs a description here.
  5  *
  6  * Copyright (c) 1991-2002 The Regents of the University of California.
  7  * All rights reserved.
  8  *
  9  * Redistribution and use in source and binary forms, with or without
 10  * modification, are permitted provided that the following conditions are met:
 11  *
 12  * A. Redistributions of source code must retain the above copyright notice,
 13  *    this list of conditions and the following disclaimer.
 14  * B. Redistributions in binary form must reproduce the above copyright notice,
 15  *    this list of conditions and the following disclaimer in the documentation
 16  *    and/or other materials provided with the distribution.
 17  * C. Neither the names of the copyright holders nor the names of its
 18  *    contributors may be used to endorse or promote products derived from this
 19  *    software without specific prior written permission.
 20  *
 21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 22  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 31  * POSSIBILITY OF SUCH DAMAGE.
 32  */
 33 
 34 static const char rcsid[] =
 35     "@(#) $Header: /usr/mash/src/repository/mash/mash-1/audio/audio.cc,v 1.19 2002/05/01 01:17:22 weitsang Exp $";
 36 
 37 #include <stdlib.h>
 38 #include <stdio.h>
 39 #include <string.h>
 40 #if defined(sgi)
 41 #include <bstring.h>
 42 #endif
 43 #ifdef WIN32
 44 #include <fcntl.h>
 45 #else
 46 #include <unistd.h>
 47 #include <sys/file.h>
 48 #include <fcntl.h>
 49 #endif
 50 
 51 #include "audio.h"
 52 #include "mulaw.h"
 53 #include "tclcl.h"
 54 
 55 
 56 Audio::Audio() :
 57         lock_fd_(-1),
 58         blksize_(AUDIO_FRAMESIZE),
 59         fd_(-1),
 60         oport_(0),
 61         iport_(0),
 62         rmute_(0),
 63         pmute_(0),
 64         rgain_(0),
 65         pgain_(0),
 66         duplex_(1),
 67         input_names_(0),
 68         output_names_(0),
 69         handler_(0),
 70         device_(-1)
 71 {
 72   omode_ = mode_mikemutesnet;
 73   bind("duplex_", &duplex_);
 74 }
 75 
 76 Audio::~Audio()
 77 {
 78         close(fd_);
 79 }
 80 
 81 void Audio::Release()
 82 {
 83         if (haveaudio()) {
 84                 unlink();
 85                 (void)close(fd_);
 86                 fd_ = -1;
 87                 notify();
 88         }
 89 }
 90 
 91 void Audio::Obtain()
 92 {
 93         link(fd_, TCL_READABLE);
 94         notify();
 95 }
 96 
 97 void Audio::InputPort(int p)
 98 {
 99         iport_ = p;
100 }
101 
102 void Audio::OutputPort(int p)
103 {
104         oport_ = p;
105 }
106 
107 void Audio::dispatch(int)
108 {
109         while (FrameReady()) {
110           if (handler_ != 0)
111             handler_->audio_handle();
112         }
113 }
114 
115 /*
116  * Output the ulaw sample in x and read the mike response back into y.
117  * The two signals are guaranteed to coincide in time.  len must be
118  * less than the max output buffer available (currently 4K).
119  */
120 int Audio::PlayRec(u_char *x, u_char *y, int len)
121 {
122         int bufsize = (len / blksize_) * blksize_;
123         int rbufsize = bufsize + 4096;
124         u_char* tmpbuf = new u_char[rbufsize];
125         Flush();
126         int cc = write(fd_, (char*)x, bufsize);
127         if (cc != bufsize) {
128                 perror("PlayRec write");
129                 delete[] tmpbuf;
130                 return (bufsize);
131         }
132         int offset = AdjustTime(0);
133         if (offset < 0 || offset + bufsize > rbufsize) {
134                 fprintf(stderr, "Playrec offset %d\n", offset);
135                 delete[] tmpbuf;
136                 return (bufsize);
137         }
138         char* bp = (char*)tmpbuf;
139         for (int rem = offset + bufsize; rem > 0; ) {
140                 if ((cc = read(fd_, bp, rem)) <= 0) {
141                         perror("PlayRec read");
142                         delete[] tmpbuf;
143                         return (bufsize);
144                 }
145                 bp += cc;
146                 rem -= cc;
147         }
148         memcpy((char*)y, (char*)&tmpbuf[offset], bufsize);
149         delete[] tmpbuf;
150         return (bufsize);
151 }
152 
153 void Audio::RMute()
154 {
155         rmute_ |= 1;
156 }
157 
158 void Audio::RUnmute()
159 {
160         rmute_ &=~ 1;
161 }
162 
163 void Audio::SetRGain(int)
164 {
165 }
166 
167 void Audio::SetPGain(int)
168 {
169 }
170 
171 #if defined(__osf__) || defined(sun) || defined(ultrix) || defined(sgi)
172 extern "C" {
173 int flock(int, int);
174 }
175 #endif
176 #if defined(hpux) || defined(__svr4__) || defined(sco) || defined(_AIX)
177 #include <fcntl.h>
178 
179 #define LOCK_SH   1    /* shared lock */
180 #define LOCK_EX   2    /* exclusive lock */
181 #define LOCK_NB   4    /* don't block when locking */
182 #define LOCK_UN   8    /* unlock */
183 
184 int flock(int fd, int op) {
185         struct flock f;
186         f.l_whence = 0;
187         f.l_start = 0;
188         f.l_len = 0;
189         if (op == LOCK_UN)
190                 f.l_type = F_UNLCK;
191         else
192                 f.l_type = F_WRLCK;
193         return (fcntl(fd, F_SETLK, &f));
194 }
195 #endif
196 
197 /* FIXME should make a NOLOCKING define that configure sets */
198 #ifdef WIN32
199 void Audio::openlock()  { printf("Audio:openlock\n"); }
200 void Audio::unlock()    { printf("Audio:unlock\n"); }
201 int Audio::lock()       { printf("Audio:lock\n"); return (0); }
202 #else
203 void Audio::openlock()
204 {
205         char *wrk = new char[sizeof("/tmp/.vat_audio_lock.") + 32];
206         sprintf(wrk, "/tmp/.vat_audio_lock.%d", (int)getuid());
207         /* open (or create) the lock file */
208         lock_fd_ = open(wrk, O_RDWR|O_CREAT, 0777);
209         if (lock_fd_ < 0) {
210                 perror(wrk);
211                 exit(2);
212         }
213         delete wrk;
214 }
215 
216 void Audio::unlock()
217 {
218         if (::flock(lock_fd_, LOCK_UN))
219                 perror("vat: sock_audio unlock");
220 }
221 
222 int Audio::lock()
223 {
224         return (::flock(lock_fd_, (LOCK_EX|LOCK_NB)));
225 }
226 #endif
227 
228 int Audio::SetAudioDevice(int dev)
229 {
230   device_ = dev;
231 
232   return(1);
233 }
234 
235 /*
236  * <otcl> Class Audio
237  * Audio is the
238  * base class for objects that represent audio codecs.
239  * An audio object is both a source and a sink of data and
240  * rather than spliced onto other objects in a pipeline,
241  * it is instanced inside of and manipulated principally by
242  * the AudioController object.
243  */
244 int Audio::command(int argc, const char*const* argv)
245 {
246         Tcl& tcl = Tcl::instance();
247         if (argc == 2) {
248                 /*
249                  * <otcl> Audio public get_input_ports {}
250                  * Return the list of available input ports.
251                  * The list consists of a sequence of names,
252                  * where the name is the nick name of the port
253                  * (e.g., "mike").  A ports position in this
254                  * list identifies its integer port number,
255                  * which must be used in many of the method
256                  * calls that select and/or manipulate the port.
257                  */
258                 if (strcmp(argv[1], "get_input_ports") == 0) {
259                         if (input_names_ == 0) {
260                             tcl.result("");
261                         } else {
262                             tcl.result(input_names_);
263                         }
264                         return (TCL_OK);
265                 }
266                 /*
267                  * <otcl> Audio public get_output_ports {}
268                  * Return the list of available output ports.
269                  * The list consists of a sequence of names,
270                  * where the name is the nick name of the port
271                  * (e.g., "speaker").  A ports position in this
272                  * list identifies its integer port number,
273                  * which must be used in many of the method
274                  * calls that select and/or manipulate the port.
275                  */
276                 if (strcmp(argv[1], "get_output_ports") == 0) {
277                         if (output_names_ == 0) {
278                             tcl.result("");
279                         } else {
280                             tcl.result(output_names_);
281                         }
282                         return (TCL_OK);
283                 }
284                 /*
285                  * <otcl> Audio public obtain {}
286                  * Attempt to obtain the audio device.  If successful,
287                  * notify observers.
288                  */
289                 if (strcmp(argv[1], "obtain") == 0) {
290                         if (haveaudio()) {
291                                 tcl.result("calling obtain when audio already held");
292                                 return (TCL_ERROR);
293                         }
294                         Obtain();
295                         return (TCL_OK);
296                 }
297                 /*
298                  * <otcl> Audio public release {}
299                  * Release the audio device and notify observers.
300                  * This allows some other Audio object running
301                  * in either the same or separate process,
302                  * to obtain the underlying audio device
303                  * (since many audio services are not shared).
304                  */
305                 if (strcmp(argv[1], "release") == 0) {
306                         Release();
307                         return (TCL_OK);
308                 }
309                 /*
310                  * <otcl> Audio public have {}
311                  * Return 1 if the underlying audio device is currently open
312                  * and ready, and 0 otherwise.
313                  */
314                 if (strcmp(argv[1], "have") == 0) {
315                         tcl.result(haveaudio() ? "1" : "");
316                         return (TCL_OK);
317                 /*
318                  * <otcl> Audio public get_input_port
319                  * Return the input port number of the currently
320                  * selected port.  This number
321                  * identifies the index of the port listed in the
322                  * set of names returned by Audio::get_input_ports.
323                  * </ul>
324                  */
325                 }
326                 if (strcmp(argv[1], "get_input_port") == 0) {
327                         sprintf(tcl.result(), "%d", InputPort());
328                         return (TCL_OK);
329                 }
330                 /*
331                  * <otcl> Audio public get_output_port
332                  * Return the output port number of the currently
333                  * selected port.  This number
334                  * identifies the index of the port listed in the
335                  * set of names returned by Audio::get_output_ports.
336                  * </ul>
337                  */
338                 if (strcmp(argv[1], "get_output_port") == 0) {
339                         sprintf(tcl.result(), "%d", OutputPort());
340                         return (TCL_OK);
341                 }
342         } else if (argc == 3) {
343                 /*
344                  * <otcl> Audio public set_speakerphone mode
345                  * Sets the speakerphone attribute as indicated
346                  * by <i>mode</i>, which can be one of:
347                  * <ul>
348                  * <li> fullduplex,
349                  * <li> mikemutesnet, or
350                  * <li> netmutesmike.
351                  * </ul>
352                  * FIXME: this should be an AudioController method
353                  */
354                 if (strcmp(argv[1], "set_speakerphone") == 0) {
355                         if (strcasecmp(argv[2], "mikemutesnet") == 0)
356                                 omode_ = mode_mikemutesnet;
357                         else if (strcasecmp(argv[2], "netmutesmike") == 0)
358                                 omode_ = mode_netmutesmike;
359                         else
360                                 omode_ = mode_none;
361 
362                         return (TCL_OK);
363                 }
364 
365                 /*
366                  * <otcl> Audio public set_input_gain level
367                  * Set the input gain for the currently enabled input
368                  * port to <i>level</i>, where level is a linear gain
369                  * factor from 0 to 255. FIXME should change this?
370                  * If the input port is changed or the device is
371                  * released and re-obtained, the gain must
372                  * be reset from OTcl to maintain a consistent
373                  * and reliable level.
374                  * </ul>
375                  */
376                 if (strcmp(argv[1], "set_input_gain") == 0) {
377                         SetRGain(atoi(argv[2]));
378                         return (TCL_OK);
379                 }
380                 /*
381                  * <otcl> Audio public set_input_port portno
382                  * Set the input port to <i>portno</i>, which
383                  * identifies the index of the port listed in the
384                  * set of names returned by Audio::get_input_ports.
385                  * </ul>
386                  */
387                 if (strcmp(argv[1], "set_input_port") == 0) {
388                         InputPort(atoi(argv[2]));
389                         return (TCL_OK);
390                 }
391                 /*
392                  * <otcl> Audio public set_input_mute val
393                  * Set the mute attribute of the current port to <i>val</i>.
394                  * If non-zero, the mike is muted and no input samples
395                  * are generated and passed on to the controller;
396                  * otherwise, the mike is enabled and becomes "live".
397                  * </ul>
398                  */
399                 if (strcmp(argv[1], "set_input_mute") == 0) {
400                         /*FIXME*/
401                         if (atoi(argv[2]))
402                                 RMute();
403                         else
404                                 RUnmute();
405                         return (TCL_OK);
406                 }
407                 /*
408                  * <otcl> Audio public set_ouptput_gain level
409                  * Set the output gain for the currently enabled output
410                  * port to <i>level</i>, where level is a linear gain
411                  * factor from 0 to 255. FIXME should change this?
412                  * If the output port is changed or the device is
413                  * released and re-obtained, the gain must
414                  * be reset from OTcl to maintain a consistent
415                  * and reliable level.
416                  * </ul>
417                  */
418                 if (strcmp(argv[1], "set_output_gain") == 0) {
419                         SetPGain(atoi(argv[2]));
420                         return (TCL_OK);
421                 }
422                 /*
423                  * <otcl> Audio public set_output_port portno
424                  * Set the input port to <i>portno</i>, which
425                  * identifies the index of the port listed in the
426                  * set of names returned by Audio::get_output_ports.
427                  * </ul>
428                  */
429                 if (strcmp(argv[1], "set_output_port") == 0) {
430                         OutputPort(atoi(argv[2]));
431                         return (TCL_OK);
432                 }
433                 /*
434                  * <otcl> Audio public set_output_mute val
435                  * Set the mute attribute of the current port to <i>val</i>.
436                  * If non-zero, the mike is muted and no output samples
437                  * are generated and passed on to the controller;
438                  * otherwise, the mike is enabled and becomes "live".
439                  * </ul>
440                  */
441                 if (strcmp(argv[1], "set_output_mute") == 0) {
442                         /*FIXME*/
443                         if (atoi(argv[2]))
444                                 PMute();
445                         else
446                                 PUnmute();
447                         return (TCL_OK);
448                 }
449 
450                 /*
451                  * Call this to set which audio device will be used by the
452                  *    audio driver.  0 => /dev/audio0, /dev/mixer0, etc
453                  */
454                 if(strcmp(argv[1], "set_device") == 0)
455                 {
456                   SetAudioDevice(atoi(argv[2]));
457                   return(TCL_OK);
458                 }
459         }
460         return (TclObject::command(argc, argv));
461 }
462 

~ [ 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.