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