Skip to content

Commit 4d4d654

Browse files
committed
MP3Decoder: set the nonblocking flag as needed
this makes SSL sockets (which return readable when not yet actually readable) work better.
1 parent 3215f6c commit 4d4d654

File tree

3 files changed

+29
-1
lines changed

3 files changed

+29
-1
lines changed

shared-bindings/audiomp3/MP3Decoder.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@
7272
//| decoder.file = stream
7373
//|
7474
//| If the stream is played with ``loop = True``, the loop will start at the beginning.
75+
//|
76+
//| It is possible to stream an mp3 from a socket, including a secure socket.
77+
//| The MP3Decoder may change the timeout and non-blocking status of the socket.
78+
//| Using a larger decode buffer with a stream can be helpful to avoid data underruns.
79+
//| An `adafruit_requests` request must be made with ``headers={"Connection": "close"}`` so
80+
//| that the socket closes when the stream ends.
7581
//| """
7682
//| ...
7783

shared-module/audiomp3/MP3Decoder.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ static off_t stream_lseek(void *stream, off_t offset, int whence) {
9595
#define INPUT_BUFFER_CONSUME(i, n) ((i).read_off += (n))
9696
#define INPUT_BUFFER_CLEAR(i) ((i).read_off = (i).write_off = 0)
9797

98+
static void stream_set_blocking(audiomp3_mp3file_obj_t *self, bool block_ok) {
99+
if (!self->settimeout_args[0]) {
100+
return;
101+
}
102+
if (block_ok == self->block_ok) {
103+
return;
104+
}
105+
self->block_ok = block_ok;
106+
self->settimeout_args[2] = block_ok ? mp_const_none : mp_obj_new_int(0);
107+
mp_call_method_n_kw(1, 0, self->settimeout_args);
108+
}
109+
98110
/** Fill the input buffer unconditionally.
99111
*
100112
* Returns true if the input buffer contains any useful data,
@@ -110,6 +122,8 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block
110122
return INPUT_BUFFER_AVAILABLE(self->inbuf) > 0;
111123
}
112124

125+
stream_set_blocking(self, block_ok);
126+
113127
// We didn't previously reach EOF and we have input buffer space available
114128

115129
// Move the unconsumed portion of the buffer to the start
@@ -119,7 +133,7 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block
119133
self->inbuf.read_off = 0;
120134
}
121135

122-
for (size_t to_read; !self->eof && (to_read = INPUT_BUFFER_SPACE(self->inbuf)) > 0 && (block_ok || stream_readable(self->stream));) {
136+
for (size_t to_read; !self->eof && (to_read = INPUT_BUFFER_SPACE(self->inbuf)) > 0;) {
123137
uint8_t *write_ptr = self->inbuf.buf + self->inbuf.write_off;
124138
ssize_t n_read = stream_read(self->stream, write_ptr, to_read);
125139

@@ -328,9 +342,14 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, mp_obj_t
328342
background_callback_prevent();
329343

330344
self->stream = stream;
345+
mp_load_method_maybe(stream, MP_QSTR_settimeout, self->settimeout_args);
331346

332347
INPUT_BUFFER_CLEAR(self->inbuf);
333348
self->eof = 0;
349+
350+
self->block_ok = false;
351+
stream_set_blocking(self, true);
352+
334353
self->other_channel = -1;
335354
mp3file_update_inbuf_half(self, true);
336355
mp3file_find_sync_word(self, true);
@@ -365,6 +384,7 @@ void common_hal_audiomp3_mp3file_deinit(audiomp3_mp3file_obj_t *self) {
365384
self->pcm_buffer[0] = NULL;
366385
self->pcm_buffer[1] = NULL;
367386
self->stream = mp_const_none;
387+
self->settimeout_args[0] = MP_OBJ_NULL;
368388
self->samples_decoded = 0;
369389
}
370390

shared-module/audiomp3/MP3Decoder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ typedef struct {
3535
uint8_t buffer_index;
3636
uint8_t channel_count;
3737
bool eof;
38+
bool block_ok;
39+
mp_obj_t settimeout_args[3];
3840

3941
int8_t other_channel;
4042
int8_t other_buffer_index;

0 commit comments

Comments
 (0)