Stability issues with Audio library for Due (DMA issue perhaps?)

Hello Arduino-land. Long-time listener, first-time caller.

I am experiencing stability issue with the Arduino Due Audio library, and am curious whether anyone else has encountered this particular issue. I am aware of the issue where there’s a problem repeating a file if you don’t call Audio.end().

The issue I’m having has to do with the Arduino completely locking up when stopping playback of a file. The issue only happens intermittently - maybe one time in 50. I’ve pasted code below. I basically took the example code and unwrapped it a bit so that it doesn’t block the loop() code, and added provision for starting and stopping file playback.

I am able to play a file, and stop playback to either play a new file or restart the current file, but a small percentage of the time, the Arduino completely locks up.

At first I suspected a file system issue, but if I disable all the Audio.xxx calls using a #define (while keeping all the file system calls), the problem goes away. This is why I suspect the issue lies with the Audio library or some interaction with it.

Looking at the Audio library code, I thought perhaps the problem is caused by by heap fragmentation, because Audio.begin() calls malloc() and Audio.end() calls free, so I tried changing the library code to use a statically allocated buffer instead, and that didn’t change the behavior either.

The Audio library uses DMA to shovel data to the DAC, and I wonder if there’s some timing criticality there - perhaps the halting of file playback occasionally occurs at a bad time with the asynchronous DMA stuff happening in the background.

I made a similar project using the Adafruit Wave shield and did not encounter this issue, but the Wave library gives you functions for halting playback. Here I was forced to roll my own, and I suspect that’s where my problem lies.

Any tips would be greatly appreciated.

#define	ENABLE_AUDIO_CALLS	1

/* audio player and file management */
File current_file;
void stop_playing_and_close_current_file(void)
{
	if (current_file) 
	{
		Serial.print("closing the file ");
		Serial.println(current_file.name());
		current_file.close(); 
	}
	Serial.println("finished playing.");
	#if ENABLE_AUDIO_CALLS
		Audio.end();
	#endif
}

int play_audio_file(const char * filename)
{
	if (current_file)
	{
		Serial.println("paf: canceled current file");
		stop_playing_and_close_current_file();
	}

	// open wave file from sdcard
	current_file = SD.open(filename);
	if (!current_file) 
	{
		// if the file didn't open, print an error and stop
		Serial.print("error opening file ");
		Serial.println(filename);
		return 1;
	}
	Serial.print("opened the file ");
	Serial.println(filename);
	#if ENABLE_AUDIO_CALLS
		Audio.begin(88200, 100);
	#endif
	Serial.print("Playing ");
	Serial.println(filename);
	return 0;
}

void service_audio(void)
{
	int count = 0;
	const int S = 1024; // Number of samples to read in block
	short buffer[S];


	if (!current_file)
	{
		return;
	}

	if (current_file.available()) 
	{
		// read from the file into buffer
		current_file.read(buffer, sizeof(buffer));

		// Prepare samples
		int volume = 1024;
		#if ENABLE_AUDIO_CALLS
			Audio.prepare(buffer, S, volume);
			Audio.write(buffer, S);
		#endif

		// Every 100 block print a '.'
		count++;
		if (count == 100) 
		{
			Serial.print(".");
			count = 0;
		}
	}
	else
	{
		stop_playing_and_close_current_file();
	}
}

Well, I was away over the long weekend, and for grins when I got back I added a synchronization wrapper around the audio player. In the polled routine called by loop(), I added a few flags so that: if I want to cancel playback, the next time the audio player wants to read from the file system, it instead closes the file and then waits ~100 mSec before calling Audio.end(). This allows the DAC code to finish up with its DMA process before dac.end() gets called.

I've also noticed that this library is super touchy about what files it sees. I'm generating all 44.1 kHz 16 bit stereo files, but the ones created by Audacity cause the player to blow up after playback, but ones created in Logic are OK. I am guessing that Audacity generates metadata this audio library doesn't like, but I haven't had an opportunity to dig further.

Audacity only generates meta data when you give it some. Just leave that pop up window blank and you get no meta data.