Typo correction patch [ 1208110 ] Lots of typo corrections
[wxWidgets.git] / contrib / src / mmedia / sndwin.cpp
1 // --------------------------------------------------------------------------
2 // Name: sndwin.cpp
3 // Purpose:
4 // Date: 08/11/1999
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
6 // CVSID: $Id$
7 // wxWindows licence
8 // --------------------------------------------------------------------------
9 #ifdef __GNUG__
10 #pragma implementation "sndwin.cpp"
11 #endif
12
13 #include "wx/wxprec.h"
14
15 #ifdef __WINDOWS__
16
17 #ifndef WX_PRECOMP
18 #include "wx/defs.h"
19 #include "wx/app.h"
20 #include "wx/string.h"
21 #endif
22
23 #include "wx/module.h"
24 #include "wx/msw/private.h"
25
26 // -------------------------------------------------------------------------
27 // MMedia headers
28 // -------------------------------------------------------------------------
29
30 #include "wx/mmedia/sndbase.h"
31 #include "wx/mmedia/sndwin.h"
32 #include "wx/mmedia/sndpcm.h"
33
34 // -------------------------------------------------------------------------
35 // System headers
36 // -------------------------------------------------------------------------
37
38 #include <windows.h>
39 #include <mmsystem.h>
40
41 // -------------------------------------------------------------------------
42 // External definitions, forward, ...
43 // -------------------------------------------------------------------------
44
45 typedef struct _wxSoundInternal wxSoundInternal;
46 typedef struct _wxSoundInfoHeader wxSoundInfoHeader;
47
48 extern const wxChar *wxCanvasClassName;
49
50 wxList *wxSoundHandleList = NULL;
51
52 static inline wxSoundStreamWin *wxFindSoundFromHandle(WXHWND hWnd)
53 {
54 wxObjectList::compatibility_iterator node = wxSoundHandleList->Find((long)hWnd);
55 if (!node)
56 return NULL;
57 return (wxSoundStreamWin *)node->GetData();
58 }
59
60 struct _wxSoundInternal {
61 HWND m_sndWin;
62 HWAVEIN m_devin;
63 HWAVEOUT m_devout;
64 bool m_output_enabled, m_input_enabled;
65 };
66
67 struct _wxSoundInfoHeader {
68 HGLOBAL m_h_header, m_h_data;
69 char *m_data;
70 WAVEHDR *m_header;
71 int m_mode;
72 bool m_playing, m_recording;
73 wxUint32 m_position, m_size;
74
75 wxSoundStreamWin *m_driver;
76 };
77
78 #define WXSOUND_MAX_QUEUE 10
79
80 wxSoundStreamWin::wxSoundStreamWin()
81 {
82 wxSoundFormatPcm pcm;
83
84 m_production_started = false;
85 m_internal = new wxSoundInternal;
86 if (!m_internal) {
87 m_snderror = wxSOUND_MEMERROR;
88 m_internal = NULL;
89 return;
90 }
91 m_snderror = wxSOUND_NOERROR;
92
93 // Setup defaults
94 CreateSndWindow();
95 SetSoundFormat(pcm);
96
97 m_internal->m_input_enabled = false;
98 m_internal->m_output_enabled = false;
99
100 m_waiting_for = false;
101
102 if (!OpenDevice(wxSOUND_OUTPUT)) {
103 m_snderror = wxSOUND_NOERROR; //next call to OpenDevice won't do this
104 if (!OpenDevice(wxSOUND_INPUT))
105 return;
106 }
107
108 CloseDevice();
109 }
110
111 wxSoundStreamWin::~wxSoundStreamWin()
112 {
113 if (m_internal) {
114 if (m_production_started)
115 StopProduction();
116 DestroySndWindow();
117
118 delete m_internal;
119 }
120 }
121
122 // -----------------------------------------------------------------------
123 // _wxSoundHandlerWndProc: Window callback to handle buffer completion
124 // -----------------------------------------------------------------------
125 LRESULT APIENTRY _EXPORT
126
127 _wxSoundHandlerWndProc(HWND hWnd, UINT message,
128 WPARAM wParam, LPARAM WXUNUSED(lParam))
129 {
130 wxSoundStreamWin *sndwin;
131
132 sndwin = wxFindSoundFromHandle((WXHWND)hWnd);
133 if (!sndwin)
134 return (LRESULT)0;
135
136 switch (message) {
137 case MM_WOM_DONE:
138 sndwin->NotifyDoneBuffer(wParam, wxSOUND_OUTPUT);
139 break;
140 case MM_WIM_DATA:
141 sndwin->NotifyDoneBuffer(wParam, wxSOUND_INPUT);
142 break;
143 default:
144 break;
145 }
146 return (LRESULT)0;
147 }
148
149 // -----------------------------------------------------------------------
150 // CreateSndWindow() creates an hidden window which will receive the sound
151 // events
152 // -----------------------------------------------------------------------
153
154 void wxSoundStreamWin::CreateSndWindow()
155 {
156 FARPROC proc = MakeProcInstance((FARPROC)_wxSoundHandlerWndProc,
157 wxGetInstance());
158 // NB: class name must be kept in sync with wxCanvasClassName in
159 // src/msw/app.cpp!
160 m_internal->m_sndWin = ::CreateWindow(wxT("wxWindowClass"), NULL, 0,
161 0, 0, 0, 0, NULL, (HMENU) NULL,
162 wxGetInstance(), NULL);
163
164 GetLastError();
165
166 ::SetWindowLong(m_internal->m_sndWin, GWL_WNDPROC, (LONG)proc);
167
168 // Add this window to the sound handle list so we'll be able to redecode
169 // the "magic" number.
170 wxSoundHandleList->Append((long)m_internal->m_sndWin, (wxObject *)this);
171 }
172
173 // -----------------------------------------------------------------------
174 // DestroySndWindow() destroys the hidden window
175 // -----------------------------------------------------------------------
176
177 void wxSoundStreamWin::DestroySndWindow()
178 {
179 if (m_internal->m_sndWin) {
180 ::DestroyWindow(m_internal->m_sndWin);
181 wxSoundHandleList->DeleteObject((wxObject *)this);
182 }
183 }
184
185 // -------------------------------------------------------------------------
186 // OpenDevice(int mode) initializes the windows driver for a "mode"
187 // operation. mode is a bit mask: if the bit "wxSOUND_OUTPUT" is set,
188 // the driver is opened for output operation, and if the bit "wxSOUND_INPUT"
189 // is set, then the driver is opened for input operation. The two modes
190 // aren't exclusive.
191 // The initialization parameters (sample rate, ...) are taken from the
192 // m_sndformat object.
193 // At the end, OpenDevice() calls AllocHeaders() to initialize the Sound IO
194 // queue.
195 // -------------------------------------------------------------------------
196 bool wxSoundStreamWin::OpenDevice(int mode)
197 {
198 wxSoundFormatPcm *pcm;
199 WAVEFORMATEX wformat;
200
201 if (!m_sndformat) {
202 m_snderror = wxSOUND_INVFRMT;
203 return false;
204 }
205
206 pcm = (wxSoundFormatPcm *)m_sndformat;
207
208 wformat.wFormatTag = WAVE_FORMAT_PCM;
209 wformat.nChannels = pcm->GetChannels();
210 wformat.nBlockAlign = wformat.nChannels * pcm->GetBPS() / 8;
211 wformat.nSamplesPerSec = pcm->GetSampleRate();
212 wformat.nAvgBytesPerSec = wformat.nSamplesPerSec * wformat.nBlockAlign;
213 wformat.wBitsPerSample = pcm->GetBPS();
214 wformat.cbSize = 0;
215
216 // -----------------------------------
217 // Open the driver for Output operation
218 // -----------------------------------
219 if (mode & wxSOUND_OUTPUT) {
220 MMRESULT result;
221
222 result = waveOutOpen(&m_internal->m_devout,
223 WAVE_MAPPER, &wformat,
224 (DWORD)m_internal->m_sndWin, 0,
225 CALLBACK_WINDOW);
226
227 if (result != MMSYSERR_NOERROR) {
228 m_snderror = wxSOUND_INVDEV;
229 return false;
230 }
231
232 m_output_frag_out = WXSOUND_MAX_QUEUE-1;
233 m_current_frag_out = 0;
234
235 m_internal->m_output_enabled = true;
236 }
237 // -----------------------------------
238 // Open the driver for Input operation
239 // -----------------------------------
240 if (mode & wxSOUND_INPUT) {
241 MMRESULT result;
242
243 result = waveInOpen(&m_internal->m_devin,
244 WAVE_MAPPER, &wformat,
245 (DWORD)m_internal->m_sndWin, 0,
246 CALLBACK_WINDOW);
247
248 if (result != MMSYSERR_NOERROR) {
249 m_snderror = wxSOUND_INVDEV;
250 return false;
251 }
252
253 m_current_frag_in = WXSOUND_MAX_QUEUE-1;
254 m_input_frag_in = 0;
255
256 m_internal->m_input_enabled = true;
257 }
258
259 if (mode & wxSOUND_OUTPUT) {
260 if (!AllocHeaders(wxSOUND_OUTPUT)) {
261 CloseDevice();
262 return false;
263 }
264 }
265 if (mode & wxSOUND_INPUT) {
266 if (!AllocHeaders(wxSOUND_INPUT)) {
267 CloseDevice();
268 return false;
269 }
270 }
271
272 return true;
273 }
274
275 // -------------------------------------------------------------------------
276 // CloseDevice() closes the driver handles and frees memory allocated for
277 // IO queues.
278 // -------------------------------------------------------------------------
279 void wxSoundStreamWin::CloseDevice()
280 {
281 if (m_internal->m_output_enabled) {
282 FreeHeaders(wxSOUND_OUTPUT);
283 m_internal->m_output_enabled = false;
284 waveOutClose(m_internal->m_devout);
285 }
286
287 if (m_internal->m_input_enabled) {
288 FreeHeaders(wxSOUND_INPUT);
289 m_internal->m_input_enabled = false;
290 waveInClose(m_internal->m_devin);
291 }
292 }
293
294 // -------------------------------------------------------------------------
295 // AllocHeader(int mode)
296 //
297 // mode has the same mean as in OpenDevice() except that here the two flags
298 // must be exclusive.
299 // AllocHeader() initializes an element of an operation (this can be input
300 // or output). It means it allocates the sound header's memory block
301 // and "prepares" it (It is needed by Windows). At the same time, it sets
302 // private datas so we can the header's owner (See callback).
303 //
304 // It returns the new allocated block or NULL.
305 // -------------------------------------------------------------------------
306 wxSoundInfoHeader *wxSoundStreamWin::AllocHeader(int mode)
307 {
308 wxSoundInfoHeader *info;
309 WAVEHDR *header;
310
311 // Some memory allocation
312 info = new wxSoundInfoHeader;
313 info->m_h_data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, GetBestSize());
314 info->m_h_header = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, sizeof(WAVEHDR));
315 if (!info->m_h_data || !info->m_h_header) {
316 delete info;
317 m_snderror = wxSOUND_MEMERROR;
318 return NULL;
319 }
320
321 // Get the two pointers from the system
322 info->m_data = (char *)GlobalLock(info->m_h_data);
323 info->m_header = (WAVEHDR *)GlobalLock(info->m_h_header);
324 // Set the header's mode
325 info->m_mode = mode;
326 // Set the parent of the header
327 info->m_driver = this;
328 // Clean it up
329 ClearHeader(info);
330
331 header = info->m_header;
332 // Initialize Windows variables
333 header->lpData = info->m_data;
334 header->dwBufferLength = GetBestSize();
335 header->dwUser = (DWORD)info;
336 header->dwFlags = WHDR_DONE;
337
338 // "Prepare" the header
339 if (mode == wxSOUND_INPUT) {
340 MMRESULT result;
341
342 result = waveInPrepareHeader(m_internal->m_devin, header,
343 sizeof(WAVEHDR));
344
345 if (result != MMSYSERR_NOERROR) {
346 // If something goes wrong, free everything.
347 GlobalUnlock(info->m_data);
348 GlobalUnlock(info->m_header);
349 GlobalFree(info->m_h_data);
350 GlobalFree(info->m_h_header);
351 delete info;
352
353 m_snderror = wxSOUND_IOERROR;
354 return NULL;
355 }
356 } else if (mode == wxSOUND_OUTPUT) {
357 MMRESULT result;
358
359 result = waveOutPrepareHeader(m_internal->m_devout, header,
360 sizeof(WAVEHDR));
361
362 if (result != MMSYSERR_NOERROR) {
363 // If something goes wrong, free everything.
364 GlobalUnlock(info->m_data);
365 GlobalUnlock(info->m_header);
366 GlobalFree(info->m_h_data);
367 GlobalFree(info->m_h_header);
368 delete info;
369
370 m_snderror = wxSOUND_IOERROR;
371 return NULL;
372 }
373 }
374 return info;
375 }
376
377 // -------------------------------------------------------------------------
378 // AllocHeaders(int mode)
379 //
380 // "mode" has the same mean as for OpenDevice() except that the two flags must
381 // be exclusive.
382 // AllocHeaders() allocates WXSOUND_MAX_QUEUE (= 128) blocks for an operation
383 // queue. It uses AllocHeader() for each element.
384 //
385 // Once it has allocated all blocks, it returns true and if an error occurred
386 // it returns false.
387 // -------------------------------------------------------------------------
388 bool wxSoundStreamWin::AllocHeaders(int mode)
389 {
390 int i;
391 wxSoundInfoHeader **headers;
392
393 if (mode == wxSOUND_OUTPUT)
394 headers = m_headers_play = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE];
395 else
396 headers = m_headers_rec = new wxSoundInfoHeader *[WXSOUND_MAX_QUEUE];
397
398 memset(headers, 0, WXSOUND_MAX_QUEUE*sizeof(wxSoundInfoHeader *));
399
400 for (i=0;i<WXSOUND_MAX_QUEUE;i++) {
401 headers[i] = AllocHeader(mode);
402 if (!headers[i]) {
403 FreeHeaders(mode);
404 return false;
405 }
406 }
407 return true;
408 }
409
410 // -------------------------------------------------------------------------
411 // FreeHeader(int mode)
412 //
413 // "mode" has the same mean as for OpenDevice() except that the two flags must
414 // be exclusive.
415 // FreeHeader() frees a memory block and "unprepares" it.
416 // -------------------------------------------------------------------------
417 void wxSoundStreamWin::FreeHeader(wxSoundInfoHeader *header, int mode)
418 {
419 if (mode == wxSOUND_OUTPUT)
420 waveOutUnprepareHeader(m_internal->m_devout, header->m_header, sizeof(WAVEHDR));
421 else
422 waveInUnprepareHeader(m_internal->m_devin, header->m_header, sizeof(WAVEHDR));
423
424 GlobalUnlock(header->m_data);
425 GlobalUnlock(header->m_header);
426 GlobalFree(header->m_h_header);
427 GlobalFree(header->m_h_data);
428 delete header;
429 }
430
431 // -------------------------------------------------------------------------
432 // FreeHeaders(int mode)
433 //
434 // "mode" has the same mean as for OpenDevice() except that the two flags must
435 // be exclusive.
436 // FreeHeaders() frees all an operation queue once it has checked that
437 // all buffers have been terminated.
438 // -------------------------------------------------------------------------
439 void wxSoundStreamWin::FreeHeaders(int mode)
440 {
441 int i;
442 wxSoundInfoHeader ***headers;
443
444 if (mode == wxSOUND_OUTPUT)
445 headers = &m_headers_play;
446 else
447 headers = &m_headers_rec;
448
449 for (i=0;i<WXSOUND_MAX_QUEUE;i++) {
450 if ((*headers)[i]) {
451 // We wait for the end of the buffer
452 WaitFor((*headers)[i]);
453 // Then, we free the header
454 FreeHeader((*headers)[i], mode);
455 }
456 }
457 delete[] (*headers);
458 (*headers) = NULL;
459 }
460
461 // -------------------------------------------------------------------------
462 // WaitFor(wxSoundInfoHeader *info)
463 //
464 // "info" is one element of an IO queue
465 // WaitFor() checks whether the specified block has been terminated.
466 // If it hasn't been terminated, it waits for its termination.
467 //
468 // NB: if it's a partially filled buffer it adds it to the Windows queue
469 // -------------------------------------------------------------------------
470 void wxSoundStreamWin::WaitFor(wxSoundInfoHeader *info)
471 {
472 // If the buffer is finished, we return immediately
473 if (!info->m_playing) {
474
475 // We begun filling it: we must send it to the Windows queue
476 if (info->m_position != 0) {
477 memset(info->m_data + info->m_position, 0, info->m_size);
478 AddToQueue(info);
479 }
480 }
481
482 if (m_waiting_for) {
483 // PROBLEM //
484 return;
485 }
486 m_waiting_for = true;
487 // Else, we wait for its termination
488 while (info->m_playing || info->m_recording)
489 wxYield();
490 m_waiting_for = false;
491 }
492
493 // -------------------------------------------------------------------------
494 // AddToQueue(wxSoundInfoHeader *info)
495 //
496 // For "info", see WaitFor()
497 // AddToQueue() sends the IO queue element to the Windows queue.
498 //
499 // Warning: in the current implementation, it partially assume we send the
500 // element in the right order. This is true in that implementation but if
501 // you use it elsewhere, be careful: it may shuffle all your sound datas.
502 // -------------------------------------------------------------------------
503 bool wxSoundStreamWin::AddToQueue(wxSoundInfoHeader *info)
504 {
505 MMRESULT result;
506
507 if (info->m_mode == wxSOUND_INPUT) {
508 // Increment the input fragment pointer
509 result = waveInAddBuffer(m_internal->m_devin,
510 info->m_header, sizeof(WAVEHDR));
511 if (result == MMSYSERR_NOERROR)
512 info->m_recording = true;
513 else
514 return false;
515 } else if (info->m_mode == wxSOUND_OUTPUT) {
516 result = waveOutWrite(m_internal->m_devout,
517 info->m_header, sizeof(WAVEHDR));
518 if (result == MMSYSERR_NOERROR)
519 info->m_playing = true;
520 else
521 return false;
522 }
523 return true;
524 }
525
526 // -------------------------------------------------------------------------
527 // ClearHeader(wxSoundInfoHeader *info)
528 //
529 // ClearHeader() reinitializes the parameters of "info" to their default
530 // value.
531 // -------------------------------------------------------------------------
532 void wxSoundStreamWin::ClearHeader(wxSoundInfoHeader *info)
533 {
534 info->m_playing = false;
535 info->m_recording = false;
536 info->m_position = 0;
537 info->m_size = GetBestSize();
538 }
539
540 // -------------------------------------------------------------------------
541 // wxSoundInfoHeader *NextFragmentOutput()
542 //
543 // NextFragmentOutput() looks for a free output block. It will always
544 // return you a non-NULL pointer but it may waits for an empty buffer a long
545 // time.
546 // -------------------------------------------------------------------------
547 wxSoundInfoHeader *wxSoundStreamWin::NextFragmentOutput()
548 {
549 if (m_headers_play[m_current_frag_out]->m_playing) {
550 m_current_frag_out = (m_current_frag_out + 1) % WXSOUND_MAX_QUEUE;
551
552 if (m_headers_play[m_current_frag_out]->m_playing)
553 WaitFor(m_headers_play[m_current_frag_out]);
554 }
555 if (m_current_frag_out == m_output_frag_out)
556 m_queue_filled = true;
557 return m_headers_play[m_current_frag_out];
558 }
559
560 // -------------------------------------------------------------------------
561 // The behaviour of Write is documented in the global documentation.
562 // -------------------------------------------------------------------------
563 wxSoundStream& wxSoundStreamWin::Write(const void *buffer, wxUint32 len)
564 {
565 m_lastcount = 0;
566 if (!m_internal->m_output_enabled) {
567 m_snderror = wxSOUND_NOTSTARTED;
568 return *this;
569 }
570
571
572 while (len > 0) {
573 wxSoundInfoHeader *header;
574 wxUint32 to_copy;
575
576 // Get a new output fragment
577 header = NextFragmentOutput();
578
579 to_copy = (len > header->m_size) ? header->m_size : len;
580 memcpy(header->m_data + header->m_position, buffer, to_copy);
581
582 header->m_position += to_copy;
583 header->m_size -= to_copy;
584 buffer = (((const char *)buffer) + to_copy);
585 len -= to_copy;
586 m_lastcount += to_copy;
587
588 // If the fragment is full, we send it to the Windows queue.
589 if (header->m_size == 0)
590 if (!AddToQueue(header)) {
591 m_snderror = wxSOUND_IOERROR;
592 return *this;
593 }
594 }
595 return *this;
596 }
597
598 // -------------------------------------------------------------------------
599 // NextFragmentInput is not functional.
600 // -------------------------------------------------------------------------
601 wxSoundInfoHeader *wxSoundStreamWin::NextFragmentInput()
602 {
603 wxSoundInfoHeader *header;
604
605 // Queue pointer: reader
606 m_current_frag_in = (m_current_frag_in + 1) % WXSOUND_MAX_QUEUE;
607
608 header = m_headers_rec[m_current_frag_in];
609 // If the current buffer is in recording mode, we must wait for its
610 // completion.
611 if (header->m_recording)
612 WaitFor(header);
613
614 // We reached the writer position: the queue is full.
615 if (m_current_frag_in == m_input_frag_in)
616 m_queue_filled = true;
617
618 return header;
619 }
620
621 // -------------------------------------------------------------------------
622 // The behaviour of Read is documented in the global documentation.
623 // -------------------------------------------------------------------------
624 wxSoundStream& wxSoundStreamWin::Read(void *buffer, wxUint32 len)
625 {
626 wxSoundInfoHeader *header;
627 wxUint32 to_copy;
628
629 m_lastcount = 0;
630 if (!m_internal->m_input_enabled)
631 return *this;
632
633 while (len > 0) {
634 header = NextFragmentInput();
635
636 to_copy = (len > header->m_size) ? header->m_size : len;
637 memcpy(buffer, header->m_data + header->m_position, to_copy);
638
639 header->m_position += to_copy;
640 header->m_size -= to_copy;
641 buffer = (((char *)buffer) + to_copy);
642 len -= to_copy;
643 m_lastcount += to_copy;
644
645 if (header->m_size == 0) {
646 ClearHeader(header);
647 if (!AddToQueue(header)) {
648 m_snderror = wxSOUND_IOERROR;
649 return *this;
650 }
651 }
652 }
653 return *this;
654 }
655
656 // -------------------------------------------------------------------------
657 // NotifyDoneBuffer(wxUint32 dev_handle)
658 //
659 // NotifyDoneBuffer() is called by wxSoundHandlerProc each time a sound
660 // fragment finished. It reinitializes the parameters of the fragment and
661 // sends an event to the clients.
662 // -------------------------------------------------------------------------
663 void wxSoundStreamWin::NotifyDoneBuffer(wxUint32 WXUNUSED(dev_handle), int flag)
664 {
665 wxSoundInfoHeader *info;
666
667 if (flag == wxSOUND_OUTPUT) {
668 if (!m_internal->m_output_enabled)
669 return;
670
671 // Queue pointer: reader
672 m_output_frag_out = (m_output_frag_out + 1) % WXSOUND_MAX_QUEUE;
673 info = m_headers_play[m_output_frag_out];
674 // Clear header to tell the system the buffer is free now
675 ClearHeader(info);
676 m_queue_filled = false;
677 if (!m_waiting_for)
678 // Try to requeue a new buffer.
679 OnSoundEvent(wxSOUND_OUTPUT);
680 } else {
681 if (!m_internal->m_input_enabled)
682 return;
683
684 // Recording completed
685 m_headers_rec[m_input_frag_in]->m_recording = false;
686 // Queue pointer: writer
687 m_input_frag_in = (m_input_frag_in + 1) % WXSOUND_MAX_QUEUE;
688 if (!m_waiting_for)
689 OnSoundEvent(wxSOUND_INPUT);
690 m_queue_filled = false;
691 }
692 }
693
694 // -------------------------------------------------------------------------
695 // SetSoundFormat()
696 // -------------------------------------------------------------------------
697 bool wxSoundStreamWin::SetSoundFormat(const wxSoundFormatBase& base)
698 {
699 // TODO: detect best format
700 return wxSoundStream::SetSoundFormat(base);
701 }
702
703 // -------------------------------------------------------------------------
704 // StartProduction()
705 // -------------------------------------------------------------------------
706 bool wxSoundStreamWin::StartProduction(int evt)
707 {
708 if (!m_internal)
709 return false;
710
711 if ((m_internal->m_output_enabled && (evt & wxSOUND_OUTPUT)) ||
712 (m_internal->m_input_enabled && (evt & wxSOUND_INPUT)))
713 CloseDevice();
714
715 if (!OpenDevice(evt))
716 return false;
717
718 m_production_started = true;
719 m_queue_filled = false;
720 // Send a dummy event to start.
721 if (evt & wxSOUND_OUTPUT)
722 OnSoundEvent(wxSOUND_OUTPUT);
723
724 if (evt & wxSOUND_INPUT) {
725 int i;
726 for (i=0;i<WXSOUND_MAX_QUEUE;i++)
727 AddToQueue(m_headers_rec[i]);
728
729 waveInStart(m_internal->m_devin);
730 }
731
732 return true;
733 }
734
735 // -------------------------------------------------------------------------
736 // StopProduction()
737 // ------------------------------------------------------------------------
738 bool wxSoundStreamWin::StopProduction()
739 {
740 if (!m_production_started) {
741 m_snderror = wxSOUND_NOTSTARTED;
742 return false;
743 }
744
745 m_snderror = wxSOUND_NOERROR;
746 m_production_started = false;
747 CloseDevice();
748 return true;
749 }
750
751 // -------------------------------------------------------------------------
752 // QueueFilled()
753 // -------------------------------------------------------------------------
754 bool wxSoundStreamWin::QueueFilled() const
755 {
756 return (!m_production_started || m_queue_filled);
757 }
758
759
760 // --------------------------------------------------------------------------
761 // wxSoundWinModule
762 // --------------------------------------------------------------------------
763
764 class wxSoundWinModule : public wxModule {
765 DECLARE_DYNAMIC_CLASS(wxSoundWinModule)
766 public:
767 bool OnInit();
768 void OnExit();
769 };
770
771 IMPLEMENT_DYNAMIC_CLASS(wxSoundWinModule, wxModule)
772
773 bool wxSoundWinModule::OnInit() {
774 wxSoundHandleList = new wxList(wxKEY_INTEGER);
775 return true;
776 }
777
778 void wxSoundWinModule::OnExit() {
779 delete wxSoundHandleList;
780 }
781
782 #endif
783 // __WINDOWS__