0662cd3286
Changed size_t to wxUint32 Added support for G72X WAV format multi-codec handling git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@3508 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
336 lines
6.8 KiB
C++
336 lines
6.8 KiB
C++
// --------------------------------------------------------------------------
|
|
// Name: sndoss.cpp
|
|
// Purpose:
|
|
// Date: 08/11/1999
|
|
// Author: Guilhem Lavaux <lavaux@easynet.fr> (C) 1999
|
|
// CVSID: $Id$
|
|
// --------------------------------------------------------------------------
|
|
#ifdef __GNUG__
|
|
#pragma implementation "sndoss.cpp"
|
|
#endif
|
|
|
|
#include <sys/soundcard.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/ioctl.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <wx/defs.h>
|
|
#include <wx/string.h>
|
|
#include "sndbase.h"
|
|
#include "sndoss.h"
|
|
#include "sndpcm.h"
|
|
#ifdef __WXGTK__
|
|
#include <gdk/gdk.h>
|
|
#endif
|
|
|
|
wxSoundStreamOSS::wxSoundStreamOSS(const wxString& dev_name)
|
|
{
|
|
wxSoundFormatPcm pcm_default;
|
|
|
|
m_fd = open(dev_name.mb_str(), O_RDWR);
|
|
|
|
if (m_fd == -1) {
|
|
m_snderror = wxSOUND_INVDEV;
|
|
return;
|
|
}
|
|
|
|
m_devname = dev_name;
|
|
|
|
wxSoundStreamOSS::SetSoundFormat(pcm_default);
|
|
|
|
ioctl(m_fd, SNDCTL_DSP_GETBLKSIZE, &m_bufsize);
|
|
|
|
m_snderror = wxSOUND_NOERR;
|
|
|
|
close(m_fd);
|
|
|
|
m_oss_stop = TRUE;
|
|
m_q_filled = TRUE;
|
|
}
|
|
|
|
wxSoundStreamOSS::~wxSoundStreamOSS()
|
|
{
|
|
if (m_fd > 0)
|
|
close(m_fd);
|
|
}
|
|
|
|
wxUint32 wxSoundStreamOSS::GetBestSize() const
|
|
{
|
|
return m_bufsize;
|
|
}
|
|
|
|
wxSoundStream& wxSoundStreamOSS::Read(void *buffer, wxUint32 len)
|
|
{
|
|
int ret;
|
|
|
|
m_lastcount = (wxUint32)ret = read(m_fd, buffer, len);
|
|
m_q_filled = TRUE;
|
|
|
|
if (ret < 0)
|
|
m_snderror = wxSOUND_IOERR;
|
|
else
|
|
m_snderror = wxSOUND_NOERR;
|
|
|
|
return *this;
|
|
}
|
|
|
|
wxSoundStream& wxSoundStreamOSS::Write(const void *buffer, wxUint32 len)
|
|
{
|
|
int ret;
|
|
|
|
m_lastcount = (wxUint32)ret = write(m_fd, buffer, len);
|
|
m_q_filled = TRUE;
|
|
|
|
if (ret < 0)
|
|
m_snderror = wxSOUND_IOERR;
|
|
else
|
|
m_snderror = wxSOUND_NOERR;
|
|
|
|
return *this;
|
|
}
|
|
|
|
bool wxSoundStreamOSS::SetSoundFormat(const wxSoundFormatBase& format)
|
|
{
|
|
int tmp;
|
|
wxSoundFormatPcm *pcm_format;
|
|
|
|
if (format.GetType() != wxSOUND_PCM) {
|
|
m_snderror = wxSOUND_INVFRMT;
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_fd == -1) {
|
|
m_snderror = wxSOUND_INVDEV;
|
|
return FALSE;
|
|
}
|
|
|
|
if (m_sndformat)
|
|
delete m_sndformat;
|
|
|
|
m_sndformat = format.Clone();
|
|
if (!m_sndformat) {
|
|
m_snderror = wxSOUND_MEMERR;
|
|
return FALSE;
|
|
}
|
|
pcm_format = (wxSoundFormatPcm *)m_sndformat;
|
|
|
|
// Set the sample rate field.
|
|
tmp = pcm_format->GetSampleRate();
|
|
ioctl(m_fd, SNDCTL_DSP_SPEED, &tmp);
|
|
|
|
pcm_format->SetSampleRate(tmp);
|
|
|
|
// Detect the best format
|
|
DetectBest(pcm_format);
|
|
SetupFormat(pcm_format);
|
|
|
|
tmp = pcm_format->GetChannels();
|
|
ioctl(m_fd, SNDCTL_DSP_CHANNELS, &tmp);
|
|
pcm_format->SetChannels(tmp);
|
|
|
|
m_snderror = wxSOUND_NOERR;
|
|
if (*pcm_format != format) {
|
|
m_snderror = wxSOUND_NOTEXACT;
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
bool wxSoundStreamOSS::SetupFormat(wxSoundFormatPcm *pcm_format)
|
|
{
|
|
int tmp;
|
|
|
|
switch(pcm_format->GetBPS()) {
|
|
case 8:
|
|
if (pcm_format->Signed())
|
|
tmp = AFMT_S8;
|
|
else
|
|
tmp = AFMT_U8;
|
|
break;
|
|
case 16:
|
|
switch (pcm_format->GetOrder()) {
|
|
case wxBIG_ENDIAN:
|
|
if (pcm_format->Signed())
|
|
tmp = AFMT_S16_BE;
|
|
else
|
|
tmp = AFMT_U16_BE;
|
|
break;
|
|
case wxLITTLE_ENDIAN:
|
|
if (pcm_format->Signed())
|
|
tmp = AFMT_S16_LE;
|
|
else
|
|
tmp = AFMT_U16_LE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
ioctl(m_fd, SNDCTL_DSP_SETFMT, &tmp);
|
|
|
|
// Demangling.
|
|
switch (tmp) {
|
|
case AFMT_U8:
|
|
pcm_format->SetBPS(8);
|
|
pcm_format->Signed(FALSE);
|
|
break;
|
|
case AFMT_S8:
|
|
pcm_format->SetBPS(8);
|
|
pcm_format->Signed(TRUE);
|
|
break;
|
|
case AFMT_U16_LE:
|
|
pcm_format->SetBPS(16);
|
|
pcm_format->Signed(FALSE);
|
|
pcm_format->SetOrder(wxLITTLE_ENDIAN);
|
|
break;
|
|
case AFMT_U16_BE:
|
|
pcm_format->SetBPS(16);
|
|
pcm_format->Signed(FALSE);
|
|
pcm_format->SetOrder(wxBIG_ENDIAN);
|
|
break;
|
|
case AFMT_S16_LE:
|
|
pcm_format->SetBPS(16);
|
|
pcm_format->Signed(TRUE);
|
|
pcm_format->SetOrder(wxLITTLE_ENDIAN);
|
|
break;
|
|
case AFMT_S16_BE:
|
|
pcm_format->SetBPS(16);
|
|
pcm_format->Signed(TRUE);
|
|
pcm_format->SetOrder(wxBIG_ENDIAN);
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef __WXGTK__
|
|
static void _wxSound_OSS_CBack(gpointer data, int source,
|
|
GdkInputCondition condition)
|
|
{
|
|
wxSoundStreamOSS *oss = (wxSoundStreamOSS *)data;
|
|
|
|
switch (condition) {
|
|
case GDK_INPUT_READ:
|
|
oss->WakeUpEvt(wxSOUND_INPUT);
|
|
break;
|
|
case GDK_INPUT_WRITE:
|
|
oss->WakeUpEvt(wxSOUND_OUTPUT);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void wxSoundStreamOSS::WakeUpEvt(int evt)
|
|
{
|
|
m_q_filled = FALSE;
|
|
OnSoundEvent(evt);
|
|
}
|
|
|
|
bool wxSoundStreamOSS::StartProduction(int evt)
|
|
{
|
|
wxSoundFormatBase *old_frmt;
|
|
|
|
if (!m_oss_stop)
|
|
StopProduction();
|
|
|
|
old_frmt = m_sndformat->Clone();
|
|
|
|
if (evt == wxSOUND_OUTPUT)
|
|
m_fd = open(m_devname.mb_str(), O_WRONLY);
|
|
else if (evt == wxSOUND_INPUT)
|
|
m_fd = open(m_devname.mb_str(), O_RDONLY);
|
|
|
|
if (m_fd == -1) {
|
|
m_snderror = wxSOUND_INVDEV;
|
|
return FALSE;
|
|
}
|
|
|
|
SetSoundFormat(*old_frmt);
|
|
delete old_frmt;
|
|
|
|
#ifdef __WXGTK__
|
|
int trig;
|
|
|
|
if (evt == wxSOUND_OUTPUT) {
|
|
m_tag = gdk_input_add(m_fd, GDK_INPUT_WRITE, _wxSound_OSS_CBack, (gpointer)this);
|
|
trig = PCM_ENABLE_OUTPUT;
|
|
} else {
|
|
m_tag = gdk_input_add(m_fd, GDK_INPUT_READ, _wxSound_OSS_CBack, (gpointer)this);
|
|
trig = PCM_ENABLE_INPUT;
|
|
}
|
|
#else
|
|
while (!m_oss_stop)
|
|
OnSoundEvent(evt);
|
|
#endif
|
|
|
|
ioctl(m_fd, SNDCTL_DSP_SETTRIGGER, &trig);
|
|
|
|
m_oss_stop = FALSE;
|
|
m_q_filled = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool wxSoundStreamOSS::StopProduction()
|
|
{
|
|
if (m_oss_stop)
|
|
return FALSE;
|
|
|
|
#ifdef __WXGTK__
|
|
gdk_input_remove(m_tag);
|
|
#endif
|
|
|
|
close(m_fd);
|
|
m_oss_stop = TRUE;
|
|
m_q_filled = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
bool wxSoundStreamOSS::QueueFilled() const
|
|
{
|
|
return m_q_filled;
|
|
}
|
|
|
|
//
|
|
// Detect the closest format (The best).
|
|
//
|
|
void wxSoundStreamOSS::DetectBest(wxSoundFormatPcm *pcm)
|
|
{
|
|
#define MASK_16BITS (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
|
|
|
|
int fmt_mask;
|
|
wxSoundFormatPcm best_pcm;
|
|
|
|
// We change neither the number of channels nor the sample rate
|
|
|
|
best_pcm.SetSampleRate(pcm->GetSampleRate());
|
|
best_pcm.SetChannels(pcm->GetChannels());
|
|
|
|
// Get the supported format by the sound card
|
|
ioctl(m_fd, SNDCTL_DSP_GETFMTS, &fmt_mask);
|
|
|
|
// It supports 16 bits
|
|
if (pcm->GetBPS() == 16 && ((fmt_mask & MASK_16BITS) != 0))
|
|
best_pcm.SetBPS(16);
|
|
|
|
// It supports big endianness
|
|
if (pcm->GetOrder() == wxBIG_ENDIAN && ((fmt_mask & (AFMT_S16_BE | AFMT_U16_BE)) != 0))
|
|
best_pcm.SetOrder(wxBIG_ENDIAN);
|
|
|
|
// It supports little endianness
|
|
if (pcm->GetOrder() == wxLITTLE_ENDIAN && ((fmt_mask & (AFMT_S16_LE | AFMT_U16_LE)) != 0))
|
|
best_pcm.SetOrder(wxLITTLE_ENDIAN);
|
|
|
|
// It supports signed samples
|
|
if (pcm->Signed() && ((fmt_mask & (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)) != 0))
|
|
best_pcm.Signed(TRUE);
|
|
|
|
// It supports unsigned samples
|
|
if (!pcm->Signed() && ((fmt_mask & (AFMT_U16_LE | AFMT_U16_BE | AFMT_U8)) != 0))
|
|
best_pcm.Signed(FALSE);
|
|
|
|
// Finally recopy the new format
|
|
*pcm = best_pcm;
|
|
}
|