]> git.saurik.com Git - wxWidgets.git/blame - utils/wxMMedia2/lib/sndoss.cpp
Minor changes.
[wxWidgets.git] / utils / wxMMedia2 / lib / sndoss.cpp
CommitLineData
526ddb13
GL
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
27wxSoundStreamOSS::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;
503aa33d 49 m_q_filled = TRUE;
526ddb13
GL
50}
51
52wxSoundStreamOSS::~wxSoundStreamOSS()
53{
54 if (m_fd > 0)
55 close(m_fd);
56}
57
58wxUint32 wxSoundStreamOSS::GetBestSize() const
59{
60 return m_bufsize;
61}
62
0662cd32 63wxSoundStream& wxSoundStreamOSS::Read(void *buffer, wxUint32 len)
526ddb13
GL
64{
65 int ret;
66
0662cd32 67 m_lastcount = (wxUint32)ret = read(m_fd, buffer, len);
503aa33d 68 m_q_filled = TRUE;
526ddb13
GL
69
70 if (ret < 0)
71 m_snderror = wxSOUND_IOERR;
72 else
73 m_snderror = wxSOUND_NOERR;
74
75 return *this;
76}
77
0662cd32 78wxSoundStream& wxSoundStreamOSS::Write(const void *buffer, wxUint32 len)
526ddb13
GL
79{
80 int ret;
81
0662cd32 82 m_lastcount = (wxUint32)ret = write(m_fd, buffer, len);
503aa33d 83 m_q_filled = TRUE;
526ddb13
GL
84
85 if (ret < 0)
86 m_snderror = wxSOUND_IOERR;
87 else
88 m_snderror = wxSOUND_NOERR;
89
90 return *this;
91}
92
93bool 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_NOTEXACT;
135 return FALSE;
136 }
137 return TRUE;
138}
139
140bool 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__
206static 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
224void wxSoundStreamOSS::WakeUpEvt(int evt)
225{
503aa33d 226 m_q_filled = FALSE;
526ddb13
GL
227 OnSoundEvent(evt);
228}
229
230bool 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
239 if (evt == wxSOUND_OUTPUT)
240 m_fd = open(m_devname.mb_str(), O_WRONLY);
241 else if (evt == wxSOUND_INPUT)
242 m_fd = open(m_devname.mb_str(), O_RDONLY);
243
244 if (m_fd == -1) {
245 m_snderror = wxSOUND_INVDEV;
246 return FALSE;
247 }
248
249 SetSoundFormat(*old_frmt);
250 delete old_frmt;
251
252#ifdef __WXGTK__
253 int trig;
254
255 if (evt == wxSOUND_OUTPUT) {
256 m_tag = gdk_input_add(m_fd, GDK_INPUT_WRITE, _wxSound_OSS_CBack, (gpointer)this);
257 trig = PCM_ENABLE_OUTPUT;
258 } else {
259 m_tag = gdk_input_add(m_fd, GDK_INPUT_READ, _wxSound_OSS_CBack, (gpointer)this);
260 trig = PCM_ENABLE_INPUT;
261 }
262#else
263 while (!m_oss_stop)
264 OnSoundEvent(evt);
265#endif
266
267 ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &trig);
268
269 m_oss_stop = FALSE;
503aa33d 270 m_q_filled = FALSE;
526ddb13
GL
271
272 return TRUE;
273}
274
275bool wxSoundStreamOSS::StopProduction()
276{
277 if (m_oss_stop)
278 return FALSE;
279
280#ifdef __WXGTK__
281 gdk_input_remove(m_tag);
282#endif
283
284 close(m_fd);
285 m_oss_stop = TRUE;
503aa33d 286 m_q_filled = TRUE;
526ddb13
GL
287 return TRUE;
288}
289
503aa33d
GL
290bool wxSoundStreamOSS::QueueFilled() const
291{
292 return m_q_filled;
293}
294
526ddb13
GL
295//
296// Detect the closest format (The best).
297//
298void wxSoundStreamOSS::DetectBest(wxSoundFormatPcm *pcm)
299{
300#define MASK_16BITS (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
301
302 int fmt_mask;
303 wxSoundFormatPcm best_pcm;
304
305 // We change neither the number of channels nor the sample rate
306
307 best_pcm.SetSampleRate(pcm->GetSampleRate());
308 best_pcm.SetChannels(pcm->GetChannels());
309
310 // Get the supported format by the sound card
311 ioctl(m_fd, SNDCTL_DSP_GETFMTS, &fmt_mask);
312
313 // It supports 16 bits
314 if (pcm->GetBPS() == 16 && ((fmt_mask & MASK_16BITS) != 0))
315 best_pcm.SetBPS(16);
316
317 // It supports big endianness
318 if (pcm->GetOrder() == wxBIG_ENDIAN && ((fmt_mask & (AFMT_S16_BE | AFMT_U16_BE)) != 0))
319 best_pcm.SetOrder(wxBIG_ENDIAN);
320
321 // It supports little endianness
322 if (pcm->GetOrder() == wxLITTLE_ENDIAN && ((fmt_mask & (AFMT_S16_LE | AFMT_U16_LE)) != 0))
323 best_pcm.SetOrder(wxLITTLE_ENDIAN);
324
325 // It supports signed samples
326 if (pcm->Signed() && ((fmt_mask & (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)) != 0))
327 best_pcm.Signed(TRUE);
328
329 // It supports unsigned samples
330 if (!pcm->Signed() && ((fmt_mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_U8)) != 0))
331 best_pcm.Signed(FALSE);
332
333 // Finally recopy the new format
334 *pcm = best_pcm;
335}