]> git.saurik.com Git - wxWidgets.git/blame_incremental - contrib/src/mmedia/sndoss.cpp
cleanup - reformatting
[wxWidgets.git] / contrib / src / mmedia / sndoss.cpp
... / ...
CommitLineData
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
33wxSoundStreamOSS::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
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 }
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
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);
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
122bool 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
184bool 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__
250static 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
268void wxSoundStreamOSS::WakeUpEvt(int evt)
269{
270 m_q_filled = false;
271 OnSoundEvent(evt);
272}
273
274bool 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
322bool 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
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))
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}