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