On Tuesday, July 1, 2003, at 03:34 PM, Dave wrote:
Hi I've Successfully compiled madplay and it's libs for the Zaurus. Everything works. I used the following options for configure:
[...]
The playback sounds great. The only problem I've got is occasionally "skipping" which I'm assuming are some sort of buffering problem. The skips only occur when I run other apps while playing an MP3. They occur more often if the MP3 file is stored on an SD card or fetched from an SMB mounted file system.
I haven't yet taken a good look at how madplay reads and buffers the data. I originally built it with mmap. After thinking about it - if my understanding of mmap is correct - it makes little sense on a device like the Zaurus. I rebuilt madplay without mmap (is the correct way to do this to edit config.h ?) and the skipping remains. So it seems that mmap had little effect.
FYI, the madplay package also has an option --disable-mmap for 'configure'.
If mmap works on the Zaurus - when it's enabled madplay will request to have the full MP3 file "mapped" into memory to avoid disk reads while playing it (is this correct?). On the Zaurus, the MP3 will already be stored in memory, and mmap would just copy it from one chunk of memory to another. Perhaps this would save the time it take to execute the filesystem code but it would chew up memory on a limited device.
Generally mmap should use less memory than the alternative. That's because the OS can map the memory directly from its source, whether a disk buffer or a filesystem stored in flash memory, and share it with multiple processes rather than having each process read its own copy into private buffers.
With a good OS, mapping a file into memory doesn't cause the entire file to be read at once. Memory pages are read from the file and mapped into the process only as they are accessed, and they can also be released automatically by the OS as needed.
Buffering - I don't know how the buffering in madplay works. I assume that buffering would be better for the Zaurus. Is madplay meant to be a robust generic MP3 player or is just to demonstrate how to use libmad?
Yes, madplay is intended to be a robust command-line MP3 player.
There are currently two buffering possibilities in madplay: either a file is mapped into memory via mmap(), in which case madplay does no buffering and it relies on the OS to provide transparent memory access to the entire file, or a file/pipe is read into a buffer via traditional read(), in which case the buffer is replenished each time libmad indicates it needs more data to decode the next frame of audio.
In the latter case, madplay's current buffer size is 40000 bytes, which is large enough to contain 2.5 seconds of encoded audio at 128 kbps, or 1 second at 320 kbps. You could try experimenting with other buffer sizes (see MPEG_BUFSZ in player.c), but I suspect your problem has more to do with the latency between the last output sample madplay writes to the audio device and the time required for the OS to load and/or map the next segment of input data (whether via mmap or otherwise).
Finally, are there any other config options I should try? I'm not familiar with the ARM family of processors - I've noticed other posts that specify a specific arm chip in the config options. How about other options for libmad/madplay? Is there a way to get configure to tell you the full list of options? I tried --help but people here are mentioning options that aren't shown.
There probably aren't many 'configure' options to help you. (And in any case, 'configure --help' *should* list every available option; make sure they haven't scrolled off your screen.)
A larger kernel audio buffer might be one solution, if you can even change that. Another possibility is to somehow pre-cache the input data into memory. Sometimes tricks such as:
cat $file >/dev/null & madplay $file
will work, but perhaps not well on a handheld. Another possibility is:
cat $file | madplay -
which will involve a second process to read the data, hopefully in time for madplay to avoid an audio underrun.
I'm open to better buffering suggestions, but most of my ideas revolve around an auxiliary thread either to pre-fetch data or to more generally split up the decoding process between reading and writing data.
Cheers,