]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/mmedia/sndoss.cpp
Assert fix
[wxWidgets.git] / contrib / src / mmedia / sndoss.cpp
CommitLineData
e8482f24
GL
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$
58b9c9ba 7// wxWindows licence
e8482f24
GL
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// --------------------------------------------------------------------------
be5a51fb 28// wxWidgets headers
e8482f24
GL
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
36wxSoundStreamOSS::wxSoundStreamOSS(const wxString& dev_name)
37{
38 wxSoundFormatPcm pcm_default;
b7ecdec5 39
e8482f24
GL
40 // Open the OSS device
41 m_fd = open(dev_name.mb_str(), O_WRONLY);
42 if (m_fd == -1) {
43 // OSS not found
dea7e44a 44 m_oss_ok = false;
e8482f24
GL
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);
b7ecdec5 57
e8482f24
GL
58 m_snderror = wxSOUND_NOERROR;
59
60 // Close OSS
61 close(m_fd);
b7ecdec5 62
dea7e44a
WS
63 m_oss_ok = true;
64 m_oss_stop = true;
65 m_q_filled = true;
e8482f24
GL
66}
67
68wxSoundStreamOSS::~wxSoundStreamOSS()
69{
70 if (m_fd > 0)
71 close(m_fd);
72}
73
74wxUint32 wxSoundStreamOSS::GetBestSize() const
75{
76 return m_bufsize;
77}
78
79wxSoundStream& 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 }
b7ecdec5
WS
88
89 ret = read(m_fd, buffer, len);
90 m_lastcount = (wxUint32)ret;
dea7e44a 91 m_q_filled = true;
b7ecdec5 92
e8482f24
GL
93 if (ret < 0)
94 m_snderror = wxSOUND_IOERROR;
95 else
96 m_snderror = wxSOUND_NOERROR;
b7ecdec5 97
e8482f24
GL
98 return *this;
99}
100
101wxSoundStream& 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);
dea7e44a 112 m_q_filled = true;
b7ecdec5 113
e8482f24
GL
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 }
b7ecdec5 121
e8482f24
GL
122 return *this;
123}
124
125bool wxSoundStreamOSS::SetSoundFormat(const wxSoundFormatBase& format)
126{
127 int tmp;
128 wxSoundFormatPcm *pcm_format;
b7ecdec5 129
e8482f24
GL
130 if (format.GetType() != wxSOUND_PCM) {
131 m_snderror = wxSOUND_INVFRMT;
dea7e44a 132 return false;
e8482f24 133 }
b7ecdec5 134
e8482f24
GL
135 if (!m_oss_ok) {
136 m_snderror = wxSOUND_INVDEV;
dea7e44a 137 return false;
e8482f24 138 }
b7ecdec5 139
e8482f24
GL
140 if (m_sndformat)
141 delete m_sndformat;
b7ecdec5 142
e8482f24
GL
143 m_sndformat = format.Clone();
144 if (!m_sndformat) {
145 m_snderror = wxSOUND_MEMERROR;
dea7e44a 146 return false;
e8482f24
GL
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;
dea7e44a 155 return false;
e8482f24
GL
156 }
157 }
b7ecdec5 158
e8482f24
GL
159 // Set the sample rate field.
160 tmp = pcm_format->GetSampleRate();
161 ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp);
b7ecdec5 162
e8482f24 163 pcm_format->SetSampleRate(tmp);
b7ecdec5 164
e8482f24
GL
165 // Detect the best format
166 DetectBest(pcm_format);
167 // Try to apply it
168 SetupFormat(pcm_format);
b7ecdec5 169
e8482f24
GL
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);
b7ecdec5 177
e8482f24
GL
178 m_snderror = wxSOUND_NOERROR;
179 if (*pcm_format != format) {
180 m_snderror = wxSOUND_NOEXACT;
dea7e44a 181 return false;
e8482f24
GL
182 }
183
dea7e44a 184 return true;
e8482f24
GL
185}
186
187bool wxSoundStreamOSS::SetupFormat(wxSoundFormatPcm *pcm_format)
188{
189 int tmp;
b7ecdec5 190
e8482f24
GL
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 }
b7ecdec5 215
e8482f24 216 ioctl(m_fd, SNDCTL_DSP_SETFMT, &tmp);
b7ecdec5 217
e8482f24
GL
218 // Demangling.
219 switch (tmp) {
220 case AFMT_U8:
221 pcm_format->SetBPS(8);
dea7e44a 222 pcm_format->Signed(false);
e8482f24
GL
223 break;
224 case AFMT_S8:
225 pcm_format->SetBPS(8);
dea7e44a 226 pcm_format->Signed(true);
e8482f24
GL
227 break;
228 case AFMT_U16_LE:
229 pcm_format->SetBPS(16);
dea7e44a 230 pcm_format->Signed(false);
e8482f24
GL
231 pcm_format->SetOrder(wxLITTLE_ENDIAN);
232 break;
233 case AFMT_U16_BE:
234 pcm_format->SetBPS(16);
dea7e44a 235 pcm_format->Signed(false);
e8482f24
GL
236 pcm_format->SetOrder(wxBIG_ENDIAN);
237 break;
238 case AFMT_S16_LE:
239 pcm_format->SetBPS(16);
dea7e44a 240 pcm_format->Signed(true);
e8482f24
GL
241 pcm_format->SetOrder(wxLITTLE_ENDIAN);
242 break;
243 case AFMT_S16_BE:
244 pcm_format->SetBPS(16);
dea7e44a 245 pcm_format->Signed(true);
e8482f24
GL
246 pcm_format->SetOrder(wxBIG_ENDIAN);
247 break;
248 }
dea7e44a 249 return true;
e8482f24
GL
250}
251
252#ifdef __WXGTK__
253static void _wxSound_OSS_CBack(gpointer data, int source,
254 GdkInputCondition condition)
255{
256 wxSoundStreamOSS *oss = (wxSoundStreamOSS *)data;
b7ecdec5 257
e8482f24
GL
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
271void wxSoundStreamOSS::WakeUpEvt(int evt)
272{
dea7e44a 273 m_q_filled = false;
e8482f24
GL
274 OnSoundEvent(evt);
275}
276
277bool wxSoundStreamOSS::StartProduction(int evt)
278{
279 wxSoundFormatBase *old_frmt;
b7ecdec5 280
e8482f24
GL
281 if (!m_oss_stop)
282 StopProduction();
b7ecdec5 283
e8482f24
GL
284 old_frmt = m_sndformat->Clone();
285 if (!old_frmt) {
286 m_snderror = wxSOUND_MEMERROR;
dea7e44a 287 return false;
e8482f24 288 }
b7ecdec5 289
e8482f24
GL
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);
b7ecdec5 294
e8482f24
GL
295 if (m_fd == -1) {
296 m_snderror = wxSOUND_INVDEV;
dea7e44a 297 return false;
e8482f24 298 }
b7ecdec5 299
e8482f24
GL
300 SetSoundFormat(*old_frmt);
301 delete old_frmt;
b7ecdec5 302
e8482f24 303 int trig;
b7ecdec5 304
e8482f24
GL
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
dea7e44a
WS
319 m_oss_stop = false;
320 m_q_filled = false;
e8482f24 321
dea7e44a 322 return true;
e8482f24
GL
323}
324
325bool wxSoundStreamOSS::StopProduction()
326{
327 if (m_oss_stop)
dea7e44a 328 return false;
e8482f24
GL
329
330#ifdef __WXGTK__
331 gdk_input_remove(m_tag);
332#endif
333
334 close(m_fd);
dea7e44a
WS
335 m_oss_stop = true;
336 m_q_filled = true;
337 return true;
e8482f24
GL
338}
339
340bool wxSoundStreamOSS::QueueFilled() const
341{
342 return m_q_filled;
343}
344
345//
346// Detect the closest format (The best).
347//
348void 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))
dea7e44a 380 best_pcm.Signed(true);
e8482f24
GL
381
382 // It supports unsigned samples
383 if (!pcm->Signed() &&
384 ((fmt_mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_U8)) != 0))
dea7e44a 385 best_pcm.Signed(false);
e8482f24
GL
386
387 // Finally recopy the new format
388 *pcm = best_pcm;
389}