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