PageRenderTime 41ms CodeModel.GetById 17ms app.highlight 20ms RepoModel.GetById 1ms app.codeStats 0ms

/native/external/espeak/src/wave_sada.cpp

http://eyes-free.googlecode.com/
C++ | 595 lines | 233 code | 63 blank | 299 comment | 25 complexity | 6e6e9c3722c37d0c336ce8099114908c MD5 | raw file
  1/***************************************************************************
  2 *   Copyright (C) 2008, Sun Microsystems, Inc.                            *
  3 *   eSpeak driver for Solaris Audio Device Architecture (SADA)            *
  4 *   Written by Willie Walker, based on the eSpeak PulseAudio driver       *
  5 *   from Gilles Casse                                                     *
  6 *                                                                         *
  7 *   This program is free software; you can redistribute it and/or modify  *
  8 *   it under the terms of the GNU General Public License as published by  *
  9 *   the Free Software Foundation; either version 3 of the License, or     *
 10 *   (at your option) any later version.                                   *
 11 *                                                                         *
 12 *   This program is distributed in the hope that it will be useful,       *
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 15 *   GNU General Public License for more details.                          *
 16 *                                                                         *
 17 *   You should have received a copy of the GNU General Public License     *
 18 *   along with this program; if not, write to the                         *
 19 *   Free Software Foundation, Inc.,                                       *
 20 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 21 ***************************************************************************/
 22
 23#include "speech.h"
 24
 25#ifdef USE_ASYNC
 26// This source file is only used for asynchronious modes
 27
 28#include <errno.h>
 29#include <string.h>
 30#include <stropts.h>
 31#include <assert.h>
 32#include <stdlib.h>
 33#include <unistd.h>
 34#include <fcntl.h>
 35#include <sys/audioio.h>
 36
 37#include "wave.h"
 38#include "debug.h"
 39
 40enum {ONE_BILLION=1000000000};
 41#define SAMPLE_RATE 22050
 42#define SAMPLE_SIZE 16
 43
 44#ifdef USE_SADA
 45
 46static t_wave_callback* my_callback_is_output_enabled=NULL;
 47
 48static const char *sun_audio_device = "/dev/audio";
 49static int sun_audio_fd = -1;
 50
 51// The total number of 16-bit samples sent to be played via the
 52// wave_write method.
 53//
 54static uint32_t total_samples_sent;
 55
 56// The total number of samples sent to be played via the wave_write
 57// method, but which were never played because of a call to
 58// wave_close.
 59//
 60static uint32_t total_samples_skipped;
 61
 62// The last known playing index after a call to wave_close.
 63//
 64static uint32_t last_play_position=0;
 65
 66//>
 67// wave_init 
 68//
 69// DESCRIPTION:
 70//
 71// initializes the audio subsytem.
 72//
 73// GLOBALS USED/MODIFIED:
 74//
 75// sun_audio_fd: modified to hold the file descriptor of the opened
 76// audio device.
 77//
 78//<wave_init
 79
 80void wave_init() {
 81  ENTER("wave_init");
 82
 83  audio_info_t ainfo;
 84  char *audio_device = NULL;
 85
 86  audio_device = getenv("AUDIODEV");
 87  if (audio_device != NULL) {
 88    if ((sun_audio_fd = open(audio_device, O_WRONLY)) < 0) {
 89      SHOW("wave_init() could not open: %s (%d)\n", 
 90	   audio_device, sun_audio_fd);
 91    }
 92  }
 93
 94  if (sun_audio_fd < 0) {
 95    if ((sun_audio_fd = open(sun_audio_device, O_WRONLY)) < 0) {
 96      SHOW("wave_init() could not open: %s (%d)\n", 
 97           sun_audio_device, sun_audio_fd);
 98    }
 99  }
100
101  SHOW("wave_init() sun_audio_fd: %d\n", sun_audio_fd);
102
103  if (sun_audio_fd < 0) {
104    return;
105  }
106
107  ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
108  SHOW("wave_init() play buffer size: %d\n", ainfo.play.buffer_size);
109  ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
110  ainfo.play.channels = 1;
111  ainfo.play.sample_rate = SAMPLE_RATE;
112  ainfo.play.precision = SAMPLE_SIZE;
113
114  if (ioctl(sun_audio_fd, AUDIO_SETINFO, &ainfo) == -1) {
115    SHOW("wave_init() failed to set audio params: %s\n", strerror(errno));
116    close(sun_audio_fd);
117    return;
118  }
119}
120
121//>
122// wave_open
123//
124// DESCRIPTION:
125//
126// opens the audio subsystem given a specific API (e.g., "alsa",
127// "oss", ...).  We ignore the_api and just return the sun_audio_fd we
128// opened in wave_init.  This return value will be passed in as the
129// theHandler parameter in all other methods.
130//
131// PARAMETERS:
132//
133// the_api: "alsa", "oss" (ignored)
134//
135// GLOBALS USED/MODIFIED:
136//
137// sun_audio_fd: used as return value
138//
139// RETURNS:
140//
141// sun_audio_fd opened in wave_init, which is passed in as theHandler
142// parameter in all other methods
143//
144//<wave_open
145
146void* wave_open(const char* the_api)
147{
148  ENTER("wave_open");
149  return((void*) sun_audio_fd);
150}
151
152//>
153// wave_write
154//
155// DESCRIPTION:
156//
157// Meant to be asynchronous, it supplies the wave sample to the lower
158// audio layer and returns. The sample is played later on.  [[[WDW -
159// we purposely do not open the audio device as non-blocking because
160// managing that would be a pain.  So, we rely a lot upon fifo.cpp and
161// event.cpp to not overload us, allowing us to get away with a
162// blocking write.  event.cpp:polling_thread in particular appears to
163// use get_remaining_time to prevent flooding.]]]
164//
165// PARAMETERS:
166//
167// theHandler: the audio device file descriptor
168// theMono16BitsWaveBuffer: the audio data
169// theSize: the number of bytes (not 16-bit samples)
170//
171// GLOBALS USED/MODIFIED:
172//
173// total_samples_sent: modified based upon 16-bit samples sent
174//
175// RETURNS: 
176//
177// the number of bytes (not 16-bit samples) sent
178//
179//<wave_write
180
181size_t wave_write(void* theHandler, 
182		  char* theMono16BitsWaveBuffer, 
183		  size_t theSize)
184{
185  size_t num;
186  ENTER("wave_write");
187  if (my_callback_is_output_enabled && (0==my_callback_is_output_enabled())) {
188    SHOW_TIME("wave_write > my_callback_is_output_enabled: no!");
189    return 0;
190  }
191
192#if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
193  {
194    // BIG-ENDIAN, swap the order of bytes in each sound sample
195    int c;
196    char *out_ptr;
197    char *out_end;
198    out_ptr = (char *)theMono16BitsWaveBuffer;
199    out_end = out_ptr + theSize;
200    while(out_ptr < out_end)
201    {
202      c = out_ptr[0];
203      out_ptr[0] = out_ptr[1];
204      out_ptr[1] = c;
205      out_ptr += 2;
206    }
207  }
208#endif
209
210  num = write((int) theHandler, theMono16BitsWaveBuffer, theSize);
211
212  // Keep track of the total number of samples sent -- we use this in 
213  // wave_get_read_position and also use it to help calculate the
214  // total_samples_skipped in wave_close.
215  //
216  total_samples_sent += num / 2;
217
218  if (num < theSize) {
219    SHOW("ERROR: wave_write only wrote %d of %d bytes\n", num, theSize);
220  } else {
221    SHOW("wave_write wrote %d bytes\n", theSize);
222  }
223
224  SHOW_TIME("wave_write > LEAVE");
225  return num;
226}
227
228//>
229// wave_close
230//
231// DESCRIPTION:
232//
233// Does what SADA normally would call a flush, which means to cease
234// all audio production in progress and throw any remaining audio
235// away.  [[[WDW - see comment in wave_flush.]]]
236//
237// PARAMETERS:
238//
239// theHandler: the audio device file descriptor
240//
241// GLOBALS USED/MODIFIED:
242//
243// last_play_position: modified to reflect play position the last time
244//                     this method was called
245// total_samples_sent: used to help calculate total_samples_skipped
246// total_samples_skipped: modified to hold the total number of 16-bit
247//                        samples sent to wave_write, but which were
248//                        never played
249// sun_audio_fd: used because some calls to wave_close seem to 
250//               pass a NULL for theHandler for some odd reason
251//
252// RETURNS: 
253//
254// The result of the ioctl call (non-0 means failure)
255//
256//<wave_close
257
258int wave_close(void* theHandler)
259{
260  int ret;
261  audio_info_t ainfo;
262  int audio_fd = (int) theHandler;
263  if (!audio_fd) {
264    audio_fd = sun_audio_fd;
265  }
266  ENTER("wave_close");
267  // [[[WDW: maybe do a pause/resume ioctl???]]]
268  ret = ioctl(audio_fd, I_FLUSH, FLUSHRW);
269  ioctl(audio_fd, AUDIO_GETINFO, &ainfo);
270
271  // Calculate the number of samples that won't get
272  // played.  We also keep track of the last_play_position
273  // because wave_close can be called multiple times
274  // before another call to wave_write.
275  //
276  if (last_play_position != ainfo.play.samples) {
277    last_play_position = ainfo.play.samples;
278    total_samples_skipped = total_samples_sent - last_play_position;
279  }
280  SHOW_TIME("wave_close > LEAVE");
281  return ret;
282}
283
284//>
285// wave_is_busy
286//
287// DESCRIPTION:
288//
289// Returns a non-0 value if audio is being played.
290//
291// PARAMETERS:
292//
293// theHandler: the audio device file descriptor
294//
295// GLOBALS USED/MODIFIED:
296//
297// sun_audio_fd: used because some calls to wave_is_busy seem to 
298//               pass a NULL for theHandler for some odd reason
299//
300// RETURNS:
301//
302// A non-0 value if audio is being played
303//
304//<wave_is_busy
305
306int wave_is_busy(void* theHandler)
307{
308  audio_info_t ainfo;
309  int audio_fd = (int) theHandler;
310  if (!audio_fd) {
311    audio_fd = sun_audio_fd;
312  }
313  ENTER("wave_is_busy");
314  ioctl(audio_fd, AUDIO_GETINFO, &ainfo);
315  SHOW("wave_is_busy: active=%d", ainfo.play.active);
316  SHOW_TIME("wave_is_busy > LEAVE");
317  return ainfo.play.active;
318}
319
320//>
321// wave_terminate
322//
323// DESCRIPTION:
324//
325// Used to end our session with eSpeak.
326//
327// GLOBALS USED/MODIFIED:
328//
329// sun_audio_fd: modified - closed and set to -1
330//
331//<wave_terminate
332
333void wave_terminate()
334{
335  ENTER("wave_terminate");
336  close(sun_audio_fd);
337  sun_audio_fd = -1;
338  SHOW_TIME("wave_terminate > LEAVE");
339}
340
341//>
342// wave_flush
343//
344// DESCRIPTION:
345//
346// Appears to want to tell the audio subsystem to make sure it plays
347// the audio.  In our case, the system is already doing this, so this
348// is basically a no-op.  [[[WDW - if you do a drain, you block, so
349// don't do that.  In addition the typical SADA notion of flush is
350// currently handled by wave_close.  I think this is most likely just
351// terminology conflict between eSpeak and SADA.]]]
352//
353// PARAMETERS:
354//
355// theHandler: the audio device file descriptor
356//
357//<wave_flush
358
359void wave_flush(void* theHandler)
360{
361  ENTER("wave_flush");
362  //ioctl((int) theHandler, AUDIO_DRAIN, 0);
363  SHOW_TIME("wave_flush > LEAVE");
364}
365
366//>
367// wave_set_callback_is_output_enabled
368//
369// DESCRIPTION:
370//
371// Sets the callback to call from wave_write before it sends data to
372// be played.  It helps wave_write determine if the data should be
373// thrown away or not.
374//
375// PARAMETERS:
376//
377// cb: the callback to call from wave_write
378//
379//<wave_set_callback_is_output_enabled
380
381void wave_set_callback_is_output_enabled(t_wave_callback* cb)
382{
383  my_callback_is_output_enabled = cb;
384}
385
386//>
387// wave_test_get_write_buffer
388//
389// DESCRIPTION:
390//
391// Unnecessary and is used for debug output from
392// speak_lib.cpp:dispatch_audio.
393//
394// RETURNS:
395//
396// NULL
397//
398//<wave_test_get_write_buffer
399
400void *wave_test_get_write_buffer()
401{
402  return NULL;
403}
404
405//> 
406// wave_get_read_position
407//
408// DESCRIPTION:
409//
410// Concerns the sample which is currently played by the audio layer,
411// where 'sample' is a small buffer of synthesized wave data,
412// identified so that the user callback could be called when the
413// 'sample' is really played. The identifier is returned by
414// wave_get_write_position.  This method is unused.
415//
416// PARAMETERS:
417//
418// theHandler: the audio device file descriptor
419//
420// RETURNS:
421//
422// The total number of 16-bit samples played by the audio system
423// so far.
424//
425//<wave_get_read_position
426
427uint32_t wave_get_read_position(void* theHandler)
428{
429  audio_info_t ainfo;
430  ENTER("wave_get_read_position");
431  ioctl((int) theHandler, AUDIO_GETINFO, &ainfo);
432  SHOW("wave_get_read_position: %d\n", ainfo.play.samples);
433  SHOW_TIME("wave_get_read_position > LEAVE");
434  return ainfo.play.samples;
435}
436
437//>
438// wave_get_write_position
439//
440// DESCRIPTION:
441//
442// Returns an identifier for a new sample, where 'sample' is a small
443// buffer of synthesized wave data, identified so that the user
444// callback could be called when the 'sample' is really played.  This
445// implementation views the audio as one long continuous stream of
446// 16-bit samples.
447//
448// PARAMETERS:
449//
450// theHandler: the audio device file descriptor
451//
452// GLOBALS USED/MODIFIED:
453//
454// total_samples_sent: used as the return value
455//
456// RETURNS:
457//
458// total_samples_sent, which is the index for the end of this long
459// continuous stream.  [[[WDW: with a unit32_t managing 16-bit
460// samples at 22050Hz, we have about 54 hours of play time before
461// the index wraps back to 0.  We don't handle that wrapping, so
462// the behavior after 54 hours of play time is undefined.]]]
463//
464//<wave_get_write_position
465
466uint32_t wave_get_write_position(void* theHandler)
467{
468  ENTER("wave_get_write_position");
469  SHOW("wave_get_write_position: %d\n", total_samples_sent);
470  SHOW_TIME("wave_get_write_position > LEAVE");
471  return total_samples_sent;
472}
473
474//>
475// wave_get_remaining_time
476//
477// DESCRIPTION:
478//
479// Returns the remaining time (in ms) before the sample is played.
480// The sample in this case is a return value from a previous call to
481// wave_get_write_position.
482//
483// PARAMETERS:
484//
485// sample: an index returned from wave_get_write_position representing
486//         an index into the long continuous stream of 16-bit samples
487// time: a return value representing the delay in milliseconds until
488//       sample is played.  A value of 0 means the sample is either
489//       currently being played or it has already been played.
490//
491// GLOBALS USED/MODIFIED:
492//
493// sun_audio_fd: used to determine total number of samples played by
494//               the audio system
495// total_samples_skipped: used in remaining time calculation
496//
497// RETURNS:
498//
499// Time in milliseconds before the sample is played or 0 if the sample
500// is currently playing or has already been played.
501//
502//<wave_get_remaining_time
503
504int wave_get_remaining_time(uint32_t sample, uint32_t* time)
505{
506  uint32_t a_time=0;
507  uint32_t actual_index;
508
509  audio_info_t ainfo;
510  ENTER("wave_get_remaining_time");
511  if (!time) {
512    return(-1);
513    SHOW_TIME("wave_get_remaining_time > LEAVE");
514  }
515
516  ioctl(sun_audio_fd, AUDIO_GETINFO, &ainfo);
517
518  // See if this sample has already been played or is currently 
519  // playing.
520  //
521  actual_index = sample - total_samples_skipped;
522  if ((sample < total_samples_skipped) ||
523      (actual_index <= ainfo.play.samples)) { 
524    *time = 0;
525  } else {
526    a_time = ((actual_index - ainfo.play.samples) * 1000) / SAMPLE_RATE;
527    *time = (uint32_t) a_time;
528  }
529  SHOW("wave_get_remaining_time for %d: %d\n", sample, *time);
530  SHOW_TIME("wave_get_remaining_time > LEAVE");
531  return 0;
532}
533
534#else
535// notdef USE_SADA
536
537void wave_init() {}
538void* wave_open(const char* the_api) {return (void *)1;}
539size_t wave_write(void* theHandler, char* theMono16BitsWaveBuffer, size_t theSize) {return theSize;}
540int wave_close(void* theHandler) {return 0;}
541int wave_is_busy(void* theHandler) {return 0;}
542void wave_terminate() {}
543uint32_t wave_get_read_position(void* theHandler) {return 0;}
544uint32_t wave_get_write_position(void* theHandler) {return 0;}
545void wave_flush(void* theHandler) {}
546typedef int (t_wave_callback)(void);
547void wave_set_callback_is_output_enabled(t_wave_callback* cb) {}
548extern void* wave_test_get_write_buffer() {return NULL;}
549
550int wave_get_remaining_time(uint32_t sample, uint32_t* time)
551{
552	if (!time) return(-1);
553	*time = (uint32_t)0;
554	return 0;
555}
556
557#endif  // of USE_PORTAUDIO
558
559//>
560//<clock_gettime2, add_time_in_ms
561
562void clock_gettime2(struct timespec *ts)
563{
564  struct timeval tv;
565
566  if (!ts)
567    {
568      return;
569    }
570
571  assert (gettimeofday(&tv, NULL) != -1);
572  ts->tv_sec = tv.tv_sec;
573  ts->tv_nsec = tv.tv_usec*1000;
574}
575
576void add_time_in_ms(struct timespec *ts, int time_in_ms)
577{
578  if (!ts)
579    {
580      return;
581    }
582
583  uint64_t t_ns = (uint64_t)ts->tv_nsec + 1000000 * (uint64_t)time_in_ms;
584  while(t_ns >= ONE_BILLION)
585    {
586      SHOW("event > add_time_in_ms ns: %d sec %Lu nsec \n", ts->tv_sec, t_ns);
587      ts->tv_sec += 1;
588      t_ns -= ONE_BILLION;	  
589    }
590  ts->tv_nsec = (long int)t_ns;
591}
592
593#endif   // USE_ASYNC
594
595//>