3636
3737#include "shared-module/audiomp3/MP3Decoder.h"
3838#include "supervisor/shared/translate.h"
39+ #include "supervisor/background_callback.h"
3940#include "lib/mp3/src/mp3common.h"
4041
4142#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
4243
43- /** Fill the input buffer if it is less than half full .
44+ /** Fill the input buffer unconditionally .
4445 *
4546 * Returns true if the input buffer contains any useful data,
4647 * false otherwise. (The input buffer will be padded to the end with
5051 *
5152 * Sets self->eof if any read of the file returns 0 bytes
5253 */
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 ) {
5755 // If we didn't previously reach the end of file, we can try reading now
5856 if (!self -> eof ) {
5957
@@ -87,14 +85,34 @@ STATIC bool mp3file_update_inbuf(audiomp3_mp3file_obj_t* self) {
8785 return self -> inbuf_offset < self -> inbuf_length ;
8886}
8987
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+
90108#define READ_PTR (self ) (self->inbuf + self->inbuf_offset)
91109#define BYTES_LEFT (self ) (self->inbuf_length - self->inbuf_offset)
92110#define CONSUME (self , n ) (self->inbuf_offset += n)
93111
94112// http://id3.org/d3v2.3.0
95113// http://id3.org/id3v2.3.0
96114STATIC void mp3file_skip_id3v2 (audiomp3_mp3file_obj_t * self ) {
97- mp3file_update_inbuf (self );
115+ mp3file_update_inbuf_half (self );
98116 if (BYTES_LEFT (self ) < 10 ) {
99117 return ;
100118 }
@@ -129,11 +147,11 @@ STATIC void mp3file_skip_id3v2(audiomp3_mp3file_obj_t* self) {
129147 */
130148STATIC bool mp3file_find_sync_word (audiomp3_mp3file_obj_t * self ) {
131149 do {
132- mp3file_update_inbuf (self );
150+ mp3file_update_inbuf_half (self );
133151 int offset = MP3FindSyncWord (READ_PTR (self ), BYTES_LEFT (self ));
134152 if (offset >= 0 ) {
135153 CONSUME (self , offset );
136- mp3file_update_inbuf (self );
154+ mp3file_update_inbuf_half (self );
137155 return true;
138156 }
139157 CONSUME (self , MAX (0 , BYTES_LEFT (self ) - 16 ));
@@ -209,12 +227,14 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t* self,
209227}
210228
211229void common_hal_audiomp3_mp3file_set_file (audiomp3_mp3file_obj_t * self , pyb_file_obj_t * file ) {
230+ background_callback_begin_critical_section ();
231+
212232 self -> file = file ;
213233 f_lseek (& self -> file -> fp , 0 );
214234 self -> inbuf_offset = self -> inbuf_length ;
215235 self -> eof = 0 ;
216236 self -> other_channel = -1 ;
217- mp3file_update_inbuf (self );
237+ mp3file_update_inbuf_half (self );
218238 mp3file_find_sync_word (self );
219239 // It **SHOULD** not be necessary to do this; the buffer should be filled
220240 // 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
224244 memset (self -> buffers [0 ], 0 , MAX_BUFFER_LEN );
225245 memset (self -> buffers [1 ], 0 , MAX_BUFFER_LEN );
226246 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 ) {
228250 mp_raise_msg (& mp_type_RuntimeError ,
229251 translate ("Failed to parse MP3 file" ));
230252 }
@@ -277,13 +299,15 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t* self,
277299 }
278300 // We don't reset the buffer index in case we're looping and we have an odd number of buffer
279301 // loads
302+ background_callback_begin_critical_section ();
280303 f_lseek (& self -> file -> fp , 0 );
281304 self -> inbuf_offset = self -> inbuf_length ;
282305 self -> eof = 0 ;
283306 self -> other_channel = -1 ;
284- mp3file_update_inbuf (self );
307+ mp3file_update_inbuf_half (self );
285308 mp3file_skip_id3v2 (self );
286309 mp3file_find_sync_word (self );
310+ background_callback_end_critical_section ();
287311}
288312
289313audioio_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*
321345 uint8_t * inbuf = READ_PTR (self );
322346 int err = MP3Decode (self -> decoder , & inbuf , & bytes_left , buffer , 0 );
323347 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+
324356 if (err ) {
325357 return GET_BUFFER_DONE ;
326358 }
0 commit comments