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