📄 ossaix.cxx
字号:
/*
* sound.cxx
*
* Sound driver implementation.
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): Loopback feature: Philip Edelbrock <phil@netroedge.com>.
*
* $Log: ossaix.cxx,v $
* Revision 1.1 2006/06/29 04:18:41 joegenbaclor
* *** empty log message ***
*
* Revision 1.3 2002/02/09 00:52:01 robertj
* Slight adjustment to API and documentation for volume functions.
*
* Revision 1.2 2002/02/07 20:57:21 dereks
* add SetVolume and GetVolume methods to PSoundChannel
*
* Revision 1.1 2000/06/21 01:01:22 robertj
* AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
*
* Revision 1.17 2000/05/11 02:05:54 craigs
* Fixed problem with PLayFile not recognizing wait flag
*
* Revision 1.16 2000/05/10 02:10:44 craigs
* Added implementation for PlayFile command
*
* Revision 1.15 2000/05/02 08:30:26 craigs
* Removed "memory leaks" caused by brain-dead GNU linker
*
* Revision 1.14 2000/04/09 18:19:23 rogerh
* Add my changes for NetBSD support.
*
* Revision 1.13 2000/03/08 12:17:09 rogerh
* Add OpenBSD support
*
* Revision 1.12 2000/03/04 13:02:28 robertj
* Added simple play functions for sound files.
*
* Revision 1.11 2000/02/15 23:11:34 robertj
* Audio support for FreeBSD, thanks Roger Hardiman.
*
* Revision 1.10 2000/01/08 06:41:08 craigs
* Fixed problem whereby failure to open sound device returns TRUE
*
* Revision 1.9 1999/08/24 13:40:26 craigs
* Fixed problem with EINTR causing sound channel reads and write to fail
* Thanks to phil@netroedge.com!
*
* Revision 1.8 1999/08/17 09:42:22 robertj
* Fixed close of sound channel in loopback mode closing stdin!
*
* Revision 1.7 1999/08/17 09:28:47 robertj
* Added audio loopback psuedo-device (thanks Philip Edelbrock)
*
* Revision 1.6 1999/07/19 01:31:49 craigs
* Major rewrite to assure ioctls are all done in the correct order as OSS seems
* to be incredibly sensitive to this.
*
* Revision 1.5 1999/07/11 13:42:13 craigs
* pthreads support for Linux
*
* Revision 1.4 1999/06/30 13:49:26 craigs
* Added code to allow full duplex audio
*
* Revision 1.3 1999/05/28 14:14:29 robertj
* Added function to get default audio device.
*
* Revision 1.2 1999/05/22 12:49:05 craigs
* Finished implementation for Linux OSS interface
*
* Revision 1.1 1999/02/25 03:45:00 robertj
* Sound driver implementation changes for various unix platforms.
*
* Revision 1.1 1999/02/22 13:24:47 robertj
* Added first cut sound implmentation.
*
*/
#pragma implementation "sound.h"
#include <ptlib.h>
#ifdef P_LINUX
#include <sys/soundcard.h>
#include <sys/time.h>
#endif
#ifdef P_FREEBSD
#include <machine/soundcard.h>
#endif
#if defined(P_OPENBSD) || defined(P_NETBSD)
#include <soundcard.h>
#endif
///////////////////////////////////////////////////////////////////////////////
// declare type for sound handle dictionary
class SoundHandleEntry : public PObject {
PCLASSINFO(SoundHandleEntry, PObject)
public:
SoundHandleEntry();
int handle;
int direction;
unsigned numChannels;
unsigned sampleRate;
unsigned bitsPerSample;
unsigned fragmentValue;
BOOL isInitialised;
};
PDICTIONARY(SoundHandleDict, PString, SoundHandleEntry);
#define LOOPBACK_BUFFER_SIZE 5000
#define BYTESINBUF ((startptr<endptr)?(endptr-startptr):(LOOPBACK_BUFFER_SIZE+endptr-startptr))
static char buffer[LOOPBACK_BUFFER_SIZE];
static int startptr, endptr;
PMutex PSoundChannel::dictMutex;
static SoundHandleDict & handleDict()
{
static SoundHandleDict dict;
return dict;
}
PSound::PSound(unsigned channels,
unsigned samplesPerSecond,
unsigned bitsPerSample,
PINDEX bufferSize,
const BYTE * buffer)
{
encoding = 0;
numChannels = channels;
sampleRate = samplesPerSecond;
sampleSize = bitsPerSample;
SetSize(bufferSize);
if (buffer != NULL)
memcpy(GetPointer(), buffer, bufferSize);
}
PSound::PSound(const PFilePath & filename)
{
encoding = 0;
numChannels = 1;
sampleRate = 8000;
sampleSize = 16;
Load(filename);
}
PSound & PSound::operator=(const PBYTEArray & data)
{
PBYTEArray::operator=(data);
return *this;
}
void PSound::SetFormat(unsigned channels,
unsigned samplesPerSecond,
unsigned bitsPerSample)
{
encoding = 0;
numChannels = channels;
sampleRate = samplesPerSecond;
sampleSize = bitsPerSample;
formatInfo.SetSize(0);
}
BOOL PSound::Load(const PFilePath & /*filename*/)
{
return FALSE;
}
BOOL PSound::Save(const PFilePath & /*filename*/)
{
return FALSE;
}
BOOL PSound::Play()
{
PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
PSoundChannel::Player);
if (!channel.IsOpen())
return FALSE;
return channel.PlaySound(*this, TRUE);
}
BOOL PSound::PlayFile(const PFilePath & file, BOOL wait)
{
PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
PSoundChannel::Player);
if (!channel.IsOpen())
return FALSE;
return channel.PlayFile(file, wait);
}
///////////////////////////////////////////////////////////////////////////////
SoundHandleEntry::SoundHandleEntry()
{
handle = -1;
direction = 0;
}
///////////////////////////////////////////////////////////////////////////////
PSoundChannel::PSoundChannel()
{
Construct();
}
PSoundChannel::PSoundChannel(const PString & device,
Directions dir,
unsigned numChannels,
unsigned sampleRate,
unsigned bitsPerSample)
{
Construct();
Open(device, dir, numChannels, sampleRate, bitsPerSample);
}
void PSoundChannel::Construct()
{
os_handle = -1;
}
PSoundChannel::~PSoundChannel()
{
Close();
}
PStringArray PSoundChannel::GetDeviceNames(Directions /*dir*/)
{
static const char * const devices[] = {
"/dev/audio",
"/dev/dsp",
"/dev/dspW",
"loopback"
};
return PStringArray(PARRAYSIZE(devices), devices);
}
PString PSoundChannel::GetDefaultDevice(Directions /*dir*/)
{
return "/dev/dsp";
}
BOOL PSoundChannel::Open(const PString & _device,
Directions _dir,
unsigned _numChannels,
unsigned _sampleRate,
unsigned _bitsPerSample)
{
Close();
// lock the dictionary
dictMutex.Wait();
// make the direction value 1 or 2
int dir = _dir + 1;
// if this device in in the dictionary
if (handleDict().Contains(_device)) {
SoundHandleEntry & entry = handleDict()[_device];
// see if the sound channel is already open in this direction
if ((entry.direction & dir) != 0) {
dictMutex.Signal();
return FALSE;
}
// flag this entry as open in this direction
entry.direction |= dir;
os_handle = entry.handle;
} else {
// this is the first time this device has been used
// open the device in read/write mode always
if (_device == "loopback") {
startptr = endptr = 0;
os_handle = 0; // Use os_handle value 0 to indicate loopback, cannot ever be stdin!
}
else if (!ConvertOSError(os_handle = ::open((const char *)_device, O_RDWR))) {
dictMutex.Signal();
return FALSE;
}
// add the device to the dictionary
SoundHandleEntry * entry = PNEW SoundHandleEntry;
handleDict().SetAt(_device, entry);
// save the information into the dictionary entry
entry->handle = os_handle;
entry->direction = dir;
entry->numChannels = _numChannels;
entry->sampleRate = _sampleRate;
entry->bitsPerSample = _bitsPerSample;
entry->isInitialised = FALSE;
entry->fragmentValue = 0x7fff0008;
}
// unlock the dictionary
dictMutex.Signal();
// save the direction and device
direction = _dir;
device = _device;
isInitialised = FALSE;
return TRUE;
}
BOOL PSoundChannel::Setup()
{
if (os_handle < 0)
return FALSE;
if (isInitialised)
return TRUE;
// lock the dictionary
dictMutex.Wait();
// the device must always be in the dictionary
PAssertOS(handleDict().Contains(device));
// get record for the device
SoundHandleEntry & entry = handleDict()[device];
BOOL stat = FALSE;
if (entry.isInitialised) {
isInitialised = TRUE;
stat = TRUE;
} else if (device == "loopback")
stat = TRUE;
else {
// must always set paramaters in the following order:
// buffer paramaters
// sample format (number of bits)
// number of channels (mon/stereo)
// speed (sampling rate)
int arg, val;
// reset the device first so it will accept the new parms
#ifndef P_AIX
if (ConvertOSError(::ioctl(os_handle, SNDCTL_DSP_RESET, &arg))) {
arg = val = entry.fragmentValue;
//if (ConvertOSError(ioctl(os_handle, SNDCTL_DSP_SETFRAGMENT, &arg)) || (arg != val)) {
::ioctl(os_handle, SNDCTL_DSP_SETFRAGMENT, &arg); {
arg = val = (entry.bitsPerSample == 16) ? AFMT_S16_LE : AFMT_S8;
if (ConvertOSError(::ioctl(os_handle, SNDCTL_DSP_SETFMT, &arg)) || (arg != val)) {
arg = val = (entry.numChannels == 2) ? 1 : 0;
if (ConvertOSError(::ioctl(os_handle, SNDCTL_DSP_STEREO, &arg)) || (arg != val)) {
arg = val = entry.sampleRate;
if (ConvertOSError(::ioctl(os_handle, SNDCTL_DSP_SPEED, &arg)) || (arg != val))
stat = TRUE;
}
}
}
}
#endif
}
entry.isInitialised = TRUE;
isInitialised = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -