diff --git a/src/Backends/Audio/SoftwareMixer/Solaris.cpp b/src/Backends/Audio/SoftwareMixer/Solaris.cpp index 18e90149..5c95f1b0 100644 --- a/src/Backends/Audio/SoftwareMixer/Solaris.cpp +++ b/src/Backends/Audio/SoftwareMixer/Solaris.cpp @@ -17,33 +17,46 @@ #include #include -static const int samplesPerGo = 1600; -static const int parkSignal = SIGUSR1; -static pthread_t mainThread; +static const int bufferSize = 300; +static const int samplingRate = 8000; + +static int buffersWritten = 0; static int sndfp; static FILE* sndfile; static void (*parent_callback)(long *stream, size_t frames_total); -static bool audioDone = false; static inline void setUpSoundFrame(long *mix) { - memset(mix, 0, samplesPerGo * 2 * sizeof(long)); - parent_callback(mix, samplesPerGo); + memset(mix, 0, bufferSize * 2 * sizeof(long)); + parent_callback(mix, bufferSize); } -static inline void soundWait() { +static inline int soundWait() { + // Wait until at least one audio buffer has been played back. + // Return the number of audio buffers we have ever finished playing. + audio_info_t audioInfo; ioctl(sndfp, AUDIO_GETINFO, &audioInfo); - int playedBefore = audioInfo.play.samples; - int playedNow = audioInfo.play.samples; - while(playedNow - playedBefore < samplesPerGo) { - Backend_Delay(10); - ioctl(sndfp, AUDIO_GETINFO, &audioInfo); - playedNow = audioInfo.play.samples; + + // audioInfo.play.eof is the number of "end-of-file records" the sound chip + // has encountered. A "end-of-file record" is created by performing a + // write() of zero length. We end each audio buffer with one such write. + int previousEOF = audioInfo.play.eof; + + while(audioInfo.play.eof - previousEOF < 1) { + if(playedNow >= buffersWritten) { + Backend_PrintError("Audio overflow.\n"); + break; + } + + Backend_Delay(10); // Wait some reasonable time + + ioctl(sndfp, AUDIO_GETINFO, &audioInfo); // Get the new current EOF } + return playedNow; } static inline void feedOutSound(long* mix) { - for(int i = 0; i < samplesPerGo * 2; i++) { + for(int i = 0; i < bufferSize * 2; i++) { short sample = mix[i]; if(mix[i] > 0x7FFF) { sample = 0x7FFF; @@ -54,69 +67,64 @@ static inline void feedOutSound(long* mix) { fputc((sample >> 8) & 0xFF, sndfile); fputc(sample & 0xFF, sndfile); } + + // Write a "end-of-file record" here used as a end-of-buffer marker. The + // sound chip counts how many of these it has encountered and we can use + // that to tell how many sound buffers it's played. + write(sndfp, 0, 0); + fflush(sndfile); + + buffersWritten++; } -static void* soundcheckthread(void*) { - printf("Entered sound thread.\n"); - long mix[samplesPerGo * 2]; - setUpSoundFrame(mix); - feedOutSound(mix); - setUpSoundFrame(mix); - feedOutSound(mix); +static void* soundThread(void*) { + long mix[bufferSize * 2]; + Backend_PrintInfo("Entered sound thread.\n"); + while(1) { - - setUpSoundFrame(mix); - // Waiting for more to be needed - soundWait(); + int eofsPlayed = soundWait(); - feedOutSound(mix); + // Produce audio until we're three buffers ahead of playback + while(buffersWritten - eofsPlayed < 3) { + setUpSoundFrame(mix); + feedOutSound(mix); + } } } -static void threadPark(int signo) { - while(audioDone == false); -} - unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total)) { parent_callback = callback; - if(sndfp == -1) { + sndfile = fopen("/dev/audio", "wb"); + + if(sndfile == NULL) { Backend_PrintError("Failed to open audio device.\n"); return 0; } - sndfile = fopen("/dev/audio", "wb"); sndfp = fileno(sndfile); audio_info_t audioInfo; ioctl(sndfp, AUDIO_GETINFO, &audioInfo); audio_prinfo_t info = audioInfo.play; - info.sample_rate = 8000; + info.sample_rate = samplingRate; info.channels = 2; info.precision = 8; info.encoding = AUDIO_ENCODING_LINEAR; - info.port = AUDIO_SPEAKER | AUDIO_HEADPHONE; + info.port = AUDIO_HEADPHONE; info.gain = 128; audioInfo.play = info; ioctl(sndfp, AUDIO_SETINFO, &audioInfo); - //close(sndfp); - - if(signal(parkSignal, threadPark) == SIG_ERR) { - Backend_PrintError("Failed to register thread park signal handler for audio system.\n"); - return 0; - } - - mainThread = pthread_self(); pthread_t thread; pthread_attr_t thread_attr; pthread_attr_init(&thread_attr); - pthread_create(&thread, &thread_attr, soundcheckthread, (void*)NULL); + pthread_create(&thread, &thread_attr, soundThread, (void*)NULL); - return 8000; // return the sampling rate + return samplingRate; // Return the sampling rate } void SoftwareMixerBackend_Deinit(void) {