]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - snd_coreaudio.c
Add an in_releaseall command for debugging/working around stuck keys.
[xonotic/darkplaces.git] / snd_coreaudio.c
index cc5339910cabaa9b5130f7ecddee3ceb04b43566..ce8fff5bcf7d02073d025d78cc6b9bb20c929f9d 100644 (file)
@@ -20,12 +20,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 ===========================================================================
 */
 
+#include "quakedef.h"
+
 #include <limits.h>
 #include <pthread.h>
 
 #include <CoreAudio/AudioHardware.h>
 
-#include "quakedef.h"
 #include "snd_main.h"
 
 
@@ -36,6 +37,7 @@ static unsigned int coreaudiotime = 0;  // based on the number of chunks submitt
 static qboolean s_isRunning = false;
 static pthread_mutex_t coreaudio_mutex;
 static AudioDeviceID outputDeviceID = kAudioDeviceUnknown;
+static short *mixbuffer = NULL;
 
 
 /*
@@ -52,19 +54,32 @@ static OSStatus audioDeviceIOProc(AudioDeviceID inDevice,
                                                                  void *inClientData)
 {
        float *outBuffer;
-       unsigned int frameCount, factor;
+       unsigned int frameCount, factor, sampleIndex;
+       float scale = 1.0f / SHRT_MAX;
 
        outBuffer = (float*)outOutputData->mBuffers[0].mData;
        factor = snd_renderbuffer->format.channels * snd_renderbuffer->format.width;
        frameCount = 0;
+       if (snd_blocked)
+               scale = 0;
 
        // Lock the snd_renderbuffer
        if (SndSys_LockRenderBuffer())
        {
-               unsigned int maxFrames, sampleIndex, sampleCount;
+               unsigned int maxFrames, sampleCount;
                unsigned int startOffset, endOffset;
                const short *samples;
-               const float scale = 1.0f / SHRT_MAX;
+
+               if (snd_usethreadedmixing)
+               {
+                       S_MixToBuffer(mixbuffer, submissionChunk);
+                       sampleCount = submissionChunk * snd_renderbuffer->format.channels;
+                       for (sampleIndex = 0; sampleIndex < sampleCount; sampleIndex++)
+                               outBuffer[sampleIndex] = mixbuffer[sampleIndex] * scale;
+                       // unlock the mutex now
+                       SndSys_UnlockRenderBuffer();
+                       return 0;
+               }
 
                // Transfert up to a chunk of sample frames from snd_renderbuffer to outBuffer
                maxFrames = snd_renderbuffer->endframe - snd_renderbuffer->startframe;
@@ -99,7 +114,7 @@ static OSStatus audioDeviceIOProc(AudioDeviceID inDevice,
 
                snd_renderbuffer->startframe += frameCount;
 
-               // Unlock the snd_renderbuffer
+               // unlock the mutex now
                SndSys_UnlockRenderBuffer();
        }
 
@@ -109,8 +124,8 @@ static OSStatus audioDeviceIOProc(AudioDeviceID inDevice,
                unsigned int missingFrames;
 
                missingFrames = submissionChunk - frameCount;
-               if (developer.integer >= 1000 && vid_activewindow)
-                       Con_Printf("audioDeviceIOProc: %u sample frames missing\n", missingFrames);
+               if (developer_insane.integer && vid_activewindow)
+                       Con_DPrintf("audioDeviceIOProc: %u sample frames missing\n", missingFrames);
                memset(&outBuffer[frameCount * snd_renderbuffer->format.channels], 0, missingFrames * sizeof(outBuffer[0]));
        }
 
@@ -137,13 +152,14 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested)
                return true;
 
        Con_Printf("Initializing CoreAudio...\n");
+       snd_threaded = false;
 
        if(requested->width != 2)
        {
                // we can only do 16bit per sample for now
                if(suggested != NULL)
                {
-                       memcpy (suggested, requested, sizeof (suggested));
+                       memcpy (suggested, requested, sizeof (*suggested));
                        suggested->width = 2;
                }
                return false;
@@ -154,7 +170,7 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested)
        status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propertySize, &outputDeviceID);
        if (status)
        {
-               Con_Printf("CoreAudio: AudioDeviceGetProperty() returned %d when getting kAudioHardwarePropertyDefaultOutputDevice\n", status);
+               Con_Printf("CoreAudio: AudioDeviceGetProperty() returned %d when getting kAudioHardwarePropertyDefaultOutputDevice\n", (int)status);
                return false;
        }
        if (outputDeviceID == kAudioDeviceUnknown)
@@ -169,7 +185,7 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested)
        status = AudioDeviceSetProperty(outputDeviceID, NULL, 0, false, kAudioDevicePropertyBufferSize, propertySize, &bufferByteCount);
        if (status)
        {
-               Con_Printf("CoreAudio: AudioDeviceSetProperty() returned %d when setting kAudioDevicePropertyBufferSize to %d\n", status, CHUNK_SIZE);
+               Con_Printf("CoreAudio: AudioDeviceSetProperty() returned %d when setting kAudioDevicePropertyBufferSize to %d\n", (int)status, CHUNK_SIZE);
                return false;
        }
 
@@ -177,7 +193,7 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested)
        status = AudioDeviceGetProperty(outputDeviceID, 0, false, kAudioDevicePropertyBufferSize, &propertySize, &bufferByteCount);
        if (status)
        {
-               Con_Printf("CoreAudio: AudioDeviceGetProperty() returned %d when setting kAudioDevicePropertyBufferSize\n", status);
+               Con_Printf("CoreAudio: AudioDeviceGetProperty() returned %d when setting kAudioDevicePropertyBufferSize\n", (int)status);
                return false;
        }
 
@@ -188,81 +204,90 @@ qboolean SndSys_Init (const snd_format_t* requested, snd_format_t* suggested)
                return false;
        }
        submissionChunk /= requested->channels;
-       Con_DPrintf("   Chunk size = %d sample frames\n", submissionChunk);
+       Con_Printf("   Chunk size = %d sample frames\n", submissionChunk);
 
        // Print out the device status
        propertySize = sizeof(streamDesc);
        status = AudioDeviceGetProperty(outputDeviceID, 0, false, kAudioDevicePropertyStreamFormat, &propertySize, &streamDesc);
        if (status)
        {
-               Con_Printf("CoreAudio: AudioDeviceGetProperty() returned %d when getting kAudioDevicePropertyStreamFormat\n", status);
+               Con_Printf("CoreAudio: AudioDeviceGetProperty() returned %d when getting kAudioDevicePropertyStreamFormat\n", (int)status);
                return false;
        }
 
-       Con_DPrint ("   Hardware format:\n");
-       Con_DPrintf("    %5d mSampleRate\n", (unsigned int)streamDesc.mSampleRate);
-       Con_DPrintf("     %c%c%c%c mFormatID\n",
-                               (streamDesc.mFormatID & 0xff000000) >> 24,
-                               (streamDesc.mFormatID & 0x00ff0000) >> 16,
-                               (streamDesc.mFormatID & 0x0000ff00) >>  8,
-                               (streamDesc.mFormatID & 0x000000ff) >>  0);
-       Con_DPrintf("    %5d mBytesPerPacket\n", streamDesc.mBytesPerPacket);
-       Con_DPrintf("    %5d mFramesPerPacket\n", streamDesc.mFramesPerPacket);
-       Con_DPrintf("    %5d mBytesPerFrame\n", streamDesc.mBytesPerFrame);
-       Con_DPrintf("    %5d mChannelsPerFrame\n", streamDesc.mChannelsPerFrame);
-       Con_DPrintf("    %5d mBitsPerChannel\n", streamDesc.mBitsPerChannel);
+       Con_Print ("   Hardware format:\n");
+       Con_Printf("    %5d mSampleRate\n", (unsigned int)streamDesc.mSampleRate);
+       Con_Printf("     %c%c%c%c mFormatID\n",
+                               (char)(streamDesc.mFormatID >> 24),
+                               (char)(streamDesc.mFormatID >> 16),
+                               (char)(streamDesc.mFormatID >>  8),
+                               (char)(streamDesc.mFormatID >>  0));
+       Con_Printf("    %5u mBytesPerPacket\n", (unsigned int)streamDesc.mBytesPerPacket);
+       Con_Printf("    %5u mFramesPerPacket\n", (unsigned int)streamDesc.mFramesPerPacket);
+       Con_Printf("    %5u mBytesPerFrame\n", (unsigned int)streamDesc.mBytesPerFrame);
+       Con_Printf("    %5u mChannelsPerFrame\n", (unsigned int)streamDesc.mChannelsPerFrame);
+       Con_Printf("    %5u mBitsPerChannel\n", (unsigned int)streamDesc.mBitsPerChannel);
 
        // Suggest proper settings if they differ
        if (requested->channels != streamDesc.mChannelsPerFrame || requested->speed != streamDesc.mSampleRate)
        {
                if (suggested != NULL)
                {
-                       memcpy (suggested, requested, sizeof (suggested));
+                       memcpy (suggested, requested, sizeof (*suggested));
                        suggested->channels = streamDesc.mChannelsPerFrame;
                        suggested->speed = streamDesc.mSampleRate;
                }
                return false;
        }
 
-       if(streamDesc.mFormatID != kAudioFormatLinearPCM)
-       {
-               Con_Print("CoreAudio: Default audio device doesn't support linear PCM!\n");
-               return false;
-       }
-
-       // Add the callback function
-       status = AudioDeviceAddIOProc(outputDeviceID, audioDeviceIOProc, NULL);
-       if (status)
-       {
-               Con_Printf("CoreAudio: AudioDeviceAddIOProc() returned %d\n", status);
-               return false;
-       }
-
-       // We haven't sent any sample frames yet
-       coreaudiotime = 0;
-
-       if (pthread_mutex_init(&coreaudio_mutex, NULL) != 0)
+       if(streamDesc.mFormatID == kAudioFormatLinearPCM)
        {
-               Con_Print("CoreAudio: can't create pthread mutex\n");
-               AudioDeviceRemoveIOProc(outputDeviceID, audioDeviceIOProc);
-               return false;
-       }
-
-       snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL);
-
-       // Start sound running
-       status = AudioDeviceStart(outputDeviceID, audioDeviceIOProc);
-       if (status)
-       {
-               Con_Printf("CoreAudio: AudioDeviceStart() returned %d\n", status);
-               pthread_mutex_destroy(&coreaudio_mutex);
-               AudioDeviceRemoveIOProc(outputDeviceID, audioDeviceIOProc);
-               return false;
+               // Add the callback function
+               status = AudioDeviceAddIOProc(outputDeviceID, audioDeviceIOProc, NULL);
+               if (!status)
+               {
+                       // We haven't sent any sample frames yet
+                       coreaudiotime = 0;
+                       if (pthread_mutex_init(&coreaudio_mutex, NULL) == 0)
+                       {
+                               if ((snd_renderbuffer = Snd_CreateRingBuffer(requested, 0, NULL)))
+                               {
+                                       if ((mixbuffer = Mem_Alloc(snd_mempool, CHUNK_SIZE * sizeof(*mixbuffer) * requested->channels)))
+                                       {
+                                               // Start sound running
+                                               status = AudioDeviceStart(outputDeviceID, audioDeviceIOProc);
+                                               if (!status)
+                                               {
+                                                       s_isRunning = true;
+                                                       snd_threaded = true;
+                                                       Con_Print("   Initialization successful\n");
+                                                       return true;
+                                               }
+                                               else
+                                                       Con_Printf("CoreAudio: AudioDeviceStart() returned %d\n", (int)status);
+                                               Mem_Free(mixbuffer);
+                                               mixbuffer = NULL;
+                                       }
+                                       else
+                                               Con_Print("CoreAudio: can't allocate memory for mixbuffer\n");
+                                       Mem_Free(snd_renderbuffer->ring);
+                                       Mem_Free(snd_renderbuffer);
+                                       snd_renderbuffer = NULL;
+                               }
+                               else
+                                       Con_Print("CoreAudio: can't allocate memory for ringbuffer\n");
+                               pthread_mutex_destroy(&coreaudio_mutex);
+                       }
+                       else
+                               Con_Print("CoreAudio: can't create pthread mutex\n");
+                       AudioDeviceRemoveIOProc(outputDeviceID, audioDeviceIOProc);
+               }
+               else
+                       Con_Printf("CoreAudio: AudioDeviceAddIOProc() returned %d\n", (int)status);
        }
-       s_isRunning = true;
-
-       Con_Print("   Initialization successful\n");
-       return true;
+       else
+               Con_Print("CoreAudio: Default audio device doesn't support linear PCM!\n");
+       return false;
 }
 
 
@@ -283,7 +308,7 @@ void SndSys_Shutdown(void)
        status = AudioDeviceStop(outputDeviceID, audioDeviceIOProc);
        if (status)
        {
-               Con_Printf("AudioDeviceStop: returned %d\n", status);
+               Con_Printf("AudioDeviceStop: returned %d\n", (int)status);
                return;
        }
        s_isRunning = false;
@@ -293,7 +318,7 @@ void SndSys_Shutdown(void)
        status = AudioDeviceRemoveIOProc(outputDeviceID, audioDeviceIOProc);
        if (status)
        {
-               Con_Printf("AudioDeviceRemoveIOProc: returned %d\n", status);
+               Con_Printf("AudioDeviceRemoveIOProc: returned %d\n", (int)status);
                return;
        }
 
@@ -303,6 +328,10 @@ void SndSys_Shutdown(void)
                Mem_Free(snd_renderbuffer);
                snd_renderbuffer = NULL;
        }
+
+       if (mixbuffer != NULL)
+               Mem_Free(mixbuffer);
+       mixbuffer = NULL;
 }
 
 
@@ -354,5 +383,17 @@ Release the exclusive lock on "snd_renderbuffer"
 */
 void SndSys_UnlockRenderBuffer (void)
 {
-    pthread_mutex_unlock(&coreaudio_mutex);
+       pthread_mutex_unlock(&coreaudio_mutex);
+}
+
+/*
+====================
+SndSys_SendKeyEvents
+
+Send keyboard events originating from the sound system (e.g. MIDI)
+====================
+*/
+void SndSys_SendKeyEvents(void)
+{
+       // not supported
 }