diff options
Diffstat (limited to 'apps/pcmbuf.c')
-rw-r--r-- | apps/pcmbuf.c | 82 |
1 files changed, 53 insertions, 29 deletions
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index 3ec0c114da..3b461ecdc1 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <kernel.h> | 25 | #include <kernel.h> |
26 | #include "pcmbuf.h" | 26 | #include "pcmbuf.h" |
27 | #include "pcm.h" | 27 | #include "pcm.h" |
28 | #include "playback.h" | ||
28 | 29 | ||
29 | /* Define LOGF_ENABLE to enable logf output in this file */ | 30 | /* Define LOGF_ENABLE to enable logf output in this file */ |
30 | /*#define LOGF_ENABLE*/ | 31 | /*#define LOGF_ENABLE*/ |
@@ -62,8 +63,8 @@ struct pcmbufdesc | |||
62 | void *addr; | 63 | void *addr; |
63 | size_t size; | 64 | size_t size; |
64 | struct pcmbufdesc* link; | 65 | struct pcmbufdesc* link; |
65 | /* Call this when the buffer has been played */ | 66 | /* true if last chunk in the track */ |
66 | void (*callback)(void); | 67 | bool end_of_track; |
67 | }; | 68 | }; |
68 | 69 | ||
69 | #define PCMBUF_DESCS(bufsize) \ | 70 | #define PCMBUF_DESCS(bufsize) \ |
@@ -82,8 +83,8 @@ static size_t audiobuffer_fillpos IDATA_ATTR; | |||
82 | static char *fadebuf IDATA_ATTR; | 83 | static char *fadebuf IDATA_ATTR; |
83 | static char *voicebuf IDATA_ATTR; | 84 | static char *voicebuf IDATA_ATTR; |
84 | 85 | ||
85 | static void (*pcmbuf_event_handler)(void) IDATA_ATTR; | 86 | static bool end_of_track IDATA_ATTR; |
86 | static void (*position_callback)(size_t size) IDATA_ATTR; | 87 | bool track_transition IDATA_ATTR; |
87 | 88 | ||
88 | /* Crossfade related state */ | 89 | /* Crossfade related state */ |
89 | static bool crossfade_enabled; | 90 | static bool crossfade_enabled; |
@@ -134,25 +135,57 @@ static bool prepare_insert(size_t length); | |||
134 | static void pcmbuf_under_watermark(bool under); | 135 | static void pcmbuf_under_watermark(bool under); |
135 | static bool pcmbuf_flush_fillpos(void); | 136 | static bool pcmbuf_flush_fillpos(void); |
136 | 137 | ||
137 | #define CALL_IF_EXISTS(function, args...) if (function) function(args) | 138 | |
138 | /* This function has 3 major logical parts (separated by brackets both for | 139 | /* Track change functions */ |
140 | |||
141 | /* The codec is moving on to the next track, but the current track is | ||
142 | * still playing. Set flags to make sure the elapsed time of the current | ||
143 | * track is updated properly, and mark the currently written chunk as the | ||
144 | * last one in the track. */ | ||
145 | void pcmbuf_start_track_change(void) | ||
146 | { | ||
147 | /* we're starting a track transition */ | ||
148 | track_transition = true; | ||
149 | |||
150 | /* mark the last chunk in the track */ | ||
151 | end_of_track = true; | ||
152 | } | ||
153 | |||
154 | /* Called when the last chunk in the track has been played */ | ||
155 | static void pcmbuf_finish_track_change(void) | ||
156 | { | ||
157 | /* not in a track transition anymore */ | ||
158 | if(track_transition){logf("pcmbuf: (finish change) track transition false");} | ||
159 | track_transition = false; | ||
160 | |||
161 | /* notify playback that the track has just finished */ | ||
162 | audio_post_track_change(); | ||
163 | } | ||
164 | |||
165 | |||
166 | /** PCM driver callback | ||
167 | * This function has 3 major logical parts (separated by brackets both for | ||
139 | * readability and variable scoping). The first part performs the | 168 | * readability and variable scoping). The first part performs the |
140 | * operations related to finishing off the last buffer we fed to the DMA. | 169 | * operations related to finishing off the last buffer we fed to the DMA. |
141 | * The second part detects the end of playlist condition when the pcm | 170 | * The second part detects the end of playlist condition when the pcm |
142 | * buffer is empty except for uncommitted samples. Then they are committed. | 171 | * buffer is empty except for uncommitted samples. Then they are committed. |
143 | * The third part performs the operations involved in sending a new buffer | 172 | * The third part performs the operations involved in sending a new buffer |
144 | * to the DMA. */ | 173 | * to the DMA. */ |
145 | static void pcmbuf_callback(unsigned char** start, size_t* size) ICODE_ATTR; | 174 | static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) ICODE_ATTR; |
146 | static void pcmbuf_callback(unsigned char** start, size_t* size) | 175 | static void pcmbuf_pcm_callback(unsigned char** start, size_t* size) |
147 | { | 176 | { |
148 | { | 177 | { |
149 | struct pcmbufdesc *pcmbuf_current = pcmbuf_read; | 178 | struct pcmbufdesc *pcmbuf_current = pcmbuf_read; |
150 | /* Take the finished buffer out of circulation */ | 179 | /* Take the finished buffer out of circulation */ |
151 | pcmbuf_read = pcmbuf_current->link; | 180 | pcmbuf_read = pcmbuf_current->link; |
152 | 181 | ||
153 | /* The buffer is finished, call the callback functions */ | 182 | /* if during a track transition, update the elapsed time */ |
154 | CALL_IF_EXISTS(position_callback, last_chunksize); | 183 | if (track_transition) |
155 | CALL_IF_EXISTS(pcmbuf_current->callback); | 184 | audio_pcmbuf_position_callback(last_chunksize); |
185 | |||
186 | /* if last buffer in the track, let the audio thread know */ | ||
187 | if (pcmbuf_current->end_of_track) | ||
188 | pcmbuf_finish_track_change(); | ||
156 | 189 | ||
157 | /* Put the finished buffer back into circulation */ | 190 | /* Put the finished buffer back into circulation */ |
158 | pcmbuf_write_end->link = pcmbuf_current; | 191 | pcmbuf_write_end->link = pcmbuf_current; |
@@ -170,7 +203,7 @@ static void pcmbuf_callback(unsigned char** start, size_t* size) | |||
170 | /* Commit last samples at end of playlist */ | 203 | /* Commit last samples at end of playlist */ |
171 | if (audiobuffer_fillpos && !pcmbuf_read) | 204 | if (audiobuffer_fillpos && !pcmbuf_read) |
172 | { | 205 | { |
173 | logf("pcmbuf callback: commit last samples"); | 206 | logf("pcmbuf_pcm_callback: commit last samples"); |
174 | pcmbuf_flush_fillpos(); | 207 | pcmbuf_flush_fillpos(); |
175 | } | 208 | } |
176 | } | 209 | } |
@@ -195,16 +228,12 @@ static void pcmbuf_callback(unsigned char** start, size_t* size) | |||
195 | last_chunksize = 0; | 228 | last_chunksize = 0; |
196 | *realsize = 0; | 229 | *realsize = 0; |
197 | *realstart = NULL; | 230 | *realstart = NULL; |
198 | CALL_IF_EXISTS(pcmbuf_event_handler); | 231 | if (end_of_track) |
232 | pcmbuf_finish_track_change(); | ||
199 | } | 233 | } |
200 | } | 234 | } |
201 | } | 235 | } |
202 | 236 | ||
203 | void pcmbuf_set_position_callback(void (*callback)(size_t size)) | ||
204 | { | ||
205 | position_callback = callback; | ||
206 | } | ||
207 | |||
208 | static void pcmbuf_set_watermark_bytes(void) | 237 | static void pcmbuf_set_watermark_bytes(void) |
209 | { | 238 | { |
210 | pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ? | 239 | pcmbuf_watermark = (crossfade_enabled && pcmbuf_size) ? |
@@ -225,10 +254,9 @@ static inline void pcmbuf_add_chunk(void) | |||
225 | /* Fill in the values in the new buffer chunk */ | 254 | /* Fill in the values in the new buffer chunk */ |
226 | pcmbuf_current->addr = &audiobuffer[audiobuffer_pos]; | 255 | pcmbuf_current->addr = &audiobuffer[audiobuffer_pos]; |
227 | pcmbuf_current->size = size; | 256 | pcmbuf_current->size = size; |
228 | pcmbuf_current->callback = pcmbuf_event_handler; | 257 | pcmbuf_current->end_of_track = end_of_track; |
229 | pcmbuf_current->link = NULL; | 258 | pcmbuf_current->link = NULL; |
230 | /* This is single use only */ | 259 | end_of_track = false; /* This is single use only */ |
231 | pcmbuf_event_handler = NULL; | ||
232 | if (pcmbuf_read != NULL) { | 260 | if (pcmbuf_read != NULL) { |
233 | if (pcmbuf_flush) | 261 | if (pcmbuf_flush) |
234 | { | 262 | { |
@@ -320,11 +348,6 @@ static void pcmbuf_under_watermark(bool under) | |||
320 | } | 348 | } |
321 | } | 349 | } |
322 | 350 | ||
323 | void pcmbuf_set_event_handler(void (*event_handler)(void)) | ||
324 | { | ||
325 | pcmbuf_event_handler = event_handler; | ||
326 | } | ||
327 | |||
328 | unsigned int pcmbuf_get_latency(void) | 351 | unsigned int pcmbuf_get_latency(void) |
329 | { | 352 | { |
330 | /* Be careful how this calculation is rearranged, it's easy to overflow */ | 353 | /* Be careful how this calculation is rearranged, it's easy to overflow */ |
@@ -493,8 +516,9 @@ size_t pcmbuf_init(unsigned char *bufend) | |||
493 | 516 | ||
494 | pcmbuf_init_pcmbuffers(); | 517 | pcmbuf_init_pcmbuffers(); |
495 | 518 | ||
496 | position_callback = NULL; | 519 | if(track_transition){logf("pcmbuf: (init) track transition false");} |
497 | pcmbuf_event_handler = NULL; | 520 | end_of_track = false; |
521 | track_transition = false; | ||
498 | 522 | ||
499 | pcmbuf_crossfade_enable_finished(); | 523 | pcmbuf_crossfade_enable_finished(); |
500 | 524 | ||
@@ -531,7 +555,7 @@ void pcmbuf_play_start(void) | |||
531 | { | 555 | { |
532 | last_chunksize = pcmbuf_read->size; | 556 | last_chunksize = pcmbuf_read->size; |
533 | pcmbuf_unplayed_bytes -= last_chunksize; | 557 | pcmbuf_unplayed_bytes -= last_chunksize; |
534 | pcm_play_data(pcmbuf_callback, | 558 | pcm_play_data(pcmbuf_pcm_callback, |
535 | (unsigned char *)pcmbuf_read->addr, last_chunksize); | 559 | (unsigned char *)pcmbuf_read->addr, last_chunksize); |
536 | } | 560 | } |
537 | } | 561 | } |