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