]> git.saurik.com Git - wxWidgets.git/blob - utils/wxMMedia2/lib/sndoss.cpp
875d19b1678cfd5a496e8d18b0131ce95567a588
[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
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_RDWR);
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_NOERR;
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_IOERR;
72 else
73 m_snderror = wxSOUND_NOERR;
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_IOERR;
87 else
88 m_snderror = wxSOUND_NOERR;
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_MEMERR;
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_NOERR;
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_MEMERR;
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 #ifdef __WXGTK__
257 int trig;
258
259 if (evt == wxSOUND_OUTPUT) {
260 m_tag = gdk_input_add(m_fd, GDK_INPUT_WRITE, _wxSound_OSS_CBack, (gpointer)this);
261 trig = PCM_ENABLE_OUTPUT;
262 } else {
263 m_tag = gdk_input_add(m_fd, GDK_INPUT_READ, _wxSound_OSS_CBack, (gpointer)this);
264 trig = PCM_ENABLE_INPUT;
265 }
266 #else
267 while (!m_oss_stop)
268 OnSoundEvent(evt);
269 #endif
270
271 ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &trig);
272
273 m_oss_stop = FALSE;
274 m_q_filled = FALSE;
275
276 return TRUE;
277 }
278
279 bool wxSoundStreamOSS::StopProduction()
280 {
281 if (m_oss_stop)
282 return FALSE;
283
284 #ifdef __WXGTK__
285 gdk_input_remove(m_tag);
286 #endif
287
288 close(m_fd);
289 m_oss_stop = TRUE;
290 m_q_filled = TRUE;
291 return TRUE;
292 }
293
294 bool wxSoundStreamOSS::QueueFilled() const
295 {
296 return m_q_filled;
297 }
298
299 //
300 // Detect the closest format (The best).
301 //
302 void wxSoundStreamOSS::DetectBest(wxSoundFormatPcm *pcm)
303 {
304 #define MASK_16BITS (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
305
306 int fmt_mask;
307 wxSoundFormatPcm best_pcm;
308
309 // We change neither the number of channels nor the sample rate
310
311 best_pcm.SetSampleRate(pcm->GetSampleRate());
312 best_pcm.SetChannels(pcm->GetChannels());
313
314 // Get the supported format by the sound card
315 ioctl(m_fd, SNDCTL_DSP_GETFMTS, &fmt_mask);
316
317 // It supports 16 bits
318 if (pcm->GetBPS() == 16 && ((fmt_mask & MASK_16BITS) != 0))
319 best_pcm.SetBPS(16);
320
321 // It supports big endianness
322 if (pcm->GetOrder() == wxBIG_ENDIAN && ((fmt_mask & (AFMT_S16_BE | AFMT_U16_BE)) != 0))
323 best_pcm.SetOrder(wxBIG_ENDIAN);
324
325 // It supports little endianness
326 if (pcm->GetOrder() == wxLITTLE_ENDIAN && ((fmt_mask & (AFMT_S16_LE | AFMT_U16_LE)) != 0))
327 best_pcm.SetOrder(wxLITTLE_ENDIAN);
328
329 // It supports signed samples
330 if (pcm->Signed() && ((fmt_mask & (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)) != 0))
331 best_pcm.Signed(TRUE);
332
333 // It supports unsigned samples
334 if (!pcm->Signed() && ((fmt_mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_U8)) != 0))
335 best_pcm.Signed(FALSE);
336
337 // Finally recopy the new format
338 *pcm = best_pcm;
339 }