]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/mmedia/sndoss.cpp
Moved wxMMedia to contrib/src/mmedia
[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 // wxWindows 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 m_lastcount = (wxUint32)ret = read(m_fd, buffer, len);
89 m_q_filled = TRUE;
90
91 if (ret < 0)
92 m_snderror = wxSOUND_IOERROR;
93 else
94 m_snderror = wxSOUND_NOERROR;
95
96 return *this;
97 }
98
99 wxSoundStream& wxSoundStreamOSS::Write(const void *buffer, wxUint32 len)
100 {
101 int ret;
102
103 if (m_oss_stop) {
104 m_snderror = wxSOUND_NOTSTARTED;
105 m_lastcount= 0;
106 return *this;
107 }
108
109 ret = write(m_fd, buffer, len);
110 m_q_filled = TRUE;
111
112 if (ret < 0) {
113 m_lastcount = 0;
114 m_snderror = wxSOUND_IOERROR;
115 } else {
116 m_snderror = wxSOUND_NOERROR;
117 m_lastcount = (wxUint32)ret;
118 }
119
120 return *this;
121 }
122
123 bool wxSoundStreamOSS::SetSoundFormat(const wxSoundFormatBase& format)
124 {
125 int tmp;
126 wxSoundFormatPcm *pcm_format;
127
128 if (format.GetType() != wxSOUND_PCM) {
129 m_snderror = wxSOUND_INVFRMT;
130 return FALSE;
131 }
132
133 if (!m_oss_ok) {
134 m_snderror = wxSOUND_INVDEV;
135 return FALSE;
136 }
137
138 if (m_sndformat)
139 delete m_sndformat;
140
141 m_sndformat = format.Clone();
142 if (!m_sndformat) {
143 m_snderror = wxSOUND_MEMERROR;
144 return FALSE;
145 }
146 pcm_format = (wxSoundFormatPcm *)m_sndformat;
147
148 // We temporary open the OSS device
149 if (m_oss_stop) {
150 m_fd = open(m_devname.mb_str(), O_WRONLY);
151 if (m_fd == -1) {
152 m_snderror = wxSOUND_INVDEV;
153 return FALSE;
154 }
155 }
156
157 // Set the sample rate field.
158 tmp = pcm_format->GetSampleRate();
159 ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp);
160
161 pcm_format->SetSampleRate(tmp);
162
163 // Detect the best format
164 DetectBest(pcm_format);
165 // Try to apply it
166 SetupFormat(pcm_format);
167
168 tmp = pcm_format->GetChannels();
169 ioctl(m_fd, SNDCTL_DSP_CHANNELS, &tmp);
170 pcm_format->SetChannels(tmp);
171
172 // Close the OSS device
173 if (m_oss_stop)
174 close(m_fd);
175
176 m_snderror = wxSOUND_NOERROR;
177 if (*pcm_format != format) {
178 m_snderror = wxSOUND_NOEXACT;
179 return FALSE;
180 }
181
182 return TRUE;
183 }
184
185 bool wxSoundStreamOSS::SetupFormat(wxSoundFormatPcm *pcm_format)
186 {
187 int tmp;
188
189 switch(pcm_format->GetBPS()) {
190 case 8:
191 if (pcm_format->Signed())
192 tmp = AFMT_S8;
193 else
194 tmp = AFMT_U8;
195 break;
196 case 16:
197 switch (pcm_format->GetOrder()) {
198 case wxBIG_ENDIAN:
199 if (pcm_format->Signed())
200 tmp = AFMT_S16_BE;
201 else
202 tmp = AFMT_U16_BE;
203 break;
204 case wxLITTLE_ENDIAN:
205 if (pcm_format->Signed())
206 tmp = AFMT_S16_LE;
207 else
208 tmp = AFMT_U16_LE;
209 break;
210 }
211 break;
212 }
213
214 ioctl(m_fd, SNDCTL_DSP_SETFMT, &tmp);
215
216 // Demangling.
217 switch (tmp) {
218 case AFMT_U8:
219 pcm_format->SetBPS(8);
220 pcm_format->Signed(FALSE);
221 break;
222 case AFMT_S8:
223 pcm_format->SetBPS(8);
224 pcm_format->Signed(TRUE);
225 break;
226 case AFMT_U16_LE:
227 pcm_format->SetBPS(16);
228 pcm_format->Signed(FALSE);
229 pcm_format->SetOrder(wxLITTLE_ENDIAN);
230 break;
231 case AFMT_U16_BE:
232 pcm_format->SetBPS(16);
233 pcm_format->Signed(FALSE);
234 pcm_format->SetOrder(wxBIG_ENDIAN);
235 break;
236 case AFMT_S16_LE:
237 pcm_format->SetBPS(16);
238 pcm_format->Signed(TRUE);
239 pcm_format->SetOrder(wxLITTLE_ENDIAN);
240 break;
241 case AFMT_S16_BE:
242 pcm_format->SetBPS(16);
243 pcm_format->Signed(TRUE);
244 pcm_format->SetOrder(wxBIG_ENDIAN);
245 break;
246 }
247 return TRUE;
248 }
249
250 #ifdef __WXGTK__
251 static void _wxSound_OSS_CBack(gpointer data, int source,
252 GdkInputCondition condition)
253 {
254 wxSoundStreamOSS *oss = (wxSoundStreamOSS *)data;
255
256 switch (condition) {
257 case GDK_INPUT_READ:
258 oss->WakeUpEvt(wxSOUND_INPUT);
259 break;
260 case GDK_INPUT_WRITE:
261 oss->WakeUpEvt(wxSOUND_OUTPUT);
262 break;
263 default:
264 break;
265 }
266 }
267 #endif
268
269 void wxSoundStreamOSS::WakeUpEvt(int evt)
270 {
271 m_q_filled = FALSE;
272 OnSoundEvent(evt);
273 }
274
275 bool wxSoundStreamOSS::StartProduction(int evt)
276 {
277 wxSoundFormatBase *old_frmt;
278
279 if (!m_oss_stop)
280 StopProduction();
281
282 old_frmt = m_sndformat->Clone();
283 if (!old_frmt) {
284 m_snderror = wxSOUND_MEMERROR;
285 return FALSE;
286 }
287
288 if (evt == wxSOUND_OUTPUT)
289 m_fd = open(m_devname.mb_str(), O_WRONLY);
290 else if (evt == wxSOUND_INPUT)
291 m_fd = open(m_devname.mb_str(), O_RDONLY);
292
293 if (m_fd == -1) {
294 m_snderror = wxSOUND_INVDEV;
295 return FALSE;
296 }
297
298 SetSoundFormat(*old_frmt);
299 delete old_frmt;
300
301 int trig;
302
303 if (evt == wxSOUND_OUTPUT) {
304 #ifdef __WXGTK__
305 m_tag = gdk_input_add(m_fd, GDK_INPUT_WRITE, _wxSound_OSS_CBack, (gpointer)this);
306 #endif
307 trig = PCM_ENABLE_OUTPUT;
308 } else {
309 #ifdef __WXGTK__
310 m_tag = gdk_input_add(m_fd, GDK_INPUT_READ, _wxSound_OSS_CBack, (gpointer)this);
311 #endif
312 trig = PCM_ENABLE_INPUT;
313 }
314
315 ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &trig);
316
317 m_oss_stop = FALSE;
318 m_q_filled = FALSE;
319
320 return TRUE;
321 }
322
323 bool wxSoundStreamOSS::StopProduction()
324 {
325 if (m_oss_stop)
326 return FALSE;
327
328 #ifdef __WXGTK__
329 gdk_input_remove(m_tag);
330 #endif
331
332 close(m_fd);
333 m_oss_stop = TRUE;
334 m_q_filled = TRUE;
335 return TRUE;
336 }
337
338 bool wxSoundStreamOSS::QueueFilled() const
339 {
340 return m_q_filled;
341 }
342
343 //
344 // Detect the closest format (The best).
345 //
346 void wxSoundStreamOSS::DetectBest(wxSoundFormatPcm *pcm)
347 {
348 #define MASK_16BITS (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
349
350 int fmt_mask;
351 wxSoundFormatPcm best_pcm;
352
353 // We change neither the number of channels nor the sample rate
354
355 best_pcm.SetSampleRate(pcm->GetSampleRate());
356 best_pcm.SetChannels(pcm->GetChannels());
357
358 // Get the supported format by the sound card
359 ioctl(m_fd, SNDCTL_DSP_GETFMTS, &fmt_mask);
360
361 // It supports 16 bits
362 if (pcm->GetBPS() == 16 && ((fmt_mask & MASK_16BITS) != 0))
363 best_pcm.SetBPS(16);
364
365 // It supports big endianness
366 if (pcm->GetOrder() == wxBIG_ENDIAN &&
367 ((fmt_mask & (AFMT_S16_BE | AFMT_U16_BE)) != 0))
368 best_pcm.SetOrder(wxBIG_ENDIAN);
369
370 // It supports little endianness
371 if (pcm->GetOrder() == wxLITTLE_ENDIAN &&
372 ((fmt_mask & (AFMT_S16_LE | AFMT_U16_LE)) != 0))
373 best_pcm.SetOrder(wxLITTLE_ENDIAN);
374
375 // It supports signed samples
376 if (pcm->Signed() &&
377 ((fmt_mask & (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)) != 0))
378 best_pcm.Signed(TRUE);
379
380 // It supports unsigned samples
381 if (!pcm->Signed() &&
382 ((fmt_mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_U8)) != 0))
383 best_pcm.Signed(FALSE);
384
385 // Finally recopy the new format
386 *pcm = best_pcm;
387 }