77
88#include "shared-bindings/audiomp3/MP3Decoder.h"
99
10+ #include <math.h>
1011#include <stdint.h>
1112#include <string.h>
12- #include <math.h>
13+ #include <sys/types.h>
14+ #include <unistd.h>
1315
1416#include "py/mperrno.h"
1517#include "py/runtime.h"
18+ #include "py/stream.h"
1619
1720#include "shared-module/audiomp3/MP3Decoder.h"
1821#include "supervisor/background_callback.h"
1922#include "lib/mp3/src/mp3common.h"
2023
2124#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
2225
26+ // (near copy of mp_stream_posix_read, but with changes)
27+ // (circuitpy doesn't enable posix stream routines anyway)
28+ STATIC ssize_t stream_read (void * stream , void * buf , size_t len ) {
29+ int errcode ;
30+ mp_obj_base_t * o = MP_OBJ_TO_PTR (stream );
31+ const mp_stream_p_t * stream_p = MP_OBJ_TYPE_GET_SLOT (o -> type , protocol );
32+ if (!stream_p -> read ) {
33+ return - EINVAL ;
34+ }
35+ mp_uint_t out_sz = stream_p -> read (MP_OBJ_FROM_PTR (stream ), buf , len , & errcode );
36+ if (out_sz == MP_STREAM_ERROR ) {
37+ return - errcode ; // CIRCUITPY-CHANGE: returns negative errcode value
38+ } else {
39+ return out_sz ;
40+ }
41+ }
42+
43+ // (near copy of mp_stream_posix_read, but with changes)
44+ // (circuitpy doesn't enable posix stream routines anyway)
45+ STATIC ssize_t stream_read_all (void * stream , void * buf , size_t len ) {
46+ ssize_t total_read = 0 ;
47+ while (len ) {
48+ ssize_t r = stream_read (stream , buf , len );
49+ if (r <= 0 ) {
50+ if (total_read ) {
51+ break ;
52+ }
53+ return r ;
54+ }
55+ total_read += r ;
56+ buf += r ;
57+ len -= r ;
58+ }
59+ return total_read ;
60+ }
61+
62+
63+ // (near copy of mp_stream_posix_lseek, but with changes)
64+ // (circuitpy doesn't enable posix stream routines anyway)
65+ STATIC off_t stream_lseek (void * stream , off_t offset , int whence ) {
66+ int errcode ;
67+ const mp_obj_base_t * o = stream ;
68+ const mp_stream_p_t * stream_p = MP_OBJ_TYPE_GET_SLOT (o -> type , protocol );
69+ if (!stream_p -> ioctl ) {
70+ return - EINVAL ;
71+ }
72+ struct mp_stream_seek_t seek_s ;
73+ seek_s .offset = offset ;
74+ seek_s .whence = whence ;
75+ mp_uint_t res = stream_p -> ioctl (MP_OBJ_FROM_PTR (stream ), MP_STREAM_SEEK , (mp_uint_t )(uintptr_t )& seek_s , & errcode );
76+ if (res == MP_STREAM_ERROR ) {
77+ return - errcode ;
78+ }
79+ return seek_s .offset ;
80+ }
81+
2382/** Fill the input buffer unconditionally.
2483 *
2584 * Returns true if the input buffer contains any useful data,
2685 * false otherwise. (The input buffer will be padded to the end with
2786 * 0 bytes, which do not interfere with MP3 decoding)
2887 *
29- * Raises OSError if f_read fails.
88+ * Raises OSError if stream_read fails.
3089 *
3190 * Sets self->eof if any read of the file returns 0 bytes
3291 */
@@ -41,20 +100,20 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self) {
41100 self -> inbuf_length - self -> inbuf_offset );
42101 self -> inbuf_offset = 0 ;
43102
44- UINT to_read = end_of_buffer - new_end_of_data ;
45- UINT bytes_read = 0 ;
103+ ssize_t to_read = end_of_buffer - new_end_of_data ;
46104 memset (new_end_of_data , 0 , to_read );
47- if (f_read (& self -> file -> fp , new_end_of_data , to_read , & bytes_read ) != FR_OK ) {
105+ ssize_t r = stream_read_all (self -> stream , new_end_of_data , to_read );
106+ if (r < 0 ) {
48107 self -> eof = true;
49- mp_raise_OSError (MP_EIO );
108+ mp_raise_OSError (- r );
50109 }
51110
52- if (bytes_read == 0 ) {
111+ if (r == 0 ) {
53112 self -> eof = true;
54113 }
55114
56- if (to_read != bytes_read ) {
57- new_end_of_data += bytes_read ;
115+ if (to_read != r ) {
116+ new_end_of_data += r ;
58117 memset (new_end_of_data , 0 , end_of_buffer - new_end_of_data );
59118 }
60119
@@ -119,8 +178,17 @@ static void mp3file_skip_id3v2(audiomp3_mp3file_obj_t *self) {
119178 size -= to_consume ;
120179
121180 // Next, seek in the file after the header
122- f_lseek (& self -> file -> fp , f_tell (& self -> file -> fp ) + size );
123- return ;
181+ if (stream_lseek (self -> stream , SEEK_CUR , size ) == 0 ) {
182+ return ;
183+ }
184+
185+ // Couldn't seek (might be a socket), so need to actually read and discard all that data
186+ while (size > 0 && !self -> eof ) {
187+ mp3file_update_inbuf_always (self );
188+ to_consume = MIN (size , BYTES_LEFT (self ));
189+ CONSUME (self , to_consume );
190+ size -= to_consume ;
191+ }
124192}
125193
126194/* If a sync word can be found, advance to it and return true. Otherwise,
@@ -154,7 +222,7 @@ static bool mp3file_get_next_frame_info(audiomp3_mp3file_obj_t *self, MP3FrameIn
154222}
155223
156224void common_hal_audiomp3_mp3file_construct (audiomp3_mp3file_obj_t * self ,
157- pyb_file_obj_t * file ,
225+ mp_obj_t stream ,
158226 uint8_t * buffer ,
159227 size_t buffer_size ) {
160228 // XXX Adafruit_MP3 uses a 2kB input buffer and two 4kB output buffers.
@@ -202,14 +270,17 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t *self,
202270 }
203271 }
204272
205- common_hal_audiomp3_mp3file_set_file (self , file );
273+ common_hal_audiomp3_mp3file_set_file (self , stream );
206274}
207275
208- void common_hal_audiomp3_mp3file_set_file (audiomp3_mp3file_obj_t * self , pyb_file_obj_t * file ) {
276+ void common_hal_audiomp3_mp3file_set_file (audiomp3_mp3file_obj_t * self , mp_obj_t stream ) {
209277 background_callback_prevent ();
210278
211- self -> file = file ;
212- f_lseek (& self -> file -> fp , 0 );
279+ self -> stream = stream ;
280+
281+ // Seek the beginning of the stream if possible, but ignore any errors
282+ (void )stream_lseek (self -> stream , SEEK_SET , 0 );
283+
213284 self -> inbuf_offset = self -> inbuf_length ;
214285 self -> eof = 0 ;
215286 self -> other_channel = -1 ;
@@ -243,7 +314,7 @@ void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self) {
243314 self -> inbuf = NULL ;
244315 self -> buffers [0 ] = NULL ;
245316 self -> buffers [1 ] = NULL ;
246- self -> file = NULL ;
317+ self -> stream = mp_const_none ;
247318 self -> samples_decoded = 0 ;
248319}
249320
@@ -277,14 +348,15 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self,
277348 // We don't reset the buffer index in case we're looping and we have an odd number of buffer
278349 // loads
279350 background_callback_prevent ();
280- f_lseek (& self -> file -> fp , 0 );
281- self -> inbuf_offset = self -> inbuf_length ;
282- self -> eof = 0 ;
283- self -> samples_decoded = 0 ;
284- self -> other_channel = -1 ;
285- mp3file_update_inbuf_half (self );
286- mp3file_skip_id3v2 (self );
287- mp3file_find_sync_word (self );
351+ if (stream_lseek (self -> stream , SEEK_SET , 0 ) == 0 ) {
352+ self -> inbuf_offset = self -> inbuf_length ;
353+ self -> eof = 0 ;
354+ self -> samples_decoded = 0 ;
355+ self -> other_channel = -1 ;
356+ mp3file_update_inbuf_half (self );
357+ mp3file_skip_id3v2 (self );
358+ mp3file_find_sync_word (self );
359+ }
288360 background_callback_allow ();
289361}
290362
0 commit comments