1 /* libSoX device driver: MS-Windows audio   (c) 2009 SoX contributors
2  *
3  * This library is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation; either version 2.1 of the License, or (at
6  * your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation,
15  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17 
18 #include "sox_i.h"
19 
20 #include <windows.h>
21 #include <mmsystem.h>
22 #include <mmreg.h>
23 
24 /* Larger means more latency (difference between the status line and the audio you hear),
25  * but it means lower chance of stuttering/glitching. 2 buffers is usually enough. Use
26  * 4 if you want to be extra-safe.
27  */
28 #define num_buffers 4
29 
30 typedef struct waveaudio_priv_t
31 {
32   /* Handle to the input device (microphone, line in, etc.). NULL if playing. */
33   HWAVEIN hin;
34 
35   /* Handle to the output device (speakers, line out, etc.). NULL if recording. */
36   HWAVEOUT hout;
37 
38   /* Event that becomes signaled when a the system has finished processing a buffer. */
39   HANDLE block_finished_event;
40 
41   /* Data transfer buffers. The lpData member of the first buffer points at
42    * data[buf_len*sample_size*0], the second buffer's lpData points at
43    * data[buf_len*sample_size*1], etc. The dwUser field contains the number
44    * of samples of this buffer that have already been processed.
45    */
46   WAVEHDR headers[num_buffers];
47 
48   /* The combined data area shared by all transfer buffers.
49    * size = (bufsiz rounded up to a multiple of 32 samples) * num_buffers.
50    */
51   char * data;
52 
53   /* The number of samples that can fit into one transfer buffer. */
54   size_t buf_len;
55 
56   /* Index of the buffer that we're currently processing. For playback, this is the buffer
57    * that will receive the next samples. For recording, this is the buffer from which we'll
58    * be getting the next samples. If no buffers are ready for processing, this is the buffer
59    * that will be the next to become ready.
60    */
61   unsigned current;
62 
63   /* Shift sample count by this many to get byte count:
64    * 0 for 8-bit samples, 1 for 16-bit samples, or 2 for 32-bit samples.
65    */
66   unsigned char sample_shift;
67 } priv_t;
68 
fail(sox_format_t * ft,unsigned code,const char * context)69 static void fail(sox_format_t* ft, unsigned code, const char* context)
70 {
71   char message[256];
72   unsigned formatMessageOk = FormatMessageA(
73     FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
74     NULL,
75     code,
76     0,
77     message,
78     sizeof(message) / sizeof(message[0]),
79     NULL);
80   if (formatMessageOk)
81     lsx_fail_errno(ft, SOX_EOF, "WaveAudio %s failed with code %d: %s", context, (int)code, message);
82   else
83     lsx_fail_errno(ft, SOX_EOF, "WaveAudio %s failed with unrecognized MMSYSERR code: %d", context, (int)code);
84 }
85 
stop(sox_format_t * ft)86 static int stop(sox_format_t* ft)
87 {
88   priv_t *priv = (priv_t*)ft->priv;
89   if (priv == NULL) return SOX_EOF;
90 
91   if (priv->hin)
92   {
93     waveInReset(priv->hin);
94     waveInClose(priv->hin);
95   }
96 
97   if (priv->hout)
98   {
99     waveOutReset(priv->hout);
100     waveOutClose(priv->hout);
101   }
102 
103   if (priv->block_finished_event)
104     CloseHandle(priv->block_finished_event);
105 
106   if (priv->data)
107     free(priv->data);
108 
109   return SOX_SUCCESS;
110 }
111 
check_format(WAVEFORMATEXTENSIBLE * pfmt,int recording,unsigned dev,unsigned channels,unsigned width,unsigned hertz)112 static unsigned check_format(
113     WAVEFORMATEXTENSIBLE* pfmt,
114     int recording,
115     unsigned dev,
116     unsigned channels,
117     unsigned width,
118     unsigned hertz)
119 {
120   /* GUID: KSDATAFORMAT_SUBTYPE_PCM */
121   static unsigned char const SubformatPcm[] =
122       "\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71";
123 
124   const unsigned bytewidth = width > 16 ? 4 : width > 8 ? 2 : 1;
125   const int extend = channels > 2 || width > 16;
126   unsigned error;
127 
128   pfmt->Format.wFormatTag = extend ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM;
129   pfmt->Format.nChannels = channels;
130   pfmt->Format.nSamplesPerSec = hertz;
131   pfmt->Format.nAvgBytesPerSec = channels * bytewidth * hertz;
132   pfmt->Format.nBlockAlign = channels * bytewidth;
133   pfmt->Format.wBitsPerSample = bytewidth * 8;
134   pfmt->Format.cbSize = extend ? 22 : 0;
135   pfmt->Samples.wValidBitsPerSample = width;
136   pfmt->dwChannelMask = 0;
137   memcpy(&pfmt->SubFormat, SubformatPcm, 16);
138 
139   if (recording)
140     error = waveInOpen(0, dev, &pfmt->Format, 0, 0, WAVE_FORMAT_QUERY);
141   else
142     error = waveOutOpen(0, dev, &pfmt->Format, 0, 0, WAVE_FORMAT_QUERY);
143 
144   lsx_debug(
145       "%s(QUERY: Dev %d %uHz %uCh %uPrec %uWide) returned %u",
146       recording ? "waveInOpen" : "waveOutOpen",
147       dev,
148       hertz,
149       channels,
150       bytewidth * 8,
151       width,
152       error);
153   return error;
154 }
155 
negotiate_format(sox_format_t * ft,WAVEFORMATEXTENSIBLE * pfmt,unsigned dev)156 static unsigned negotiate_format(sox_format_t* ft, WAVEFORMATEXTENSIBLE* pfmt, unsigned dev)
157 {
158   int recording = ft->mode == 'r';
159   unsigned error = 0;
160 
161   unsigned precision = ft->encoding.bits_per_sample;
162   if (precision > 32)
163     precision = 32;
164   else if (precision < 8)
165     precision = 8;
166 
167   while (precision > 0)
168   {
169     error = check_format(pfmt, recording, dev, ft->signal.channels, precision, (unsigned)ft->signal.rate);
170     if (error == MMSYSERR_NOERROR)
171       return MMSYSERR_NOERROR;
172     precision = (precision - 1) & ~(7u);
173   }
174 
175   return error;
176 }
177 
start(sox_format_t * ft)178 static int start(sox_format_t* ft)
179 {
180   size_t i;
181   unsigned dev;
182   WAVEFORMATEXTENSIBLE fmt;
183   int recording = ft->mode == 'r';
184   unsigned error;
185   priv_t *priv = (priv_t*)ft->priv;
186   if (priv == NULL) return SOX_EOF;
187   memset(&fmt, 0, sizeof(fmt));
188 
189   /* Handle AUDIODEV device selection:
190    * NULL, blank, or "default" gets you the default device (WAVE_MAPPER = -1).
191    * An integer value gets you the device with that device number, if it exists (counting starts at 0).
192    * A string gets you the device with that name, if it exists.
193    */
194   if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename))
195   {
196     dev = WAVE_MAPPER;
197   }
198   else
199   {
200     WAVEINCAPSA incaps;
201     WAVEOUTCAPSA outcaps;
202     const char *dev_name;
203     char* dev_num_end;
204     dev = strtoul(ft->filename, &dev_num_end, 0);
205     if (dev_num_end[0] == 0)
206     {
207       if (recording)
208         error = waveInGetDevCapsA(dev, &incaps, sizeof(incaps));
209       else
210         error = waveOutGetDevCapsA(dev, &outcaps, sizeof(outcaps));
211 
212       if (error)
213       {
214         lsx_fail_errno(ft, ENODEV, "WaveAudio device not found.");
215         return SOX_EOF;
216       }
217     }
218     else
219     {
220       unsigned dev_count = recording ? waveInGetNumDevs() : waveOutGetNumDevs();
221       size_t name_len = strlen(ft->filename);
222       if (name_len > 31)
223           name_len = 31;
224       for (dev = WAVE_MAPPER; dev != dev_count; dev++)
225       {
226         if (recording)
227         {
228           error = waveInGetDevCapsA(dev, &incaps, sizeof(incaps));
229           dev_name = incaps.szPname;
230           lsx_debug("Enumerating input device %2d: \"%s\"", dev, dev_name);
231         }
232         else
233         {
234           error = waveOutGetDevCapsA(dev, &outcaps, sizeof(outcaps));
235           dev_name = outcaps.szPname;
236           lsx_debug("Enumerating output device %2d: \"%s\"", dev, dev_name);
237         }
238 
239         if (error)
240         {
241           fail(ft, error, recording ? "waveInGetDevCapsA" : "waveOutGetDevCapsA");
242           return SOX_EOF;
243         }
244 
245         if (!strncasecmp(ft->filename, dev_name, name_len))
246         {
247           lsx_report("Requested name \"%s\" matched device %d: \"%s\"", ft->filename, dev, dev_name);
248           break;
249         }
250       }
251 
252       if (dev == dev_count)
253       {
254         lsx_fail_errno(ft, ENODEV, "The requested WaveAudio device was not found.");
255         return SOX_EOF;
256       }
257     }
258   }
259 
260   error = negotiate_format(ft, &fmt, dev);
261   if (error != MMSYSERR_NOERROR)
262   {
263     fail(ft, error, "sample format negotiation");
264     return SOX_EOF;
265   }
266 
267   switch (fmt.Format.wBitsPerSample)
268   {
269   case 8:
270       priv->sample_shift = 0;
271       break;
272   case 16:
273       priv->sample_shift = 1;
274       break;
275   case 32:
276       priv->sample_shift = 2;
277       break;
278   default:
279       lsx_fail_errno(ft, E2BIG, "Unexpected value for WaveAudio wBitsPerSample: %u", fmt.Format.wBitsPerSample);
280       return SOX_EOF;
281   }
282 
283   ft->signal.precision = fmt.Samples.wValidBitsPerSample;
284   ft->signal.channels = fmt.Format.nChannels;
285   if (dev == WAVE_MAPPER)
286   {
287       lsx_report(
288           "Using default %s device at %uHz %uCh %uPrec %uWide.",
289           recording ? "input" : "output",
290           (unsigned)fmt.Format.nSamplesPerSec,
291           (unsigned)fmt.Format.nChannels,
292           (unsigned)fmt.Samples.wValidBitsPerSample,
293           (unsigned)fmt.Format.wBitsPerSample);
294   }
295   else
296   {
297       lsx_report(
298           "Using %s device #%d at %uHz %uCh %uPrec %uWide.",
299           recording ? "input" : "output",
300           (int)dev,
301           (unsigned)fmt.Format.nSamplesPerSec,
302           (unsigned)fmt.Format.nChannels,
303           (unsigned)fmt.Samples.wValidBitsPerSample,
304           (unsigned)fmt.Format.wBitsPerSample);
305   }
306 
307   priv->buf_len = ((sox_globals.bufsiz >> priv->sample_shift) + 31) & ~31u;
308   priv->data = lsx_malloc((priv->buf_len * num_buffers) << priv->sample_shift);
309   if (!priv->data)
310   {
311     lsx_fail_errno(ft, SOX_ENOMEM, "Out of memory.");
312     return SOX_EOF;
313   }
314 
315   priv->block_finished_event = CreateEventA(NULL, FALSE, FALSE, NULL);
316   if (!priv->block_finished_event)
317   {
318     error = GetLastError();
319     fail(ft, error, "CreateEventA");
320     stop(ft);
321     return SOX_EOF;
322   }
323 
324   if (recording)
325   {
326     error = waveInOpen(
327         &priv->hin,
328         dev,
329         &fmt.Format,
330         (DWORD_PTR)priv->block_finished_event,
331         0,
332         CALLBACK_EVENT);
333   }
334   else
335   {
336     error = waveOutOpen(
337         &priv->hout,
338         dev,
339         &fmt.Format,
340         (DWORD_PTR)priv->block_finished_event,
341         0,
342         CALLBACK_EVENT);
343   }
344 
345   if (error != MMSYSERR_NOERROR)
346   {
347     fail(ft, error, recording ? "waveInOpen" : "waveOutOpen");
348     stop(ft);
349     return SOX_EOF;
350   }
351 
352   for (i = 0; i != num_buffers; i++)
353   {
354     priv->headers[i].lpData = priv->data + ((priv->buf_len * i) << priv->sample_shift);
355     priv->headers[i].dwBufferLength = priv->buf_len << priv->sample_shift;
356 
357     if (recording)
358       error = waveInPrepareHeader(priv->hin, &priv->headers[i], sizeof(priv->headers[i]));
359     else
360       error = waveOutPrepareHeader(priv->hout, &priv->headers[i], sizeof(priv->headers[i]));
361 
362     if (error != MMSYSERR_NOERROR)
363     {
364       fail(ft, error, recording ? "waveInPrepareHeader" : "waveOutPrepareHeader");
365       stop(ft);
366       return SOX_EOF;
367     }
368 
369     if (recording)
370     {
371       error = waveInAddBuffer(priv->hin, &priv->headers[i], sizeof(priv->headers[i]));
372       if (error != MMSYSERR_NOERROR)
373       {
374         fail(ft, error, "waveInAddBuffer");
375         stop(ft);
376         return SOX_EOF;
377       }
378     }
379   }
380 
381   if (recording)
382   {
383     error = waveInStart(priv->hin);
384     if (error != MMSYSERR_NOERROR)
385     {
386       fail(ft, error, "waveInStart");
387       stop(ft);
388       return SOX_EOF;
389     }
390   }
391 
392   return SOX_SUCCESS;
393 }
394 
waveread(sox_format_t * ft,sox_sample_t * buf,size_t len)395 static size_t waveread(sox_format_t * ft, sox_sample_t* buf, size_t len)
396 {
397   size_t copied = 0;
398   priv_t *priv = (priv_t*)ft->priv;
399   unsigned error = 0;
400 
401   if (priv == NULL)
402       return (size_t)SOX_EOF;
403 
404   while (!error && copied < len)
405   {
406     LPWAVEHDR header = &priv->headers[priv->current];
407     if (0 == (header->dwFlags & WHDR_INQUEUE) ||
408       0 != (header->dwFlags & WHDR_DONE))
409     {
410       size_t length = header->dwBytesRecorded >> priv->sample_shift;
411       size_t ready = min(len - copied, length - header->dwUser);
412       size_t i;
413 
414       switch (priv->sample_shift)
415       {
416       case 0:
417           for (i = 0; i < ready; ++i)
418           {
419             buf[copied++] = SOX_UNSIGNED_8BIT_TO_SAMPLE(((uint8_t *)header->lpData)[header->dwUser++], dummy);
420           }
421           break;
422       case 1:
423           for (i = 0; i < ready; ++i)
424           {
425             buf[copied++] = SOX_SIGNED_16BIT_TO_SAMPLE(((int16_t *)header->lpData)[header->dwUser++], dummy);
426           }
427           break;
428       case 2:
429           for (i = 0; i < ready; ++i)
430           {
431             buf[copied++] = SOX_SIGNED_32BIT_TO_SAMPLE(((int32_t *)header->lpData)[header->dwUser++], dummy);
432           }
433           break;
434       }
435 
436       if (header->dwUser == length)
437       {
438         error = waveInAddBuffer(priv->hin, header, sizeof(*header));
439         priv->current = (priv->current + 1) % num_buffers;
440         priv->headers[priv->current].dwUser = 0;
441         if (error)
442         {
443           fail(ft, error, "waveInAddBuffer");
444           copied = 0;
445         }
446       }
447     }
448     else
449     {
450       WaitForSingleObject(priv->block_finished_event, INFINITE);
451     }
452   }
453 
454   return copied;
455 }
456 
wavewrite(sox_format_t * ft,const sox_sample_t * buf,size_t len)457 static size_t wavewrite(sox_format_t * ft, const sox_sample_t* buf, size_t len)
458 {
459   size_t copied = 0;
460   priv_t *priv = (priv_t*)ft->priv;
461   unsigned error = 0;
462   unsigned clips = 0;
463 
464   if (priv == NULL)
465       return (size_t)SOX_EOF;
466 
467   while (!error && copied < len)
468   {
469     LPWAVEHDR header = &priv->headers[priv->current];
470     if (0 == (header->dwFlags & WHDR_INQUEUE) ||
471       0 != (header->dwFlags & WHDR_DONE))
472     {
473       size_t ready = min(len - copied, priv->buf_len - header->dwUser);
474       size_t i;
475 
476       switch (priv->sample_shift)
477       {
478       case 0:
479           for (i = 0; i < ready; ++i)
480           {
481             SOX_SAMPLE_LOCALS;
482             ((uint8_t *)header->lpData)[header->dwUser++] = SOX_SAMPLE_TO_UNSIGNED_8BIT(buf[copied++], clips);
483           }
484           break;
485       case 1:
486           for (i = 0; i < ready; ++i)
487           {
488             SOX_SAMPLE_LOCALS;
489             ((int16_t *)header->lpData)[header->dwUser++] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[copied++], clips);
490           }
491           break;
492       case 2:
493           for (i = 0; i < ready; ++i)
494           {
495             ((int32_t *)header->lpData)[header->dwUser++] = SOX_SAMPLE_TO_SIGNED_32BIT(buf[copied++], clips);
496           }
497           break;
498       }
499 
500       header->dwBufferLength = header->dwUser << priv->sample_shift;
501       error = waveOutWrite(priv->hout, header, sizeof(*header));
502       priv->current = (priv->current + 1) % num_buffers;
503       priv->headers[priv->current].dwUser = 0;
504 
505       if (error)
506       {
507         fail(ft, error, "waveOutWrite");
508         copied = 0;
509       }
510     }
511     else
512     {
513       WaitForSingleObject(priv->block_finished_event, INFINITE);
514     }
515   }
516 
517   return copied;
518 }
519 
LSX_FORMAT_HANDLER(waveaudio)520 LSX_FORMAT_HANDLER(waveaudio)
521 {
522   static const char * const names[] = {"waveaudio", NULL};
523   static unsigned const write_encodings[] = {
524     SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0,
525     0};
526   static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
527   "Windows Multimedia Audio", names,
528   SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
529   start, waveread, stop,
530   start, wavewrite, stop,
531   NULL, write_encodings, NULL, sizeof(priv_t)
532   };
533   return &handler;
534 }
535