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