Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable mp3 output on esp32s3 #9218

Merged
merged 15 commits into from
May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/mp3
5 changes: 4 additions & 1 deletion ports/espressif/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ CFLAGS += \
-DESP_PLATFORM=1 \
-DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\" \
-DMBEDTLS_PADLOCK_FILE=\"ports/espressif/esp-idf/components/mbedtls/mbedtls/library/padlock.h\" \
-DUNITY_INCLUDE_CONFIG_H -DWITH_POSIX
-DUNITY_INCLUDE_CONFIG_H -DWITH_POSIX \
-DMP3DEC_GENERIC

# Make our canary value match FreeRTOS's
# This define is in FreeRTOS as tskSTACK_FILL_BYTE 0xa5U which we expand out to a full word.
Expand Down Expand Up @@ -303,7 +304,9 @@ SRC_C += \
peripherals/i2c.c \
peripherals/$(IDF_TARGET)/pins.c

ifeq ($(CIRCUITPY_SSL),1)
SRC_C += lib/mbedtls_config/crt_bundle.c
endif

SRC_C += $(wildcard common-hal/espidf/*.c)

Expand Down
2 changes: 1 addition & 1 deletion ports/espressif/common-hal/audiobusio/I2SOut.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self,

i2s_std_config_t i2s_config = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(48000),
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
.gpio_cfg = {
.mclk = main_clock != NULL ? main_clock->number : I2S_GPIO_UNUSED,
.bclk = bit_clock->number,
Expand Down
11 changes: 8 additions & 3 deletions ports/espressif/common-hal/audiobusio/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@

#include "shared-module/audiocore/__init__.h"

#define CIRCUITPY_BUFFER_COUNT 3
#define CIRCUITPY_BUFFER_SIZE 1023
#define CIRCUITPY_OUTPUT_SLOTS 2
// The maximum DMA buffer size (in bytes)
#define I2S_DMA_BUFFER_MAX_SIZE 4092
// The number of DMA buffers to allocate
#define CIRCUITPY_BUFFER_COUNT (3)
// The maximum DMA buffer size in frames (at stereo 16-bit)
#define CIRCUITPY_BUFFER_SIZE (I2S_DMA_BUFFER_MAX_SIZE / 4)
// The number of output channels is fixed at 2
#define CIRCUITPY_OUTPUT_SLOTS (2)

static void i2s_fill_buffer(i2s_t *self) {
if (self->next_buffer_size == 0) {
Expand Down
44 changes: 44 additions & 0 deletions ports/espressif/common-hal/audiomp3/__init__.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 Jeff Epler for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <stdlib.h>
#include <string.h>
#include "py/mpprint.h"
#include "esp_heap_caps.h"
#include "shared-module/audiomp3/__init__.h"
#include "supervisor/port_heap.h"

void *mp3_alloc(size_t sz) {
void *ptr = heap_caps_malloc(sz, MALLOC_CAP_8BIT);
if (ptr) {
memset(ptr, 0, sz);
}
return ptr;
}

void mp3_free(void *ptr) {
heap_caps_free(ptr);
}
4 changes: 4 additions & 0 deletions ports/espressif/common-hal/socketpool/Socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
#include "py/mperrno.h"
#include "py/runtime.h"
#include "shared-bindings/socketpool/SocketPool.h"
#if CIRCUITPY_SSL
#include "shared-bindings/ssl/SSLSocket.h"
#include "shared-module/ssl/SSLSocket.h"
#endif
#include "supervisor/port.h"
#include "supervisor/shared/tick.h"
#include "supervisor/workflow.h"
Expand Down Expand Up @@ -359,12 +361,14 @@ size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self,
}

void socketpool_socket_close(socketpool_socket_obj_t *self) {
#if CIRCUITPY_SSL
if (self->ssl_socket) {
ssl_sslsocket_obj_t *ssl_socket = self->ssl_socket;
self->ssl_socket = NULL;
common_hal_ssl_sslsocket_close(ssl_socket);
return;
}
#endif
self->connected = false;
int fd = self->num;
// Ignore bogus/closed sockets
Expand Down
7 changes: 7 additions & 0 deletions ports/espressif/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,11 @@
#define CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP (0)
#endif

// Protect the background queue with a lock because both cores may modify it.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
extern portMUX_TYPE background_task_mutex;
#define CALLBACK_CRITICAL_BEGIN (taskENTER_CRITICAL(&background_task_mutex))
#define CALLBACK_CRITICAL_END (taskEXIT_CRITICAL(&background_task_mutex))

#endif // MICROPY_INCLUDED_ESPRESSIF_MPCONFIGPORT_H
11 changes: 9 additions & 2 deletions ports/espressif/mpconfigport.mk
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ CIRCUITPY_ANALOGBUFIO ?= 1
CIRCUITPY_AUDIOBUSIO ?= 1
CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0
CIRCUITPY_AUDIOIO ?= 0
CIRCUITPY_AUDIOMP3 ?= 0
CIRCUITPY_BLEIO_HCI = 0
CIRCUITPY_CANIO ?= 1
CIRCUITPY_COUNTIO ?= 1
Expand Down Expand Up @@ -143,12 +142,17 @@ endif
ifeq ($(CIRCUITPY_ESP_FLASH_SIZE),4MB)
CIRCUITPY_BITMAPFILTER ?= 0
OPTIMIZATION_FLAGS ?= -Os
# Until the 4MB C6 partition table is updated, disable mp3 on the 4MB C6 parts
ifeq ($(IDF_TARGET),esp32c6)
CIRCUITPY_AUDIOMP3 ?= 0
endif
endif

# No room for dualbank on boards with 2MB flash
# No room for dualbank or mp3 on boards with 2MB flash
ifeq ($(CIRCUITPY_ESP_FLASH_SIZE),2MB)
CIRCUITPY_BITMAPFILTER ?= 0
CIRCUITPY_DUALBANK = 0
CIRCUITPY_AUDIOMP3 = 0
endif

# Modules dependent on other modules
Expand Down Expand Up @@ -178,3 +182,6 @@ USB_NUM_IN_ENDPOINTS = 5

# Usually lots of flash space available
CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1

CIRCUITPY_AUDIOMP3 ?= 1
CIRCUITPY_AUDIOMP3_USE_PORT_ALLOCATOR ?= 1
2 changes: 2 additions & 0 deletions ports/espressif/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,5 @@ extern void app_main(void);
void app_main(void) {
main();
}

portMUX_TYPE background_task_mutex = portMUX_INITIALIZER_UNLOCKED;
6 changes: 5 additions & 1 deletion py/circuitpy_defns.mk
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,11 @@ SRC_MOD += $(addprefix lib/mp3/src/, \
subband.c \
trigtabs.c \
)
$(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "py/misc.h" -D'MPDEC_ALLOCATOR(x)=m_malloc(x)' -D'MPDEC_FREE(x)=m_free(x)'
$(BUILD)/lib/mp3/src/buffers.o: CFLAGS += -include "shared-module/audiomp3/__init__.h" -D'MPDEC_ALLOCATOR(x)=mp3_alloc(x)' -D'MPDEC_FREE(x)=mp3_free(x)' -fwrapv
ifeq ($(CIRCUITPY_AUDIOMP3_USE_PORT_ALLOCATOR),1)
SRC_COMMON_HAL_ALL += \
audiomp3/__init__.c
endif
endif

ifeq ($(CIRCUITPY_GIFIO),1)
Expand Down
5 changes: 4 additions & 1 deletion shared-bindings/audiomp3/MP3Decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ STATIC mp_obj_t audiomp3_mp3file_make_new(const mp_obj_type_t *type, size_t n_ar
arg = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), arg, MP_ROM_QSTR(MP_QSTR_rb));
}

audiomp3_mp3file_obj_t *self = mp_obj_malloc(audiomp3_mp3file_obj_t, &audiomp3_mp3file_type);
audiomp3_mp3file_obj_t *self = m_new_obj_with_finaliser(audiomp3_mp3file_obj_t);
self->base.type = &audiomp3_mp3file_type;

if (!mp_obj_is_type(arg, &mp_type_fileio)) {
mp_raise_TypeError(MP_ERROR_TEXT("file must be a file opened in byte mode"));
}
Expand Down Expand Up @@ -260,6 +262,7 @@ STATIC const mp_rom_map_elem_t audiomp3_mp3file_locals_dict_table[] = {
// Methods
{ MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&audiomp3_mp3file_open_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiomp3_mp3file_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audiomp3_mp3file_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiomp3_mp3file___exit___obj) },

Expand Down
8 changes: 4 additions & 4 deletions shared-module/audiomp3/MP3Decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ void common_hal_audiomp3_mp3file_construct(audiomp3_mp3file_obj_t *self,
}

void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, pyb_file_obj_t *file) {
background_callback_begin_critical_section();
background_callback_prevent();

self->file = file;
f_lseek(&self->file->fp, 0);
Expand All @@ -244,7 +244,7 @@ void common_hal_audiomp3_mp3file_set_file(audiomp3_mp3file_obj_t *self, pyb_file
memset(self->buffers[1], 0, MAX_BUFFER_LEN);
MP3FrameInfo fi;
bool result = mp3file_get_next_frame_info(self, &fi);
background_callback_end_critical_section();
background_callback_allow();
if (!result) {
mp_raise_msg(&mp_type_RuntimeError,
MP_ERROR_TEXT("Failed to parse MP3 file"));
Expand Down Expand Up @@ -296,7 +296,7 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self,
}
// We don't reset the buffer index in case we're looping and we have an odd number of buffer
// loads
background_callback_begin_critical_section();
background_callback_prevent();
f_lseek(&self->file->fp, 0);
self->inbuf_offset = self->inbuf_length;
self->eof = 0;
Expand All @@ -305,7 +305,7 @@ void audiomp3_mp3file_reset_buffer(audiomp3_mp3file_obj_t *self,
mp3file_update_inbuf_half(self);
mp3file_skip_id3v2(self);
mp3file_find_sync_word(self);
background_callback_end_critical_section();
background_callback_allow();
}

audioio_get_buffer_result_t audiomp3_mp3file_get_buffer(audiomp3_mp3file_obj_t *self,
Expand Down
38 changes: 38 additions & 0 deletions shared-module/audiomp3/__init__.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2024 Jeff Epler for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <stdlib.h>
#include "py/mpconfig.h"
#include "py/misc.h"
#include "shared-module/audiomp3/__init__.h"

MP_WEAK void *mp3_alloc(size_t sz) {
return m_malloc_maybe(sz);
}

MP_WEAK void mp3_free(void *ptr) {
m_free(ptr);
}
8 changes: 5 additions & 3 deletions shared-module/audiomp3/__init__.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
* THE SOFTWARE.
*/

#ifndef MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H
#define MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H
#pragma once

#endif // MICROPY_INCLUDED_SHARED_MODULE_AUDIOMP3__INIT__H
#include <stdlib.h>

extern void *mp3_alloc(size_t sz);
extern void mp3_free(void *ptr);
4 changes: 2 additions & 2 deletions supervisor/background_callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ void background_callback_reset(void);
* bracket the section of code where this is the case. These calls nest, and
* begins must be balanced with ends.
*/
void background_callback_begin_critical_section(void);
void background_callback_end_critical_section(void);
void background_callback_prevent(void);
void background_callback_allow(void);

/*
* Background callbacks may stop objects from being collected
Expand Down
19 changes: 12 additions & 7 deletions supervisor/shared/background_callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,18 +76,19 @@ inline bool background_callback_pending(void) {
return callback_head != NULL;
}

static bool in_background_callback;
static int background_prevention_count;

void PLACE_IN_ITCM(background_callback_run_all)() {
port_background_task();
if (!background_callback_pending()) {
return;
}
CALLBACK_CRITICAL_BEGIN;
if (in_background_callback) {
if (background_prevention_count) {
CALLBACK_CRITICAL_END;
return;
}
in_background_callback = true;
++background_prevention_count;
background_callback_t *cb = (background_callback_t *)callback_head;
callback_head = NULL;
callback_tail = NULL;
Expand All @@ -104,15 +105,19 @@ void PLACE_IN_ITCM(background_callback_run_all)() {
CALLBACK_CRITICAL_BEGIN;
cb = next;
}
in_background_callback = false;
--background_prevention_count;
CALLBACK_CRITICAL_END;
}

void background_callback_begin_critical_section() {
void background_callback_prevent() {
CALLBACK_CRITICAL_BEGIN;
++background_prevention_count;
CALLBACK_CRITICAL_END;
}

void background_callback_end_critical_section() {
void background_callback_allow() {
CALLBACK_CRITICAL_BEGIN;
--background_prevention_count;
CALLBACK_CRITICAL_END;
}

Expand Down Expand Up @@ -146,7 +151,7 @@ void background_callback_reset() {
}
callback_head = new_head;
callback_tail = new_tail;
in_background_callback = false;
background_prevention_count = 0;
CALLBACK_CRITICAL_END;
}

Expand Down