OSDN Git Service

Import UnkoTim212
[timidity41/timidity41.git] / timidity / wasapi_a.c
1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20     wasapi_a.c
21         
22         Functions to play sound using WASAPI (Windows Vista).
23
24 Based on <https://github.com/Microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/multimedia/audio/RenderExclusiveEventDriven>,
25 which is distributed under the MIT License:
26
27 ----
28 The MIT License (MIT)
29
30 Copyright (c) Microsoft Corporation
31
32 Permission is hereby granted, free of charge, to any person obtaining a copy
33 of this software and associated documentation files (the "Software"), to deal
34 in the Software without restriction, including without limitation the rights
35 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
36 copies of the Software, and to permit persons to whom the Software is
37 furnished to do so, subject to the following conditions:
38
39 The above copyright notice and this permission notice shall be included in
40 all copies or substantial portions of the Software.
41
42 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
43 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
44 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
45 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
46 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
47 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
48 THE SOFTWARE.
49
50 Portions of this repo are provided under the SIL Open Font License.
51 See the LICENSE file in individual samples for additional details
52 ----
53
54 Written by Starg.
55
56 */
57
58
59 #ifdef HAVE_CONFIG_H
60 #include "config.h"
61 #endif /* HAVE_CONFIG_H */
62
63
64 #ifdef AU_WASAPI
65
66
67 #ifdef __W32__
68 #include "interface.h"
69 #endif
70 #include <stdio.h>
71 #include <stdlib.h>
72 #ifndef NO_STRING_H
73 #include <string.h>
74 #else
75 #include <strings.h>
76 #endif
77 #include <process.h>
78 #include <tchar.h>
79
80 #include "timidity.h"
81 #include "common.h"
82 #include "controls.h"
83 #include "output.h"
84 #include "wasapi_a.h"
85
86 int opt_wasapi_device_id = -1; // default render
87 int opt_wasapi_latency = 10; //  ms
88 int opt_wasapi_format_ext = 1;
89 int opt_wasapi_exclusive = 0; // shared
90 int opt_wasapi_polling = 0; // 0:event 1:polling
91 int opt_wasapi_priority = 0; // auto
92 int opt_wasapi_stream_category = 0;
93 int opt_wasapi_stream_option = 0;
94
95 /*****************************************************************************************************************************/
96
97 static int  open_output     (void); /* 0=success, 1=warning, -1=fatal error */
98 static void close_output    (void);
99 static int  output_data     (const uint8 *buf, size_t nbytes);
100 static int  acntl           (int request, void *arg);
101 static int  detect          (void);
102
103 /*****************************************************************************************************************************/
104
105 #define dpm wasapi_play_mode
106
107 PlayMode dpm = {
108     DEFAULT_RATE,
109     PE_16BIT | PE_SIGNED,
110     PF_PCM_STREAM | PF_CAN_TRACE | PF_BUFF_FRAGM_OPT,
111     -1,
112     {32},
113     "WASAPI", 'x',
114     NULL,
115     &open_output,
116     &close_output,
117     &output_data,
118     &acntl,
119     &detect
120 };
121
122 /*****************************************************************************************************************************/
123
124 #define CINTERFACE
125 #define COBJMACROS
126 #include <windows.h>
127 #include <winbase.h>
128 #include <objbase.h>
129 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
130 //#include <Avrt.h>
131 #include <Audioclient.h>
132 #include <audiopolicy.h>
133 #define INITGUID
134 #include <mmdeviceapi.h>
135 #include <functiondiscoverykeys.h>
136 #undef INITGUID
137 #endif
138
139 const CLSID tim_CLSID_MMDeviceEnumerator = {0xBCDE0395, 0xE52F, 0x467C, {0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E}};
140 const IID tim_IID_IMMDeviceEnumerator    = {0xA95664D2, 0x9614, 0x4F35, {0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6}};
141 const IID tim_IID_IAudioClient           = {0x1CB9AD4C, 0xDBFA, 0x4C32, {0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2}};
142 const IID tim_IID_IAudioRenderClient     = {0xF294ACFC, 0x3146, 0x4483, {0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2}};
143
144 #define SPEAKER_FRONT_LEFT        0x1
145 #define SPEAKER_FRONT_RIGHT       0x2
146 #define SPEAKER_FRONT_CENTER      0x4
147 #define SPEAKER_MONO              (SPEAKER_FRONT_CENTER)
148 #define SPEAKER_STEREO            (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
149
150 const char *ThreadPriorityName[] =
151 {
152         NULL,
153         "Audio",
154         "Capture",
155         "Distribution",
156         "Games",
157         "Playback",
158         "Pro Audio",
159         "Window Manager"
160 };
161
162 /*****************************************************************************************************************************/
163
164 typedef struct WABufferBlock_t {
165         struct WABufferBlock_t *pNext;
166         size_t CurrentSize;
167         size_t Capacity;
168         uint8 Data[1];
169 } WABufferBlock;
170
171 typedef struct WABuffer_t {
172         WABufferBlock *pHead;
173         WABufferBlock *pTail;
174         WABufferBlock *pFree;
175         uint32 FilledByte;
176 } WABuffer;
177
178 static WABuffer Buffers = {NULL, NULL, NULL, 0};
179
180 static int get_filled_byte(void)
181 {
182         return Buffers.FilledByte;
183 }
184
185 static int is_buffer_empty(void)
186 {
187         return !Buffers.pHead;
188 }
189
190 static size_t calc_output_bytes(size_t max_bytes)
191 {
192         size_t bytes = 0;
193         WABufferBlock *block = Buffers.pHead;
194
195         while(bytes < max_bytes && block){
196                 bytes += block->CurrentSize;
197                 block = block->pNext;
198         }
199         return bytes > max_bytes ? max_bytes : bytes;
200 }
201
202 static void clear_buffer(void)
203 {
204         if(Buffers.pTail){
205                 Buffers.pTail->pNext = Buffers.pFree;
206                 Buffers.pFree = Buffers.pHead;
207                 Buffers.pHead = NULL;
208                 Buffers.pTail = NULL;
209         }
210 }
211
212 static void free_buffer(void)
213 {
214         WABufferBlock *block = NULL;
215
216         clear_buffer();
217         block = Buffers.pFree;
218         while(block){
219                 WABufferBlock* pNext = block->pNext;
220                 free(block);
221                 block = pNext;
222         }
223         Buffers.pFree = NULL;   
224         Buffers.FilledByte = 0;
225 }
226
227 /* if *pbuf == NULL, appends `size` count of zeros */
228 static void input_buffer_partial(WABufferBlock *block, const uint8 **pbuf, size_t *bytes)
229 {
230         size_t pushLength = block->Capacity - block->CurrentSize;
231
232         if(pushLength > *bytes)
233                 pushLength = *bytes;
234         if(*pbuf){
235                 memcpy(block->Data + block->CurrentSize, *pbuf, pushLength);
236                 *pbuf += pushLength;
237         }else{
238                 memset(block->Data + block->CurrentSize, 0, pushLength);
239         }
240         *bytes -= pushLength;
241         block->CurrentSize += pushLength;
242 }
243
244 /* if buf == NULL, appends `size` count of zeros */
245 static int input_buffer(const uint8 *buf, size_t bytes)
246 {
247         size_t pbytes = bytes;
248
249         while (bytes > 0){
250                 if(Buffers.pTail && Buffers.pTail->CurrentSize < Buffers.pTail->Capacity){
251                         input_buffer_partial(Buffers.pTail, &buf, &bytes);
252                 }else if(Buffers.pFree){
253                         WABufferBlock *block = Buffers.pFree;
254
255                         Buffers.pFree = Buffers.pFree->pNext;
256                         block->CurrentSize = 0;
257                         block->pNext = NULL;
258                         if(Buffers.pTail){
259                                 Buffers.pTail->pNext = block;
260                                 Buffers.pTail = block;
261                         }else{
262                                 Buffers.pHead = block;
263                                 Buffers.pTail = block;
264                         }
265                         input_buffer_partial(block, &buf, &bytes);
266                 }else{
267                         size_t capacity = bytes * 4;
268                         WABufferBlock *new_block = (WABufferBlock *)safe_malloc(sizeof(WABufferBlock) + capacity);
269
270                         if(!new_block)
271                                 return FALSE;
272                         if(Buffers.pTail)
273                                 Buffers.pTail->pNext = new_block;
274                         else
275                                 Buffers.pHead = new_block;
276                         Buffers.pTail = new_block;
277                         Buffers.pTail->pNext = NULL;
278                         Buffers.pTail->Capacity = capacity;
279                         Buffers.pTail->CurrentSize = 0;
280                         input_buffer_partial(Buffers.pTail, &buf, &bytes);
281                 }
282         }
283         Buffers.FilledByte += pbytes;
284         return TRUE;
285 }
286
287 static void output_buffer(uint8 *buff, size_t bytes)
288 {
289         size_t pbytes = bytes, tmp_bytes, out_bytes = 0;
290         WABufferBlock *block = Buffers.pHead;
291
292         while(bytes > 0 && block){
293                 tmp_bytes = block->CurrentSize;
294                 if(tmp_bytes > bytes)
295                         tmp_bytes = bytes;
296                 memcpy(buff, block->Data, tmp_bytes);
297                 buff += tmp_bytes;
298                 bytes -= tmp_bytes;
299                 out_bytes += tmp_bytes;
300                 block = block->pNext;
301         }
302         while (out_bytes > 0 && Buffers.pHead){
303                 tmp_bytes = Buffers.pHead->CurrentSize;
304                 if(Buffers.pHead->CurrentSize > out_bytes){
305                         tmp_bytes = out_bytes;
306                         memmove(Buffers.pHead->Data, Buffers.pHead->Data + out_bytes, Buffers.pHead->CurrentSize - out_bytes);
307                         Buffers.pHead->CurrentSize -= out_bytes;
308                 }else{
309                         WABufferBlock *pNext = Buffers.pHead->pNext;
310                         Buffers.pHead->pNext = Buffers.pFree;
311                         Buffers.pFree = Buffers.pHead;
312                         Buffers.pHead = pNext;
313                         if(!pNext)
314                                 Buffers.pTail = NULL;
315                 }
316                 out_bytes -= tmp_bytes;
317         }
318         Buffers.FilledByte -= pbytes;
319 }
320
321 /*****************************************************************************************************************************/
322
323 typedef HANDLE (WINAPI *fAvSetMmThreadCharacteristics)(LPCSTR,LPDWORD);
324 typedef BOOL   (WINAPI *fAvRevertMmThreadCharacteristics)(HANDLE);
325
326 static HINSTANCE hDll = NULL;
327 static fAvSetMmThreadCharacteristics pAvSetMmThreadCharacteristics = NULL;
328 static fAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL;
329
330 static int load_avrt(void)
331 {
332     hDll = LoadLibrary("avrt.dll");
333     if(hDll == NULL)
334         return FALSE;   
335 #ifdef UNICODE
336         pAvSetMmThreadCharacteristics = (fAvSetMmThreadCharacteristics)GetProcAddress(hDll, "AvSetMmThreadCharacteristicsW");
337 #else
338         pAvSetMmThreadCharacteristics = (fAvSetMmThreadCharacteristics)GetProcAddress(hDll, "AvSetMmThreadCharacteristicsA");
339 #endif
340         pAvRevertMmThreadCharacteristics = (fAvRevertMmThreadCharacteristics)GetProcAddress(hDll, "AvRevertMmThreadCharacteristics");
341         return (int)pAvSetMmThreadCharacteristics && pAvRevertMmThreadCharacteristics;
342 }
343
344 static void free_avrt(void)
345 {
346     if(hDll)
347         FreeLibrary(hDll);
348         hDll = NULL;    
349         pAvSetMmThreadCharacteristics = NULL;
350         pAvRevertMmThreadCharacteristics = NULL;
351 }
352
353 static int get_winver(void)
354 {
355         DWORD winver, major, minor;
356         int ver = 0;
357
358         winver = GetVersion();          
359         major = (DWORD)(LOBYTE(LOWORD(winver)));
360         minor = (DWORD)(HIBYTE(LOWORD(winver)));
361         switch (major){
362         case 0:
363         case 1:
364         case 2:
365         case 3:
366         case 4:
367         case 5:
368                 ver = 0;
369                 break;
370         case 6:
371                 switch (minor){
372                 case 0: ver = 1; break; // vista
373                 case 1: ver = 2; break; // 7
374                 case 2: ver = 3; break; // 8
375                 case 3: ver = 4; break; // 8.1
376                 default: ver = 5; break; // 8.2?
377                 }
378                 break;
379         case 10:
380                 switch (minor){
381                 case 0: ver = 6; break; // 10
382                 default: ver = 7; break; // 10.1?
383                 }
384                 break;
385         default:
386                 ver = 8; // 11?
387                 break;
388         }
389         return ver;
390 }
391
392 /*****************************************************************************************************************************/
393
394 static HANDLE hEventTcv = NULL;
395 static HANDLE hRenderThread = NULL;
396 static IMMDevice* pMMDevice = NULL;
397 static IAudioClient* pAudioClient = NULL;
398 static IAudioRenderClient* pAudioRenderClient = NULL;
399 static REFERENCE_TIME BufferDuration = 100000;
400 static UINT32 FrameBytes = 0;
401 static UINT32 BufferFrames = 0;
402 static int ThreadPriorityNum = 0;
403 static int IsExclusive = 0;
404 static int IsPolling = 0;
405 static int IsStarted = 0;
406 static int IsOpened = 0;
407 static int IsThreadStart = 0;
408 static int IsThreadExit = 0;
409 static int IsCoInit = 0;
410 static int CoInitThreadId = 0;
411 static int CvtMode = 0; // 0:no convert 1:convert 24bit(3byte->4byte)
412 static uint32 QueueSize = sizeof(int16) * 2 * (1L << DEFAULT_AUDIO_BUFFER_BITS) * 2;
413 static uint32 WaitTime = 1;
414 static uint32 ThreadWaitTime = 1;
415
416 static int write_buffer_event(void)
417 {       
418         UINT32 padding = 0;
419         size_t out_bytes, out_frames;
420         BYTE *buf = NULL;
421
422         if(!IsExclusive)
423                 if(FAILED(IAudioClient_GetCurrentPadding(pAudioClient, &padding)))
424                         return FALSE;
425         out_bytes = calc_output_bytes((BufferFrames - padding) * FrameBytes);
426         out_frames = out_bytes / FrameBytes;
427         if(IsExclusive && out_frames < BufferFrames){
428                 if(!input_buffer(NULL, BufferFrames * FrameBytes - out_bytes))
429                         return FALSE;
430                 out_bytes = BufferFrames * FrameBytes;
431                 out_frames = out_bytes / FrameBytes;
432         }else if(out_frames == 0){
433                 if(!input_buffer(NULL, FrameBytes - out_bytes))
434                         return FALSE;           
435                 out_bytes = FrameBytes;
436                 out_frames = 1;
437         }
438         if(FAILED(IAudioRenderClient_GetBuffer(pAudioRenderClient, out_frames, &buf)))
439                 return FALSE;
440         output_buffer((uint8 *)buf, out_bytes);
441         IAudioRenderClient_ReleaseBuffer(pAudioRenderClient, out_frames, 0);
442         return TRUE;
443 }
444
445 static int write_buffer_polling(void)
446 {       
447         UINT32 padding = 0;
448         size_t out_bytes, out_frames;
449         BYTE *buf = NULL;
450
451         if(FAILED(IAudioClient_GetCurrentPadding(pAudioClient, &padding)))
452                 return FALSE;
453         out_bytes = calc_output_bytes((BufferFrames - padding) * FrameBytes);
454         out_frames = out_bytes / FrameBytes;
455         if(FAILED(IAudioRenderClient_GetBuffer(pAudioRenderClient, out_frames, &buf)))
456                 return FALSE;
457         output_buffer((uint8 *)buf, out_bytes);
458         IAudioRenderClient_ReleaseBuffer(pAudioRenderClient, out_frames, 0);
459         return TRUE;
460 }
461
462 static unsigned int WINAPI render_thread(void *arglist)
463 {
464         int ret = 1;
465         HANDLE hMmCss = NULL;
466         DWORD mmCssTaskIndex = 0;
467                 
468         if(FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED)))
469                 return 1;
470         hMmCss = (pAvSetMmThreadCharacteristics)(ThreadPriorityName[ThreadPriorityNum], &mmCssTaskIndex);
471         if(!hMmCss)
472                 goto thread_exit;
473         IsThreadStart = 1;
474         WaitForSingleObject(hEventTcv, INFINITE); // wait initialize open_output
475         ResetEvent(hEventTcv);
476         if(!IsPolling){
477                 for(;;){ // event
478                         WaitForSingleObject(hEventTcv, INFINITE);
479                         ResetEvent(hEventTcv);
480                         if(IsThreadExit) break;         
481                         EnterCriticalSection(&critSect);
482                         write_buffer_event();
483                         LeaveCriticalSection(&critSect);
484                 }
485         }else{
486                 for(;;){ // polling
487                         WaitForSingleObject(hEventTcv, ThreadWaitTime);
488                         ResetEvent(hEventTcv);
489                         if(IsThreadExit) break;
490                         EnterCriticalSection(&critSect);
491                         write_buffer_polling();
492                         LeaveCriticalSection(&critSect);
493                 }
494         }
495         ret = 0;
496 thread_exit:
497         if(hMmCss)
498                 (pAvRevertMmThreadCharacteristics)(hMmCss);
499         CoUninitialize();
500         IsThreadStart = 0;
501         return ret;
502 }
503
504 /*****************************************************************************************************************************/
505
506 /* returns TRUE on success */
507 static int get_default_device(IMMDevice** ppMMDevice)
508 {
509         IMMDeviceEnumerator *pEnumerator = NULL;
510
511         if(FAILED(CoCreateInstance(&tim_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &tim_IID_IMMDeviceEnumerator, (void**)&pEnumerator)))
512                 goto error;
513         if(FAILED(IMMDeviceEnumerator_GetDefaultAudioEndpoint(pEnumerator, eRender, eConsole, ppMMDevice)))
514                 goto error;
515         if(pEnumerator)
516                 IMMDeviceEnumerator_Release(pEnumerator);
517         return TRUE;
518 error:
519         if(pEnumerator)
520                 IMMDeviceEnumerator_Release(pEnumerator);
521         return FALSE;
522 }
523
524 static int get_device(IMMDevice **ppMMDevice, int devnum)
525 {
526         int i;
527         UINT num;
528         HRESULT hr;
529         IMMDeviceEnumerator *pde = NULL;
530         IMMDeviceCollection *pdc = NULL;
531         IMMDevice *pdev = NULL;
532         WCHAR *pszDeviceId = NULL;
533
534         if(devnum > WASAPI_DEVLIST_MAX - 2)
535                 devnum = -1;
536         if(devnum < 0)
537                 return get_default_device(ppMMDevice);          
538         if(FAILED(CoCreateInstance(&tim_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &tim_IID_IMMDeviceEnumerator, (void **)&pde)))
539                 goto error;
540         if(FAILED(IMMDeviceEnumerator_EnumAudioEndpoints(pde, eRender, DEVICE_STATE_ACTIVE, &pdc)))
541                 goto error;     
542         if(FAILED(IMMDeviceCollection_GetCount(pdc, &num)))
543                 goto error;
544         if(num <= 0)
545                 goto error;
546         if(num > WASAPI_DEVLIST_MAX - 2)
547                 num = WASAPI_DEVLIST_MAX - 2;
548         if(devnum > num)
549                 goto error;
550         if(FAILED(IMMDeviceCollection_Item(pdc, devnum, &pdev)))
551                 goto error;  
552         if(FAILED(IMMDevice_GetId(pdev, &pszDeviceId)))
553                 goto error;
554         if(FAILED(IMMDeviceEnumerator_GetDevice(pde, pszDeviceId, ppMMDevice)))
555                 goto error;             
556         if(pszDeviceId)
557                 CoTaskMemFree(pszDeviceId);
558         if(pde)
559                 IMMDeviceEnumerator_Release(pde);
560         return TRUE;
561
562 error:  
563         if(pszDeviceId)
564                 CoTaskMemFree(pszDeviceId);
565         if(pde)
566                 IMMDeviceEnumerator_Release(pde);
567         return FALSE;
568 }
569
570
571 /*****************************************************************************************************************************/
572 /* interface function */
573
574 void close_output(void)
575 {
576         if(IsStarted){
577                 if(pAudioClient){
578                         IAudioClient_Stop(pAudioClient);
579                 }
580                 IsStarted = FALSE;
581         }
582         IsThreadExit = 1;
583         if(hRenderThread){
584                 if(hEventTcv){
585                         SetEvent(hEventTcv);
586                         WaitForSingleObject(hRenderThread, INFINITE);
587                 }
588                 CloseHandle(hRenderThread);
589                 hRenderThread = NULL;
590         }
591         IsThreadExit = 0;
592         free_buffer();
593         if(pAudioRenderClient){
594                 IAudioRenderClient_Release(pAudioRenderClient);
595                 pAudioRenderClient = NULL;
596         }
597         if(pAudioClient){
598                 IAudioClient_Release(pAudioClient);
599                 pAudioClient = NULL;
600         }
601         if(pMMDevice){
602                 IMMDevice_Release(pMMDevice);
603                 pMMDevice = NULL;
604         }
605         if(hEventTcv){
606                 CloseHandle(hEventTcv);
607                 hEventTcv = NULL;
608         }
609         if(IsCoInit && CoInitThreadId == GetCurrentThreadId()){
610                 CoUninitialize();
611                 IsCoInit = 0;
612         }
613         BufferFrames = 0;
614         free_avrt();
615 #ifdef CNV_USE_TEMP_ENCODE
616         reset_temporary_encoding();
617 #endif
618         IsOpened = 0;
619 }
620
621 /* 0=success, 1=warning, -1=fatal error */
622 int open_output(void)
623 {
624         HRESULT hr;
625         int include_enc, exclude_enc;
626         WAVEFORMATEXTENSIBLE wfe = {0};
627         WAVEFORMATEX *pwf = NULL;
628         AUDCLNT_SHAREMODE ShareMode;
629         uint32 StreamFlags;
630         REFERENCE_TIME Periodicity, LatencyMax, LatencyMin;     
631         GUID guid_WAVE_FORMAT = {WAVE_FORMAT_UNKNOWN,0x0000,0x0010,{0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
632         BYTE *buf;
633
634         close_output(); 
635         if(!get_winver()){
636                 ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "ERROR! WASAPI require Windows Vista and later.");
637                 return -1;
638         }
639         if(!load_avrt()){
640                 ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "ERROR! AVRT.DLL function failed.");
641                 goto error;
642         }       
643         IsExclusive = opt_wasapi_exclusive;
644         IsPolling = opt_wasapi_polling;
645         hEventTcv = CreateEvent(NULL,FALSE,FALSE,NULL); // reset manual
646         if(!hEventTcv)
647                 goto error;     
648         hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
649     if(FAILED(hr) && hr != RPC_E_CHANGED_MODE)
650                 goto error;     
651     if(hr != RPC_E_CHANGED_MODE){
652                 IsCoInit = 1;
653                 CoInitThreadId = GetCurrentThreadId();
654     }
655         if(!get_device(&pMMDevice, opt_output_device_id == -3 ? opt_wasapi_device_id : opt_output_device_id))
656                 goto error;
657         if(FAILED(IMMDevice_Activate(pMMDevice, &tim_IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&pAudioClient)))
658                 goto error;     
659
660 #if 0 // test format
661         {
662         IPropertyStore *pps = NULL;
663         PROPVARIANT value;
664         int cpsz;
665
666         if(FAILED(IMMDevice_OpenPropertyStore(pMMDevice, STGM_READ, &pps)))
667                 goto error;
668     PropVariantInit(&value);
669     if(FAILED(IPropertyStore_GetValue(pps, &PKEY_AudioEngine_DeviceFormat, &value)))
670                 goto error;
671         cpsz = min(sizeof(WAVEFORMATEXTENSIBLE), value.blob.cbSize);
672         memcpy(&wfe, value.blob.pBlobData, cpsz);
673     PropVariantClear(&value);
674         if(pps){
675                 pps->lpVtbl->Release(pps); 
676                 pps = NULL;
677         }
678         if(cpsz == sizeof(WAVEFORMATEX)){
679                 pwf = (WAVEFORMATEX *)&wfe;
680                 opt_wasapi_format_ext = 0;
681         }else{
682                 pwf = &wfe.Format;
683                 opt_wasapi_format_ext = 1;
684         }
685         }
686 #endif
687
688         include_enc = PE_SIGNED;
689         exclude_enc = PE_BYTESWAP | PE_ULAW | PE_ALAW;  
690         if(!(dpm.encoding & (PE_F64BIT | PE_64BIT | PE_F32BIT | PE_32BIT | PE_24BIT | PE_16BIT))) // 8bit
691                 include_enc |= PE_16BIT;
692         dpm.encoding = validate_encoding(dpm.encoding, include_enc, exclude_enc);
693         
694         if(opt_wasapi_format_ext){
695                 pwf = &wfe.Format;
696                 memcpy(&wfe.SubFormat, &guid_WAVE_FORMAT, sizeof(GUID));
697                 pwf->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
698                 pwf->cbSize       = (WORD)22;
699         }else{
700                 pwf = (WAVEFORMATEX *)&wfe;
701                 pwf->cbSize       = (WORD)0;
702         }
703         CvtMode = 0;
704         if(dpm.encoding & PE_16BIT){
705                 if(opt_wasapi_format_ext){                      
706                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
707                         wfe.Samples.wValidBitsPerSample = 16;
708 #if 1
709                         pwf->wBitsPerSample = (WORD) 16;
710 #else
711                         if(opt_wasapi_exclusive){
712                                 pwf->wBitsPerSample = (WORD) 32;
713                                 CvtMode = 1;
714                         }else{
715                                 pwf->wBitsPerSample = (WORD) 16;
716                         }               
717 #endif
718                 }else{
719                         pwf->wFormatTag = WAVE_FORMAT_PCM;
720                         pwf->wBitsPerSample = (WORD) 16;
721                 }
722         }else if(dpm.encoding & PE_24BIT){
723                 if(opt_wasapi_format_ext){
724                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
725                         wfe.Samples.wValidBitsPerSample = 24;
726                         if(IsExclusive){
727                                 pwf->wBitsPerSample = (WORD) 32;
728                                 CvtMode = 2;
729                         }else{
730                                 pwf->wBitsPerSample = (WORD) 24;
731                         }
732                 }else{
733                         pwf->wFormatTag = WAVE_FORMAT_PCM;
734                         pwf->wBitsPerSample = (WORD) 24;
735                 }
736         }else if(dpm.encoding & PE_32BIT){
737                 if(opt_wasapi_format_ext){
738                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
739                         wfe.Samples.wValidBitsPerSample = 32;
740                         pwf->wBitsPerSample = (WORD) 32;                        
741                 }else{
742                         pwf->wFormatTag = WAVE_FORMAT_PCM;
743                         pwf->wBitsPerSample = (WORD) 32;
744                 }
745         }else if(dpm.encoding & PE_F32BIT){
746                 if(opt_wasapi_format_ext){
747                         wfe.SubFormat.Data1 = WAVE_FORMAT_IEEE_FLOAT;
748                         wfe.Samples.wValidBitsPerSample = 32;
749                         pwf->wBitsPerSample = (WORD) 32;                        
750                 }else{
751                         pwf->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
752                         pwf->wBitsPerSample = (WORD) 32;
753                 }
754         }else if(dpm.encoding & PE_64BIT){
755                 if(opt_wasapi_format_ext){
756                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
757                         wfe.Samples.wValidBitsPerSample = 64;
758                         pwf->wBitsPerSample = (WORD) 64;                        
759                 }else{
760                         pwf->wFormatTag = WAVE_FORMAT_PCM;
761                         pwf->wBitsPerSample = (WORD) 64;
762                 }
763         }else if(dpm.encoding & PE_F64BIT){
764                 if(opt_wasapi_format_ext){
765                         wfe.SubFormat.Data1 = WAVE_FORMAT_IEEE_FLOAT;
766                         wfe.Samples.wValidBitsPerSample = 64;
767                         pwf->wBitsPerSample = (WORD) 64;                        
768                 }else{
769                         pwf->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
770                         pwf->wBitsPerSample = (WORD) 64;
771                 }
772         }else{ // 8bit // error
773                 if(opt_wasapi_format_ext){
774                         wfe.SubFormat.Data1 = WAVE_FORMAT_PCM;
775                         wfe.Samples.wValidBitsPerSample = 8;
776                         pwf->wBitsPerSample = (WORD) 8;                 
777                 }else{
778                         pwf->wFormatTag = WAVE_FORMAT_PCM;
779                         pwf->wBitsPerSample = (WORD) 8;
780                 }
781         }
782         pwf->nChannels       = (WORD)dpm.encoding & PE_MONO ? 1 : 2;
783         pwf->nSamplesPerSec  = (DWORD)dpm.rate;
784         pwf->nBlockAlign     = (WORD)(pwf->nChannels * pwf->wBitsPerSample / 8);
785         pwf->nAvgBytesPerSec = (DWORD)pwf->nSamplesPerSec * pwf->nBlockAlign;
786         wfe.dwChannelMask = pwf->nChannels==1 ? SPEAKER_MONO : SPEAKER_STEREO;
787
788 #ifdef CNV_USE_TEMP_ENCODE
789         if(CvtMode == 2){                       
790                 int tmp_enc = dpm.encoding;
791                 tmp_enc &= ~PE_24BIT;
792                 tmp_enc |= PE_32BIT;
793                 set_temporary_encoding(tmp_enc);
794         }else if(CvtMode == 1){                 
795                 int tmp_enc = dpm.encoding;
796                 tmp_enc &= ~PE_16BIT;
797                 tmp_enc |= PE_32BIT;
798                 set_temporary_encoding(tmp_enc);
799         }else{
800                 reset_temporary_encoding();
801         }
802 #endif
803
804         FrameBytes = pwf->nBlockAlign;
805         
806 #ifdef __IAudioClient2_INTERFACE_DEFINED__      
807         {
808                 int ver = get_winver();
809
810                 if(ver >= 3) // win8\88È\8fã
811                 {
812                         AudioClientProperties acp = {0};
813                         acp.cbSize     = sizeof(AudioClientProperties);
814                         acp.bIsOffload = FALSE;
815                         acp.eCategory  = opt_wasapi_stream_category;
816                 
817                         if(opt_wasapi_stream_option >= 2){
818                                 if(ver >= 6) // win10\88È\8fã
819                                         acp.Options = AUDCLNT_STREAMOPTIONS_MATCH_FORMAT;
820                         }else if(opt_wasapi_stream_option == 1){
821                                 if(ver >= 6) // win8.1\88È\8fã
822                                         acp.Options = AUDCLNT_STREAMOPTIONS_RAW;
823                         }
824                         hr = IAudioClient2_SetClientProperties((IAudioClient2 *)pAudioClient, (AudioClientProperties *)&acp);
825                                 goto error;
826                 }
827         }
828 #endif
829         
830         if(opt_wasapi_priority <= 0 || opt_wasapi_priority > 7)
831                 ThreadPriorityNum = IsExclusive ? 6 : 1;
832         else
833                 ThreadPriorityNum = opt_wasapi_priority;
834         ShareMode = IsExclusive ? AUDCLNT_SHAREMODE_EXCLUSIVE : AUDCLNT_SHAREMODE_SHARED;
835         StreamFlags = IsPolling ? 0x0 : AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
836         StreamFlags |= AUDCLNT_STREAMFLAGS_NOPERSIST;
837 #if 1
838         LatencyMax = 100000;
839         LatencyMin = 30000;
840         if(FAILED(IAudioClient_GetDevicePeriod(pAudioClient, &LatencyMax, &LatencyMin))){
841                 LatencyMax = 100000;
842                 LatencyMin = 30000;
843         }
844         if(LatencyMax > 10000000) // 1000ms
845                 LatencyMax = 10000000;
846         else if(LatencyMin < 10000)
847                 LatencyMin = 10000; // 1ms
848         BufferDuration = opt_wasapi_latency * 10000; // ms to 100ns
849         if(BufferDuration > LatencyMax)
850                 BufferDuration = LatencyMax;
851         if(BufferDuration < LatencyMin)
852                 BufferDuration = LatencyMin;
853 #else
854         BufferDuration = (IsExclusive ? 10 : 30) * 10000; // 10ms,30ms
855 #endif
856         Periodicity = IsExclusive ? BufferDuration : 0;
857         
858         hr = IAudioClient_Initialize(pAudioClient, ShareMode, StreamFlags, BufferDuration, Periodicity, (WAVEFORMATEX *)&wfe, NULL);
859         if(hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED){
860                 UINT32 bufferSize;
861
862                 if(FAILED(IAudioClient_GetBufferSize(pAudioClient, &bufferSize)))
863                         goto error;
864                 IAudioClient_Release(pAudioClient);
865                 pAudioClient = NULL;
866                 BufferDuration = (REFERENCE_TIME)(10000.0f * 1000 * bufferSize / pwf->nSamplesPerSec + 0.5);
867                 if(FAILED(IMMDevice_Activate(pMMDevice, &tim_IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, (void**)&pAudioClient)))
868                         goto error;
869                 hr = IAudioClient_Initialize(pAudioClient, ShareMode, StreamFlags, BufferDuration, Periodicity, (WAVEFORMATEX *)&wfe, NULL);
870         }
871         if(FAILED(hr))
872                 goto error;
873         if(FAILED(IAudioClient_GetBufferSize(pAudioClient, &BufferFrames)))
874                 goto error;
875         if(!IsPolling)
876                 if(FAILED(IAudioClient_SetEventHandle(pAudioClient, hEventTcv)))
877                         goto error;
878         if(FAILED(IAudioClient_GetService(pAudioClient, &tim_IID_IAudioRenderClient, (void**)&pAudioRenderClient)))
879                 goto error;
880         
881         if(dpm.extra_param[0] < 2){
882                 ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Too small -B option: %d,X", dpm.extra_param[0]);
883                 dpm.extra_param[0] = 2;
884         }       
885         if(audio_buffer_size < 5){
886                 ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Too small -B option: X,%d", audio_buffer_bits);
887                 audio_buffer_bits = 5;
888         }
889         QueueSize = audio_buffer_size * FrameBytes * dpm.extra_param[0];
890         WaitTime = (double)audio_buffer_size * div_playmode_rate * 1000.0 * DIV_4; // blocktime/4
891         if(IsPolling){ // for polling
892                 DWORD sleep_ms_in = (double)audio_buffer_size * div_playmode_rate * 1000.0 * DIV_2;
893                 DWORD sleep_ms_out = (double)BufferDuration * DIV_10000 * DIV_2; // 100ns to ms
894                 ThreadWaitTime = sleep_ms_in < sleep_ms_out ? sleep_ms_in : sleep_ms_out;
895         }
896         IsOpened = 1;
897         IsThreadStart = 0;
898         IsThreadExit = 0;
899         if(!hRenderThread){
900                 hRenderThread = (HANDLE)_beginthreadex(NULL, 0, &render_thread, NULL, 0, NULL);
901                 if(!hRenderThread)
902                         goto error;
903         }
904         if(!IsStarted){
905                 int count = 20; // 200ms
906                 if(FAILED(IAudioRenderClient_GetBuffer(pAudioRenderClient, BufferFrames, &buf)))
907                         goto error;
908                 IAudioRenderClient_ReleaseBuffer(pAudioRenderClient, BufferFrames, AUDCLNT_BUFFERFLAGS_SILENT);
909                 while(!IsThreadStart && count > 0){ // 
910                         Sleep(10);
911                         --count;
912                 }
913                 if(count <= 0) // time out
914                         goto error;
915                 if(FAILED(IAudioClient_Start(pAudioClient)))
916                         goto error;     
917                 SetEvent(hEventTcv); // start process
918                 IsStarted = TRUE;
919         }
920         return 0;
921 error:
922         close_output();
923         return -1;
924 }
925
926 int output_data(const uint8 *buf, size_t nbytes)
927 {
928         int flg = TRUE, i;
929         int32 max_count = 64; // wait =  blocktime/4 * max_count
930 #ifndef CNV_USE_TEMP_ENCODE
931         uint8 tbuff[2 * (1L << DEFAULT_AUDIO_BUFFER_BITS) * sizeof(int16) * 2] = {0};
932 #endif
933
934         if(!IsOpened) 
935                 return -1;      
936 #ifndef CNV_USE_TEMP_ENCODE
937         if(CvtMode == 2){ // 24bit 3byte->4byte
938                 int samples = nbytes / 3;
939                 uint8 *in = (uint8 *)buf, *out = tbuff;
940                 for(i = 0; i < samples; i++){
941                         *out++ = 0;
942                         *out++ = *(in)++;
943                         *out++ = *(in)++;
944                         *out++ = *(in)++;
945                 }
946                 buf = (const uint8 *)&tbuff;
947                 nbytes = samples * 4;
948         }else if(CvtMode == 1){ // 16bit 2byte->4byte
949                 int samples = nbytes / 2;
950                 uint8 *in = (uint8 *)buf, *out = tbuff;
951                 for(i = 0; i < samples; i++){
952                         *out++ = 0;
953                         *out++ = 0;
954                         *out++ = *(in)++;
955                         *out++ = *(in)++;
956                 }
957                 buf = (const uint8 *)&tbuff;
958                 nbytes = samples * 4;
959         }
960 #endif
961         for(;;){
962                 if(!IsOpened)
963                         return -1; 
964                 if(get_filled_byte() < QueueSize)
965                         break;
966                 if(max_count <= 0){
967                         ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "WASAPI error: timeout output_data().");
968                         return -1; 
969                 }
970                 Sleep(WaitTime);
971                 --max_count; 
972         }
973         EnterCriticalSection(&critSect);
974         flg = input_buffer(buf, nbytes);
975         LeaveCriticalSection(&critSect);
976         if(flg)
977                 return 0;
978         close_output();
979         return -1;
980 }
981
982 int acntl(int request, void *arg)
983 {
984         switch(request){
985         //case PM_REQ_GETFRAGSIZ:
986         //      return 0;
987         case PM_REQ_GETQSIZ:
988                 *(int *)arg = QueueSize;
989                 return 0;
990         case PM_REQ_GETFILLED:
991                 *(int *)arg = get_filled_byte();
992                 return 0;
993         case PM_REQ_FLUSH: // thru
994                 while (!is_buffer_empty())
995                         WaitForSingleObject(hRenderThread, 10); 
996         case PM_REQ_DISCARD:
997                 close_output();
998                 open_output();
999                 return 0;
1000         case PM_REQ_PLAY_START:
1001                 return 0;
1002         case PM_REQ_PLAY_END:
1003                 return 0;
1004         default:
1005                 return -1;
1006         }
1007 }
1008
1009 int detect(void)
1010 {
1011         IMMDevice *pMMDevice = NULL;
1012         int result = get_default_device(&pMMDevice);
1013         if(pMMDevice)
1014                 IMMDevice_Release(pMMDevice);
1015         return result;
1016 }
1017
1018 /*****************************************************************************************************************************/
1019
1020 int wasapi_device_list(WASAPI_DEVICELIST *device)
1021 {
1022         int i;
1023         UINT num;
1024         HRESULT hr;
1025         IMMDeviceEnumerator *pde = NULL;
1026         IMMDeviceCollection *pdc = NULL;
1027         IPropertyStore *pps = NULL;
1028         IAudioClient *tmpClient = NULL; 
1029         REFERENCE_TIME LatencyMax, LatencyMin;
1030         IMMDevice *defdev = NULL;
1031         
1032         device[0].deviceID = -1;
1033         device[0].LatencyMax = 10;
1034         device[0].LatencyMin = 3;
1035         strcpy(device[0].name, "Default Render Device");
1036         
1037         if(!get_winver())
1038                 goto error0;
1039         if(detect() == FALSE)
1040                 goto error0;    
1041         if(!get_default_device(&defdev))
1042                 goto error0;    
1043         if(FAILED(CoCreateInstance(&tim_CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &tim_IID_IMMDeviceEnumerator, (void **)&pde)))
1044                 goto error1;
1045         if(FAILED(IMMDeviceEnumerator_EnumAudioEndpoints(pde, eRender, DEVICE_STATE_ACTIVE, &pdc)))
1046                 goto error1;    
1047         LatencyMax = 100000;
1048         LatencyMin = 30000;
1049         if(FAILED(IMMDevice_Activate(defdev, &tim_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&tmpClient))){
1050                 LatencyMin =LatencyMin;
1051         }else if(FAILED(IAudioClient_GetDevicePeriod(tmpClient, &LatencyMax, &LatencyMin))){
1052                 LatencyMin =LatencyMin;
1053         }       
1054         LatencyMax /= 10000; // hns to ms
1055         LatencyMin /= 10000; // hns to ms
1056         if(LatencyMax > 1000)
1057                 LatencyMax = 1000;
1058         if(LatencyMin < 0)
1059                 LatencyMin = 1;
1060         device[0].LatencyMax = LatencyMax;
1061         device[0].LatencyMin = LatencyMin;
1062         if(tmpClient){
1063                 tmpClient->lpVtbl->Release(tmpClient);
1064                 tmpClient = NULL;
1065         }       
1066         if(defdev){
1067                 IMMDevice_Release(defdev);
1068                 defdev = NULL;
1069         }
1070         if(FAILED(IMMDeviceCollection_GetCount(pdc, &num)))
1071                 goto error1;
1072         if(num <= 0)
1073                 goto error1;
1074         if(num > WASAPI_DEVLIST_MAX - 2)
1075                 num = WASAPI_DEVLIST_MAX - 2;
1076         for(i = 0; i < num; i++){ // -1, 0
1077                 IMMDevice *dev = NULL;
1078                 PROPVARIANT value;
1079                 IAudioClient *tmpClient = NULL;
1080
1081                 if(FAILED(IMMDeviceCollection_Item(pdc, i, &dev)))
1082                         goto error1;    
1083                 device[i+1].deviceID = i;
1084                 if(FAILED(IMMDevice_OpenPropertyStore(dev, STGM_READ, &pps)))
1085                         goto error1;
1086                 PropVariantInit(&value);
1087                 if(FAILED(IPropertyStore_GetValue(pps, &PKEY_Device_FriendlyName, &value))){
1088                         PropVariantClear(&value);
1089                 }else{
1090                         if(value.pwszVal)
1091 #ifdef UNICODE
1092                                 WideCharToMultiByte(CP_UTF8, 0, value.pwszVal, (int)wcslen(value.pwszVal), device[i+1].name, WASAPI_DEVLIST_LEN - 1, 0, 0);
1093 #else
1094                                 WideCharToMultiByte(CP_ACP, 0, value.pwszVal, (int)wcslen(value.pwszVal), device[i+1].name, WASAPI_DEVLIST_LEN - 1, 0, 0);
1095 #endif
1096                         else
1097                                 _snprintf(device[i+1].name, WASAPI_DEVLIST_LEN - 1, "Device Error %d", i);
1098                 }
1099                 PropVariantClear(&value);
1100                 LatencyMax = 100000;
1101                 LatencyMin = 30000;
1102                 if(FAILED(IMMDevice_Activate(dev, &tim_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&tmpClient))){
1103                 }else if(FAILED(IAudioClient_GetDevicePeriod(tmpClient, &LatencyMax, &LatencyMin))){
1104                 }
1105                 LatencyMax /= 10000; // hns to ms
1106                 LatencyMin /= 10000; // hns to ms
1107                 if(LatencyMax > 1000)
1108                         LatencyMax = 1000;
1109                 if(LatencyMin < 0)
1110                         LatencyMin = 1;
1111                 device[i+1].LatencyMax = LatencyMax;
1112                 device[i+1].LatencyMin = LatencyMin;
1113                 if(tmpClient){
1114                         tmpClient->lpVtbl->Release(tmpClient);
1115                         tmpClient = NULL;
1116                 }               
1117                 if(dev){
1118                         IMMDevice_Release(dev);
1119                         dev = NULL;
1120                 }
1121                 if(pps){
1122                         pps->lpVtbl->Release(pps); 
1123                         pps = NULL;
1124                 }
1125         }
1126         if(pdc)
1127                 pdc->lpVtbl->Release(pdc); 
1128         if(pde)
1129                 IMMDeviceEnumerator_Release(pde);
1130         return num + 1; // +1 def dev
1131
1132 error1:
1133         if(tmpClient)
1134                 tmpClient->lpVtbl->Release(tmpClient);
1135         if(pdc){
1136                 pdc->lpVtbl->Release(pdc);
1137         }
1138         if(pde)
1139                 IMMDeviceEnumerator_Release(pde);
1140         return 1;
1141 error0:
1142         return 0;
1143 }
1144
1145
1146 #endif /* AU_WASAPI */
1147
1148