Hi again,

after some debugging I found out that the playback was working out of the box
when the raspberry pi pico 2 port was added. After bisecting I have identified 2
commits that progressively broke the playback. The nature of changes in those
commits suggests that the problem is not platform specific.

The setup is:
config: raspberrypi-pico-2:spisd, no manual changes
board: raspberry pi pico 2 connected to an SD card with SPI.
I2S pins are monitored with an oscilloscope.

Goal: Play a 41kHz, 16-bit, stereo WAV file using nxplayer.
nsh> nxplayer
nxplayer> play /mnt/sd0/test.wav

I have not been exposed to NuttX audio stack (or any other audio stack) before
investigating this issue, so please bear that in mind if you find my
interpretation incorrect.

Both breaking commits arrived with the "audio: upper half enhancement" PR merged
on Feb 5.
https://github.com/apache/nuttx/pull/18348

The first breaking change comes from two commits (the first one contains the
breaking code, but cannot be built therefore tested)

commit d85c4db9321255555089f2a14354617d4a32aa44 (first testable breaking)
Author: yangyalei <[email protected]>
Date:   Wed Jun 11 16:42:50 2025 +0800

    nuttx/audio: Add Hardware pointer
    
    Add Hw pointer recored apb buffer read/write position
    
    Signed-off-by: yangyalei <[email protected]>

commit 2cc624a4c4332aeadb59491f5e07a95944cbf74d (breaking but error building)
Author: yangyalei <[email protected]>
Date:   Fri May 30 11:12:21 2025 +0800

    nuttx/audio: add AUDIOIOC_GETSTATE ioctl
    
    support get lower driver state
    
    Signed-off-by: yangyalei <[email protected]>

=====

Symptoms: When nxplayer prompted "nxplayer> play /mnt/sd0/test.wav" to play the
file, nothing happens.

Diagnosis:
The problem stems from changing the way audio upper driver is handling its
internal status and nxplayer not handling wav files properly.
Before the change the audio driver allowed for AUDIOIOC_START ioctl to
successfully proceed without prior calling of the AUDIOIOC_CONFIGURE with
audio_caps_s caps->ac_type set to AUDIO_TYPE_INPUT or AUDIO_TYPE_OUTPUT.

In nxplayer there is no pre_parse (header parsing function) function for wav
files because the header decoding is deferred to pcm_decode (audio lower) by the
audio upper. In other words it is solved by the OS.
After decoding the header (if applicable), there is a condition for calling the
AUDIOIOC_CONFIGURE ioctl:
if (nchannels && samprate && bpsamp)
  {
    ...
    ioctl(pplayer->dev_fd, AUDIOIOC_CONFIGURE, (unsigned long)&cap_desc);
  }

But since nchannels, samprate and bpsamp are zero since no pre_parse was called,
the ioctl doesn't get called.
The AUDIOIOC_START then gets blocked by the new audio driver status logic.

Treatment:
First solution that comes to mind is fixing nxplayer so that it always calls the
AUDIOIOC_CONFIGURE ioctl before playing. Even when nchannels, samprate, bpsamp
are not available, the pcm_decode driver should fill that for us in its
pcm_enqueuebuffer routine.
In fact this is what happens when

nxplayer> playraw /mnt/sd0/test.wav

is invoked. When playraw is not supplied with nchannels, bpsamp, and samprate
arguments (in the app prompt) it fills in some defaults and therefore the
AUDIOIOC_CONFIGURE ioctl is called later. (The defaults are then overridden by
the pcm_decode according to the wav header anyway).

This problem with the "play" command might have slipped the author(s) of the
changes because in the PR, they claim to have tested using the "playraw"
command.

===== end of the first breaking change =====

The second breaking change comes with the following commit:

commit b13defe9e4edbb39331b8bc5637e86e314a4300d
Author: fangyibo <[email protected]>
Date:   Thu Nov 20 17:04:29 2025 +0800

    nuttx/audio: ALLOCATE_BUFFER & BUFFERINFO support multiple calling
    
    support multiple applications simultaneously calling ALLOCATE_BUFFER
    
    Signed-off-by: fangyibo <[email protected]>

Symptoms: Same as before + workaround with playraw does not work either. When
compiled with audio debug features. nxplayer_playtrhead spits out (among other
messages) "Unable to allocate buffer" or something like that.

Diagnosis:
What I see this commit do is adding functionality to enforce maximum number of
allocated buffers. This is done by adding

  uint8_t nbuffers; /* Max ap buffers number */

into the driver struct and adding enforcing logic. Especially the guard

  if (upper->periods >= upper->nbuffers)
    {
      return 0;  // zero return here means unsuccessful operation(Michal's note)
    }

in audio_allocbuffer function that handles AUDIOIOC_ALLOCBUFFER.

The upper->nbuffers is the newly added nbuffers. In order for the allocation to
be possible upper->nbuffers needs to be set to some non zero value. This is done
(solely) by a newly added "middle handler" for the AUDIOIOC_GETBUFFERINFO ioctl:

  case AUDIOIOC_GETBUFFERINFO:
    {
      audinfo("AUDIOIOC_GETBUFFERINFO\n");

      ret = lower->ops->ioctl(lower, AUDIOIOC_GETBUFFERINFO, arg);
      if (ret >= 0)
        {
          upper->nbuffers =
              ((FAR struct ap_buffer_info_s *)arg)->nbuffers;
        }
    }
    break;

Therefore the AUDIOIOC_GETBUFFERINFO ioctl is now mandatory for the lower layer
drivers. Without that audio buffers can't be allocated.

Down in the chain of drivers of my setup (that is)
- audio.c
 - pcm_decode.c
  - audio_i2s.c
   - rp23xx_i2s.c

Non of the drivers below the audio.c has this ioctl implemented.

Solution?:
I solved this by implementing the AUDIOIOC_GETBUFFERINFO ioctl in rp23xx_i2s.c
returning values for CONFIG_AUDIO_BUFFER_NUMBYTES and CONFIG_AUDIO_NUM_BUFFERS.

Is this the right solution? Maybe the defaults should be put directly into
audio.c?

What do you think?

Kind Regards
Michal

On Thu, 2026-07-30 at 04:28 +0200, [email protected] wrote:
> Hi,
> 
> as part of a side project I've been trying to play a wav file from an SD card
> out of Raspberry Pi Pico 2 over I2S. SD is successfully mounted and I2S is
> registered under /dev/audio/pcm0. But unfortunately when using nxplayer with 
> the
> sound file (44.1K, 16 bit stereo WAV), pins allocated for I2S are still (no
> clock, no data, no sign of activity). The configuration used is raspberrypi-
> pico-2:spisd as it closely resembles the raspberrypi-pico:audiopack config 
> that
> seems to be meant to support sound. However, the situation with the latter
> config and with the RPi Pico (RP2040) results in the same behavior.
> 
> Debugging sessions so far led me to the nxplayer_playthread not being able to
> allocate audio buffer with ALLOCBUFFER ioctl.
> 
> Is someone working with RPi Pico and sound? Am I missing some important 
> detail?
> Please let me know.
> 
> Kind Regards
> Michal

Reply via email to