Main Page   Data Structures   File List   Data Fields   Globals  

audio.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2006 by André Lindhjem <belgarat@sdf.lonestar.org>,     *
00003  *                         Kjetil Holien <kjetil.holien@gmail.com>,        *
00004  *                         Terje Risa <terje.risa@gmail.com> &             *
00005  *                         Øyvind Nerbråten <oyvind@nerbraten.com>         *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  *   This program is distributed in the hope that it will be useful,       *
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015  *   GNU General Public License for more details.                          *
00016  *                                                                         *
00017  *   You should have received a copy of the GNU General Public License     *
00018  *   along with this program; if not, write to the                         *
00019  *   Free Software Foundation, Inc.,                                       *
00020  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00021  ***************************************************************************
00022  *
00023  * \file audio.c
00024  * \author André Lindhjem, Kjetil Holien, Terje Risa & Øyvind Nerbråten
00025  * \date 25.02.2006
00026  * 
00027  * Audio module. This handles the task of reading audio files and playing
00028  * the audio output. It uses a MP3-decoder and libao, and it can easilly be
00029  * extended with more decoders.
00030  */
00031 
00032 
00036 #include <unistd.h>
00037 #include <sys/stat.h>
00038 #include <sys/mman.h>
00039 #include <sys/types.h>
00040 #include <fcntl.h>
00041 #include <assert.h>
00042 #include <stdbool.h>
00043 #include <sys/time.h>   /* for timeval */
00044 
00045 #include "common.h"             /* common project settings */
00046 #include "audio.h"              /* common for all audio */
00047 #include "mp3.h"                /* mp3 decoder */
00048 #include "parsetime.h"          /* converts time-formats */
00049 #include "report.h"             /* reporter class */
00050 #include "snprintf/snprintf.h"  /* printf function */
00051 
00052 #ifdef WITH_AAC     /* enable this to build with AAC support. NOTE: AAC support is not yet fully implemented */
00053 #include "aac.h"        /* aac decoder */
00054 #endif  /* WITH_AAC */
00055 
00056 
00057 #define AUDIO_MAGIC_NUMBER 0x6B2F6EEF   /* magic number. we use this to check that the struct are valid */
00058 
00059 
00060 /* ************************************************ *
00061  *          Static function declarations            *
00062  * ************************************************ */
00063  
00064 static
00065 bool open_file (struct_audio_data_t *data, const char *fname);
00066 
00067 static
00068 audio_file_t get_file_type (const char *file);
00069 
00070 static
00071 bool is_new_file (struct_audio_data_t *data);
00072 
00073 static
00074 void *audio_decoder (void*);
00075 
00076 
00077 /* ************************************************ *
00078  *          Static function definitions             *
00079  * ************************************************ */
00080 
00089 static
00090 bool open_file (struct_audio_data_t *data, const char *fname)
00091 {
00092     assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00093 
00094     /* did we already load the file? */
00095     if ((data->file_name != NULL) && !strcmp (data->file_name, fname)) {
00096         if (DEBUG_AUDIO) report ("File already loaded", REP_DEBUG);
00097     }
00098 
00099     else {  /* file is NOT already loaded!
00100                We'll need to:
00101                1: free the old mmap
00102                2: open the new file
00103                3: create a new mmap */
00104 
00105         if (data->fdm != NULL)  /* 1: Free mmap, clean data */
00106         {
00107             /* freeing the mmap before creating a new one */
00108             if (munmap (data->fdm, data->stat.st_size) == -1)
00109             {
00110                 data->cb_error (data->daisy, DAISY_ERROR_AUDIO_FREE_MMAP, NULL);
00111                 report ("Unable to free mmap", REP_ERROR);
00112             }
00113 
00114             if (DEBUG_AUDIO) {
00115                 char rep[STRLEN];
00116                 snprintf (rep, sizeof (rep), "Freed mmap. Pointer: %p, Size: %d", data->fdm, (int) data->stat.st_size);
00117                 report (rep, REP_DEBUG);
00118             }
00119 
00120             data->fdm = NULL;       /* we have freed the data - don't want an old pointer to point there! */
00121             data->file_name = NULL; /* this file is no longer in our memory */
00122             close (data->fd);       /* closing the file before we open a new one */
00123         }
00124         
00125         /* udating the data-struct with the new file_name */
00126         if (data->file_name != NULL)
00127             free(data->file_name);
00128         data->file_name = (char *) malloc (strlen(fname)+1);
00129         if (data == NULL) {
00130             data->cb_error (data->daisy, DAISY_ERROR_AUDIO_MALLOC, NULL);
00131             return false;   /* malloc failed */
00132         }
00133         strcpy (data->file_name, fname);
00134         
00135         /* open the new file */
00136         if ((data->fd = open (fname, O_RDONLY)) == -1)
00137         {
00138             data->cb_error (data->daisy, DAISY_ERROR_AUDIO_OPEN, NULL);
00139             report ("Error opening file", REP_WARNING);
00140             return false;   /* open file failed */
00141         }
00142 
00143         /* setting filetype */
00144         data->prev_file_type = data->file_type;
00145         data->file_type = get_file_type(fname);
00146 
00147         /* fstating file. this gives us alot of information about
00148          * the file (we'll use the st_size (filesize) here) */
00149         if (stat(fname, &data->stat) == -1 || data->stat.st_size == 0)
00150         {
00151             data->cb_error (data->daisy, DAISY_ERROR_AUDIO_FSTAT, NULL);
00152             report ("Error fstating file or filesize is 0", REP_WARNING);
00153             return false;   /* fstat failed */
00154         }
00155 
00156         /* create a new mmap */
00157         data->fdm = mmap (0, data->stat.st_size, PROT_READ, MAP_SHARED, data->fd, 0);
00158         if (data->fdm == MAP_FAILED)
00159         {
00160             data->cb_error (data->daisy, DAISY_ERROR_AUDIO_CREATE_MMAP, NULL);  /* report error */
00161             report ("Error mmapping file", REP_WARNING);
00162             return false;   /* mmap failed */
00163         }
00164         
00165         if (DEBUG_AUDIO)
00166         {
00167             char rep[STRLEN];       
00168             snprintf (rep, sizeof (rep), "mmapped new file. Pointer: %p, size: %d", data->fdm, (int) data->stat.st_size);       
00169             report (rep, REP_DEBUG);
00170         }
00171     }
00172     return true;
00173 }
00174 
00175 
00182 static
00183 audio_file_t get_file_type (const char *fname)
00184 {
00185     assert (fname);
00186     if (DEBUG_AUDIO) report("Querying file_type. Returning mp3 for now.", REP_DEBUG);
00187     return AUDIO_FILE_MP3;
00188 }
00189 
00195 static
00196 bool is_new_file (struct_audio_data_t *data)
00197 {
00198     assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00199 
00200     if (data->prev_file_name != NULL)   /* prev_file_name is already set to a value */
00201     {
00202         if (!strcmp (data->prev_file_name, data->file_name))
00203         {
00204             return false;   /* the filenames are the same */
00205         }
00206         else
00207         {
00208             return true;    /* the filenames differ */
00209         }
00210     }
00211     else
00212     {
00213         data->prev_file_name = data->file_name;
00214         return true;
00215     }
00216 }
00217 
00222 static void *audio_decoder (audio_data_t _data)
00223 {
00224     audio_state_t playing;
00225     struct_audio_data_t *data = _data;  /* we need to access information in _data */
00226 
00227     assert (data != NULL);  /* checks for conditions that shouldn't ever happen */
00228     assert (_data != NULL);
00229 
00230     pthread_mutex_lock (&data->mutex);  /* get mutex - we work on "data" */
00231     if (DEBUG_THREADS) printf ("audio_decoder has mutex\n");
00232     
00233     assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00234 
00235     if (DEBUG_AUDIO) report ("playing file. . ", REP_DEBUG);
00236 
00237     switch (get_file_type(data->file_name)) /* finds out the filetype */
00238     {
00239 #ifdef WITH_AAC /* do we build with or without AAC support? */
00240         case (AUDIO_FILE_AAC):
00241             if (DEBUG_AUDIO) report ("audio.c: audio-file is aac", REP_DEBUG);
00242 
00243             if ((is_new_file (data)) &&
00244                 (data->prev_file_type != AUDIO_FILE_AAC))   /* last file_type was NOT aac */
00245             {
00246                 if (DEBUG_AUDIO) report ("the last filetype was NOT aac", REP_DEBUG);
00247                 mp3_close (data);   /* close decoder and start a new one */
00248                 aac_initiate (data);
00249             }
00250             (void *) aac_play (data);
00251             break;
00252 #endif  /* WITH_AAC */
00253         case (AUDIO_FILE_MP3):
00254             if (DEBUG_AUDIO) report ("audio.c: audio-file is mp3", REP_DEBUG);
00255 
00256             if ((is_new_file (data)) &&
00257                 (data->prev_file_type != AUDIO_FILE_MP3)) /* last file_type was NOT mp3 */
00258             {
00259                 if (DEBUG_AUDIO) report ("the last filetype was NOT mp3", REP_DEBUG);
00260                 pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00261                 if (DEBUG_THREADS) printf ("audio_decoder released mutex. calling mp3_init\n");
00262 #ifdef WITH_AAC
00263                 aac_terminate (data);   /* close decoder and start a new one */
00264 #endif  /* WITH_AAC */
00265                 mp3_init (data);
00266                 pthread_mutex_lock (&data->mutex);
00267                 if (DEBUG_THREADS) printf ("audio_decoder after mp3_init has mutex\n");
00268             }
00269             pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00270             if (DEBUG_THREADS) printf ("audio_decoder released mutex before mp3_play\n");
00271             mp3_play (data);
00272             pthread_mutex_lock (&data->mutex);
00273             if (DEBUG_THREADS) printf ("audio_decoder has mutex after mp3_play\n");
00274             break;
00275         case (AUDIO_FILE_WAV):
00276             report ("wav parsing isn't implemented yet", REP_MESSAGE);
00277             break;
00278         case (AUDIO_FILE_UNKNOWN):
00279         default:        /* This should never happen! */
00280             assert (0); /* Report where we are and exit the program */
00281             break;
00282     }
00283 
00284     if (DEBUG_AUDIO) report ("start_decoder thread exiting", REP_DEBUG);
00285 
00286     playing = data->state;
00287 
00288     data->is_playing = false;               /* we're not playing anymore */
00289     data->state = AUDIO_STATE_STOP;         /* settings state to stopped */
00290 
00291     data->do_callback_done = true;
00292 
00293     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00294     if (DEBUG_THREADS) printf ("audio_decoder released mutex\n");
00295     pthread_exit (0);
00296 }
00297 
00298 
00299 
00300 /* ************************************************** *
00301  *          Global function definitions               *
00302  * ************************************************** */
00303 
00312 unsigned
00313 long
00314 int audio_play (audio_data_t _data, const char *fname, const char *start, const char *stop)
00315 {
00316     struct_audio_data_t *data = _data;
00317     unsigned long int ret;
00318     
00319     pthread_mutex_lock (&data->mutex);
00320     if (DEBUG_THREADS) printf ("audio_play has mutex\n");
00321     assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00322 
00323     if (data->state != AUDIO_STATE_STOP) {  /* make sure we are stopped */
00324         data->cb_error (data->daisy, DAISY_ERROR_AUDIO_NOT_STOPPED, "audio_play called when state is NOT stopped");
00325         if (DEBUG_AUDIO) report ("audio_play called when state is NOT stopped", REP_ERROR);
00326         ret = -1;
00327     }
00328     else {
00329         data->progress.seconds  = 0;    /* reset the progress */
00330         data->progress.fraction = 0;
00331 
00332         ret =           parse_time_get_dur(start, stop);    /* get duration in ms */
00333         data->start =   parse_time_mad_time_t (start);  /* and set start- and stop-times. */
00334         data->stop  =   parse_time_mad_time_t (stop);
00335         
00336         if (open_file (data, fname) == false) { /* constructing and reporting an error-message */
00337             char message[STRLEN];
00338             snprintf (message, sizeof (message), "Could not open file. (%s)", fname);
00339             report (message, REP_WARNING);
00340             data->cb_error (data->daisy, DAISY_ERROR_AUDIO_OPEN, "could not open audio file");
00341             return false;
00342         }
00343 
00344         data->state = AUDIO_STATE_PLAY;     /* set state to playing */
00345     }   
00346     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00347     if (DEBUG_THREADS) printf ("audio_play unlocked mutex\n");
00348     return ret; /* we return the duration of this clip (or -1 if we fail) */
00349 }
00350 
00357 int audio_pause (audio_data_t _data)
00358 {
00359     struct_audio_data_t *data = _data;
00360     bool playing = NULL;
00361     audio_state_t state = AUDIO_STATE_NOOP;
00362     
00363     pthread_mutex_lock (&data->mutex);
00364     if (DEBUG_THREADS) printf ("audio_stop has mutex\n");
00365     assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00366 
00367     playing = data->is_playing;
00368     state = data->state;    /* copy data->state to a local variable */
00369     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00370 
00371     if (playing)
00372     {
00373         if (state == AUDIO_STATE_PAUSE)
00374         {
00375             if (DEBUG_AUDIO) report ("unpausing", REP_DEBUG);
00376             pthread_mutex_lock (&data->mutex);
00377             if (DEBUG_THREADS) printf ("audio_pause has mutex");
00378             data->state = AUDIO_STATE_PLAY;
00379             pthread_cond_signal (&data->unpause_cond);
00380             pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00381         }
00382         else
00383         {
00384             if (DEBUG_AUDIO) report ("pausing", REP_DEBUG);
00385             pthread_mutex_lock (&data->mutex);
00386             if (DEBUG_THREADS) printf ("audio_stop has mutex");
00387             data->state = AUDIO_STATE_PAUSE;
00388             pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00389         }
00390         return 1;   /* success */
00391     }
00392     data->cb_error (data->daisy, DAISY_ERROR_AUDIO_PAUSED_WHILE_NOT_PLAYING, "audio engine was paused while not playing");
00393     return -1;  /* pause failed */
00394 }
00395 
00402 int audio_stop (audio_data_t _data)
00403 {
00404     struct_audio_data_t *data = _data;
00405     void *daisy = NULL; /* pointer to daisy struct in case we need to call cb_error */
00406     void (*cb_error) (void *, enum daisy_status, const char *); /* error callback. this should be defined the same was as in struct_audio_data_t */
00407 
00408     int ret = -1;   /* return value */
00409     
00410     if (DEBUG_AUDIO) report ("stopping", REP_DEBUG);
00411     pthread_mutex_lock (&data->mutex);
00412     if (DEBUG_THREADS) printf ("audio_stop has mutex\n");   
00413     assert (data->magic == AUDIO_MAGIC_NUMBER);
00414 
00415     daisy = data->daisy;
00416     cb_error = data->cb_error;
00417     
00418     if (data == NULL) { /* stop are called before we are initialized! (data doesn't exist yet!) */
00419         pthread_mutex_unlock (&data->mutex);
00420         if (DEBUG_THREADS) printf ("audio_stop released mutex (data == NULL)\n");   
00421         cb_error (daisy, DAISY_ERROR_AUDIO_DATA_IS_NULL, "audio data not initialized! (audio.c:audio_stop)");
00422         pthread_mutex_lock (&data->mutex);
00423         if (DEBUG_THREADS) printf ("audio_stop has mutex (data == NULL)\n");    
00424         ret = -1;
00425     }
00426     else if (data->state == AUDIO_STATE_PLAY)
00427     {
00428         assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00429         data->state = AUDIO_STATE_STOP;
00430         while (data->is_playing)
00431         {
00432             pthread_mutex_unlock (&data->mutex);
00433             usleep(500);
00434             pthread_mutex_lock (&data->mutex);
00435             
00436         }
00437 
00438         ret = 1;    /* stop succeeds */
00439     }
00440     else {  /* we can't stop if we aren't currently playing! */
00441         assert (cb_error == data->cb_error);
00442         pthread_mutex_unlock (&data->mutex);
00443         if (DEBUG_THREADS) printf ("audio_stop released mutex (stop called when not currently playing)\n"); 
00444         cb_error (daisy, DAISY_ERROR_AUDIO_STOPPED_WHILE_NOT_PLAYING, "stop called while we're not playing (audio.c:audio_stop)");
00445         pthread_mutex_lock (&data->mutex);
00446         if (DEBUG_THREADS) printf ("audio_stop has mutex (stop called when not currently playing)\n");
00447         ret = -1;   /* error stopping */
00448     }
00449 
00450     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00451     if (DEBUG_THREADS) printf ("audio_stop released mutex\n");
00452     return ret;
00453 }
00454 
00461 int callback (audio_data_t _data, long int progress_ms)
00462 {
00463     struct_audio_data_t *data = _data;
00464     
00465     int ret = 0;    /* default return value */
00466     void (*progress_callback) (void *, long int);
00467 
00468     pthread_mutex_lock (&data->mutex);
00469     /*if (DEBUG_THREADS) printf ("audio_callback has mutex\n");*/
00470     assert (data != NULL);
00471     assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00472 
00473     if (data->state == AUDIO_STATE_PAUSE)
00474         pthread_cond_wait (&data->unpause_cond, &data->mutex);
00475 
00476     if (data->state == AUDIO_STATE_STOP) {
00477         if (DEBUG_AUDIO) report ("callback stopping audio decoder", REP_DEBUG);
00478         ret = -1;   /* -1 tells the decoder to stop */
00479     }
00480     
00481     progress_callback = data->cb_progress;  /* copy progress callback to a local function pointer (data must be mutex locked) */
00482     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00483     /*if (DEBUG_THREADS) printf ("audio_callback released mutex\n");*/
00484 
00485     progress_callback (data->daisy, progress_ms);   /* call progress callback */
00486     return ret;
00487 }
00488 
00494 void audio_terminate (audio_data_t _data)
00495 {
00496     struct_audio_data_t *data = _data;
00497     
00498     /* stopping audio first */
00499     if (audio_get_state(data) != AUDIO_STATE_STOP) audio_stop (data);
00500 
00501     pthread_mutex_lock (&data->mutex);
00502     if (DEBUG_THREADS) printf ("audio_terminate has mutex\n");
00503 
00504     assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00505 
00506 /*  NOTE: We call audio_stop above rather than signaling audio_thread directly..
00507 
00508     if (data->state != AUDIO_STATE_STOP) {
00509         data->state = AUDIO_STATE_STOP;
00510         pthread_cond_wait(&data->stopped_cond, &data->mutex);
00511     }*/
00512 
00513     /* *********************************************** *
00514      *  By this point, audio_thread should be stopped  *
00515      *  and data should be rady to be freed            *
00516      * *********************************************** */
00517 
00518     switch (data->file_type)    /* call the correct decoder terminate-function */
00519     {
00520         case (AUDIO_FILE_MP3):
00521             mp3_close(data);
00522             break;
00523         case (AUDIO_FILE_AAC):
00524 #ifdef WITH_AAC
00525             aac_terminate (data);
00526 #endif  /* WITH_AAC */
00527             break;
00528         case (AUDIO_FILE_WAV):
00529 /*              wav_terminate (data); */
00530             break;
00531         default:
00532             break;
00533     }
00534 
00535     /* Attempting to free mmap */
00536     if (data->fdm != NULL) {    /* if data->fdm is null, no file is read into memory and we won't have to free anything */
00537         if (munmap (data->fdm, data->stat.st_size) == -1) {
00538             data->cb_error (data->daisy, DAISY_ERROR_AUDIO_FREE_MMAP, NULL);
00539             report ("Error freeing mmap", REP_MESSAGE);
00540         }
00541     }
00542 
00543     close (data->fd);   /* closing the file */
00544 
00545     munmap (data->fdm, data->stat.st_size); /* free the mmap'ed audio file */
00546 
00547     free (data->file_name); /* release space allocated for the filename */
00548 
00549     data->magic = 0x00000000;   /* resetting magic number - we can't use struct anymore! */
00550 
00551     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00552     if (DEBUG_THREADS) printf ("audio_terminate released mutex\n");
00553     if (data->mp3_dither != NULL) {
00554         free (data->mp3_dither);
00555         data->mp3_dither = NULL;
00556     }
00557     free (data);    /* Free data struct */
00558 }
00559 
00569 audio_data_t audio_initiate (daisyplayer_t _daisy,
00570                             void (*done) (daisyplayer_t d),
00571                             void (*error) (void *data, enum daisy_status status, const char *daisy_status_msg),
00572                             void (*progress) (void *data, long int progress_ms))
00573 {
00574     struct_audio_data_t *data = (struct_audio_data_t *) malloc (sizeof (struct_audio_data_t));
00575     if (data == NULL) {
00576         error (data, DAISY_ERROR_AUDIO_INITIATE_DATA, NULL);
00577         report ("Cannot malloc size for data", REP_ERROR);
00578         return NULL;    /* fail */
00579     }
00580 
00581     data->magic = AUDIO_MAGIC_NUMBER;   /* set magic number */
00582     assert (data->magic == AUDIO_MAGIC_NUMBER);
00583 
00584     /* And setting some values to safe defaults */
00585     data->fd = -1;
00586     data->fdm = NULL;
00587     data->file_name = NULL;
00588     data->prev_file_name = NULL;
00589 
00590     data->mp3_dither = NULL;
00591     
00592     data->file_type = AUDIO_FILE_UNKNOWN;
00593     data->prev_file_type = AUDIO_FILE_UNKNOWN;
00594 
00595     data->state = AUDIO_STATE_STOP;     /* default state is stopped */
00596     data->is_playing = false;
00597     
00598     /* callback functions */    
00599     data->cb_playing_done = done;   /* callback function. playback_done () should
00600                                        be called whenever we're done playing
00601                                        a segment */
00602     data->do_callback_done = false;
00603 
00604     data->cb_error = error;         /* callback function. cb_error () should
00605                                        be called when an error occur. */
00606 
00607     data->cb_progress = progress;   /* callback function. cb_progress are called during playback */
00608 
00609     data->daisy = _daisy;           /* we keep a pointer to the main daisy struct */
00610 
00611     /* Setting up some thread data */
00612     if (pthread_cond_init(&data->unpause_cond, NULL) != 0) {
00613         data->cb_error (data->daisy, DAISY_ERROR_AUDIO_INITIATE_DATA, NULL);
00614         report ("Could not initialize data->unpause_cond", REP_ERROR);
00615         return NULL; /* fail */
00616     }
00617     if (pthread_mutex_init(&data->mutex, NULL) != 0) {
00618         data->cb_error (data->daisy, DAISY_ERROR_AUDIO_INITIATE_DATA, NULL);
00619         report ("Could not initialize data->mutex", REP_ERROR);
00620         return NULL; /* fail */
00621     }
00622 
00623     if (DEBUG_AUDIO) report ("data struct initialized", REP_DEBUG);
00624 
00625     return data;
00626 }
00627 
00635 void *audio_thread (void *_data)
00636 {
00637     struct_audio_data_t *data = (struct_audio_data_t *) _data;
00638 
00639     pthread_t audio_decoder_thread;
00640     void (*cb_playing_done) (daisyplayer_t daisy);  /* pointer to callback function */
00641     audio_state_t state;
00642     bool playing;
00643     bool exit;
00644     bool l_do_callback_done;
00645     
00646     pthread_mutex_lock (&data->mutex);
00647     /*if (DEBUG_THREADS) printf ("audio_thread has mutex\n");*/
00648     assert (data->magic == AUDIO_MAGIC_NUMBER); /* check magic number */
00649 
00650     data->is_playing = false;
00651     data->state = AUDIO_STATE_STOP;
00652     
00653     cb_playing_done = data->cb_playing_done;
00654 
00655     pthread_mutex_unlock (&data->mutex);    /* release mutex - we're done with "data" */
00656     /*if (DEBUG_THREADS) printf ("audio_thread released mutex\n");*/
00657 
00658     exit = false;
00659     while (!exit)
00660     {
00661         pthread_mutex_lock (&data->mutex);
00662         /*if (DEBUG_THREADS) printf ("audio_thread loop has mutex\n");*/
00663         state   = data->state;
00664         playing = data->is_playing;
00665         l_do_callback_done = data->do_callback_done;
00666 
00667         if (l_do_callback_done) {           
00668             data->do_callback_done = false;
00669             pthread_mutex_unlock (&data->mutex);
00670             cb_playing_done (data->daisy);
00671             pthread_mutex_lock (&data->mutex);
00672         }
00673         
00674         /* by this point, the mutex SHOULD be unlocked */
00675         if (state == AUDIO_STATE_PLAY)
00676         {
00677             if (!playing)
00678             {
00679                 /*if (DEBUG_AUDIO) report ("audio_thread: starting start_decoder thread", REP_DEBUG);*/
00680                 /*if (DEBUG_THREADS) printf ("audio_thread playing has mutex\n");*/
00681                 data->is_playing = true;
00682                 pthread_create(&audio_decoder_thread, NULL, &audio_decoder, data);
00683                 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);   /* set cancel type. this thread should be canceled at any time and not just on cancellation points */
00684                 /*if (DEBUG_THREADS) printf ("audio_thread playing released mutex\n");*/
00685             }
00686         }
00687         
00688         /* by this point, the mutex SHOULD be unlocked */
00689         
00690         else if (state == AUDIO_STATE_STOP)
00691         {
00692             if (playing)
00693             {
00694                 if (DEBUG_AUDIO) report ("audio_thread: stopping start_decoder thread", REP_DEBUG);
00695                 if (DEBUG_THREADS) printf ("audio_thread stop has mutex\n");
00696                 data->is_playing = false;               /* we're not playing anymore */
00697                 pthread_cancel (audio_decoder_thread);  /* stopping thread */
00698                 if (DEBUG_THREADS) printf ("audio_thread stop released mutex\n");
00699             }
00700         }
00701         pthread_mutex_unlock (&data->mutex);
00702         /* by this point, the mutex SHOULD be unlocked */
00703         usleep (500);   /* don't throttle the cpu */
00704 
00705         if (data->magic != AUDIO_MAGIC_NUMBER) {    /* data struct is not intact - exit */
00706             exit = true;
00707         }
00708     }
00709     pthread_exit(NULL);
00710 }
00711 
00717 audio_state_t audio_get_state (audio_data_t _data)
00718 {
00719     struct_audio_data_t *data = _data;
00720     audio_state_t state;
00721     
00722     pthread_mutex_lock (&data->mutex);
00723     state = data->state;
00724     pthread_mutex_unlock (&data->mutex);
00725 
00726     return state;
00727 }

Generated on Tue Sep 5 12:14:06 2006 for libdaisy by doxygen1.2.15