diff options
Diffstat (limited to 'firmware/pcm.c')
-rw-r--r-- | firmware/pcm.c | 195 |
1 files changed, 92 insertions, 103 deletions
diff --git a/firmware/pcm.c b/firmware/pcm.c index 94b0d6eefb..6bf0e12c8d 100644 --- a/firmware/pcm.c +++ b/firmware/pcm.c | |||
@@ -86,7 +86,7 @@ | |||
86 | static bool pcm_is_ready = false; | 86 | static bool pcm_is_ready = false; |
87 | 87 | ||
88 | /* The registered callback function to ask for more mp3 data */ | 88 | /* The registered callback function to ask for more mp3 data */ |
89 | static volatile pcm_play_callback_type | 89 | volatile pcm_play_callback_type |
90 | pcm_callback_for_more SHAREDBSS_ATTR = NULL; | 90 | pcm_callback_for_more SHAREDBSS_ATTR = NULL; |
91 | /* The registered callback function to inform of DMA status */ | 91 | /* The registered callback function to inform of DMA status */ |
92 | volatile pcm_status_callback_type | 92 | volatile pcm_status_callback_type |
@@ -102,9 +102,89 @@ unsigned long pcm_sampr SHAREDBSS_ATTR = HW_SAMPR_DEFAULT; | |||
102 | /* samplerate frequency selection index */ | 102 | /* samplerate frequency selection index */ |
103 | int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT; | 103 | int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT; |
104 | 104 | ||
105 | /* Called internally by functions to reset the state */ | 105 | static void pcm_play_data_start_int(const void *addr, size_t size); |
106 | static void pcm_play_stopped(void) | 106 | static void pcm_play_pause_int(bool play); |
107 | void pcm_play_stop_int(void); | ||
108 | |||
109 | #ifndef HAVE_SW_VOLUME_CONTROL | ||
110 | /** Standard hw volume control functions - otherwise, see pcm_sw_volume.c **/ | ||
111 | static inline void pcm_play_dma_start_int(const void *addr, size_t size) | ||
112 | { | ||
113 | pcm_play_dma_start(addr, size); | ||
114 | } | ||
115 | |||
116 | static inline void pcm_play_dma_pause_int(bool pause) | ||
117 | { | ||
118 | if (pause || pcm_get_bytes_waiting() > 0) | ||
119 | { | ||
120 | pcm_play_dma_pause(pause); | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | logf(" no data"); | ||
125 | pcm_play_data_start_int(NULL, 0); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static inline void pcm_play_dma_stop_int(void) | ||
130 | { | ||
131 | pcm_play_dma_stop(); | ||
132 | } | ||
133 | |||
134 | static inline const void * pcm_play_dma_get_peak_buffer_int(int *count) | ||
135 | { | ||
136 | return pcm_play_dma_get_peak_buffer(count); | ||
137 | } | ||
138 | |||
139 | bool pcm_play_dma_complete_callback(enum pcm_dma_status status, | ||
140 | const void **addr, size_t *size) | ||
141 | { | ||
142 | /* Check status callback first if error */ | ||
143 | if (status < PCM_DMAST_OK) | ||
144 | status = pcm_play_dma_status_callback(status); | ||
145 | |||
146 | if (status >= PCM_DMAST_OK && pcm_get_more_int(addr, size)) | ||
147 | return true; | ||
148 | |||
149 | /* Error, callback missing or no more DMA to do */ | ||
150 | pcm_play_stop_int(); | ||
151 | return false; | ||
152 | } | ||
153 | #endif /* ndef HAVE_SW_VOLUME_CONTROL */ | ||
154 | |||
155 | static void pcm_play_data_start_int(const void *addr, size_t size) | ||
107 | { | 156 | { |
157 | ALIGN_AUDIOBUF(addr, size); | ||
158 | |||
159 | if ((addr && size) || pcm_get_more_int(&addr, &size)) | ||
160 | { | ||
161 | pcm_apply_settings(); | ||
162 | logf(" pcm_play_dma_start_int"); | ||
163 | pcm_play_dma_start_int(addr, size); | ||
164 | pcm_playing = true; | ||
165 | pcm_paused = false; | ||
166 | } | ||
167 | else | ||
168 | { | ||
169 | /* Force a stop */ | ||
170 | logf(" pcm_play_stop_int"); | ||
171 | pcm_play_stop_int(); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | static void pcm_play_pause_int(bool play) | ||
176 | { | ||
177 | if (play) | ||
178 | pcm_apply_settings(); | ||
179 | |||
180 | logf(" pcm_play_dma_pause_int"); | ||
181 | pcm_play_dma_pause_int(!play); | ||
182 | pcm_paused = !play && pcm_playing; | ||
183 | } | ||
184 | |||
185 | void pcm_play_stop_int(void) | ||
186 | { | ||
187 | pcm_play_dma_stop_int(); | ||
108 | pcm_callback_for_more = NULL; | 188 | pcm_callback_for_more = NULL; |
109 | pcm_play_status_callback = NULL; | 189 | pcm_play_status_callback = NULL; |
110 | pcm_paused = false; | 190 | pcm_paused = false; |
@@ -195,7 +275,7 @@ void pcm_calculate_peaks(int *left, int *right) | |||
195 | static struct pcm_peaks peaks; | 275 | static struct pcm_peaks peaks; |
196 | 276 | ||
197 | int count; | 277 | int count; |
198 | const void *addr = pcm_play_dma_get_peak_buffer(&count); | 278 | const void *addr = pcm_play_dma_get_peak_buffer_int(&count); |
199 | 279 | ||
200 | pcm_do_peak_calculation(&peaks, pcm_playing && !pcm_paused, | 280 | pcm_do_peak_calculation(&peaks, pcm_playing && !pcm_paused, |
201 | addr, count); | 281 | addr, count); |
@@ -207,9 +287,9 @@ void pcm_calculate_peaks(int *left, int *right) | |||
207 | *right = peaks.right; | 287 | *right = peaks.right; |
208 | } | 288 | } |
209 | 289 | ||
210 | const void* pcm_get_peak_buffer(int * count) | 290 | const void * pcm_get_peak_buffer(int *count) |
211 | { | 291 | { |
212 | return pcm_play_dma_get_peak_buffer(count); | 292 | return pcm_play_dma_get_peak_buffer_int(count); |
213 | } | 293 | } |
214 | 294 | ||
215 | bool pcm_is_playing(void) | 295 | bool pcm_is_playing(void) |
@@ -233,8 +313,6 @@ void pcm_init(void) | |||
233 | { | 313 | { |
234 | logf("pcm_init"); | 314 | logf("pcm_init"); |
235 | 315 | ||
236 | pcm_play_stopped(); | ||
237 | |||
238 | pcm_set_frequency(HW_SAMPR_DEFAULT); | 316 | pcm_set_frequency(HW_SAMPR_DEFAULT); |
239 | 317 | ||
240 | logf(" pcm_play_dma_init"); | 318 | logf(" pcm_play_dma_init"); |
@@ -258,41 +336,6 @@ bool pcm_is_initialized(void) | |||
258 | return pcm_is_ready; | 336 | return pcm_is_ready; |
259 | } | 337 | } |
260 | 338 | ||
261 | /* Common code to pcm_play_data and pcm_play_pause */ | ||
262 | static void pcm_play_data_start(const void *addr, size_t size) | ||
263 | { | ||
264 | ALIGN_AUDIOBUF(addr, size); | ||
265 | |||
266 | if (!(addr && size)) | ||
267 | { | ||
268 | pcm_play_callback_type get_more = pcm_callback_for_more; | ||
269 | addr = NULL; | ||
270 | size = 0; | ||
271 | |||
272 | if (get_more) | ||
273 | { | ||
274 | logf(" get_more"); | ||
275 | get_more(&addr, &size); | ||
276 | ALIGN_AUDIOBUF(addr, size); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | if (addr && size) | ||
281 | { | ||
282 | logf(" pcm_play_dma_start"); | ||
283 | pcm_apply_settings(); | ||
284 | pcm_play_dma_start(addr, size); | ||
285 | pcm_playing = true; | ||
286 | pcm_paused = false; | ||
287 | return; | ||
288 | } | ||
289 | |||
290 | /* Force a stop */ | ||
291 | logf(" pcm_play_dma_stop"); | ||
292 | pcm_play_dma_stop(); | ||
293 | pcm_play_stopped(); | ||
294 | } | ||
295 | |||
296 | void pcm_play_data(pcm_play_callback_type get_more, | 339 | void pcm_play_data(pcm_play_callback_type get_more, |
297 | pcm_status_callback_type status_cb, | 340 | pcm_status_callback_type status_cb, |
298 | const void *start, size_t size) | 341 | const void *start, size_t size) |
@@ -304,41 +347,12 @@ void pcm_play_data(pcm_play_callback_type get_more, | |||
304 | pcm_callback_for_more = get_more; | 347 | pcm_callback_for_more = get_more; |
305 | pcm_play_status_callback = status_cb; | 348 | pcm_play_status_callback = status_cb; |
306 | 349 | ||
307 | logf(" pcm_play_data_start"); | 350 | logf(" pcm_play_data_start_int"); |
308 | pcm_play_data_start(start, size); | 351 | pcm_play_data_start_int(start, size); |
309 | 352 | ||
310 | pcm_play_unlock(); | 353 | pcm_play_unlock(); |
311 | } | 354 | } |
312 | 355 | ||
313 | bool pcm_play_dma_complete_callback(enum pcm_dma_status status, | ||
314 | const void **addr, size_t *size) | ||
315 | { | ||
316 | /* Check status callback first if error */ | ||
317 | if (status < PCM_DMAST_OK) | ||
318 | status = pcm_play_dma_status_callback(status); | ||
319 | |||
320 | pcm_play_callback_type get_more = pcm_callback_for_more; | ||
321 | |||
322 | if (get_more && status >= PCM_DMAST_OK) | ||
323 | { | ||
324 | *addr = NULL; | ||
325 | *size = 0; | ||
326 | |||
327 | /* Call registered callback to obtain next buffer */ | ||
328 | get_more(addr, size); | ||
329 | ALIGN_AUDIOBUF(*addr, *size); | ||
330 | |||
331 | if (*addr && *size) | ||
332 | return true; | ||
333 | } | ||
334 | |||
335 | /* Error, callback missing or no more DMA to do */ | ||
336 | pcm_play_dma_stop(); | ||
337 | pcm_play_stopped(); | ||
338 | |||
339 | return false; | ||
340 | } | ||
341 | |||
342 | void pcm_play_pause(bool play) | 356 | void pcm_play_pause(bool play) |
343 | { | 357 | { |
344 | logf("pcm_play_pause: %s", play ? "play" : "pause"); | 358 | logf("pcm_play_pause: %s", play ? "play" : "pause"); |
@@ -347,28 +361,8 @@ void pcm_play_pause(bool play) | |||
347 | 361 | ||
348 | if (play == pcm_paused && pcm_playing) | 362 | if (play == pcm_paused && pcm_playing) |
349 | { | 363 | { |
350 | if (!play) | 364 | logf(" pcm_play_pause_int"); |
351 | { | 365 | pcm_play_pause_int(play); |
352 | logf(" pcm_play_dma_pause"); | ||
353 | pcm_play_dma_pause(true); | ||
354 | pcm_paused = true; | ||
355 | } | ||
356 | else if (pcm_get_bytes_waiting() > 0) | ||
357 | { | ||
358 | logf(" pcm_play_dma_pause"); | ||
359 | pcm_apply_settings(); | ||
360 | pcm_play_dma_pause(false); | ||
361 | pcm_paused = false; | ||
362 | } | ||
363 | else | ||
364 | { | ||
365 | logf(" pcm_play_dma_start: no data"); | ||
366 | pcm_play_data_start(NULL, 0); | ||
367 | } | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | logf(" no change"); | ||
372 | } | 366 | } |
373 | 367 | ||
374 | pcm_play_unlock(); | 368 | pcm_play_unlock(); |
@@ -382,13 +376,8 @@ void pcm_play_stop(void) | |||
382 | 376 | ||
383 | if (pcm_playing) | 377 | if (pcm_playing) |
384 | { | 378 | { |
385 | logf(" pcm_play_dma_stop"); | 379 | logf(" pcm_play_stop_int"); |
386 | pcm_play_dma_stop(); | 380 | pcm_play_stop_int(); |
387 | pcm_play_stopped(); | ||
388 | } | ||
389 | else | ||
390 | { | ||
391 | logf(" not playing"); | ||
392 | } | 381 | } |
393 | 382 | ||
394 | pcm_play_unlock(); | 383 | pcm_play_unlock(); |