summaryrefslogtreecommitdiff
path: root/apps/playback.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/playback.c')
-rw-r--r--apps/playback.c211
1 files changed, 90 insertions, 121 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 65783414fe..7dad08644a 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -330,7 +330,7 @@ static struct
330static bool codec_skip_pending = false; 330static bool codec_skip_pending = false;
331static int codec_skip_status; 331static int codec_skip_status;
332static bool codec_seeking = false; /* Codec seeking ack expected? */ 332static bool codec_seeking = false; /* Codec seeking ack expected? */
333 333static unsigned int position_key = 0;
334 334
335/* Event queues */ 335/* Event queues */
336static struct event_queue audio_queue SHAREDBSS_ATTR; 336static struct event_queue audio_queue SHAREDBSS_ATTR;
@@ -353,14 +353,13 @@ static void audio_stop_playback(void);
353static void buffer_event_buffer_low_callback(void *data); 353static void buffer_event_buffer_low_callback(void *data);
354static void buffer_event_rebuffer_callback(void *data); 354static void buffer_event_rebuffer_callback(void *data);
355static void buffer_event_finished_callback(void *data); 355static void buffer_event_finished_callback(void *data);
356void audio_pcmbuf_sync_position(void);
356 357
357 358
358/**************************************/ 359/**************************************/
359 360
360/** --- audio_queue helpers --- **/ 361/** --- audio_queue helpers --- **/
361 362static void audio_queue_post(long id, intptr_t data)
362/* codec thread needs access */
363void audio_queue_post(long id, intptr_t data)
364{ 363{
365 queue_post(&audio_queue, id, data); 364 queue_post(&audio_queue, id, data);
366} 365}
@@ -805,14 +804,10 @@ static void audio_reset_buffer(void)
805 aids viewing and the summation of certain variables should add up to 804 aids viewing and the summation of certain variables should add up to
806 the location of others. */ 805 the location of others. */
807 { 806 {
808 size_t pcmbufsize;
809 const unsigned char *pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
810 logf("fbuf: %08X", (unsigned)filebuf); 807 logf("fbuf: %08X", (unsigned)filebuf);
811 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen)); 808 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
812 logf("sbuf: %08X", (unsigned)audio_scratch_memory); 809 logf("sbuf: %08X", (unsigned)audio_scratch_memory);
813 logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize)); 810 logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize));
814 logf("pcmb: %08X", (unsigned)pcmbuf);
815 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
816 } 811 }
817#endif 812#endif
818 813
@@ -978,7 +973,8 @@ static void audio_handle_track_load_status(int trackstat)
978/* Announce the end of playing the current track */ 973/* Announce the end of playing the current track */
979static void audio_playlist_track_finish(void) 974static void audio_playlist_track_finish(void)
980{ 975{
981 struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3)); 976 struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
977 struct mp3entry *id3 = valid_mp3entry(ply_id3);
982 978
983 playlist_update_resume_info(filling == STATE_ENDED ? NULL : id3); 979 playlist_update_resume_info(filling == STATE_ENDED ? NULL : id3);
984 980
@@ -1001,6 +997,8 @@ static void audio_playlist_track_change(void)
1001 if (id3) 997 if (id3)
1002 send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3); 998 send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3);
1003 999
1000 position_key = pcmbuf_get_position_key();
1001
1004 playlist_update_resume_info(id3); 1002 playlist_update_resume_info(id3);
1005} 1003}
1006 1004
@@ -1014,26 +1012,28 @@ static void audio_update_and_announce_next_track(const struct mp3entry *id3_next
1014 1012
1015/* Bring the user current mp3entry up to date and set a new offset for the 1013/* Bring the user current mp3entry up to date and set a new offset for the
1016 buffered metadata */ 1014 buffered metadata */
1017static void playing_id3_sync(struct track_info *user_info, size_t offset) 1015static void playing_id3_sync(struct track_info *user_info, off_t offset)
1018{ 1016{
1019 id3_mutex_lock(); 1017 id3_mutex_lock();
1020 1018
1021 struct mp3entry *id3 = bufgetid3(user_info->id3_hid); 1019 struct mp3entry *id3 = bufgetid3(user_info->id3_hid);
1020 struct mp3entry *playing_id3 = id3_get(PLAYING_ID3);
1022 1021
1023 if (offset == (size_t)-1) 1022 pcm_play_lock();
1023
1024 unsigned long e = playing_id3->elapsed;
1025 unsigned long o = playing_id3->offset;
1026
1027 id3_write(PLAYING_ID3, id3);
1028
1029 if (offset < 0)
1024 { 1030 {
1025 struct mp3entry *ply_id3 = id3_get(PLAYING_ID3); 1031 playing_id3->elapsed = e;
1026 size_t play_offset = ply_id3->offset; 1032 playing_id3->offset = o;
1027 long play_elapsed = ply_id3->elapsed;
1028 id3_write(PLAYING_ID3, id3);
1029 ply_id3->offset = play_offset;
1030 ply_id3->elapsed = play_elapsed;
1031 offset = 0; 1033 offset = 0;
1032 } 1034 }
1033 else 1035
1034 { 1036 pcm_play_unlock();
1035 id3_write(PLAYING_ID3, id3);
1036 }
1037 1037
1038 if (id3) 1038 if (id3)
1039 id3->offset = offset; 1039 id3->offset = offset;
@@ -1093,13 +1093,6 @@ static bool halt_decoding_track(bool stop)
1093 return retval; 1093 return retval;
1094} 1094}
1095 1095
1096/* Clear the PCM on a manual skip */
1097static void audio_clear_paused_pcm(void)
1098{
1099 if (play_status == PLAY_PAUSED && !pcmbuf_is_crossfade_active())
1100 pcmbuf_play_stop();
1101}
1102
1103/* Wait for any in-progress fade to complete */ 1096/* Wait for any in-progress fade to complete */
1104static void audio_wait_fade_complete(void) 1097static void audio_wait_fade_complete(void)
1105{ 1098{
@@ -1121,6 +1114,7 @@ static void audio_ff_rewind_end(void)
1121 { 1114 {
1122 /* Clear the buffer */ 1115 /* Clear the buffer */
1123 pcmbuf_play_stop(); 1116 pcmbuf_play_stop();
1117 audio_pcmbuf_sync_position();
1124 } 1118 }
1125 1119
1126 if (play_status != PLAY_PAUSED) 1120 if (play_status != PLAY_PAUSED)
@@ -2063,7 +2057,7 @@ static void audio_on_handle_finished(int hid)
2063 2057
2064/* Called to make an outstanding track skip the current track and to send the 2058/* Called to make an outstanding track skip the current track and to send the
2065 transition events */ 2059 transition events */
2066static void audio_finalise_track_change(bool delayed) 2060static void audio_finalise_track_change(void)
2067{ 2061{
2068 switch (skip_pending) 2062 switch (skip_pending)
2069 { 2063 {
@@ -2117,15 +2111,6 @@ static void audio_finalise_track_change(bool delayed)
2117 2111
2118 id3_write(PLAYING_ID3, track_id3); 2112 id3_write(PLAYING_ID3, track_id3);
2119 2113
2120 if (delayed)
2121 {
2122 /* Delayed skip where codec is ahead of user's current track */
2123 struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
2124 struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
2125 ply_id3->elapsed = ci_id3->elapsed;
2126 ply_id3->offset = ci_id3->offset;
2127 }
2128
2129 /* The skip is technically over */ 2114 /* The skip is technically over */
2130 skip_pending = TRACK_SKIP_NONE; 2115 skip_pending = TRACK_SKIP_NONE;
2131 2116
@@ -2141,25 +2126,25 @@ static void audio_finalise_track_change(bool delayed)
2141} 2126}
2142 2127
2143/* Actually begin a transition and take care of the codec change - may complete 2128/* Actually begin a transition and take care of the codec change - may complete
2144 it now or ask pcmbuf for notification depending on the type and what pcmbuf 2129 it now or ask pcmbuf for notification depending on the type */
2145 has to say */ 2130static void audio_begin_track_change(enum pcm_track_change_type type,
2146static void audio_begin_track_change(bool auto_skip, int trackstat) 2131 int trackstat)
2147{ 2132{
2148 /* Even if the new track is bad, the old track must be finished off */ 2133 /* Even if the new track is bad, the old track must be finished off */
2149 bool finalised = pcmbuf_start_track_change(auto_skip); 2134 pcmbuf_start_track_change(type);
2135
2136 bool auto_skip = type != TRACK_CHANGE_MANUAL;
2150 2137
2151 if (finalised) 2138 if (!auto_skip)
2152 { 2139 {
2153 /* pcmbuf says that the transition happens now - complete it */ 2140 /* Manual track change happens now */
2154 audio_finalise_track_change(false); 2141 audio_finalise_track_change();
2142 pcmbuf_sync_position_update();
2155 2143
2156 if (play_status == PLAY_STOPPED) 2144 if (play_status == PLAY_STOPPED)
2157 return; /* Stopped us */ 2145 return; /* Stopped us */
2158 } 2146 }
2159 2147
2160 if (!auto_skip)
2161 audio_clear_paused_pcm();
2162
2163 if (trackstat >= LOAD_TRACK_OK) 2148 if (trackstat >= LOAD_TRACK_OK)
2164 { 2149 {
2165 struct track_info *info = track_list_current(0); 2150 struct track_info *info = track_list_current(0);
@@ -2170,7 +2155,7 @@ static void audio_begin_track_change(bool auto_skip, int trackstat)
2170 /* Everything needed for the codec is ready - start it */ 2155 /* Everything needed for the codec is ready - start it */
2171 if (audio_start_codec(auto_skip)) 2156 if (audio_start_codec(auto_skip))
2172 { 2157 {
2173 if (finalised) 2158 if (!auto_skip)
2174 playing_id3_sync(info, -1); 2159 playing_id3_sync(info, -1);
2175 return; 2160 return;
2176 } 2161 }
@@ -2186,7 +2171,7 @@ static void audio_monitor_end_of_playlist(void)
2186{ 2171{
2187 skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST; 2172 skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
2188 filling = STATE_ENDING; 2173 filling = STATE_ENDING;
2189 pcmbuf_monitor_track_change(true); 2174 pcmbuf_start_track_change(TRACK_CHANGE_END_OF_DATA);
2190} 2175}
2191 2176
2192/* Codec has completed decoding the track 2177/* Codec has completed decoding the track
@@ -2221,14 +2206,6 @@ static void audio_on_codec_complete(int status)
2221 2206
2222 codec_skip_pending = false; 2207 codec_skip_pending = false;
2223 2208
2224#ifdef AB_REPEAT_ENABLE
2225 if (status >= 0)
2226 {
2227 /* Normal automatic skip */
2228 ab_end_of_track_report();
2229 }
2230#endif
2231
2232 int trackstat = LOAD_TRACK_OK; 2209 int trackstat = LOAD_TRACK_OK;
2233 2210
2234 automatic_skip = true; 2211 automatic_skip = true;
@@ -2263,7 +2240,7 @@ static void audio_on_codec_complete(int status)
2263 { 2240 {
2264 /* Continue filling after this track */ 2241 /* Continue filling after this track */
2265 audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1); 2242 audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1);
2266 audio_begin_track_change(true, trackstat); 2243 audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
2267 return; 2244 return;
2268 } 2245 }
2269 /* else rebuffer at this track; status applies to the track we 2246 /* else rebuffer at this track; status applies to the track we
@@ -2299,7 +2276,7 @@ static void audio_on_codec_complete(int status)
2299 } 2276 }
2300 } 2277 }
2301 2278
2302 audio_begin_track_change(true, trackstat); 2279 audio_begin_track_change(TRACK_CHANGE_AUTO, trackstat);
2303} 2280}
2304 2281
2305/* Called when codec completes seek operation 2282/* Called when codec completes seek operation
@@ -2316,7 +2293,7 @@ static void audio_on_codec_seek_complete(void)
2316static void audio_on_track_changed(void) 2293static void audio_on_track_changed(void)
2317{ 2294{
2318 /* Finish whatever is pending so that the WPS is in sync */ 2295 /* Finish whatever is pending so that the WPS is in sync */
2319 audio_finalise_track_change(true); 2296 audio_finalise_track_change();
2320 2297
2321 if (codec_skip_pending) 2298 if (codec_skip_pending)
2322 { 2299 {
@@ -2367,8 +2344,7 @@ static void audio_start_playback(size_t offset, unsigned int flags)
2367 track_list_clear(TRACK_LIST_CLEAR_ALL); 2344 track_list_clear(TRACK_LIST_CLEAR_ALL);
2368 2345
2369 /* Indicate manual track change */ 2346 /* Indicate manual track change */
2370 pcmbuf_start_track_change(false); 2347 pcmbuf_start_track_change(TRACK_CHANGE_MANUAL);
2371 audio_clear_paused_pcm();
2372 wipe_track_metadata(true); 2348 wipe_track_metadata(true);
2373 } 2349 }
2374 2350
@@ -2398,6 +2374,10 @@ static void audio_start_playback(size_t offset, unsigned int flags)
2398 play_status = PLAY_PLAYING; 2374 play_status = PLAY_PLAYING;
2399 } 2375 }
2400 2376
2377 /* Codec's position should be available as soon as it knows it */
2378 position_key = pcmbuf_get_position_key();
2379 pcmbuf_sync_position_update();
2380
2401 /* Start fill from beginning of playlist */ 2381 /* Start fill from beginning of playlist */
2402 playlist_peek_offset = -1; 2382 playlist_peek_offset = -1;
2403 buf_set_base_handle(-1); 2383 buf_set_base_handle(-1);
@@ -2592,7 +2572,7 @@ static void audio_on_skip(void)
2592 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1); 2572 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1);
2593 } 2573 }
2594 2574
2595 audio_begin_track_change(false, trackstat); 2575 audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat);
2596} 2576}
2597 2577
2598/* Skip to the next/previous directory 2578/* Skip to the next/previous directory
@@ -2638,7 +2618,7 @@ static void audio_on_dir_skip(int direction)
2638 return; 2618 return;
2639 } 2619 }
2640 2620
2641 audio_begin_track_change(false, trackstat); 2621 audio_begin_track_change(TRACK_CHANGE_MANUAL, trackstat);
2642} 2622}
2643 2623
2644/* Enter seek mode in order to start a seek 2624/* Enter seek mode in order to start a seek
@@ -2689,11 +2669,6 @@ static void audio_on_ff_rewind(long time)
2689 if (time == 0) 2669 if (time == 0)
2690 send_event(PLAYBACK_EVENT_TRACK_FINISH, id3); 2670 send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
2691 2671
2692 /* Prevent user codec time update - coerce to something that is
2693 innocuous concerning lookaheads */
2694 if (pending == TRACK_SKIP_NONE)
2695 skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
2696
2697 id3->elapsed = time; 2672 id3->elapsed = time;
2698 queue_reply(&audio_queue, 1); 2673 queue_reply(&audio_queue, 1);
2699 2674
@@ -2703,6 +2678,9 @@ static void audio_on_ff_rewind(long time)
2703 halt that will reset it */ 2678 halt that will reset it */
2704 codec_seeking = true; 2679 codec_seeking = true;
2705 2680
2681 /* If in transition, key will have changed - sync to it */
2682 position_key = pcmbuf_get_position_key();
2683
2706 if (pending == TRACK_SKIP_AUTO) 2684 if (pending == TRACK_SKIP_AUTO)
2707 { 2685 {
2708 if (!track_list_advance_current(-1)) 2686 if (!track_list_advance_current(-1))
@@ -3124,75 +3102,66 @@ static void buffer_event_finished_callback(void *data)
3124 3102
3125/** -- Codec callbacks -- **/ 3103/** -- Codec callbacks -- **/
3126 3104
3127/* Update elapsed times with latency-adjusted values */ 3105/* Update elapsed time for next PCM insert */
3128void audio_codec_update_elapsed(unsigned long value) 3106void audio_codec_update_elapsed(unsigned long elapsed)
3129{ 3107{
3130#ifdef AB_REPEAT_ENABLE 3108#ifdef AB_REPEAT_ENABLE
3131 ab_position_report(value); 3109 ab_position_report(elapsed);
3132#endif 3110#endif
3133 3111 /* Save in codec's id3 where it is used at next pcm insert */
3134 unsigned long latency = pcmbuf_get_latency(); 3112 id3_get(CODEC_ID3)->elapsed = elapsed;
3135
3136 if (LIKELY(value >= latency))
3137 {
3138 unsigned long elapsed = value - latency;
3139
3140 if (elapsed > value || elapsed < value - 2)
3141 value = elapsed;
3142 }
3143 else
3144 {
3145 value = 0;
3146 }
3147
3148 /* Track codec: used later when updating the playing at the user
3149 transition */
3150 id3_get(CODEC_ID3)->elapsed = value;
3151
3152 /* If a skip is pending, the PCM buffer is updating the time on the
3153 previous song */
3154 if (LIKELY(skip_pending == TRACK_SKIP_NONE))
3155 id3_get(PLAYING_ID3)->elapsed = value;
3156} 3113}
3157 3114
3158/* Update offsets with latency-adjusted values */ 3115/* Update offset for next PCM insert */
3159void audio_codec_update_offset(size_t value) 3116void audio_codec_update_offset(size_t offset)
3160{ 3117{
3161 struct mp3entry *ci_id3 = id3_get(CODEC_ID3); 3118 /* Save in codec's id3 where it is used at next pcm insert */
3162 unsigned long latency = pcmbuf_get_latency() * ci_id3->bitrate / 8; 3119 id3_get(CODEC_ID3)->offset = offset;
3120}
3163 3121
3164 if (LIKELY(value >= latency)) 3122/* Codec has finished running */
3165 { 3123void audio_codec_complete(int status)
3166 value -= latency; 3124{
3167 } 3125#ifdef AB_REPEAT_ENABLE
3168 else 3126 if (status >= CODEC_OK)
3169 { 3127 {
3170 value = 0; 3128 /* Normal automatic skip */
3129 ab_end_of_track_report();
3171 } 3130 }
3131#endif
3172 3132
3173 /* Track codec: used later when updating the playing id3 at the user 3133 LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
3174 transition */ 3134 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
3175 ci_id3->offset = value; 3135}
3176 3136
3177 /* If a skip is pending, the PCM buffer is updating the time on the 3137/* Codec has finished seeking */
3178 previous song */ 3138void audio_codec_seek_complete(void)
3179 if (LIKELY(skip_pending == TRACK_SKIP_NONE)) 3139{
3180 id3_get(PLAYING_ID3)->offset = value; 3140 LOGFQUEUE("codec > audio Q_AUDIO_CODEC_SEEK_COMPLETE");
3141 audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0);
3181} 3142}
3182 3143
3183 3144
3184/** --- Pcmbuf callbacks --- **/ 3145/** --- Pcmbuf callbacks --- **/
3185 3146
3186/* Between the codec and PCM track change, we need to keep updating the 3147/* Update the elapsed and offset from the information cached during the
3187 * "elapsed" value of the previous (to the codec, but current to the 3148 PCM buffer insert */
3188 * user/PCM/WPS) track, so that the progressbar reaches the end. */ 3149void audio_pcmbuf_position_callback(unsigned long elapsed, off_t offset,
3189void audio_pcmbuf_position_callback(unsigned int time) 3150 unsigned int key)
3190{ 3151{
3191 struct mp3entry *id3 = id3_get(PLAYING_ID3); 3152 if (key == position_key)
3192 3153 {
3193 time += id3->elapsed; 3154 struct mp3entry *id3 = id3_get(PLAYING_ID3);
3155 id3->elapsed = elapsed;
3156 id3->offset = offset;
3157 }
3158}
3194 3159
3195 id3->elapsed = MIN(time, id3->length); 3160/* Synchronize position info to the codec's */
3161void audio_pcmbuf_sync_position(void)
3162{
3163 audio_pcmbuf_position_callback(ci.id3->elapsed, ci.id3->offset,
3164 pcmbuf_get_position_key());
3196} 3165}
3197 3166
3198/* Post message from pcmbuf that the end of the previous track has just 3167/* Post message from pcmbuf that the end of the previous track has just