7
7
8
8
#include "shared-bindings/audiomp3/MP3Decoder.h"
9
9
10
+ #include <math.h>
10
11
#include <stdint.h>
11
12
#include <string.h>
12
- #include <math.h>
13
+ #include <sys/types.h>
14
+ #include <unistd.h>
13
15
14
16
#include "py/mperrno.h"
15
17
#include "py/runtime.h"
18
+ #include "py/stream.h"
16
19
17
20
#include "shared-module/audiomp3/MP3Decoder.h"
18
21
#include "supervisor/background_callback.h"
19
22
#include "lib/mp3/src/mp3common.h"
20
23
21
24
#define MAX_BUFFER_LEN (MAX_NSAMP * MAX_NGRAN * MAX_NCHAN * sizeof(int16_t))
22
25
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
+
23
82
/** Fill the input buffer unconditionally.
24
83
*
25
84
* Returns true if the input buffer contains any useful data,
26
85
* false otherwise. (The input buffer will be padded to the end with
27
86
* 0 bytes, which do not interfere with MP3 decoding)
28
87
*
29
- * Raises OSError if f_read fails.
88
+ * Raises OSError if stream_read fails.
30
89
*
31
90
* Sets self->eof if any read of the file returns 0 bytes
32
91
*/
@@ -41,20 +100,20 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self) {
41
100
self -> inbuf_length - self -> inbuf_offset );
42
101
self -> inbuf_offset = 0 ;
43
102
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 ;
46
104
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 ) {
48
107
self -> eof = true;
49
- mp_raise_OSError (MP_EIO );
108
+ mp_raise_OSError (- r );
50
109
}
51
110
52
- if (bytes_read == 0 ) {
111
+ if (r == 0 ) {
53
112
self -> eof = true;
54
113
}
55
114
56
- if (to_read != bytes_read ) {
57
- new_end_of_data += bytes_read ;
115
+ if (to_read != r ) {
116
+ new_end_of_data += r ;
58
117
memset (new_end_of_data , 0 , end_of_buffer - new_end_of_data );
59
118
}
60
119
@@ -119,8 +178,17 @@ static void mp3file_skip_id3v2(audiomp3_mp3file_obj_t *self) {
119
178
size -= to_consume ;
120
179
121
180
// 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
+ }
124
192
}
125
193
126
194
/* 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
154
222
}
155
223
156
224
void common_hal_audiomp3_mp3file_construct (audiomp3_mp3file_obj_t * self ,
157
- pyb_file_obj_t * file ,
225
+ mp_obj_t stream ,
158
226
uint8_t * buffer ,
159
227
size_t buffer_size ) {
160
228
// 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,
202
270
}
203
271
}
204
272
205
- common_hal_audiomp3_mp3file_set_file (self , file );
273
+ common_hal_audiomp3_mp3file_set_file (self , stream );
206
274
}
207
275
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 ) {
209
277
background_callback_prevent ();
210
278
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
+
213
284
self -> inbuf_offset = self -> inbuf_length ;
214
285
self -> eof = 0 ;
215
286
self -> other_channel = -1 ;
@@ -243,7 +314,7 @@ void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self) {
243
314
self -> inbuf = NULL ;
244
315
self -> buffers [0 ] = NULL ;
245
316
self -> buffers [1 ] = NULL ;
246
- self -> file = NULL ;
317
+ self -> stream = mp_const_none ;
247
318
self -> samples_decoded = 0 ;
248
319
}
249
320
@@ -277,14 +348,15 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self,
277
348
// We don't reset the buffer index in case we're looping and we have an odd number of buffer
278
349
// loads
279
350
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
+ }
288
360
background_callback_allow ();
289
361
}
290
362
0 commit comments