Skip to content

Commit

Permalink
Merge pull request #9218 from jepler/mp3-esp
Browse files Browse the repository at this point in the history
Enable mp3 output on esp32s3
  • Loading branch information
tannewt committed May 2, 2024
2 parents 8734076 + 8cbd9d9 commit 9ab8831
Show file tree
Hide file tree
Showing 16 changed files with 150 additions and 26 deletions.
2 changes: 1 addition & 1 deletion lib/mp3
5 changes: 4 additions & 1 deletion ports/espressif/Makefile
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
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
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
@@ -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
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 @@ -362,12 +364,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
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
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
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
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
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
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
@@ -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
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
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
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

0 comments on commit 9ab8831

Please sign in to comment.