]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - snd_alsa.c
some work on SV_TestEntityPosition and entity unsticking, now only checks against...
[xonotic/darkplaces.git] / snd_alsa.c
index 0aa875282447891245caa476f1a0d304a3b607f3..03c713bf95ee085d43463b6afec4dccf93311462 100644 (file)
@@ -29,9 +29,8 @@
 #include <alsa/asoundlib.h>
 
 #include "quakedef.h"
+#include "snd_main.h"
 
-static int                     snd_inited;
-static int                     snd_blocked = 0;
 static snd_pcm_uframes_t buffer_size;
 
 static const char  *pcmname = NULL;
@@ -39,232 +38,176 @@ static snd_pcm_t   *pcm;
 
 qboolean SNDDMA_Init (void)
 {
-       int                                      err, i;
-       int                                      bps = -1, stereo = -1;
-       unsigned int             rate = 0;
+       int                                     err, i, j;
+       int                                     width;
+       int                                     channels;
+       unsigned int            rate;
        snd_pcm_hw_params_t     *hw;
        snd_pcm_sw_params_t     *sw;
-       snd_pcm_uframes_t        frag_size;
+       snd_pcm_uframes_t       frag_size;
 
        snd_pcm_hw_params_alloca (&hw);
        snd_pcm_sw_params_alloca (&sw);
 
-// COMMANDLINEOPTION: -sndpcm <devicename> selects which pcm device to us, default is "default" (ALSA sound driver only)
-       if ((i=COM_CheckParm("-sndpcm"))!=0)
-               pcmname=com_argv[i+1];
-       if (!pcmname)
-               pcmname = "default";
-
-// COMMANDLINEOPTION: -sndbits <number> sets sound precision to 8 or 16 bit (email me if you want others added)
+// COMMANDLINEOPTION: Linux ALSA Sound: -sndbits <number> sets sound precision to 8 or 16 bit (email me if you want others added)
+       width = 2;
        if ((i=COM_CheckParm("-sndbits")) != 0)
        {
-               bps = atoi(com_argv[i+1]);
-               if (bps != 16 && bps != 8)
-               {
-                       Con_Printf("Error: invalid sample bits: %d\n", bps);
-                       return false;
-               }
+               j = atoi(com_argv[i+1]);
+               if (j == 16 || j == 8)
+                       width = j / 8;
+               else
+                       Con_Printf("Error: invalid sample bits: %d\n", j);
        }
 
-// COMMANDLINEOPTION: -sndspeed <hz> chooses 44100 hz, 22100 hz, or 11025 hz sound output rate
+// COMMANDLINEOPTION: Linux ALSA Sound: -sndspeed <hz> chooses 44100 hz, 22100 hz, or 11025 hz sound output rate
+       rate = 44100;
        if ((i=COM_CheckParm("-sndspeed")) != 0)
        {
-               rate = atoi(com_argv[i+1]);
-               if (rate!=44100 && rate!=22050 && rate!=11025)
-               {
+               j = atoi(com_argv[i+1]);
+               if (j >= 1)
+                       rate = j;
+               else
                        Con_Printf("Error: invalid sample rate: %d\n", rate);
-                       return false;
-               }
-       }
-
-// COMMANDLINEOPTION: -sndmono sets sound output to mono
-       if ((i=COM_CheckParm("-sndmono")) != 0)
-               stereo=0;
-// COMMANDLINEOPTION: -sndstereo sets sound output to stereo
-       if ((i=COM_CheckParm("-sndstereo")) != 0)
-               stereo=1;
-
-       err = snd_pcm_open (&pcm, pcmname, SND_PCM_STREAM_PLAYBACK,
-                                                 SND_PCM_NONBLOCK);
-       if (0 > err) {
-               Sys_Printf ("Error: audio open error: %s\n", snd_strerror (err));
-               return 0;
        }
-       Sys_Printf ("ALSA: Using PCM %s.\n", pcmname);
 
-       err = snd_pcm_hw_params_any (pcm, hw);
-       if (0 > err) {
-               Sys_Printf ("ALSA: error setting hw_params_any. %s\n",
-                                       snd_strerror (err));
-               goto error;
-       }
-
-       err = snd_pcm_hw_params_set_access (pcm, hw,
-                                                                                 SND_PCM_ACCESS_MMAP_INTERLEAVED);
-       if (0 > err) {
-               Sys_Printf ("ALSA: Failure to set noninterleaved PCM access. %s\n"
-                                       "Note: Interleaved is not supported\n",
-                                       snd_strerror (err));
-               goto error;
-       }
+       for (channels = 8;channels >= 1;channels--)
+       {
+               if ((channels & 1) && channels != 1)
+                       continue;
+// COMMANDLINEOPTION: Linux ALSA Sound: -sndmono sets sound output to mono
+               if ((i=COM_CheckParm("-sndmono")) != 0)
+                       if (channels != 1)
+                               continue;
+// COMMANDLINEOPTION: Linux ALSA Sound: -sndstereo sets sound output to stereo
+               if ((i=COM_CheckParm("-sndstereo")) != 0)
+                       if (channels != 2)
+                               continue;
+
+// COMMANDLINEOPTION: Linux ALSA Sound: -sndpcm <devicename> selects which pcm device to us, default is "default"
+               if (channels == 8)
+                       pcmname = "surround71";
+               else if (channels == 6)
+                       pcmname = "surround51";
+               else if (channels == 4)
+                       pcmname = "surround40";
+               else
+                       pcmname = "default";
+               if ((i=COM_CheckParm("-sndpcm"))!=0)
+                       pcmname = com_argv[i+1];
+
+               Con_Printf ("ALSA: Trying PCM %s.\n", pcmname);
+
+               err = snd_pcm_open (&pcm, pcmname, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+               if (0 > err)
+               {
+                       Con_Printf ("Error: audio open error: %s\n", snd_strerror (err));
+                       continue;
+               }
 
-       switch (bps) {
-               case -1:
-                       err = snd_pcm_hw_params_set_format (pcm, hw,
-                                                                                                 SND_PCM_FORMAT_S16);
-                       if (0 <= err) {
-                               bps = 16;
-                       } else if (0 <= (err = snd_pcm_hw_params_set_format (pcm, hw,
-                                                                                                                SND_PCM_FORMAT_U8))) {
-                               bps = 8;
-                       } else {
-                               Sys_Printf ("ALSA: no useable formats. %s\n",
-                                                       snd_strerror (err));
-                               goto error;
-                       }
-                       break;
-               case 8:
-               case 16:
-                       err = snd_pcm_hw_params_set_format (pcm, hw, bps == 8 ?
-                                                                                                 SND_PCM_FORMAT_U8 :
-                                                                                                 SND_PCM_FORMAT_S16);
-                       if (0 > err) {
-                               Sys_Printf ("ALSA: no usable formats. %s\n",
-                                                       snd_strerror (err));
-                               goto error;
-                       }
-                       break;
-               default:
-                       Sys_Printf ("ALSA: desired format not supported\n");
-                       goto error;
-       }
+               err = snd_pcm_hw_params_any (pcm, hw);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: error setting hw_params_any. %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
 
-       switch (stereo) {
-               case -1:
-                       err = snd_pcm_hw_params_set_channels (pcm, hw, 2);
-                       if (0 <= err) {
-                               stereo = 1;
-                       } else if (0 <= (err = snd_pcm_hw_params_set_channels (pcm, hw,
-                                                                                                                                        1))) {
-                               stereo = 0;
-                       } else {
-                               Sys_Printf ("ALSA: no usable channels. %s\n",
-                                                       snd_strerror (err));
-                               goto error;
-                       }
-                       break;
-               case 0:
-               case 1:
-                       err = snd_pcm_hw_params_set_channels (pcm, hw, stereo ? 2 : 1);
-                       if (0 > err) {
-                               Sys_Printf ("ALSA: no usable channels. %s\n",
-                                                       snd_strerror (err));
-                               goto error;
-                       }
-                       break;
-               default:
-                       Sys_Printf ("ALSA: desired channels not supported\n");
-                       goto error;
-       }
+               err = snd_pcm_hw_params_set_access (pcm, hw, SND_PCM_ACCESS_MMAP_INTERLEAVED);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: Failure to set interleaved mmap PCM access. %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
 
-       switch (rate) {
-               case 0:
-                       rate = 44100;
-                       err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, 0);
-                       if (0 <= err) {
-                               frag_size = 32 * bps;
-                       } else {
-                               rate = 22050;
-                               err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, 0);
-                               if (0 <= err) {
-                                       frag_size = 16 * bps;
-                               } else {
-                                       rate = 11025;
-                                       err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate,
-                                                                                                                        0);
-                                       if (0 <= err) {
-                                               frag_size = 8 * bps;
-                                       } else {
-                                               Sys_Printf ("ALSA: no usable rates. %s\n",
-                                                                       snd_strerror (err));
-                                               goto error;
-                                       }
-                               }
-                       }
-                       break;
-               case 11025:
-               case 22050:
-               case 44100:
-                       err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, 0);
-                       if (0 > err) {
-                               Sys_Printf ("ALSA: desired rate %i not supported. %s\n", rate,
-                                                       snd_strerror (err));
-                               goto error;
-                       }
-                       frag_size = 8 * bps * rate / 11025;
-                       break;
-               default:
-                       Sys_Printf ("ALSA: desired rate %i not supported.\n", rate);
-                       goto error;
-       }
+               err = snd_pcm_hw_params_set_format (pcm, hw, width == 1 ? SND_PCM_FORMAT_U8 : SND_PCM_FORMAT_S16);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: desired bits %i not supported by driver.  %s\n", width * 8, snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
 
-       err = snd_pcm_hw_params_set_period_size_near (pcm, hw, &frag_size, 0);
-       if (0 > err) {
-               Sys_Printf ("ALSA: unable to set period size near %i. %s\n",
-                                       (int) frag_size, snd_strerror (err));
-               goto error;
-       }
-       err = snd_pcm_hw_params (pcm, hw);
-       if (0 > err) {
-               Sys_Printf ("ALSA: unable to install hw params: %s\n",
-                                       snd_strerror (err));
-               goto error;
-       }
-       err = snd_pcm_sw_params_current (pcm, sw);
-       if (0 > err) {
-               Sys_Printf ("ALSA: unable to determine current sw params. %s\n",
-                                       snd_strerror (err));
-               goto error;
-       }
-       err = snd_pcm_sw_params_set_start_threshold (pcm, sw, ~0U);
-       if (0 > err) {
-               Sys_Printf ("ALSA: unable to set playback threshold. %s\n",
-                                       snd_strerror (err));
-               goto error;
-       }
-       err = snd_pcm_sw_params_set_stop_threshold (pcm, sw, ~0U);
-       if (0 > err) {
-               Sys_Printf ("ALSA: unable to set playback stop threshold. %s\n",
-                                       snd_strerror (err));
-               goto error;
-       }
-       err = snd_pcm_sw_params (pcm, sw);
-       if (0 > err) {
-               Sys_Printf ("ALSA: unable to install sw params. %s\n",
-                                       snd_strerror (err));
-               goto error;
-       }
+               err = snd_pcm_hw_params_set_channels (pcm, hw, channels);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: no usable channels. %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
 
