winmm: Implemented audio capture support.
authorRyan C. Gordon <icculus@icculus.org>
Sat, 06 Aug 2016 19:34:32 -0400
changeset 102667c430819edd2
parent 10265 886ab9de5f43
child 10267 0abfef2f7fc5
winmm: Implemented audio capture support.
src/audio/winmm/SDL_winmm.c
     1.1 --- a/src/audio/winmm/SDL_winmm.c	Sat Aug 06 03:45:45 2016 -0400
     1.2 +++ b/src/audio/winmm/SDL_winmm.c	Sat Aug 06 19:34:32 2016 -0400
     1.3 @@ -27,6 +27,7 @@
     1.4  #include "../../core/windows/SDL_windows.h"
     1.5  #include <mmsystem.h>
     1.6  
     1.7 +#include "SDL_assert.h"
     1.8  #include "SDL_timer.h"
     1.9  #include "SDL_audio.h"
    1.10  #include "../SDL_audio_c.h"
    1.11 @@ -152,30 +153,83 @@
    1.12      } while (left > 0);
    1.13  }
    1.14  
    1.15 +static int
    1.16 +WINMM_CaptureFromDevice(_THIS, void *buffer, int buflen)
    1.17 +{
    1.18 +    const int nextbuf = this->hidden->next_buffer;
    1.19 +    MMRESULT result;
    1.20 +
    1.21 +    SDL_assert(buflen == this->spec.size);
    1.22 +
    1.23 +    /* Wait for an audio chunk to finish */
    1.24 +    WaitForSingleObject(this->hidden->audio_sem, INFINITE);
    1.25 +
    1.26 +    /* Copy it to caller's buffer... */
    1.27 +    SDL_memcpy(buffer, this->hidden->wavebuf[nextbuf].lpData, this->spec.size);
    1.28 +
    1.29 +    /* requeue the buffer that just finished. */
    1.30 +    result = waveInAddBuffer(this->hidden->hin,
    1.31 +                             &this->hidden->wavebuf[nextbuf],
    1.32 +                             sizeof (this->hidden->wavebuf[nextbuf]));
    1.33 +    if (result != MMSYSERR_NOERROR) {
    1.34 +        return -1;  /* uhoh! Disable the device. */
    1.35 +    }
    1.36 +
    1.37 +    /* queue the next buffer in sequence, next time. */
    1.38 +    this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
    1.39 +    return this->spec.size;
    1.40 +}
    1.41 +
    1.42 +static void
    1.43 +WINMM_FlushCapture(_THIS)
    1.44 +{
    1.45 +    /* Wait for an audio chunk to finish */
    1.46 +    if (WaitForSingleObject(this->hidden->audio_sem, 0) == WAIT_OBJECT_0) {
    1.47 +        const int nextbuf = this->hidden->next_buffer;
    1.48 +        /* requeue the buffer that just finished without reading from it. */
    1.49 +        waveInAddBuffer(this->hidden->hin,
    1.50 +                        &this->hidden->wavebuf[nextbuf],
    1.51 +                        sizeof (this->hidden->wavebuf[nextbuf]));
    1.52 +        this->hidden->next_buffer = (nextbuf + 1) % NUM_BUFFERS;
    1.53 +    }
    1.54 +}
    1.55 +
    1.56  static void
    1.57  WINMM_CloseDevice(_THIS)
    1.58  {
    1.59      int i;
    1.60  
    1.61 -    if (this->hidden->audio_sem) {
    1.62 -        CloseHandle(this->hidden->audio_sem);
    1.63 -    }
    1.64 +    if (this->hidden->hout) {
    1.65 +        waveOutReset(this->hidden->hout);
    1.66  
    1.67 -    /* Clean up mixing buffers */
    1.68 -    for (i = 0; i < NUM_BUFFERS; ++i) {
    1.69 -        if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
    1.70 -            waveOutUnprepareHeader(this->hidden->hout,
    1.71 -                                   &this->hidden->wavebuf[i],
    1.72 -                                   sizeof (this->hidden->wavebuf[i]));
    1.73 +        /* Clean up mixing buffers */
    1.74 +        for (i = 0; i < NUM_BUFFERS; ++i) {
    1.75 +            if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
    1.76 +                waveOutUnprepareHeader(this->hidden->hout,
    1.77 +                                       &this->hidden->wavebuf[i],
    1.78 +                                       sizeof (this->hidden->wavebuf[i]));
    1.79 +            }
    1.80          }
    1.81 +
    1.82 +        waveOutClose(this->hidden->hout);
    1.83      }
    1.84  
    1.85      if (this->hidden->hin) {
    1.86 +        waveInReset(this->hidden->hin);
    1.87 +
    1.88 +        /* Clean up mixing buffers */
    1.89 +        for (i = 0; i < NUM_BUFFERS; ++i) {
    1.90 +            if (this->hidden->wavebuf[i].dwUser != 0xFFFF) {
    1.91 +                waveInUnprepareHeader(this->hidden->hin,
    1.92 +                                       &this->hidden->wavebuf[i],
    1.93 +                                       sizeof (this->hidden->wavebuf[i]));
    1.94 +            }
    1.95 +        }
    1.96          waveInClose(this->hidden->hin);
    1.97      }
    1.98  
    1.99 -    if (this->hidden->hout) {
   1.100 -        waveOutClose(this->hidden->hout);
   1.101 +    if (this->hidden->audio_sem) {
   1.102 +        CloseHandle(this->hidden->audio_sem);
   1.103      }
   1.104  
   1.105      SDL_free(this->hidden->mixbuf);
   1.106 @@ -269,32 +323,44 @@
   1.107          result = waveInOpen(&this->hidden->hin, devId, &waveformat,
   1.108                               (DWORD_PTR) CaptureSound, (DWORD_PTR) this,
   1.109                               CALLBACK_FUNCTION);
   1.110 +        if (result != MMSYSERR_NOERROR) {
   1.111 +            return SetMMerror("waveInOpen()", result);
   1.112 +        }
   1.113      } else {
   1.114          result = waveOutOpen(&this->hidden->hout, devId, &waveformat,
   1.115                               (DWORD_PTR) FillSound, (DWORD_PTR) this,
   1.116                               CALLBACK_FUNCTION);
   1.117 +        if (result != MMSYSERR_NOERROR) {
   1.118 +            return SetMMerror("waveOutOpen()", result);
   1.119 +        }
   1.120      }
   1.121  
   1.122 -    if (result != MMSYSERR_NOERROR) {
   1.123 -        return SetMMerror("waveOutOpen()", result);
   1.124 -    }
   1.125  #ifdef SOUND_DEBUG
   1.126      /* Check the sound device we retrieved */
   1.127      {
   1.128 -        WAVEOUTCAPS caps;
   1.129 -
   1.130 -        result = waveOutGetDevCaps((UINT) this->hidden->hout,
   1.131 -                                   &caps, sizeof(caps));
   1.132 -        if (result != MMSYSERR_NOERROR) {
   1.133 -            return SetMMerror("waveOutGetDevCaps()", result);
   1.134 +        if (iscapture) {
   1.135 +            WAVEINCAPS caps;
   1.136 +            result = waveInGetDevCaps((UINT) this->hidden->hout,
   1.137 +                                      &caps, sizeof (caps));
   1.138 +            if (result != MMSYSERR_NOERROR) {
   1.139 +                return SetMMerror("waveInGetDevCaps()", result);
   1.140 +            }
   1.141 +            printf("Audio device: %s\n", caps.szPname);
   1.142 +        } else {
   1.143 +            WAVEOUTCAPS caps;
   1.144 +            result = waveOutGetDevCaps((UINT) this->hidden->hout,
   1.145 +                                       &caps, sizeof(caps));
   1.146 +            if (result != MMSYSERR_NOERROR) {
   1.147 +                return SetMMerror("waveOutGetDevCaps()", result);
   1.148 +            }
   1.149 +            printf("Audio device: %s\n", caps.szPname);
   1.150          }
   1.151 -        printf("Audio device: %s\n", caps.szPname);
   1.152      }
   1.153  #endif
   1.154  
   1.155      /* Create the audio buffer semaphore */
   1.156      this->hidden->audio_sem =
   1.157 -        CreateSemaphore(NULL, NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
   1.158 +		CreateSemaphore(NULL, iscapture ? 0 : NUM_BUFFERS - 1, NUM_BUFFERS, NULL);
   1.159      if (this->hidden->audio_sem == NULL) {
   1.160          return SDL_SetError("Couldn't create semaphore");
   1.161      }
   1.162 @@ -312,11 +378,35 @@
   1.163          this->hidden->wavebuf[i].dwFlags = WHDR_DONE;
   1.164          this->hidden->wavebuf[i].lpData =
   1.165              (LPSTR) & this->hidden->mixbuf[i * this->spec.size];
   1.166 -        result = waveOutPrepareHeader(this->hidden->hout,
   1.167 -                                      &this->hidden->wavebuf[i],
   1.168 -                                      sizeof(this->hidden->wavebuf[i]));
   1.169 +
   1.170 +        if (iscapture) {
   1.171 +            result = waveInPrepareHeader(this->hidden->hin,
   1.172 +                                          &this->hidden->wavebuf[i],
   1.173 +                                          sizeof(this->hidden->wavebuf[i]));
   1.174 +            if (result != MMSYSERR_NOERROR) {
   1.175 +                return SetMMerror("waveInPrepareHeader()", result);
   1.176 +            }
   1.177 +
   1.178 +            result = waveInAddBuffer(this->hidden->hin,
   1.179 +                                     &this->hidden->wavebuf[i],
   1.180 +                                     sizeof(this->hidden->wavebuf[i]));
   1.181 +            if (result != MMSYSERR_NOERROR) {
   1.182 +                return SetMMerror("waveInAddBuffer()", result);
   1.183 +            }
   1.184 +        } else {
   1.185 +            result = waveOutPrepareHeader(this->hidden->hout,
   1.186 +                                          &this->hidden->wavebuf[i],
   1.187 +                                          sizeof(this->hidden->wavebuf[i]));
   1.188 +            if (result != MMSYSERR_NOERROR) {
   1.189 +                return SetMMerror("waveOutPrepareHeader()", result);
   1.190 +            }
   1.191 +        }
   1.192 +    }
   1.193 +
   1.194 +    if (iscapture) {
   1.195 +        result = waveInStart(this->hidden->hin);
   1.196          if (result != MMSYSERR_NOERROR) {
   1.197 -            return SetMMerror("waveOutPrepareHeader()", result);
   1.198 +            return SetMMerror("waveInStart()", result);
   1.199          }
   1.200      }
   1.201  
   1.202 @@ -334,8 +424,12 @@
   1.203      impl->WaitDevice = WINMM_WaitDevice;
   1.204      impl->WaitDone = WINMM_WaitDone;
   1.205      impl->GetDeviceBuf = WINMM_GetDeviceBuf;
   1.206 +    impl->CaptureFromDevice = WINMM_CaptureFromDevice;
   1.207 +    impl->FlushCapture = WINMM_FlushCapture;
   1.208      impl->CloseDevice = WINMM_CloseDevice;
   1.209  
   1.210 +    impl->HasCaptureSupport = SDL_TRUE;
   1.211 +
   1.212      return 1;   /* this audio target is available. */
   1.213  }
   1.214