📄 sound_oss.cxx
字号:
PINDEX bytes = 0;
while (!ConvertOSError(bytes = ::read(os_handle, (void *)(((unsigned char *)buf) + total), len-total))) {
if (GetErrorCode() != Interrupted) {
PTRACE(6, "OSS\tRead failed");
return FALSE;
}
PTRACE(6, "OSS\tRead interrupted");
}
total += bytes;
if (total != len)
PTRACE(6, "OSS\tRead completed short - " << total << " vs " << len << ". Reading more data");
}
lastReadCount = total;
}
else {
// downsample the data
BYTE * dst = (BYTE *)buf;
BYTE * dstEnd = dst + len;
lastReadCount = 0;
PBYTEArray resampleBuffer((1024 / resampleRate) * resampleRate);
// downsample the data into 1K blocks
while (dst < dstEnd) {
// calculate number of source bytes needed to fill the buffer
PINDEX srcBytes = resampleRate * (dstEnd - dst);
PINDEX bytes;
{
PINDEX bufLen = PMIN(resampleBuffer.GetSize(), srcBytes);
while (!ConvertOSError(bytes = ::read(os_handle, resampleBuffer.GetPointer(), bufLen))) {
if (GetErrorCode() != Interrupted)
return FALSE;
}
}
// use an average, not just a single sample
const BYTE * src = resampleBuffer;
while ( ((src - resampleBuffer) < bytes) && (dst < dstEnd)) {
int sample = 0;
unsigned j;
for (j = 0; j < resampleRate; ++j) {
sample += *(PUInt16l *)src;
src += 2;
}
*(PUInt16l *)dst = sample / resampleRate;
dst +=2 ;
lastReadCount += 2;
}
}
}
if (lastReadCount != len)
PTRACE(6, "OSS\tRead completed short - " << lastReadCount << " vs " << len);
else
PTRACE(6, "OSS\tRead completed");
return TRUE;
}
BOOL PSoundChannelOSS::SetFormat(unsigned numChannels,
unsigned sampleRate,
unsigned bitsPerSample)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
// check parameters
PAssert((bitsPerSample == 8) || (bitsPerSample == 16), PInvalidParameter);
PAssert(numChannels >= 1 && numChannels <= 2, PInvalidParameter);
// lock the dictionary
PWaitAndSignal mutex(dictMutex);
// the device must always be in the dictionary
PAssertOS(handleDict().Contains(device));
// get record for the device
SoundHandleEntry & entry = handleDict()[device];
if (entry.isInitialised) {
if ((numChannels != entry.numChannels) ||
(sampleRate != entry.sampleRate) ||
(bitsPerSample != entry.bitsPerSample)) {
PTRACE(6, "OSS\tTried to change read/write format without stopping");
return FALSE;
}
return TRUE;
}
Abort();
entry.numChannels = numChannels;
entry.sampleRate = sampleRate;
entry.bitsPerSample = bitsPerSample;
entry.isInitialised = FALSE;
// mark this channel as uninitialised
isInitialised = FALSE;
return TRUE;
}
// Get the number of channels (mono/stereo) in the sound.
unsigned PSoundChannelOSS::GetChannels() const
{
return mNumChannels;
}
// Get the sample rate in samples per second.
unsigned PSoundChannelOSS::GetSampleRate() const
{
return actualSampleRate;
}
// Get the sample size in bits per sample.
unsigned PSoundChannelOSS::GetSampleSize() const
{
return mBitsPerSample;
}
BOOL PSoundChannelOSS::SetBuffers(PINDEX size, PINDEX count)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
//PINDEX totalSize = size * count;
//size = 16;
//count = (totalSize + 15) / 16;
PAssert(size > 0 && count > 0 && count < 65536, PInvalidParameter);
int arg = 1;
while (size > (PINDEX)(1 << arg))
arg++;
arg |= count << 16;
// lock the dictionary
PWaitAndSignal mutex(dictMutex);
// the device must always be in the dictionary
PAssertOS(handleDict().Contains(device));
// get record for the device
SoundHandleEntry & entry = handleDict()[device];
if (entry.isInitialised) {
if (entry.fragmentValue != (unsigned)arg) {
PTRACE(6, "OSS\tTried to change buffers without stopping");
return FALSE;
}
return TRUE;
}
Abort();
// set information in the common record
entry.fragmentValue = arg;
entry.isInitialised = FALSE;
// flag this channel as not initialised
isInitialised = FALSE;
return TRUE;
}
BOOL PSoundChannelOSS::GetBuffers(PINDEX & size, PINDEX & count)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
// lock the dictionary
PWaitAndSignal mutex(dictMutex);
// the device must always be in the dictionary
PAssertOS(handleDict().Contains(device));
SoundHandleEntry & entry = handleDict()[device];
int arg = entry.fragmentValue;
count = arg >> 16;
size = 1 << (arg&0xffff);
return TRUE;
}
BOOL PSoundChannelOSS::PlaySound(const PSound & sound, BOOL wait)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
Abort();
if (!Write((const BYTE *)sound, sound.GetSize()))
return FALSE;
if (wait)
return WaitForPlayCompletion();
return TRUE;
}
BOOL PSoundChannelOSS::PlayFile(const PFilePath & filename, BOOL wait)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
PFile file(filename, PFile::ReadOnly);
if (!file.IsOpen())
return FALSE;
for (;;) {
BYTE buffer[256];
if (!file.Read(buffer, 256))
break;
PINDEX len = file.GetLastReadCount();
if (len == 0)
break;
if (!Write(buffer, len))
break;
}
file.Close();
if (wait)
return WaitForPlayCompletion();
return TRUE;
}
BOOL PSoundChannelOSS::HasPlayCompleted()
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
audio_buf_info info;
if (!ConvertOSError(::ioctl(os_handle, SNDCTL_DSP_GETOSPACE, &info)))
return FALSE;
return info.fragments == info.fragstotal;
}
BOOL PSoundChannelOSS::WaitForPlayCompletion()
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
return ConvertOSError(::ioctl(os_handle, SNDCTL_DSP_SYNC, NULL));
}
BOOL PSoundChannelOSS::RecordSound(PSound & sound)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
return FALSE;
}
BOOL PSoundChannelOSS::RecordFile(const PFilePath & filename)
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
return FALSE;
}
BOOL PSoundChannelOSS::StartRecording()
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
if (os_handle == 0)
return TRUE;
P_fd_set fds = os_handle;
P_timeval instant;
return ConvertOSError(::select(1, fds, NULL, NULL, instant));
}
BOOL PSoundChannelOSS::IsRecordBufferFull()
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
audio_buf_info info;
if (!ConvertOSError(::ioctl(os_handle, SNDCTL_DSP_GETISPACE, &info)))
return FALSE;
return info.fragments > 0;
}
BOOL PSoundChannelOSS::AreAllRecordBuffersFull()
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
audio_buf_info info;
if (!ConvertOSError(::ioctl(os_handle, SNDCTL_DSP_GETISPACE, &info)))
return FALSE;
return info.fragments == info.fragstotal;
}
BOOL PSoundChannelOSS::WaitForRecordBufferFull()
{
if (os_handle < 0)
return SetErrorValues(NotOpen, EBADF);
return PXSetIOBlock(PXReadBlock, readTimeout);
}
BOOL PSoundChannelOSS::WaitForAllRecordBuffersFull()
{
return FALSE;
}
BOOL PSoundChannelOSS::Abort()
{
return ConvertOSError(ioctl(os_handle, SNDCTL_DSP_RESET, NULL));
}
BOOL PSoundChannelOSS::SetVolume(unsigned newVal)
{
if (os_handle <= 0) //CAnnot set volume in loop back mode.
return FALSE;
int rc, deviceVol = (newVal << 8) | newVal;
if (direction == Player)
rc = ::ioctl(os_handle, MIXER_WRITE(SOUND_MIXER_VOLUME), &deviceVol);
else
rc = ::ioctl(os_handle, MIXER_WRITE(SOUND_MIXER_MIC), &deviceVol);
if (rc < 0) {
PTRACE(1, "PSoundChannelOSS::SetVolume failed : " << ::strerror(errno));
return FALSE;
}
return TRUE;
}
BOOL PSoundChannelOSS::GetVolume(unsigned &devVol)
{
if (os_handle <= 0) //CAnnot get volume in loop back mode.
return FALSE;
int vol, rc;
if (direction == Player)
rc = ::ioctl(os_handle, MIXER_READ(SOUND_MIXER_VOLUME), &vol);
else
rc = ::ioctl(os_handle, MIXER_READ(SOUND_MIXER_MIC), &vol);
if (rc < 0) {
PTRACE(1, "PSoundChannelOSS::GetVolume failed : " << ::strerror(errno)) ;
return FALSE;
}
devVol = vol & 0xff;
return TRUE;
}
// End of file
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -