1 // --------------------------------------------------------------------------
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
7 // --------------------------------------------------------------------------
9 #pragma implementation "sndoss.cpp"
12 // --------------------------------------------------------------------------
13 // System dependent headers
14 // --------------------------------------------------------------------------
16 #include <sys/soundcard.h>
17 #include <sys/types.h>
19 #include <sys/ioctl.h>
26 // --------------------------------------------------------------------------
28 // --------------------------------------------------------------------------
30 #include "wx/string.h"
31 #include "wx/mmedia/sndbase.h"
32 #include "wx/mmedia/sndoss.h"
33 #include "wx/mmedia/sndpcm.h"
35 wxSoundStreamOSS::wxSoundStreamOSS(const wxString
& dev_name
)
37 wxSoundFormatPcm pcm_default
;
39 // Open the OSS device
40 m_fd
= open(dev_name
.mb_str(), O_WRONLY
);
44 m_snderror
= wxSOUND_INVDEV
;
48 // Remember the device name
51 // Initialize the default format
52 wxSoundStreamOSS::SetSoundFormat(pcm_default
);
54 // Get the default best size for OSS
55 ioctl(m_fd
, SNDCTL_DSP_GETBLKSIZE
, &m_bufsize
);
57 m_snderror
= wxSOUND_NOERROR
;
67 wxSoundStreamOSS::~wxSoundStreamOSS()
73 wxUint32
wxSoundStreamOSS::GetBestSize() const
78 wxSoundStream
& wxSoundStreamOSS::Read(void *buffer
, wxUint32 len
)
83 m_snderror
= wxSOUND_NOTSTARTED
;
88 m_lastcount
= (wxUint32
)ret
= read(m_fd
, buffer
, len
);
92 m_snderror
= wxSOUND_IOERROR
;
94 m_snderror
= wxSOUND_NOERROR
;
99 wxSoundStream
& wxSoundStreamOSS::Write(const void *buffer
, wxUint32 len
)
104 m_snderror
= wxSOUND_NOTSTARTED
;
109 ret
= write(m_fd
, buffer
, len
);
114 m_snderror
= wxSOUND_IOERROR
;
116 m_snderror
= wxSOUND_NOERROR
;
117 m_lastcount
= (wxUint32
)ret
;
123 bool wxSoundStreamOSS::SetSoundFormat(const wxSoundFormatBase
& format
)
126 wxSoundFormatPcm
*pcm_format
;
128 if (format
.GetType() != wxSOUND_PCM
) {
129 m_snderror
= wxSOUND_INVFRMT
;
134 m_snderror
= wxSOUND_INVDEV
;
141 m_sndformat
= format
.Clone();
143 m_snderror
= wxSOUND_MEMERROR
;
146 pcm_format
= (wxSoundFormatPcm
*)m_sndformat
;
148 // We temporary open the OSS device
150 m_fd
= open(m_devname
.mb_str(), O_WRONLY
);
152 m_snderror
= wxSOUND_INVDEV
;
157 // Set the sample rate field.
158 tmp
= pcm_format
->GetSampleRate();
159 ioctl(m_fd
, SNDCTL_DSP_SPEED
, &tmp
);
161 pcm_format
->SetSampleRate(tmp
);
163 // Detect the best format
164 DetectBest(pcm_format
);
166 SetupFormat(pcm_format
);
168 tmp
= pcm_format
->GetChannels();
169 ioctl(m_fd
, SNDCTL_DSP_CHANNELS
, &tmp
);
170 pcm_format
->SetChannels(tmp
);
172 // Close the OSS device
176 m_snderror
= wxSOUND_NOERROR
;
177 if (*pcm_format
!= format
) {
178 m_snderror
= wxSOUND_NOEXACT
;
185 bool wxSoundStreamOSS::SetupFormat(wxSoundFormatPcm
*pcm_format
)
189 switch(pcm_format
->GetBPS()) {
191 if (pcm_format
->Signed())
197 switch (pcm_format
->GetOrder()) {
199 if (pcm_format
->Signed())
204 case wxLITTLE_ENDIAN
:
205 if (pcm_format
->Signed())
214 ioctl(m_fd
, SNDCTL_DSP_SETFMT
, &tmp
);
219 pcm_format
->SetBPS(8);
220 pcm_format
->Signed(FALSE
);
223 pcm_format
->SetBPS(8);
224 pcm_format
->Signed(TRUE
);
227 pcm_format
->SetBPS(16);
228 pcm_format
->Signed(FALSE
);
229 pcm_format
->SetOrder(wxLITTLE_ENDIAN
);
232 pcm_format
->SetBPS(16);
233 pcm_format
->Signed(FALSE
);
234 pcm_format
->SetOrder(wxBIG_ENDIAN
);
237 pcm_format
->SetBPS(16);
238 pcm_format
->Signed(TRUE
);
239 pcm_format
->SetOrder(wxLITTLE_ENDIAN
);
242 pcm_format
->SetBPS(16);
243 pcm_format
->Signed(TRUE
);
244 pcm_format
->SetOrder(wxBIG_ENDIAN
);
251 static void _wxSound_OSS_CBack(gpointer data
, int source
,
252 GdkInputCondition condition
)
254 wxSoundStreamOSS
*oss
= (wxSoundStreamOSS
*)data
;
258 oss
->WakeUpEvt(wxSOUND_INPUT
);
260 case GDK_INPUT_WRITE
:
261 oss
->WakeUpEvt(wxSOUND_OUTPUT
);
269 void wxSoundStreamOSS::WakeUpEvt(int evt
)
275 bool wxSoundStreamOSS::StartProduction(int evt
)
277 wxSoundFormatBase
*old_frmt
;
282 old_frmt
= m_sndformat
->Clone();
284 m_snderror
= wxSOUND_MEMERROR
;
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
);
294 m_snderror
= wxSOUND_INVDEV
;
298 SetSoundFormat(*old_frmt
);
303 if (evt
== wxSOUND_OUTPUT
) {
305 m_tag
= gdk_input_add(m_fd
, GDK_INPUT_WRITE
, _wxSound_OSS_CBack
, (gpointer
)this);
307 trig
= PCM_ENABLE_OUTPUT
;
310 m_tag
= gdk_input_add(m_fd
, GDK_INPUT_READ
, _wxSound_OSS_CBack
, (gpointer
)this);
312 trig
= PCM_ENABLE_INPUT
;
315 ioctl(m_fd
, SNDCTL_DSP_SETTRIGGER
, &trig
);
323 bool wxSoundStreamOSS::StopProduction()
329 gdk_input_remove(m_tag
);
338 bool wxSoundStreamOSS::QueueFilled() const
344 // Detect the closest format (The best).
346 void wxSoundStreamOSS::DetectBest(wxSoundFormatPcm
*pcm
)
348 #define MASK_16BITS (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
351 wxSoundFormatPcm best_pcm
;
353 // We change neither the number of channels nor the sample rate
355 best_pcm
.SetSampleRate(pcm
->GetSampleRate());
356 best_pcm
.SetChannels(pcm
->GetChannels());
358 // Get the supported format by the sound card
359 ioctl(m_fd
, SNDCTL_DSP_GETFMTS
, &fmt_mask
);
361 // It supports 16 bits
362 if (pcm
->GetBPS() == 16 && ((fmt_mask
& MASK_16BITS
) != 0))
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
);
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
);
375 // It supports signed samples
377 ((fmt_mask
& (AFMT_S16_LE
| AFMT_S16_BE
| AFMT_S8
)) != 0))
378 best_pcm
.Signed(TRUE
);
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
);
385 // Finally recopy the new format