36
36
37
37
#include "shared-module/audiomp3/MP3Decoder.h"
38
38
#include "supervisor/shared/translate.h"
39
+ #include "supervisor/background_callback.h"
39
40
#include "lib/mp3/src/mp3common.h"
40
41
41
42
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
42
43
43
- /** Fill the input buffer if it is less than half full .
44
+ /** Fill the input buffer unconditionally .
44
45
*
45
46
* Returns true if the input buffer contains any useful data,
46
47
* false otherwise. (The input buffer will be padded to the end with
50
51
*
51
52
* Sets self->eof if any read of the file returns 0 bytes
52
53
*/
53
- STATIC bool mp3file_update_inbuf (audiomp3_mp3file_obj_t * self ) {
54
- // If buffer is over half full, do nothing
55
- if (self -> inbuf_offset < self -> inbuf_length /2 ) return true;
56
-
54
+ STATIC bool mp3file_update_inbuf_always (audiomp3_mp3file_obj_t * self ) {
57
55
// If we didn't previously reach the end of file, we can try reading now
58
56
if (!self -> eof ) {
59
57
@@ -87,14 +85,34 @@ STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
87
85
return self -> inbuf_offset < self -> inbuf_length ;
88
86
}
89
87
88
+ /** Update the inbuf from a background callback.
89
+ *
90
+ * This variant is introduced so that at the site of the
91
+ * add_background_callback_core call, the prototype matches.
92
+ */
93
+ STATIC void mp3file_update_inbuf_cb (void * self ) {
94
+ mp3file_update_inbuf_always (self );
95
+ }
96
+
97
+ /** Fill the input buffer if it is less than half full.
98
+ *
99
+ * Returns the same as mp3file_update_inbuf_always.
100
+ */
101
+ STATIC bool mp3file_update_inbuf_half (audiomp3_mp3file_obj_t * self ) {
102
+ // If buffer is over half full, do nothing
103
+ if (self -> inbuf_offset < self -> inbuf_length /2 ) return true;
104
+
105
+ return mp3file_update_inbuf_always (self );
106
+ }
107
+
90
108
#define READ_PTR (self ) (self->inbuf + self->inbuf_offset)
91
109
#define BYTES_LEFT (self ) (self->inbuf_length - self->inbuf_offset)
92
110
#define CONSUME (self , n ) (self->inbuf_offset += n)
93
111
94
112
// http://id3.org/d3v2.3.0
95
113
// http://id3.org/id3v2.3.0
96
114
STATIC void mp3file_skip_id3v2 (audiomp3_mp3file_obj_t * self ) {
97
- mp3file_update_inbuf (self );
115
+ mp3file_update_inbuf_half (self );
98
116
if (BYTES_LEFT (self ) < 10 ) {
99
117
return ;
100
118
}
@@ -129,11 +147,11 @@ STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
129
147
*/
130
148
STATIC bool mp3file_find_sync_word (audiomp3_mp3file_obj_t * self ) {
131
149
do {
132
- mp3file_update_inbuf (self );
150
+ mp3file_update_inbuf_half (self );
133
151
int offset = MP3FindSyncWord (READ_PTR (self ), BYTES_LEFT (self ));
134
152
if (offset >= 0 ) {
135
153
CONSUME (self , offset );
136
- mp3file_update_inbuf (self );
154
+ mp3file_update_inbuf_half (self );
137
155
return true;
138
156
}
139
157
CONSUME (self , MAX (0 , BYTES_LEFT (self ) - 16 ));
@@ -209,12 +227,14 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
209
227
}
210
228
211
229
void common_hal_audiomp3_mp3file_set_file (audiomp3_mp3file_obj_t * self , pyb_file_obj_t * file ) {
230
+ background_callback_begin_critical_section ();
231
+
212
232
self -> file = file ;
213
233
f_lseek (& self -> file -> fp , 0 );
214
234
self -> inbuf_offset = self -> inbuf_length ;
215
235
self -> eof = 0 ;
216
236
self -> other_channel = -1 ;
217
- mp3file_update_inbuf (self );
237
+ mp3file_update_inbuf_half (self );
218
238
mp3file_find_sync_word (self );
219
239
// It **SHOULD** not be necessary to do this; the buffer should be filled
220
240
// with fresh content before it is returned by get_buffer(). The fact that
@@ -224,7 +244,9 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t* self, pyb_file
224
244
memset (self -> buffers [0 ], 0 , MAX_BUFFER_LEN );
225
245
memset (self -> buffers [1 ], 0 , MAX_BUFFER_LEN );
226
246
MP3FrameInfo fi ;
227
- if (!mp3file_get_next_frame_info (self , & fi )) {
247
+ bool result = mp3file_get_next_frame_info (self , & fi );
248
+ background_callback_end_critical_section ();
249
+ if (!result ) {
228
250
mp_raise_msg (& mp_type_RuntimeError ,
229
251
translate ("Failed to parse MP3 file" ));
230
252
}
@@ -277,13 +299,15 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t* self,
277
299
}
278
300
// We don't reset the buffer index in case we're looping and we have an odd number of buffer
279
301
// loads
302
+ background_callback_begin_critical_section ();
280
303
f_lseek (& self -> file -> fp , 0 );
281
304
self -> inbuf_offset = self -> inbuf_length ;
282
305
self -> eof = 0 ;
283
306
self -> other_channel = -1 ;
284
- mp3file_update_inbuf (self );
307
+ mp3file_update_inbuf_half (self );
285
308
mp3file_skip_id3v2 (self );
286
309
mp3file_find_sync_word (self );
310
+ background_callback_end_critical_section ();
287
311
}
288
312
289
313
audioio_get_buffer_result_t audiomp3_mp3file_get_buffer (audiomp3_mp3file_obj_t * self ,
@@ -321,6 +345,14 @@ audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t*
321
345
uint8_t * inbuf = READ_PTR (self );
322
346
int err = MP3Decode (self -> decoder , & inbuf , & bytes_left , buffer , 0 );
323
347
CONSUME (self , BYTES_LEFT (self ) - bytes_left );
348
+
349
+ if (self -> inbuf_offset >= 512 ) {
350
+ background_callback_add (
351
+ & self -> inbuf_fill_cb ,
352
+ mp3file_update_inbuf_cb ,
353
+ self );
354
+ }
355
+
324
356
if (err ) {
325
357
return GET_BUFFER_DONE ;
326
358
}
0 commit comments