00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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>
00044
00045 #include "common.h"
00046 #include "audio.h"
00047 #include "mp3.h"
00048 #include "parsetime.h"
00049 #include "report.h"
00050 #include "snprintf/snprintf.h"
00051
00052 #ifdef WITH_AAC
00053 #include "aac.h"
00054 #endif
00055
00056
00057 #define AUDIO_MAGIC_NUMBER 0x6B2F6EEF
00058
00059
00060
00061
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
00079
00080
00089 static
00090 bool open_file (struct_audio_data_t *data, const char *fname)
00091 {
00092 assert (data->magic == AUDIO_MAGIC_NUMBER);
00093
00094
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 {
00100
00101
00102
00103
00104
00105 if (data->fdm != NULL)
00106 {
00107
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;
00121 data->file_name = NULL;
00122 close (data->fd);
00123 }
00124
00125
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;
00132 }
00133 strcpy (data->file_name, fname);
00134
00135
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;
00141 }
00142
00143
00144 data->prev_file_type = data->file_type;
00145 data->file_type = get_file_type(fname);
00146
00147
00148
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;
00154 }
00155
00156
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);
00161 report ("Error mmapping file", REP_WARNING);
00162 return false;
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);
00199
00200 if (data->prev_file_name != NULL)
00201 {
00202 if (!strcmp (data->prev_file_name, data->file_name))
00203 {
00204 return false;
00205 }
00206 else
00207 {
00208 return true;
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;
00226
00227 assert (data != NULL);
00228 assert (_data != NULL);
00229
00230 pthread_mutex_lock (&data->mutex);
00231 if (DEBUG_THREADS) printf ("audio_decoder has mutex\n");
00232
00233 assert (data->magic == AUDIO_MAGIC_NUMBER);
00234
00235 if (DEBUG_AUDIO) report ("playing file. . ", REP_DEBUG);
00236
00237 switch (get_file_type(data->file_name))
00238 {
00239 #ifdef WITH_AAC
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))
00245 {
00246 if (DEBUG_AUDIO) report ("the last filetype was NOT aac", REP_DEBUG);
00247 mp3_close (data);
00248 aac_initiate (data);
00249 }
00250 (void *) aac_play (data);
00251 break;
00252 #endif
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))
00258 {
00259 if (DEBUG_AUDIO) report ("the last filetype was NOT mp3", REP_DEBUG);
00260 pthread_mutex_unlock (&data->mutex);
00261 if (DEBUG_THREADS) printf ("audio_decoder released mutex. calling mp3_init\n");
00262 #ifdef WITH_AAC
00263 aac_terminate (data);
00264 #endif
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);
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:
00280 assert (0);
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;
00289 data->state = AUDIO_STATE_STOP;
00290
00291 data->do_callback_done = true;
00292
00293 pthread_mutex_unlock (&data->mutex);
00294 if (DEBUG_THREADS) printf ("audio_decoder released mutex\n");
00295 pthread_exit (0);
00296 }
00297
00298
00299
00300
00301
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);
00322
00323 if (data->state != AUDIO_STATE_STOP) {
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;
00330 data->progress.fraction = 0;
00331
00332 ret = parse_time_get_dur(start, stop);
00333 data->start = parse_time_mad_time_t (start);
00334 data->stop = parse_time_mad_time_t (stop);
00335
00336 if (open_file (data, fname) == false) {
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;
00345 }
00346 pthread_mutex_unlock (&data->mutex);
00347 if (DEBUG_THREADS) printf ("audio_play unlocked mutex\n");
00348 return ret;
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);
00366
00367 playing = data->is_playing;
00368 state = data->state;
00369 pthread_mutex_unlock (&data->mutex);
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);
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);
00389 }
00390 return 1;
00391 }
00392 data->cb_error (data->daisy, DAISY_ERROR_AUDIO_PAUSED_WHILE_NOT_PLAYING, "audio engine was paused while not playing");
00393 return -1;
00394 }
00395
00402 int audio_stop (audio_data_t _data)
00403 {
00404 struct_audio_data_t *data = _data;
00405 void *daisy = NULL;
00406 void (*cb_error) (void *, enum daisy_status, const char *);
00407
00408 int ret = -1;
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) {
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);
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;
00439 }
00440 else {
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;
00448 }
00449
00450 pthread_mutex_unlock (&data->mutex);
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;
00466 void (*progress_callback) (void *, long int);
00467
00468 pthread_mutex_lock (&data->mutex);
00469
00470 assert (data != NULL);
00471 assert (data->magic == AUDIO_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;
00479 }
00480
00481 progress_callback = data->cb_progress;
00482 pthread_mutex_unlock (&data->mutex);
00483
00484
00485 progress_callback (data->daisy, progress_ms);
00486 return ret;
00487 }
00488
00494 void audio_terminate (audio_data_t _data)
00495 {
00496 struct_audio_data_t *data = _data;
00497
00498
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);
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 switch (data->file_type)
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
00527 break;
00528 case (AUDIO_FILE_WAV):
00529
00530 break;
00531 default:
00532 break;
00533 }
00534
00535
00536 if (data->fdm != NULL) {
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);
00544
00545 munmap (data->fdm, data->stat.st_size);
00546
00547 free (data->file_name);
00548
00549 data->magic = 0x00000000;
00550
00551 pthread_mutex_unlock (&data->mutex);
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);
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;
00579 }
00580
00581 data->magic = AUDIO_MAGIC_NUMBER;
00582 assert (data->magic == AUDIO_MAGIC_NUMBER);
00583
00584
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;
00596 data->is_playing = false;
00597
00598
00599 data->cb_playing_done = done;
00600
00601
00602 data->do_callback_done = false;
00603
00604 data->cb_error = error;
00605
00606
00607 data->cb_progress = progress;
00608
00609 data->daisy = _daisy;
00610
00611
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;
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;
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);
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
00648 assert (data->magic == AUDIO_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);
00656
00657
00658 exit = false;
00659 while (!exit)
00660 {
00661 pthread_mutex_lock (&data->mutex);
00662
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
00675 if (state == AUDIO_STATE_PLAY)
00676 {
00677 if (!playing)
00678 {
00679
00680
00681 data->is_playing = true;
00682 pthread_create(&audio_decoder_thread, NULL, &audio_decoder, data);
00683 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
00684
00685 }
00686 }
00687
00688
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;
00697 pthread_cancel (audio_decoder_thread);
00698 if (DEBUG_THREADS) printf ("audio_thread stop released mutex\n");
00699 }
00700 }
00701 pthread_mutex_unlock (&data->mutex);
00702
00703 usleep (500);
00704
00705 if (data->magic != AUDIO_MAGIC_NUMBER) {
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 }