wip: async flush
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 4m43s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 10s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 8s
Run pytests / Check-Pytest (push) Successful in 11s
All checks were successful
Build RPi Pico firmware image / Build-Firmware (push) Successful in 4m43s
Check code formatting / Check-C-Format (push) Successful in 7s
Check code formatting / Check-Python-Flake8 (push) Successful in 10s
Check code formatting / Check-Bash-Shellcheck (push) Successful in 5s
Run unit tests on host / Run-Unit-Tests (push) Successful in 8s
Run pytests / Check-Pytest (push) Successful in 11s
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
# Copyright (c) 2025 Matthias Blankertz <matthias@blankertz.org>
|
||||
|
||||
import _audiocore
|
||||
from asyncio import ThreadSafeFlag
|
||||
import asyncio
|
||||
from asyncio import Lock, ThreadSafeFlag
|
||||
from utils import get_pin_index
|
||||
|
||||
|
||||
@@ -11,20 +12,35 @@ class Audiocore:
|
||||
# PIO requires sideset pins to be adjacent
|
||||
assert get_pin_index(lrclk) == get_pin_index(dclk)+1 or get_pin_index(lrclk) == get_pin_index(dclk)-1
|
||||
self.notify = ThreadSafeFlag()
|
||||
self.audiocore_lock = Lock()
|
||||
self._audiocore = _audiocore.Audiocore(din, dclk, lrclk, self._interrupt)
|
||||
|
||||
def deinit(self):
|
||||
assert not self.audiocore_lock.locked()
|
||||
self._audiocore.deinit()
|
||||
|
||||
def _interrupt(self, _):
|
||||
self.notify.set()
|
||||
|
||||
def flush(self):
|
||||
assert not self.audiocore_lock.locked()
|
||||
self._audiocore.flush()
|
||||
|
||||
def set_volume(self, volume):
|
||||
async def async_flush(self):
|
||||
async with self.audiocore_lock:
|
||||
self._audiocore.flush(False)
|
||||
while True:
|
||||
if self._audiocore.get_async_result() is not None:
|
||||
return
|
||||
await self.notify.wait()
|
||||
|
||||
async def async_set_volume(self, volume):
|
||||
async with self.audiocore_lock:
|
||||
self._audiocore.set_volume(volume)
|
||||
|
||||
def set_volume(self, volume):
|
||||
asyncio.create_task(self.async_set_volume(volume))
|
||||
|
||||
def put(self, buffer, blocking=False):
|
||||
pos = 0
|
||||
while True:
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
// Include MicroPython API.
|
||||
#include "py/mperrno.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/persistentcode.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared/runtime/mpirq.h"
|
||||
|
||||
@@ -61,6 +63,20 @@ static uint32_t get_fifo_read_value_blocking(struct audiocore_obj *obj)
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_fifo_read_value(struct audiocore_obj *obj, uint32_t *result)
|
||||
{
|
||||
const long flags = save_and_disable_interrupts();
|
||||
const uint32_t value = obj->fifo_read_value;
|
||||
obj->fifo_read_value = 0;
|
||||
if (value & AUDIOCORE_FIFO_DATA_FLAG) {
|
||||
restore_interrupts(flags);
|
||||
*result = value & ~AUDIOCORE_FIFO_DATA_FLAG;
|
||||
return true;
|
||||
}
|
||||
restore_interrupts(flags);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* audiocore.Context.deinit(self)
|
||||
*
|
||||
@@ -125,15 +141,31 @@ static MP_DEFINE_CONST_FUN_OBJ_2(audiocore_put_obj, audiocore_put);
|
||||
* Tells the audiocore to stop playback as soon as all MP3 frames still in the buffer have been decoded.
|
||||
* This function blocks until playback has ended.
|
||||
*/
|
||||
static mp_obj_t audiocore_flush(mp_obj_t self_in)
|
||||
static mp_obj_t audiocore_flush(size_t n_args, const mp_obj_t *args)
|
||||
{
|
||||
struct audiocore_obj *self = MP_OBJ_TO_PTR(self_in);
|
||||
struct audiocore_obj *self = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_obj_t blocking = MP_ROM_TRUE;
|
||||
if (n_args == 2) {
|
||||
blocking = args[1];
|
||||
}
|
||||
multicore_fifo_push_blocking(AUDIOCORE_CMD_FLUSH);
|
||||
wake_core1();
|
||||
if (mp_obj_is_true(blocking))
|
||||
get_fifo_read_value_blocking(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(audiocore_flush_obj, audiocore_flush);
|
||||
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiocore_flush_obj, 1, 2, audiocore_flush);
|
||||
|
||||
static mp_obj_t audiocore_get_async_result(mp_obj_t self_in)
|
||||
{
|
||||
uint32_t result;
|
||||
struct audiocore_obj *self = MP_OBJ_TO_PTR(self_in);
|
||||
if (get_fifo_read_value(self, &result)) {
|
||||
return mp_obj_new_int(result);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
static MP_DEFINE_CONST_FUN_OBJ_1(audiocore_get_async_result_obj, audiocore_get_async_result);
|
||||
|
||||
/*
|
||||
* audiocore.set_volume(self, volume)
|
||||
@@ -240,6 +272,7 @@ static const mp_rom_map_elem_t audiocore_locals_dict_table[] = {
|
||||
{MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiocore_deinit_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_put), MP_ROM_PTR(&audiocore_put_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_flush), MP_ROM_PTR(&audiocore_flush_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_get_async_result), MP_ROM_PTR(&audiocore_get_async_result_obj)},
|
||||
{MP_ROM_QSTR(MP_QSTR_set_volume), MP_ROM_PTR(&audiocore_set_volume_obj)},
|
||||
};
|
||||
static MP_DEFINE_CONST_DICT(audiocore_locals_dict, audiocore_locals_dict_table);
|
||||
|
||||
@@ -74,7 +74,7 @@ class MP3Player:
|
||||
# Call onPlaybackDone after flush
|
||||
send_done = True
|
||||
finally:
|
||||
self.audiocore.flush()
|
||||
await self.audiocore.async_flush()
|
||||
if send_done:
|
||||
# Only call onPlaybackDone if exit due to end of stream
|
||||
# Use timer with time 0 to call callback "immediately" but from a different task
|
||||
|
||||
Reference in New Issue
Block a user