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