1 // --------------------------------------------------------------------------
5 // Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999, 2000
8 // --------------------------------------------------------------------------
10 #pragma implementation "sndoss.cpp"
13 // --------------------------------------------------------------------------
14 // System dependent headers
15 // --------------------------------------------------------------------------
17 #include <sys/soundcard.h>
18 #include <sys/types.h>
20 #include <sys/ioctl.h>
27 // --------------------------------------------------------------------------
29 // --------------------------------------------------------------------------
31 #include "wx/string.h"
32 #include "wx/mmedia/sndbase.h"
33 #include "wx/mmedia/sndoss.h"
34 #include "wx/mmedia/sndpcm.h"
36 wxSoundStreamOSS::wxSoundStreamOSS(const wxString
& dev_name
)
38 wxSoundFormatPcm pcm_default
;
40 // Open the OSS device
41 m_fd
= open(dev_name
.mb_str(), O_WRONLY
);
45 m_snderror
= wxSOUND_INVDEV
;
49 // Remember the device name
52 // Initialize the default format
53 wxSoundStreamOSS::SetSoundFormat(pcm_default
);
55 // Get the default best size for OSS
56 ioctl(m_fd
, SNDCTL_DSP_GETBLKSIZE
, &m_bufsize
);
58 m_snderror
= wxSOUND_NOERROR
;
68 wxSoundStreamOSS::~wxSoundStreamOSS()
74 wxUint32
wxSoundStreamOSS::GetBestSize() const
79 wxSoundStream
& wxSoundStreamOSS::Read(void *buffer
, wxUint32 len
)
84 m_snderror
= wxSOUND_NOTSTARTED
;
89 ret
= read(m_fd
, buffer
, len
);
90 m_lastcount
= (wxUint32
)ret
;
94 m_snderror
= wxSOUND_IOERROR
;
96 m_snderror
= wxSOUND_NOERROR
;
101 wxSoundStream
& wxSoundStreamOSS::Write(const void *buffer
, wxUint32 len
)
106 m_snderror
= wxSOUND_NOTSTARTED
;
111 ret
= write(m_fd
, buffer
, len
);
116 m_snderror
= wxSOUND_IOERROR
;
118 m_snderror
= wxSOUND_NOERROR
;
119 m_lastcount
= (wxUint32
)ret
;
125 bool wxSoundStreamOSS::SetSoundFormat(const wxSoundFormatBase
& format
)
128 wxSoundFormatPcm
*pcm_format
;
130 if (format
.GetType() != wxSOUND_PCM
) {
131 m_snderror
= wxSOUND_INVFRMT
;
136 m_snderror
= wxSOUND_INVDEV
;
143 m_sndformat
= format
.Clone();
145 m_snderror
= wxSOUND_MEMERROR
;
148 pcm_format
= (wxSoundFormatPcm
*)m_sndformat
;
150 // We temporary open the OSS device
152 m_fd
= open(m_devname
.mb_str(), O_WRONLY
);
154 m_snderror
= wxSOUND_INVDEV
;
159 // Set the sample rate field.
160 tmp
= pcm_format
->GetSampleRate();
161 ioctl(m_fd
, SNDCTL_DSP_SPEED
, &tmp
);
163 pcm_format
->SetSampleRate(tmp
);
165 // Detect the best format
166 DetectBest(pcm_format
);
168 SetupFormat(pcm_format
);
170 tmp
= pcm_format
->GetChannels();
171 ioctl(m_fd
, SNDCTL_DSP_CHANNELS
, &tmp
);
172 pcm_format
->SetChannels(tmp
);
174 // Close the OSS device
178 m_snderror
= wxSOUND_NOERROR
;
179 if (*pcm_format
!= format
) {
180 m_snderror
= wxSOUND_NOEXACT
;
187 bool wxSoundStreamOSS::SetupFormat(wxSoundFormatPcm
*pcm_format
)
191 switch(pcm_format
->GetBPS()) {
193 if (pcm_format
->Signed())
199 switch (pcm_format
->GetOrder()) {
201 if (pcm_format
->Signed())
206 case wxLITTLE_ENDIAN
:
207 if (pcm_format
->Signed())
216 ioctl(m_fd
, SNDCTL_DSP_SETFMT
, &tmp
);
221 pcm_format
->SetBPS(8);
222 pcm_format
->Signed(false);
225 pcm_format
->SetBPS(8);
226 pcm_format
->Signed(true);
229 pcm_format
->SetBPS(16);
230 pcm_format
->Signed(false);
231 pcm_format
->SetOrder(wxLITTLE_ENDIAN
);
234 pcm_format
->SetBPS(16);
235 pcm_format
->Signed(false);
236 pcm_format
->SetOrder(wxBIG_ENDIAN
);
239 pcm_format
->SetBPS(16);
240 pcm_format
->Signed(true);
241 pcm_format
->SetOrder(wxLITTLE_ENDIAN
);
244 pcm_format
->SetBPS(16);
245 pcm_format
->Signed(true);
246 pcm_format
->SetOrder(wxBIG_ENDIAN
);
253 static void _wxSound_OSS_CBack(gpointer data
, int source
,
254 GdkInputCondition condition
)
256 wxSoundStreamOSS
*oss
= (wxSoundStreamOSS
*)data
;
260 oss
->WakeUpEvt(wxSOUND_INPUT
);
262 case GDK_INPUT_WRITE
:
263 oss
->WakeUpEvt(wxSOUND_OUTPUT
);
271 void wxSoundStreamOSS::WakeUpEvt(int evt
)
277 bool wxSoundStreamOSS::StartProduction(int evt
)
279 wxSoundFormatBase
*old_frmt
;
284 old_frmt
= m_sndformat
->Clone();
286 m_snderror
= wxSOUND_MEMERROR
;
290 if (evt
== wxSOUND_OUTPUT
)
291 m_fd
= open(m_devname
.mb_str(), O_WRONLY
);
292 else if (evt
== wxSOUND_INPUT
)
293 m_fd
= open(m_devname
.mb_str(), O_RDONLY
);
296 m_snderror
= wxSOUND_INVDEV
;
300 SetSoundFormat(*old_frmt
);
305 if (evt
== wxSOUND_OUTPUT
) {
307 m_tag
= gdk_input_add(m_fd
, GDK_INPUT_WRITE
, _wxSound_OSS_CBack
, (gpointer
)this);
309 trig
= PCM_ENABLE_OUTPUT
;
312 m_tag
= gdk_input_add(m_fd
, GDK_INPUT_READ
, _wxSound_OSS_CBack
, (gpointer
)this);
314 trig
= PCM_ENABLE_INPUT
;
317 ioctl(m_fd
, SNDCTL_DSP_SETTRIGGER
, &trig
);
325 bool wxSoundStreamOSS::StopProduction()
331 gdk_input_remove(m_tag
);
340 bool wxSoundStreamOSS::QueueFilled() const
346 // Detect the closest format (The best).
348 void wxSoundStreamOSS::DetectBest(wxSoundFormatPcm
*pcm
)
350 #define MASK_16BITS (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
353 wxSoundFormatPcm best_pcm
;
355 // We change neither the number of channels nor the sample rate
357 best_pcm
.SetSampleRate(pcm
->GetSampleRate());
358 best_pcm
.SetChannels(pcm
->GetChannels());
360 // Get the supported format by the sound card
361 ioctl(m_fd
, SNDCTL_DSP_GETFMTS
, &fmt_mask
);
363 // It supports 16 bits
364 if (pcm
->GetBPS() == 16 && ((fmt_mask
& MASK_16BITS
) != 0))
367 // It supports big endianness
368 if (pcm
->GetOrder() == wxBIG_ENDIAN
&&
369 ((fmt_mask
& (AFMT_S16_BE
| AFMT_U16_BE
)) != 0))
370 best_pcm
.SetOrder(wxBIG_ENDIAN
);
372 // It supports little endianness
373 if (pcm
->GetOrder() == wxLITTLE_ENDIAN
&&
374 ((fmt_mask
& (AFMT_S16_LE
| AFMT_U16_LE
)) != 0))
375 best_pcm
.SetOrder(wxLITTLE_ENDIAN
);
377 // It supports signed samples
379 ((fmt_mask
& (AFMT_S16_LE
| AFMT_S16_BE
| AFMT_S8
)) != 0))
380 best_pcm
.Signed(true);
382 // It supports unsigned samples
383 if (!pcm
->Signed() &&
384 ((fmt_mask
& (AFMT_U16_LE
| AFMT_U16_BE
| AFMT_U8
)) != 0))
385 best_pcm
.Signed(false);
387 // Finally recopy the new format