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