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 #include <stdio.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #include <unistd.h>
00035 #include <assert.h>
00036
00037 #include "libdaisy.h"
00038 #include "control.h"
00039 #include "common.h"
00040 #include "snprintf/snprintf.h"
00041 #include "audio.h"
00042 #include "report.h"
00043
00044 #define DAISYPLAYER_MAGIC_NUMBER 0xC729A4BF
00045
00046
00047
00052 typedef struct {
00053 void *data;
00054 void (*cb_daisy_audio_done) (void *);
00055 void (*cb_daisy_audio_next) (void *, unsigned long int);
00056 void (*cb_daisy_text) (void *, void *);
00057 void (*cb_daisy_id) (void *, void *);
00058 void (*cb_daisy_error) (void *, enum daisy_status, const char *daisy_status_msg);
00059 void (*cb_daisy_progress) (void *, long int);
00060
00061 void *audio_data;
00062 struct DaisyData *daisy_book_data;
00063 unsigned int magic;
00064
00065 pthread_mutex_t daisy_mutex;
00066
00067 } struct_daisyplayer_t;
00068
00069
00070
00071
00072
00073
00074
00082 static void local_cb_daisy_audio_done (daisyplayer_t daisy);
00083
00097 static audio_data_t start_audio (daisyplayer_t daisy,
00098 void (*done) (daisyplayer_t),
00099 void (*error) (void *data, enum daisy_status, const char *),
00100 void (*progress) (void *data, long int progress_ms));
00101
00107 static void stop_audio (daisyplayer_t daisy, audio_data_t data);
00108
00109
00110
00111
00112
00113
00114
00122 static void local_cb_daisy_audio_done (daisyplayer_t daisy)
00123 {
00124 int result;
00125 struct_daisyplayer_t *_daisy = daisy;
00126
00127 _daisy->cb_daisy_audio_done (_daisy->data);
00128
00129 result = daisy_seek (_daisy, DAISY_SEEK_NEXT_PASSAGE);
00130
00131 if (result != 1 )
00132 {
00133 if (result == 0)
00134 {
00135 _daisy->cb_daisy_error (_daisy->data, DAISY_END_OF_BOOK, NULL);
00136 }
00137 else
00138 {
00139 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_SEEK_FAILED, NULL);
00140 }
00141 }
00142 }
00143
00157 static audio_data_t start_audio (daisyplayer_t daisy,
00158 void (*done) (daisyplayer_t d),
00159 void (*error) (void *data, enum daisy_status, const char *daisy_error_msg),
00160 void (*progress) (void *data, long int progress_ms))
00161 {
00162 audio_data_t ret;
00163 struct_daisyplayer_t *_daisy = daisy;
00164
00165 ret = audio_initiate (_daisy, done, error, progress);
00166
00167 if (DEBUG_DAISYPLAYER) report ("control.c: in start_audio", REP_DEBUG);
00168
00169 if (pthread_create (&_daisy->daisy_book_data->thread_audio, NULL, &audio_thread, ret))
00170 {
00171 report ("Error creating audio thread", REP_CRITICAL);
00172 return NULL;
00173 }
00174 else
00175 {
00176 if (DEBUG_DAISYPLAYER) report ("control.c: audio_thread started", REP_DEBUG);
00177 }
00178
00179 return ret;
00180 }
00181
00187 static void stop_audio (daisyplayer_t daisy, audio_data_t data)
00188 {
00189 struct_daisyplayer_t *_daisy = daisy;
00190
00191 audio_terminate(data);
00192 pthread_cancel (_daisy->daisy_book_data->thread_audio);
00193 }
00194
00195
00196
00197
00198
00199
00200
00216 daisyplayer_t daisy_init (void *data,
00217 void (*l_cb_daisy_audio_done) (void *),
00218 void (*l_cb_daisy_audio_next) (void *, unsigned long int),
00219 void (*l_cb_daisy_text) (void *, void *),
00220 void (*l_cb_daisy_id) (void *, void *),
00221 void (*l_cb_daisy_error) (void *, enum daisy_status, const char *),
00222 void (*l_cb_daisy_progress) (void *, long int))
00223
00224 {
00225 struct_daisyplayer_t *daisy = malloc (sizeof(struct_daisyplayer_t));
00226
00227 daisy->magic = DAISYPLAYER_MAGIC_NUMBER;
00228
00229 if (pthread_mutex_init(&daisy->daisy_mutex, NULL) != 0) {
00230 l_cb_daisy_error (daisy, DAISY_ERROR_MISC_INIT_MUTEX, NULL);
00231 report ("Could not initialize daisy->daisy_mutex", REP_ERROR);
00232 return NULL;
00233 }
00234
00235 daisy->data = data;
00236
00237
00238 daisy->cb_daisy_audio_done = l_cb_daisy_audio_done;
00239 daisy->cb_daisy_audio_next = l_cb_daisy_audio_next;
00240 daisy->cb_daisy_text = l_cb_daisy_text;
00241 daisy->cb_daisy_id = l_cb_daisy_id;
00242 daisy->cb_daisy_error = l_cb_daisy_error;
00243 daisy->cb_daisy_progress = l_cb_daisy_progress;
00244
00245
00246 daisy->daisy_book_data = parseInit ();
00247
00248
00249 daisy->audio_data = start_audio (daisy, local_cb_daisy_audio_done, daisy->cb_daisy_error, daisy->cb_daisy_progress);
00250 assert (daisy->magic == DAISYPLAYER_MAGIC_NUMBER);
00251 return daisy;
00252 }
00253
00259 void daisy_term (daisyplayer_t daisy)
00260 {
00261 struct_daisyplayer_t *_daisy = daisy;
00262
00263 if (DEBUG_DAISYPLAYER) report ("daisy_term\n", REP_DEBUG);
00264
00265 parseTerminate (_daisy->daisy_book_data);
00266
00267 stop_audio(_daisy, _daisy->audio_data);
00268
00269 _daisy->magic = 0x00000000;
00270 free (_daisy);
00271 }
00272
00279 int daisy_load (daisyplayer_t daisy, char *path)
00280 {
00281 int result;
00282 struct_daisyplayer_t *_daisy = daisy;
00283
00284 if (DEBUG_DAISYPLAYER) report ("daisy_load\n", REP_DEBUG);
00285
00286 stop_audio(_daisy, _daisy->audio_data); _daisy->audio_data = NULL;
00287 _daisy->audio_data = start_audio(_daisy, local_cb_daisy_audio_done, _daisy->cb_daisy_error, _daisy->cb_daisy_progress);
00288
00289 result = parse (_daisy->daisy_book_data, path);
00290 if (result != 1)
00291 return result;
00292 result = seek (_daisy->daisy_book_data, DAISY_SEEK_NEXT_PASSAGE);
00293 return result;
00294 }
00295
00301 int daisy_play (daisyplayer_t daisy)
00302 {
00303 struct_daisyplayer_t *_daisy = daisy;
00304 unsigned long int duration_ms;
00305 char audiopath[STRLEN];
00306
00307 if (DEBUG_DAISYPLAYER) report ("daisy_play\n", REP_DEBUG);
00308
00309
00310 if (_daisy->daisy_book_data->smilHead->next == _daisy->daisy_book_data->smilTail)
00311 {
00312 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_DTB_LOADED, NULL);
00313 return -1;
00314 }
00315
00316
00317 if (_daisy->daisy_book_data->nodePos->audiofilename != NULL)
00318 {
00319 snprintf (audiopath, sizeof (audiopath), "%s%s", _daisy->daisy_book_data->path, _daisy->daisy_book_data->nodePos->audiofilename);
00320 duration_ms = audio_play (_daisy->audio_data, audiopath, _daisy->daisy_book_data->nodePos->audioStartPos, _daisy->daisy_book_data->nodePos->audioStopPos);
00321 if ((int) duration_ms == -1)
00322 return -1;
00323 _daisy->cb_daisy_audio_next (_daisy->data, duration_ms);
00324 }
00325 else
00326 {
00327 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_AUDIO_IN_SEGMENT, NULL);
00328 }
00329
00330
00331 if (_daisy->daisy_book_data->nodePos->textPassage != NULL && _daisy->daisy_book_data->nodePos->fragmentIdentifier != NULL)
00332 {
00333 _daisy->cb_daisy_id (_daisy->data, (void *) _daisy->daisy_book_data->nodePos->fragmentIdentifier);
00334 _daisy->cb_daisy_text (_daisy->data, (void *) _daisy->daisy_book_data->nodePos->textPassage);
00335 }
00336 else
00337 {
00338 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_TEXT_IN_SEGMENT, NULL);
00339 }
00340
00341 return 1;
00342 }
00343
00351 int daisy_seek (daisyplayer_t daisy, int seek_option)
00352 {
00353 struct_daisyplayer_t *_daisy = daisy;
00354 audio_state_t aState;
00355
00356 if (DEBUG_DAISYPLAYER) report ("daisy_seek\n", REP_DEBUG);
00357
00358
00359 if (pthread_mutex_trylock (&_daisy->daisy_mutex) != 0)
00360 {
00361 return -1;
00362 }
00363
00364 if (DEBUG_THREADS) report ("daisy_seek has daisy_mutex", REP_DEBUG);
00365
00366
00367 if (_daisy->daisy_book_data->smilHead->next == _daisy->daisy_book_data->smilTail)
00368 {
00369 pthread_mutex_unlock (&_daisy->daisy_mutex);
00370 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00371 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_DTB_LOADED, NULL);
00372 return -1;
00373 }
00374
00375
00376 aState = audio_get_state (_daisy->audio_data);
00377
00378 if (aState != AUDIO_STATE_STOP)
00379 {
00380 if (audio_stop (_daisy->audio_data) != 1)
00381 {
00382 pthread_mutex_unlock (&_daisy->daisy_mutex);
00383 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00384 return -1;
00385 }
00386 }
00387
00388 if (audio_get_state (_daisy->audio_data) == AUDIO_STATE_STOP)
00389 {
00390 int ret = seek (_daisy->daisy_book_data, seek_option);
00391
00392 if (ret != 1)
00393 {
00394 pthread_mutex_unlock (&_daisy->daisy_mutex);
00395
00396 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00397
00398 if (ret == 0)
00399 {
00400 return 0;
00401 }
00402 else
00403 {
00404 return -1;
00405 }
00406 }
00407 } else {
00408 pthread_mutex_unlock (&_daisy->daisy_mutex);
00409 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00410 return -1;
00411 }
00412
00413 if (daisy_play(_daisy) != 1)
00414 {
00415 pthread_mutex_unlock (&_daisy->daisy_mutex);
00416 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00417 return -1;
00418 }
00419
00420 pthread_mutex_unlock (&_daisy->daisy_mutex);
00421
00422 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00423
00424 return 1;
00425 }
00426
00435 daisy_position *daisy_get_position (daisyplayer_t daisy)
00436 {
00437 struct_daisyplayer_t *_daisy = daisy;
00438 int smilp = 0, nodep = 0;
00439 daisy_position *position = NULL;
00440
00441 if (DEBUG_DAISYPLAYER) report ("daisy_get_bookmark\n", REP_DEBUG);
00442
00443
00444 if (_daisy->daisy_book_data->smilHead->next == _daisy->daisy_book_data->smilTail)
00445 {
00446 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_DTB_LOADED, NULL);
00447 return NULL;
00448 }
00449
00450 smilp = getSmilPos(_daisy->daisy_book_data);
00451 nodep = getNodePos(_daisy->daisy_book_data);
00452
00453 if (smilp != -1 && nodep != -1)
00454 {
00455
00456 position = (daisy_position *) malloc (sizeof (daisy_position));
00457 position->smilpos = smilp;
00458 position->nodepos = nodep;
00459 } else
00460 return NULL;
00461
00462 return position;
00463 }
00464
00473 int daisy_goto_position (daisyplayer_t daisy, daisy_position *position)
00474 {
00475 struct_daisyplayer_t *_daisy = daisy;
00476 audio_state_t aState;
00477
00478 if (DEBUG_DAISYPLAYER) report ("daisy_goto_bookmark\n", REP_DEBUG);
00479
00480 pthread_mutex_lock (&_daisy->daisy_mutex);
00481 if (DEBUG_THREADS) report ("daisy_seek has daisy_mutex", REP_DEBUG);
00482
00483
00484 if (_daisy->daisy_book_data->smilHead->next == _daisy->daisy_book_data->smilTail)
00485 {
00486 pthread_mutex_unlock (&_daisy->daisy_mutex);
00487 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00488 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_DTB_LOADED, NULL);
00489 return -1;
00490 }
00491
00492
00493 aState = audio_get_state (_daisy->audio_data);
00494
00495 if (aState != AUDIO_STATE_STOP)
00496 {
00497 if (audio_stop (_daisy->audio_data) != 1)
00498 {
00499 pthread_mutex_unlock (&_daisy->daisy_mutex);
00500 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00501 return -1;
00502 }
00503 }
00504 if (audio_get_state (_daisy->audio_data) == AUDIO_STATE_STOP)
00505 {
00506 if (gotoSmilPosition (_daisy->daisy_book_data, position->smilpos) != 1 || gotoNodePosition (_daisy->daisy_book_data, position->nodepos) != 1)
00507 {
00508 pthread_mutex_unlock (&_daisy->daisy_mutex);
00509 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00510 return -1;
00511 }
00512 } else {
00513 pthread_mutex_unlock (&_daisy->daisy_mutex);
00514 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00515 return -1;
00516 }
00517
00518 if (daisy_play(_daisy) != 1)
00519 {
00520 pthread_mutex_unlock (&_daisy->daisy_mutex);
00521 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00522 return -1;
00523 }
00524
00525 pthread_mutex_unlock (&_daisy->daisy_mutex);
00526 if (DEBUG_THREADS) report ("daisy_seek released_mutex", REP_DEBUG);
00527 return 1;
00528 }
00529
00535 int daisy_stop (daisyplayer_t daisy)
00536 {
00537 int ret = 0;
00538 struct_daisyplayer_t *_daisy = daisy;
00539 if (pthread_mutex_trylock (&_daisy->daisy_mutex) != 0)
00540 return -1;
00541 if (DEBUG_DAISYPLAYER) report ("daisy_stop\n", REP_DEBUG);
00542 ret = audio_stop (_daisy->audio_data);
00543 pthread_mutex_unlock (&_daisy->daisy_mutex);
00544 return ret;
00545 }
00546
00552 int daisy_pause (daisyplayer_t daisy)
00553 {
00554 struct_daisyplayer_t *_daisy = daisy;
00555 if (DEBUG_DAISYPLAYER) report ("daisy_pause\n", REP_DEBUG);
00556 return audio_pause (_daisy->audio_data);
00557 }
00558
00566 char* daisy_get_info (daisyplayer_t daisy, int value)
00567 {
00568 char* returnvalue = NULL;
00569
00570 struct_daisyplayer_t *_daisy = daisy;
00571
00572
00573 if (_daisy->daisy_book_data->smilHead->next == _daisy->daisy_book_data->smilTail)
00574 {
00575 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_DTB_LOADED, NULL);
00576 return NULL;
00577 }
00578
00579
00580 if(value == DAISY_BOOKINFO_TITLETEXT)
00581 {
00582
00583 if(_daisy->daisy_book_data->bookInfo->titleText != NULL)
00584 {
00585
00586 returnvalue = (char *) malloc (strlen ((char *)_daisy->daisy_book_data->bookInfo->titleText)+1);
00587 strcpy (returnvalue, _daisy->daisy_book_data->bookInfo->titleText);
00588 }
00589 }
00590
00591 else if(value == DAISY_BOOKINFO_TITLEIMAGE)
00592 {
00593 if(_daisy->daisy_book_data->bookInfo->titleImage != NULL)
00594 {
00595 returnvalue = (char *) malloc (strlen ((char *)_daisy->daisy_book_data->bookInfo->titleImage)+1);
00596 strcpy (returnvalue, _daisy->daisy_book_data->bookInfo->titleImage);
00597 }
00598 }
00599
00600 else if(value == DAISY_BOOKINFO_TOTALTIME)
00601 {
00602 if(_daisy->daisy_book_data->bookInfo->totalTime != NULL)
00603 {
00604 returnvalue = (char *) malloc (strlen ((char *)_daisy->daisy_book_data->bookInfo->totalTime)+1);
00605 strcpy (returnvalue, _daisy->daisy_book_data->bookInfo->totalTime);
00606 }
00607 }
00608
00609 else return NULL;
00610 return returnvalue;
00611 }
00612
00618 int daisy_get_chapter_count (daisyplayer_t daisy)
00619 {
00620 int count = 0;
00621 struct SmilNode *tmpSmil = NULL;
00622 struct_daisyplayer_t *_daisy = daisy;
00623
00624 tmpSmil = _daisy->daisy_book_data->smilHead;
00625
00626 if (tmpSmil->next == _daisy->daisy_book_data->smilTail)
00627 {
00628 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_DTB_LOADED, NULL);
00629 return -1;
00630 }
00631
00632 tmpSmil = tmpSmil->next;
00633
00634 while (tmpSmil != _daisy->daisy_book_data->smilTail)
00635 {
00636 count++;
00637 tmpSmil = tmpSmil->next;
00638 }
00639
00640 return count;
00641 }
00642
00653 char *daisy_get_chapter_info (daisyplayer_t daisy, int num, int option)
00654 {
00655 int i = 0;
00656 char *value = NULL;
00657 struct SmilNode *tmpSmil = NULL;
00658 struct_daisyplayer_t *_daisy = daisy;
00659
00660
00661 if (num < 1)
00662 return NULL;
00663 tmpSmil = _daisy->daisy_book_data->smilHead;
00664
00665 if (tmpSmil->next == _daisy->daisy_book_data->smilTail)
00666 {
00667 _daisy->cb_daisy_error (_daisy->data, DAISY_ERROR_PLAYBACK_NO_DTB_LOADED, NULL);
00668 return NULL;
00669 }
00670
00671 for (i = 0; i<num && tmpSmil != _daisy->daisy_book_data->smilTail; i++)
00672 {
00673 tmpSmil = tmpSmil->next;
00674 }
00675 if (tmpSmil == _daisy->daisy_book_data->smilTail)
00676 return NULL;
00677
00678 switch (option)
00679 {
00680 case DAISY_CHAPTER_TITLE:
00681 value = tmpSmil->header;
00682 return value;
00683 break;
00684
00685 case DAISY_CHAPTER_WEIGHT:
00686 return NULL;
00687 break;
00688
00689 default:
00690 return NULL;
00691 }
00692 }