]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndoss.cpp
Bumping the version number also requires that version.h be modified,
[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
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 // --------------------------------------------------------------------------
25 // wxWidgets headers
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
33 wxSoundStreamOSS::wxSoundStreamOSS(const wxString& dev_name)
34 {
35 wxSoundFormatPcm pcm_default;
36
37 // Open the OSS device
38 m_fd = open(dev_name.mb_str(), O_WRONLY);
39 if (m_fd == -1) {
40 // OSS not found
41 m_oss_ok = false;
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);
54
55 m_snderror = wxSOUND_NOERROR;
56
57 // Close OSS
58 close(m_fd);
59
60 m_oss_ok = true;
61 m_oss_stop = true;
62 m_q_filled = true;
63 }
64
65 wxSoundStreamOSS::~wxSoundStreamOSS()
66 {
67 if (m_fd > 0)
68 close(m_fd);
69 }
70
71 wxUint32 wxSoundStreamOSS::GetBestSize() const
72 {
73 return m_bufsize;
74 }
75
76 wxSoundStream& 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 }
85
86 ret = read(m_fd, buffer, len);
87 m_lastcount = (wxUint32)ret;
88 m_q_filled = true;
89
90 if (ret < 0)
91 m_snderror = wxSOUND_IOERROR;
92 else
93 m_snderror = wxSOUND_NOERROR;
94
95 return *this;
96 }
97
98 wxSoundStream& 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);
109 m_q_filled = true;
110
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 }
118
119 return *this;
120 }
121
122 bool wxSoundStreamOSS::SetSoundFormat(const wxSoundFormatBase& format)
123 {
124 int tmp;
125 wxSoundFormatPcm *pcm_format;
126
127 if (format.GetType() != wxSOUND_PCM) {
128 m_snderror = wxSOUND_INVFRMT;
129 return false;
130 }
131
132 if (!m_oss_ok) {
133 m_snderror = wxSOUND_INVDEV;
134 return false;
135 }
136
137 if (m_sndformat)
138 delete m_sndformat;
139
140 m_sndformat = format.Clone();
141 if (!m_sndformat) {
142 m_snderror = wxSOUND_MEMERROR;
143 return false;
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;
152 return false;
153 }
154 }
155
156 // Set the sample rate field.
157 tmp = pcm_format->GetSampleRate();
158 ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp);
159
160 pcm_format->SetSampleRate(tmp);
161
162 // Detect the best format
163 DetectBest(pcm_format);
164 // Try to apply it
165 SetupFormat(pcm_format);
166
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);
174
175 m_snderror = wxSOUND_NOERROR;
176 if (*pcm_format != format) {
177 m_snderror = wxSOUND_NOEXACT;
178 return false;
179 }
180
181 return true;
182 }
183
184 bool wxSoundStreamOSS::SetupFormat(wxSoundFormatPcm *pcm_format)
185 {
186 int tmp;
187
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 }
212
213 ioctl(m_fd, SNDCTL_DSP_SETFMT, &tmp);
214
215 // Demangling.
216 switch (tmp) {
217 case AFMT_U8:
218 pcm_format->SetBPS(8);
219 pcm_format->Signed(false);
220 break;
221 case AFMT_S8:
222 pcm_format->SetBPS(8);
223 pcm_format->Signed(true);
224 break;
225 case AFMT_U16_LE:
226 pcm_format->SetBPS(16);
227 pcm_format->Signed(false);
228 pcm_format->SetOrder(wxLITTLE_ENDIAN);
229 break;
230 case AFMT_U16_BE:
231 pcm_format->SetBPS(16);
232 pcm_format->Signed(false);
233 pcm_format->SetOrder(wxBIG_ENDIAN);
234 break;
235 case AFMT_S16_LE:
236 pcm_format->SetBPS(16);
237 pcm_format->Signed(true);
238 pcm_format->SetOrder(wxLITTLE_ENDIAN);
239 break;
240 case AFMT_S16_BE:
241 pcm_format->SetBPS(16);
242 pcm_format->Signed(true);
243 pcm_format->SetOrder(wxBIG_ENDIAN);
244 break;
245 }
246 return true;
247 }
248
249 #ifdef __WXGTK__
250 static void _wxSound_OSS_CBack(gpointer data, int source,
251 GdkInputCondition condition)
252 {
253 wxSoundStreamOSS *oss = (wxSoundStreamOSS *)data;
254
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
268 void wxSoundStreamOSS::WakeUpEvt(int evt)
269 {
270 m_q_filled = false;
271 OnSoundEvent(evt);
272 }
273
274 bool wxSoundStreamOSS::StartProduction(int evt)
275 {
276 wxSoundFormatBase *old_frmt;
277
278 if (!m_oss_stop)
279 StopProduction();
280
281 old_frmt = m_sndformat->Clone();
282 if (!old_frmt) {
283 m_snderror = wxSOUND_MEMERROR;
284 return false;
285 }
286
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);
291
292 if (m_fd == -1) {
293 m_snderror = wxSOUND_INVDEV;
294 return false;
295 }
296
297 SetSoundFormat(*old_frmt);
298 delete old_frmt;
299
300 int trig;
301
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
316 m_oss_stop = false;
317 m_q_filled = false;
318
319 return true;
320 }
321
322 bool wxSoundStreamOSS::StopProduction()
323 {
324 if (m_oss_stop)
325 return false;
326
327 #ifdef __WXGTK__
328 gdk_input_remove(m_tag);
329 #endif
330
331 close(m_fd);
332 m_oss_stop = true;
333 m_q_filled = true;
334 return true;
335 }
336
337 bool wxSoundStreamOSS::QueueFilled() const
338 {
339 return m_q_filled;
340 }
341
342 //
343 // Detect the closest format (The best).
344 //
345 void 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))
377 best_pcm.Signed(true);
378
379 // It supports unsigned samples
380 if (!pcm->Signed() &&
381 ((fmt_mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_U8)) != 0))
382 best_pcm.Signed(false);
383
384 // Finally recopy the new format
385 *pcm = best_pcm;
386 }