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