diff --git a/apps/buffering.c b/apps/buffering.c index 99a4a3b..13fbcbc 100644 --- a/apps/buffering.c +++ b/apps/buffering.c @@ -50,6 +50,7 @@ #include "buffer.h" #include "bmp.h" #include "events.h" +#include "metadata.h" #ifdef SIMULATOR #define ata_disk_is_active() 1 @@ -586,6 +587,18 @@ static bool buffer_handle(int handle_id) trigger_cpu_boost(); + if (h->type == TYPE_ID3) + { + get_metadata((struct mp3entry *)(buffer + h->data), h->fd, h->path); + close(h->fd); + h->fd = -1; + h->filerem = 0; + h->available = sizeof(struct mp3entry); + h->widx += sizeof(struct mp3entry); + send_event(EVENT_HANDLE_FINISHED, &h->id); + return true; + } + while (h->filerem > 0) { /* max amount to copy */ @@ -871,7 +884,31 @@ management functions for all the actual handle management work. */ int bufopen(const char *file, size_t offset, enum data_type type) { - size_t adjusted_offset = offset; + if (type == TYPE_ID3) + { + /* ID3 case: allocate space, init the handle and return. */ + + struct memory_handle *h = add_handle(sizeof(struct mp3entry), false, true); + if (!h) + return ERR_BUFFER_FULL; + + h->fd = -1; + h->filesize = sizeof(struct mp3entry); + h->filerem = sizeof(struct mp3entry); + h->offset = 0; + h->data = buf_widx; + h->ridx = buf_widx; + h->widx = buf_widx; + h->available = 0; + h->type = type; + strncpy(h->path, file, MAX_PATH); + + buf_widx += sizeof(struct mp3entry); /* safe because the handle + can't wrap */ + return h->id; + } + + /* Other cases: there is a little more work. */ int fd = open(file, O_RDONLY); if (fd < 0) @@ -880,6 +917,7 @@ int bufopen(const char *file, size_t offset, enum data_type type) size_t size = filesize(fd); bool can_wrap = type==TYPE_PACKET_AUDIO || type==TYPE_CODEC; + size_t adjusted_offset = offset; if (adjusted_offset > size) adjusted_offset = 0; diff --git a/apps/playback.c b/apps/playback.c index 4d00eda..e8f8ba4 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -131,6 +131,7 @@ enum { Q_AUDIO_DIR_SKIP, Q_AUDIO_POSTINIT, Q_AUDIO_FILL_BUFFER, + Q_AUDIO_FINISH_LOAD, Q_CODEC_REQUEST_COMPLETE, Q_CODEC_REQUEST_FAILED, @@ -249,6 +250,9 @@ static bool new_playlist = false; /* Are we starting a new playlist? (A) */ static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */ static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */ +static bool start_play_g = false; /* Used by audio_load_track to notify + audio_finish_load_track about start_play */ + /* Set to true if the codec thread should send an audio stop request * (typically because the end of the playlist has been reached). */ @@ -607,6 +611,9 @@ struct mp3entry* audio_next_track(void) next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK; + if (tracks[next_idx].id3_hid >= 0) + return bufgetid3(tracks[next_idx].id3_hid); + if (next_idx == track_widx) { /* The next track hasn't been buffered yet, so we return the static @@ -614,10 +621,7 @@ struct mp3entry* audio_next_track(void) return &lasttrack_id3; } - if (tracks[next_idx].id3_hid < 0) - return NULL; - else - return bufgetid3(tracks[next_idx].id3_hid); + return NULL; } bool audio_has_changed_track(void) @@ -1409,7 +1413,15 @@ static void buffering_handle_rebuffer_callback(void *data) static void buffering_handle_finished_callback(int *data) { logf("handle %d finished buffering", *data); - strip_tags(*data); + + if (*data == tracks[track_widx].id3_hid) { + DEBUGF("ID3 handle n° %d ready\n", *data); + LOGFQUEUE("audio >| audio Q_AUDIO_FINISH_LOAD"); + queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0); + } else { + DEBUGF("handle n° %d ready\n", *data); + strip_tags(*data); + } } @@ -1442,12 +1454,10 @@ long audio_filebufused(void) static void audio_update_trackinfo(void) { /* Load the curent track's metadata into curtrack_id3 */ - CUR_TI->taginfo_ready = (CUR_TI->id3_hid >= 0); if (CUR_TI->id3_hid >= 0) copy_mp3entry(&curtrack_id3, bufgetid3(CUR_TI->id3_hid)); int next_idx = (track_ridx + 1) & MAX_TRACK_MASK; - tracks[next_idx].taginfo_ready = (tracks[next_idx].id3_hid >= 0); /* Reset current position */ curtrack_id3.elapsed = 0; @@ -1561,10 +1571,11 @@ static bool audio_loadcodec(bool start_play) static bool audio_load_track(int offset, bool start_play) { const char *trackname; - char msgbuf[80]; int fd = -1; int file_offset = 0; - struct mp3entry id3; + struct mp3entry *id3; + + start_play_g = start_play; /* will be read by audio_finish_load_track */ /* Stop buffer filling if there is no free track entries. Don't fill up the last track entry (we wan't to store next track @@ -1621,46 +1632,51 @@ static bool audio_load_track(int offset, bool start_play) /* Get track metadata if we don't already have it. */ if (tracks[track_widx].id3_hid < 0) { - if (get_metadata(&id3, fd, trackname)) - { - id3.index = playlist_get_display_index() + last_peek_offset - 1; + /* send_event(PLAYBACK_EVENT_TRACK_BUFFER, &id3); */ - send_event(PLAYBACK_EVENT_TRACK_BUFFER, &id3); - - tracks[track_widx].id3_hid = - bufalloc(&id3, sizeof(struct mp3entry), TYPE_ID3); + tracks[track_widx].id3_hid = bufopen(trackname, 0, TYPE_ID3); if (tracks[track_widx].id3_hid < 0) { last_peek_offset--; close(fd); - copy_mp3entry(&lasttrack_id3, &id3); + /* copy_mp3entry(&lasttrack_id3, &id3); */ goto buffer_full; } - if (track_widx == track_ridx) - copy_mp3entry(&curtrack_id3, &id3); + if (start_play) + buf_request_buffer_handle(tracks[track_widx].id3_hid); + + if (track_widx == track_ridx) { + copy_mp3entry(&curtrack_id3, bufgetid3(tracks[track_widx].id3_hid)); + curtrack_id3.offset = offset; + } if (start_play) { track_changed = true; playlist_update_resume_info(audio_current_track()); } - } - else - { - logf("mde:%s!",trackname); - - /* Skip invalid entry from playlist. */ - playlist_skip_entry(NULL, last_peek_offset); - close(fd); - goto peek_again; - } } close(fd); + return true; + +buffer_full: + logf("buffer is full for now"); + filling = STATE_FULL; + return false; +} + +static bool audio_finish_load_track(void) +{ + char msgbuf[80]; + int file_offset = 0; + bool start_play = start_play_g; + int offset = 0; + #if 0 if (cuesheet_is_enabled() && tracks[track_widx].id3.cuesheet_type == 1) { @@ -1678,6 +1694,9 @@ static bool audio_load_track(int offset, bool start_play) } #endif + if (tracks[track_widx].id3_hid < 0) + return false; + struct mp3entry *track_id3; if (track_widx == track_ridx) @@ -1700,20 +1719,21 @@ static bool audio_load_track(int offset, bool start_play) if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL) { /* No space for codec on buffer, not an error */ - goto buffer_full; + return false; } /* This is an error condition, either no codec was found, or reading * the codec file failed part way through, either way, skip the track */ - snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname); + snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", track_id3->path); /* We should not use gui_syncplash from audio thread! */ gui_syncsplash(HZ*2, msgbuf); /* Skip invalid entry from playlist. */ playlist_skip_entry(NULL, last_peek_offset); - goto peek_again; + return false; } track_id3->elapsed = 0; + offset = track_id3->offset; enum data_type type = TYPE_PACKET_AUDIO; @@ -1755,7 +1775,7 @@ static bool audio_load_track(int offset, bool start_play) break; } - logf("alt:%s", trackname); + logf("alt:%s", track_id3->path); if (file_offset > AUDIO_REBUFFER_GUESS_SIZE) file_offset -= AUDIO_REBUFFER_GUESS_SIZE; @@ -1764,10 +1784,10 @@ static bool audio_load_track(int offset, bool start_play) else file_offset = 0; - tracks[track_widx].audio_hid = bufopen(trackname, file_offset, type); + tracks[track_widx].audio_hid = bufopen(track_id3->path, file_offset, type); if (tracks[track_widx].audio_hid < 0) - goto buffer_full; + return false; /* All required data is now available for the codec. */ tracks[track_widx].taginfo_ready = true; @@ -1780,12 +1800,11 @@ static bool audio_load_track(int offset, bool start_play) track_widx = (track_widx + 1) & MAX_TRACK_MASK; - return true; + /* load next track */ + LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER"); + queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); -buffer_full: - logf("buffer is full for now"); - filling = STATE_FULL; - return false; + return true; } static void audio_fill_file_buffer(bool start_play, size_t offset) @@ -1815,6 +1834,7 @@ static void audio_fill_file_buffer(bool start_play, size_t offset) playlist_update_resume_info(audio_current_track()); continue_buffering = audio_load_track(offset, start_play); +#if 0 do { sleep(1); if (!queue_empty(&audio_queue)) @@ -1822,6 +1842,7 @@ static void audio_fill_file_buffer(bool start_play, size_t offset) break; continue_buffering = audio_load_track(0, false); } while (continue_buffering); +#endif if (!had_next_track && audio_next_track()) track_changed = true; @@ -2196,22 +2217,22 @@ static void audio_finalise_track_change(void) { wps_offset = 0; automatic_skip = false; - } - /* Invalidate prevtrack_id3 */ - prevtrack_id3.path[0] = 0; + /* Invalidate prevtrack_id3 */ + prevtrack_id3.path[0] = 0; - if (prev_ti && prev_ti->audio_hid < 0) - { - /* No audio left so we clear all the track info. */ - clear_track_info(prev_ti); - } + if (prev_ti && prev_ti->audio_hid < 0) + { + /* No audio left so we clear all the track info. */ + clear_track_info(prev_ti); + } - if (prev_ti && prev_ti->id3_hid >= 0) - { - /* Reset the elapsed time to force the progressbar to be empty if - the user skips back to this track */ - bufgetid3(prev_ti->id3_hid)->elapsed = 0; + if (prev_ti && prev_ti->id3_hid >= 0) + { + /* Reset the elapsed time to force the progressbar to be empty if + the user skips back to this track */ + bufgetid3(prev_ti->id3_hid)->elapsed = 0; + } } send_event(PLAYBACK_EVENT_TRACK_CHANGE, &curtrack_id3); @@ -2298,6 +2319,11 @@ static void audio_thread(void) audio_fill_file_buffer(false, 0); break; + case Q_AUDIO_FINISH_LOAD: + LOGFQUEUE("audio < Q_AUDIO_FINISH_LOAD"); + audio_finish_load_track(); + break; + case Q_AUDIO_PLAY: LOGFQUEUE("audio < Q_AUDIO_PLAY"); if (playing && ev.data <= 0) @@ -2397,8 +2423,8 @@ static void audio_thread(void) case SYS_TIMEOUT: LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT"); - if (filling == STATE_FILLING) - audio_fill_file_buffer(false, 0); + /* if (filling == STATE_FILLING) + audio_fill_file_buffer(false, 0); */ break; default: