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