]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndoss.cpp
fix evaluation order bug (patch 1158099)
[wxWidgets.git] / contrib / src / mmedia / sndoss.cpp
1 // --------------------------------------------------------------------------
2 // Name: sndoss.cpp
3 // Purpose:
4 // Date: 08/11/1999
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
6 // CVSID: $Id$
7 // wxWindows licence
8 // --------------------------------------------------------------------------
9 #ifdef __GNUG__
10 #pragma implementation "sndoss.cpp"
11 #endif
12
13 // --------------------------------------------------------------------------
14 // System dependent headers
15 // --------------------------------------------------------------------------
16
17 #include <sys/soundcard.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/ioctl.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #ifdef __WXGTK__
24 #include <gdk/gdk.h>
25 #endif
26
27 // --------------------------------------------------------------------------
28 // wxWidgets headers
29 // --------------------------------------------------------------------------
30 #include "wx/defs.h"
31 #include "wx/string.h"
32 #include "wx/mmedia/sndbase.h"
33 #include "wx/mmedia/sndoss.h"
34 #include "wx/mmedia/sndpcm.h"
35
36 wxSoundStreamOSS::wxSoundStreamOSS(const wxString& dev_name)
37 {
38 wxSoundFormatPcm pcm_default;
39
40 // Open the OSS device
41 m_fd = open(dev_name.mb_str(), O_WRONLY);
42 if (m_fd == -1) {
43 // OSS not found
44 m_oss_ok = false;
45 m_snderror = wxSOUND_INVDEV;
46 return;
47 }
48
49 // Remember the device name
50 m_devname = dev_name;
51
52 // Initialize the default format
53 wxSoundStreamOSS::SetSoundFormat(pcm_default);
54
55 // Get the default best size for OSS
56 ioctl(m_fd, SNDCTL_DSP_GETBLKSIZE, &m_bufsize);
57
58 m_snderror = wxSOUND_NOERROR;
59
60 // Close OSS
61 close(m_fd);
62
63 m_oss_ok = true;
64 m_oss_stop = true;
65 m_q_filled = true;
66 }
67
68 wxSoundStreamOSS::~wxSoundStreamOSS()
69 {
70 if (m_fd > 0)
71 close(m_fd);
72 }
73
74 wxUint32 wxSoundStreamOSS::GetBestSize() const
75 {
76 return m_bufsize;
77 }
78
79 wxSoundStream& wxSoundStreamOSS::Read(void *buffer, wxUint32 len)
80 {
81 int ret;
82
83 if (m_oss_stop) {
84 m_snderror = wxSOUND_NOTSTARTED;
85 m_lastcount = 0;
86 return *this;
87 }
88
89 ret = read(m_fd, buffer, len);
90 m_lastcount = (wxUint32)ret;
91 m_q_filled = true;
92
93 if (ret < 0)
94 m_snderror = wxSOUND_IOERROR;
95 else
96 m_snderror = wxSOUND_NOERROR;
97
98 return *this;
99 }
100
101 wxSoundStream& wxSoundStreamOSS::Write(const void *buffer, wxUint32 len)
102 {
103 int ret;
104
105 if (m_oss_stop) {
106 m_snderror = wxSOUND_NOTSTARTED;
107 m_lastcount= 0;
108 return *this;
109 }
110
111 ret = write(m_fd, buffer, len);
112 m_q_filled = true;
113
114 if (ret < 0) {
115 m_lastcount = 0;
116 m_snderror = wxSOUND_IOERROR;
117 } else {
118 m_snderror = wxSOUND_NOERROR;
119 m_lastcount = (wxUint32)ret;
120 }
121
122 return *this;
123 }
124
125 bool wxSoundStreamOSS::SetSoundFormat(const wxSoundFormatBase& format)
126 {
127 int tmp;
128 wxSoundFormatPcm *pcm_format;
129
130 if (format.GetType() != wxSOUND_PCM) {
131 m_snderror = wxSOUND_INVFRMT;
132 return false;
133 }
134
135 if (!m_oss_ok) {
136 m_snderror = wxSOUND_INVDEV;
137 return false;
138 }
139
140 if (m_sndformat)
141 delete m_sndformat;
142
143 m_sndformat = format.Clone();
144 if (!m_sndformat) {
145 m_snderror = wxSOUND_MEMERROR;
146 return false;
147 }
148 pcm_format = (wxSoundFormatPcm *)m_sndformat;
149
150 // We temporary open the OSS device
151 if (m_oss_stop) {
152 m_fd = open(m_devname.mb_str(), O_WRONLY);
153 if (m_fd == -1) {
154 m_snderror = wxSOUND_INVDEV;
155 return false;
156 }
157 }
158
159 // Set the sample rate field.
160 tmp = pcm_format->GetSampleRate();
161 ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp);
162
163 pcm_format->SetSampleRate(tmp);
164
165 // Detect the best format
166 DetectBest(pcm_format);
167 // Try to apply it
168 SetupFormat(pcm_format);
169
170 tmp = pcm_format->GetChannels();
171 ioctl(m_fd, SNDCTL_DSP_CHANNELS, &tmp);
172 pcm_format->SetChannels(tmp);
173
174 // Close the OSS device
175 if (m_oss_stop)
176 close(m_fd);
177
178 m_snderror = wxSOUND_NOERROR;
179 if (*pcm_format != format) {
180 m_snderror = wxSOUND_NOEXACT;
181 return false;
182 }
183
184 return true;
185 }
186
187 bool wxSoundStreamOSS::SetupFormat(wxSoundFormatPcm *pcm_format)
188 {
189 int tmp;
190
191 switch(pcm_format->GetBPS()) {
192 case 8:
193 if (pcm_format->Signed())
194 tmp = AFMT_S8;
195 else
196 tmp = AFMT_U8;
197 break;
198 case 16:
199 switch (pcm_format->GetOrder()) {
200 case wxBIG_ENDIAN:
201 if (pcm_format->Signed())
202 tmp = AFMT_S16_BE;
203 else
204 tmp = AFMT_U16_BE;
205 break;
206 case wxLITTLE_ENDIAN:
207 if (pcm_format->Signed())
208 tmp = AFMT_S16_LE;
209 else
210 tmp = AFMT_U16_LE;
211 break;
212 }
213 break;
214 }
215
216 ioctl(m_fd, SNDCTL_DSP_SETFMT, &tmp);
217
218 // Demangling.
219 switch (tmp) {
220 case AFMT_U8:
221 pcm_format->SetBPS(8);
222 pcm_format->Signed(false);
223 break;
224 case AFMT_S8:
225 pcm_format->SetBPS(8);
226 pcm_format->Signed(true);
227 break;
228 case AFMT_U16_LE:
229 pcm_format->SetBPS(16);
230 pcm_format->Signed(false);
231 pcm_format->SetOrder(wxLITTLE_ENDIAN);
232 break;
233 case AFMT_U16_BE:
234 pcm_format->SetBPS(16);
235 pcm_format->Signed(false);
236 pcm_format->SetOrder(wxBIG_ENDIAN);
237 break;
238 case AFMT_S16_LE:
239 pcm_format->SetBPS(16);
240 pcm_format->Signed(true);
241 pcm_format->SetOrder(wxLITTLE_ENDIAN);
242 break;
243 case AFMT_S16_BE:
244 pcm_format->SetBPS(16);
245 pcm_format->Signed(true);
246 pcm_format->SetOrder(wxBIG_ENDIAN);
247 break;
248 }
249 return true;
250 }
251
252 #ifdef __WXGTK__
253 static void _wxSound_OSS_CBack(gpointer data, int source,
254 GdkInputCondition condition)
255 {
256 wxSoundStreamOSS *oss = (wxSoundStreamOSS *)data;
257
258 switch (condition) {
259 case GDK_INPUT_READ:
260 oss->WakeUpEvt(wxSOUND_INPUT);
261 break;
262 case GDK_INPUT_WRITE:
263 oss->WakeUpEvt(wxSOUND_OUTPUT);
264 break;
265 default:
266 break;
267 }
268 }
269 #endif
270
271 void wxSoundStreamOSS::WakeUpEvt(int evt)
272 {
273 m_q_filled = false;
274 OnSoundEvent(evt);
275 }
276
277 bool wxSoundStreamOSS::StartProduction(int evt)
278 {
279 wxSoundFormatBase *old_frmt;
280
281 if (!m_oss_stop)
282 StopProduction();
283
284 old_frmt = m_sndformat->Clone();
285 if (!old_frmt) {
286 m_snderror = wxSOUND_MEMERROR;
287 return false;
288 }
289
290 if (evt == wxSOUND_OUTPUT)
291 m_fd = open(m_devname.mb_str(), O_WRONLY);
292 else if (evt == wxSOUND_INPUT)
293 m_fd = open(m_devname.mb_str(), O_RDONLY);
294
295 if (m_fd == -1) {
296 m_snderror = wxSOUND_INVDEV;
297 return false;
298 }
299
300 SetSoundFormat(*old_frmt);
301 delete old_frmt;
302
303 int trig;
304
305 if (evt == wxSOUND_OUTPUT) {
306 #ifdef __WXGTK__
307 m_tag = gdk_input_add(m_fd, GDK_INPUT_WRITE, _wxSound_OSS_CBack, (gpointer)this);
308 #endif
309 trig = PCM_ENABLE_OUTPUT;
310 } else {
311 #ifdef __WXGTK__
312 m_tag = gdk_input_add(m_fd, GDK_INPUT_READ, _wxSound_OSS_CBack, (gpointer)this);
313 #endif
314 trig = PCM_ENABLE_INPUT;
315 }
316
317 ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &trig);
318
319 m_oss_stop = false;
320 m_q_filled = false;
321
322 return true;
323 }
324
325 bool wxSoundStreamOSS::StopProduction()
326 {
327 if (m_oss_stop)
328 return false;
329
330 #ifdef __WXGTK__
331 gdk_input_remove(m_tag);
332 #endif
333
334 close(m_fd);
335 m_oss_stop = true;
336 m_q_filled = true;
337 return true;
338 }
339
340 bool wxSoundStreamOSS::QueueFilled() const
341 {
342 return m_q_filled;
343 }
344
345 //
346 // Detect the closest format (The best).
347 //
348 void wxSoundStreamOSS::DetectBest(wxSoundFormatPcm *pcm)
349 {
350 #define MASK_16BITS (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
351
352 int fmt_mask;
353 wxSoundFormatPcm best_pcm;
354
355 // We change neither the number of channels nor the sample rate
356
357 best_pcm.SetSampleRate(pcm->GetSampleRate());
358 best_pcm.SetChannels(pcm->GetChannels());
359
360 // Get the supported format by the sound card
361 ioctl(m_fd, SNDCTL_DSP_GETFMTS, &fmt_mask);
362
363 // It supports 16 bits
364 if (pcm->GetBPS() == 16 && ((fmt_mask & MASK_16BITS) != 0))
365 best_pcm.SetBPS(16);
366
367 // It supports big endianness
368 if (pcm->GetOrder() == wxBIG_ENDIAN &&
369 ((fmt_mask & (AFMT_S16_BE | AFMT_U16_BE)) != 0))
370 best_pcm.SetOrder(wxBIG_ENDIAN);
371
372 // It supports little endianness
373 if (pcm->GetOrder() == wxLITTLE_ENDIAN &&
374 ((fmt_mask & (AFMT_S16_LE | AFMT_U16_LE)) != 0))
375 best_pcm.SetOrder(wxLITTLE_ENDIAN);
376
377 // It supports signed samples
378 if (pcm->Signed() &&
379 ((fmt_mask & (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)) != 0))
380 best_pcm.Signed(true);
381
382 // It supports unsigned samples
383 if (!pcm->Signed() &&
384 ((fmt_mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_U8)) != 0))
385 best_pcm.Signed(false);
386
387 // Finally recopy the new format
388 *pcm = best_pcm;
389 }