📄 sound.cpp
字号:
{
if (ret == -EPIPE)
{
qDebug("rpipe");
/* Under-run */
qDebug("rprepare");
ret = snd_pcm_prepare(rhandle);
if (ret < 0)
qDebug("Can't recover from underrun, prepare failed: %s", snd_strerror(ret));
ret = snd_pcm_start(rhandle);
if (ret < 0)
qDebug("Can't recover from underrun, start failed: %s", snd_strerror(ret));
return 0;
}
else if (ret == -ESTRPIPE)
{
qDebug("strpipe");
/* Wait until the suspend flag is released */
while ((ret = snd_pcm_resume(rhandle)) == -EAGAIN)
sleep(1);
if (ret < 0)
{
ret = snd_pcm_prepare(rhandle);
if (ret < 0)
qDebug("Can't recover from suspend, prepare failed: %s", snd_strerror(ret));
throw CGenErr("CSound:Read");
}
return 0;
}
else
{
qDebug("CSound::Read: %s", snd_strerror(ret));
throw CGenErr("CSound:Read");
}
} else
return ret;
}
int CSound::write_HW( _SAMPLE *playbuf, int size ){
int start = 0;
int ret;
while (size) {
ret = snd_pcm_writei(phandle, &playbuf[start], size );
if (ret < 0) {
if (ret == -EAGAIN) {
if ((ret = snd_pcm_wait (phandle, 100)) < 0) {
qDebug ("poll failed (%s)", snd_strerror (ret));
break;
}
continue;
} else
if (ret == -EPIPE) { /* under-run */
qDebug("underrun");
ret = snd_pcm_prepare(phandle);
if (ret < 0)
qDebug("Can't recover from underrun, prepare failed: %s", snd_strerror(ret));
continue;
} else if (ret == -ESTRPIPE) {
qDebug("strpipe");
while ((ret = snd_pcm_resume(phandle)) == -EAGAIN)
sleep(1); /* wait until the suspend flag is released */
if (ret < 0) {
ret = snd_pcm_prepare(phandle);
if (ret < 0)
qDebug("Can't recover from suspend, prepare failed: %s", snd_strerror(ret));
}
continue;
} else {
qDebug("Write error: %s", snd_strerror(ret));
throw CGenErr("Write error");
}
break; /* skip one period */
}
size -= ret;
start += ret;
}
return 0;
}
void CSound::close_HW( void ) {
if (rhandle != NULL)
snd_pcm_close( rhandle );
rhandle = NULL;
}
#endif
/* ************************************************************************* */
class CSoundBuf : public CCyclicBuffer<_SAMPLE> {
public:
CSoundBuf() : keep_running(TRUE) {}
void lock (void){ data_accessed.lock(); }
void unlock (void){ data_accessed.unlock(); }
bool keep_running;
protected:
QMutex data_accessed;
} SoundBufP, SoundBufR;
class RecThread : public QThread {
public:
virtual void run() {
while (SoundBufR.keep_running) {
int fill;
SoundBufR.lock();
fill = SoundBufR.GetFillLevel();
SoundBufR.unlock();
if ( (SOUNDBUFLEN - fill) > (FRAGSIZE * NUM_IN_OUT_CHANNELS) ) {
// enough space in the buffer
int size = CSound::read_HW( tmprecbuf, FRAGSIZE);
// common code
if (size > 0) {
CVectorEx<_SAMPLE>* ptarget;
/* Copy data from temporary buffer in output buffer */
SoundBufR.lock();
ptarget = SoundBufR.QueryWriteBuffer();
for (int i = 0; i < size * NUM_IN_OUT_CHANNELS; i++)
(*ptarget)[i] = tmprecbuf[i];
SoundBufR.Put( size * NUM_IN_OUT_CHANNELS );
SoundBufR.unlock();
}
} else {
msleep( 1 );
}
}
qDebug("Rec Thread stopped");
}
protected:
_SAMPLE tmprecbuf[NUM_IN_OUT_CHANNELS * FRAGSIZE];
} RecThread1;
/* Wave in ********************************************************************/
void CSound::InitRecording(int iNewBufferSize, _BOOLEAN bNewBlocking)
{
qDebug("initrec %d", iNewBufferSize);
/* Save < */
SoundBufR.lock();
iInBufferSize = iNewBufferSize;
bBlockingRec = bNewBlocking;
SoundBufR.unlock();
Init_HW( RECORD );
if ( RecThread1.running() == FALSE ) {
SoundBufR.Init( SOUNDBUFLEN );
SoundBufR.unlock();
RecThread1.start();
}
}
_BOOLEAN CSound::Read(CVector< _SAMPLE >& psData)
{
CVectorEx<_SAMPLE>* p;
SoundBufR.lock(); // we need exclusive access
while ( SoundBufR.GetFillLevel() < iInBufferSize ) {
// not enough data, sleep a little
SoundBufR.unlock();
usleep(1000); //1ms
SoundBufR.lock();
}
// copy data
p = SoundBufR.Get( iInBufferSize );
for (int i=0; i<iInBufferSize; i++)
psData[i] = (*p)[i];
SoundBufR.unlock();
return FALSE;
}
/* Wave out *******************************************************************/
class PlayThread : public QThread {
public:
virtual void run() {
while ( SoundBufP.keep_running ) {
int fill;
SoundBufP.lock();
fill = SoundBufP.GetFillLevel();
SoundBufP.unlock();
if ( fill > (FRAGSIZE * NUM_IN_OUT_CHANNELS) ) {
// enough data in the buffer
CVectorEx<_SAMPLE>* p;
SoundBufP.lock();
p = SoundBufP.Get( FRAGSIZE * NUM_IN_OUT_CHANNELS );
for (int i=0; i < FRAGSIZE * NUM_IN_OUT_CHANNELS; i++)
tmpplaybuf[i] = (*p)[i];
SoundBufP.unlock();
CSound::write_HW( tmpplaybuf, FRAGSIZE );
} else {
do {
msleep( 1 );
SoundBufP.lock();
fill = SoundBufP.GetFillLevel();
SoundBufP.unlock();
} while ((SoundBufP.keep_running) && ( fill < SOUNDBUFLEN/2 )); // wait until buffer is at least half full
}
}
qDebug("Play Thread stopped");
}
protected:
_SAMPLE tmpplaybuf[NUM_IN_OUT_CHANNELS * FRAGSIZE];
} PlayThread1;
void CSound::InitPlayback(int iNewBufferSize, _BOOLEAN bNewBlocking)
{
qDebug("initplay %d", iNewBufferSize);
/* Save buffer size */
SoundBufP.lock();
iBufferSize = iNewBufferSize;
bBlockingPlay = bNewBlocking;
SoundBufP.unlock();
Init_HW( PLAY );
if ( PlayThread1.running() == FALSE ) {
SoundBufP.Init( SOUNDBUFLEN );
SoundBufP.unlock();
PlayThread1.start();
}
}
_BOOLEAN CSound::Write(CVector< _SAMPLE >& psData)
{
if ( bBlockingPlay ) {
// blocking write
while( SoundBufP.keep_running ) {
SoundBufP.lock();
int fill = SOUNDBUFLEN - SoundBufP.GetFillLevel();
SoundBufP.unlock();
if ( fill > iBufferSize) break;
}
}
SoundBufP.lock(); // we need exclusive access
if ( ( SOUNDBUFLEN - SoundBufP.GetFillLevel() ) > iBufferSize) {
CVectorEx<_SAMPLE>* ptarget;
// data fits, so copy
ptarget = SoundBufP.QueryWriteBuffer();
for (int i=0; i < iBufferSize; i++)
(*ptarget)[i] = psData[i];
SoundBufP.Put( iBufferSize );
}
SoundBufP.unlock();
return FALSE;
}
void CSound::Close()
{
qDebug("stoprec/play");
// stop the recording and playback threads
if (RecThread1.running() ) {
SoundBufR.keep_running = FALSE;
// wait 1sec max. for the threads to terminate
RecThread1.wait(1000);
}
if (PlayThread1.running() ) {
SoundBufP.keep_running = FALSE;
PlayThread1.wait(1000);
}
close_HW();
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -