]> git.saurik.com Git - wxWidgets.git/blame - utils/wxMMedia/snduss.cpp
fixed somebody's poorly done StreamSize-->GetSize transition
[wxWidgets.git] / utils / wxMMedia / snduss.cpp
CommitLineData
4d6306eb
GL
1////////////////////////////////////////////////////////////////////////////////
2// Name: snduss.cpp
3// Purpose: wxMMedia
4// Author: Guilhem Lavaux
5// Created: 1997
6// Updated: 1998
7// Copyright: (C) 1997, 1998, Guilhem Lavaux
8// License: wxWindows license
9////////////////////////////////////////////////////////////////////////////////
10#ifdef __GNUG__
11#pragma implementation "snduss.h"
12#endif
13
14#include <sys/soundcard.h>
15#include <sys/ioctl.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <time.h>
4d6306eb
GL
19
20#include "wx/app.h"
21#include "wx/utils.h"
22
23#define WXMMEDIA_INTERNAL
24#include "snduss.h"
25#include "sndfrmt.h"
26
27wxUssSound::wxUssSound()
28 : wxSound(),
29 m_srate(0), m_bps(0), m_stereo(0),
30 m_mode(wxSND_OTHER_IO),
31 m_stop_thrd(TRUE), m_sleeping(FALSE)
32{
33 m_fd = -1;
34 m_ussformat.SetCodecNo(WXSOUND_PCM);
35 m_ussformat.SetSign(wxSND_SAMPLE_SIGNED);
36 m_ussformat.SetByteOrder(wxSND_SAMPLE_LE);
37
38 m_sndbuf = new wxStreamBuffer(wxStreamBuffer::read_write);
39 m_sndbuf->Flushable(FALSE);
40 m_sndbuf->Fixed(TRUE);
41}
42
43wxUssSound::~wxUssSound()
44{
45 if (!m_stop_thrd) {
46 m_stop_thrd = TRUE;
47 if (m_sleeping) {
48 m_sleep_mtx.Lock();
49 m_sleep_cond.Signal();
50 m_sleep_mtx.Unlock();
51 }
9fc0fe37
GL
52 while (IsAlive())
53 Yield();
4d6306eb
GL
54 }
55
56 if (m_fd != -1)
57 close(m_fd);
58}
59
60bool wxUssSound::Wakeup(wxSndBuffer& WXUNUSED(buf))
61{
62 printf("Waking up (wxUssSound::Wakeup) ...\n");
63 if (m_stop_thrd) {
64 m_stop_thrd = FALSE;
65 Entry();
66// wxThread::Create();
67 }
68
69 if (m_sleeping) {
70 m_sleep_mtx.Lock();
71 m_sleep_cond.Signal();
72 m_sleep_mtx.Unlock();
73 }
74
75 return TRUE;
76}
77
78void wxUssSound::StopBuffer(wxSndBuffer& buf)
79{
80 buf.HardLock();
81 buf.Set(wxSND_BUFSTOP);
82 buf.HardUnlock();
83 while (buf.IsSet(wxSND_BUFSTOP))
84 wxYield();
85// usleep(0);
86}
87
88void wxUssSound::USS_Sleep()
89{
90 bool ret;
91
92 printf("Asleeping ...\n");
93 m_sleeping = TRUE;
94 m_sleep_mtx.Lock();
95 ret = m_sleep_cond.Wait(m_sleep_mtx, 10, 0);
96 m_sleep_mtx.Unlock();
97 m_sleeping = FALSE;
98
99 printf("Waking up ...\n");
100 if (!ret)
101 m_stop_thrd = TRUE;
102}
103
104bool wxUssSound::DoInput(wxSndBuffer *buf)
105{
106 wxUint32 bufsize;
eb4e516d 107 wxSoundCodec *codec = buf->GetCurrentCodec();
4d6306eb
GL
108
109 m_sndbuf->ResetBuffer();
4d6306eb
GL
110
111 bufsize = codec->Available();
112 if (bufsize > m_max_bufsize)
113 bufsize = m_max_bufsize;
114
115 if (!bufsize) {
116 buf->Clear(wxSND_BUFLOCKED | wxSND_BUFREADY);
117 return false;
118 }
eb4e516d 119 read(m_fd, m_sndbuf->GetBufferStart(), bufsize);
4d6306eb
GL
120 codec->Encode();
121
122 return true;
123}
124
125bool wxUssSound::DoOutput(wxSndBuffer *buf)
126{
127 wxSoundCodec *codec = buf->GetCurrentCodec();
128
129 m_sndbuf->ResetBuffer();
4d6306eb
GL
130
131 if (!codec->Available()) {
132 buf->Clear(wxSND_BUFLOCKED | wxSND_BUFREADY);
eb4e516d 133 return FALSE;
4d6306eb
GL
134 }
135 codec->Decode();
eb4e516d 136 write(m_fd, m_sndbuf->GetBufferStart(), m_sndbuf->GetIntPosition());
4d6306eb
GL
137
138 // Well ... it's not accurate ! :-|
139 buf->OnBufferOutFinished();
140
eb4e516d
GL
141 return TRUE;
142}
143
144bool wxUssSound::InitBuffer(wxSndBuffer *buf)
145{
146 wxSoundCodec *codec;
147
148 if (!OnSetupDriver(*buf, buf->GetMode())) {
149 if (buf->IsNotSet(wxSND_BUFREADY))
150 return FALSE;
151 }
152
153 codec = buf->GetCurrentCodec();
2a040d3f
GL
154 switch (m_mode) {
155 case wxSND_INPUT:
156 codec->SetInStream(m_sndbuf);
157 codec->InitIO(m_ussformat);
158 codec->InitMode(wxSoundCodec::ENCODING);
159 break;
160 case wxSND_OUTPUT:
161 codec->SetOutStream(m_sndbuf);
162 codec->InitIO(m_ussformat);
163 codec->InitMode(wxSoundCodec::DECODING);
164 break;
8a7c9dcc
GL
165 case wxSND_DUPLEX:
166 case wxSND_OTHER_IO:
167 break;
2a040d3f 168 }
eb4e516d 169 return TRUE;
4d6306eb
GL
170}
171
172void *wxUssSound::Entry()
173{
174 wxNode *node;
175 wxSndBuffer *buf;
176
eb4e516d
GL
177 node = m_buffers.First();
178 if (!node) {
179 m_stop_thrd = FALSE;
180 return NULL;
181 }
182
183 buf = (wxSndBuffer *)node->Data();
184 InitBuffer(buf);
4d6306eb 185
eb4e516d 186 while (!m_stop_thrd) {
4d6306eb
GL
187 buf->HardLock();
188 if (buf->IsSet(wxSND_BUFSTOP)) {
189 buf->HardUnlock();
eb4e516d 190 goto sound_clean_buffer;
4d6306eb
GL
191 }
192 switch(m_mode) {
193 case wxSND_INPUT:
194 if (!DoInput(buf))
eb4e516d 195 goto sound_clean_buffer;
4d6306eb
GL
196 break;
197 case wxSND_OUTPUT:
198 if (!DoOutput(buf))
eb4e516d 199 goto sound_clean_buffer;
4d6306eb
GL
200 break;
201 case wxSND_DUPLEX:
202 case wxSND_OTHER_IO:
eb4e516d 203 goto sound_clean_buffer;
4d6306eb
GL
204 break;
205 }
206 buf->HardUnlock();
eb4e516d 207 continue;
8a7c9dcc 208
eb4e516d
GL
209 sound_clean_buffer:
210 buf->GetCurrentCodec()->ExitMode();
211 delete node;
212 node = m_buffers.First();
213 if (!node)
214 USS_Sleep();
215 if (node)
216 buf = (wxSndBuffer *)node->Data();
4d6306eb
GL
217 }
218 return NULL;
219}
220
221bool wxUssSound::OnSetupDriver(wxSndBuffer& buf, wxSndMode WXUNUSED(mode))
222{
223 wxSoundDataFormat format;
224 wxSoundCodec *codec;
225
eb4e516d 226 codec = buf.GetCurrentCodec();
4d6306eb
GL
227 format = codec->GetPreferredFormat(WXSOUND_PCM);
228
229 if ((format.GetSampleRate() != m_srate) ||
230 (format.GetBps() != m_bps) ||
231 (format.GetStereo() != m_stereo)) {
232
233 if (!SetupSound(format.GetSampleRate(), format.GetBps(),
234 format.GetStereo())) {
235 m_buffers.DeleteObject(&buf);
236 buf.Clear(wxSND_BUFLOCKED | wxSND_BUFREADY);
237 buf.SetError(wxSND_CANTSET);
eb4e516d 238 return FALSE;
4d6306eb
GL
239 }
240 m_mode = wxSND_OTHER_IO;
241 }
242
243 if (buf.GetMode() != m_mode) {
244 m_mode = buf.GetMode();
eb4e516d 245 return FALSE;
4d6306eb
GL
246 }
247
eb4e516d 248 return TRUE;
4d6306eb
GL
249}
250
251wxUint32 wxUssSound::GetNbFragments()
252{
253 struct audio_buf_info frag_info;
254
255 ioctl(m_fd, SNDCTL_DSP_GETOSPACE, &frag_info);
256
257 return frag_info.fragstotal;
258}
259
260wxUint32 wxUssSound::GetFragmentSize()
261{
262 return m_max_bufsize;
263}
264
265bool wxUssSound::SetupSound(wxUint16 srate, wxUint8 bps, bool stereo)
266{
267 int tmp;
268 unsigned long tmp_ul;
269
270 if (m_fd != -1) {
271 delete m_sndbuf;
272 fsync(m_fd);
273 close(m_fd);
274 }
275
276 m_fd = open("/dev/dsp", O_RDWR);
277
278 tmp = stereo;
279 if (ioctl(m_fd, SNDCTL_DSP_STEREO, &tmp) < 0)
280 return FALSE;
281 m_stereo = tmp;
282
283 tmp_ul = srate;
284 if (ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp_ul) < 0)
285 return FALSE;
286 m_srate = tmp_ul;
287
288 tmp = bps;
289 if (ioctl(m_fd, SNDCTL_DSP_SAMPLESIZE, &tmp) < 0)
290 return FALSE;
291 m_bps = tmp;
292
293 ioctl(m_fd, SNDCTL_DSP_GETBLKSIZE, &tmp);
294 m_max_bufsize = tmp;
295 m_sndbuf->SetBufferIO(m_max_bufsize);
296
297 m_ussformat.SetBps(m_bps);
298 m_ussformat.SetChannels((m_stereo) ? 2 : 1);
299 m_ussformat.SetSampleRate(m_srate);
300
301 return TRUE;
302}