-       shm->format.channels = stereo + 1;
-       shm->samplepos = 0;
-       shm->format.width = bps / 8;
+               err = snd_pcm_hw_params_set_rate_near (pcm, hw, &rate, 0);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: desired rate %i not supported by driver. %s\n", rate, snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
 
-       err = snd_pcm_hw_params_get_buffer_size (hw, &buffer_size);
-       if (0 > err) {
-               Sys_Printf ("ALSA: unable to get buffer size. %s\n",
-                                       snd_strerror (err));
-               goto error;
-       }
+               frag_size = 64 * width * rate / 11025;
+               err = snd_pcm_hw_params_set_period_size_near (pcm, hw, &frag_size, 0);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: unable to set period size near %i. %s\n", (int) frag_size, snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
+               err = snd_pcm_hw_params (pcm, hw);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: unable to install hw params: %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
+               err = snd_pcm_sw_params_current (pcm, sw);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: unable to determine current sw params. %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
+               err = snd_pcm_sw_params_set_start_threshold (pcm, sw, ~0U);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: unable to set playback threshold. %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
+               err = snd_pcm_sw_params_set_stop_threshold (pcm, sw, ~0U);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: unable to set playback stop threshold. %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
+               err = snd_pcm_sw_params (pcm, sw);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: unable to install sw params. %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
 
-       shm->samples = buffer_size * shm->format.channels;              // mono samples in buffer
-       shm->format.speed = rate;
-       SNDDMA_GetDMAPos ();            // sets shm->buffer
+               err = snd_pcm_hw_params_get_buffer_size (hw, &buffer_size);
+               if (0 > err)
+               {
+                       Con_Printf ("ALSA: unable to get buffer size. %s\n", snd_strerror (err));
+                       snd_pcm_close (pcm);
+                       continue;
+               }
 
-       snd_inited = 1;
-       return true;
+               memset( (void*) shm, 0, sizeof(*shm) );
+               shm->format.channels = channels;
+               shm->format.width = width;
+               shm->format.speed = rate;
+               shm->samplepos = 0;
+               shm->sampleframes = buffer_size;
+               shm->samples = shm->sampleframes * shm->format.channels;
+               SNDDMA_GetDMAPos ();            // sets shm->buffer
 
-error:
-       snd_pcm_close (pcm);
+               return true;
+       }
        return false;
 }
 
@@ -272,9 +215,9 @@ int SNDDMA_GetDMAPos (void)
 {
        const snd_pcm_channel_area_t *areas;
        snd_pcm_uframes_t offset;
-       snd_pcm_uframes_t nframes = shm->samples/shm->format.channels;
+       snd_pcm_uframes_t nframes = shm->sampleframes;
 
-       if (!snd_inited)
+       if (!shm)
                return 0;
 
        snd_pcm_avail_update (pcm);
@@ -282,16 +225,13 @@ int SNDDMA_GetDMAPos (void)
        offset *= shm->format.channels;
        nframes *= shm->format.channels;
        shm->samplepos = offset;
-       shm->buffer = areas->addr;
+       shm->buffer = (unsigned char *)areas->addr;
        return shm->samplepos;
 }
 
 void SNDDMA_Shutdown (void)
 {
-       if (snd_inited) {
-               snd_pcm_close (pcm);
-               snd_inited = 0;
-       }
+       snd_pcm_close (pcm);
 }
 
 /*
@@ -307,9 +247,6 @@ void SNDDMA_Submit (void)
        snd_pcm_uframes_t nframes;
        snd_pcm_uframes_t offset;
 
-       if (snd_blocked)
-               return;
-
        nframes = count / shm->format.channels;
 
        snd_pcm_avail_update (pcm);