diff --git a/src/client.cpp b/src/client.cpp index 57ee15c5..7f95e05f 100755 --- a/src/client.cpp +++ b/src/client.cpp @@ -210,11 +210,6 @@ void CClient::run() PostWinMessage ( MS_SOUND_IN, MUL_COL_LED_GREEN ); } - -// TEST -//Sleep(300); -//wait(3000); - // copy data from one stereo buffer in two separate buffers iInCnt = 0; for ( i = 0; i < iSndCrdBlockSizeSam; i++ ) diff --git a/src/clientsettingsdlgbase.ui b/src/clientsettingsdlgbase.ui index 81e6e3e6..199eabb2 100755 --- a/src/clientsettingsdlgbase.ui +++ b/src/clientsettingsdlgbase.ui @@ -19,24 +19,42 @@ true - - 9 - 6 + + 9 + + + 9 + + + 9 + + + 9 + Jitter Buffer - - 9 - 6 + + 9 + + + 9 + + + 9 + + + 9 + @@ -58,12 +76,21 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -120,18 +147,25 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + - - 0 - 0 + 0 0 @@ -153,9 +187,7 @@ - - 0 - 0 + 0 0 @@ -185,12 +217,21 @@ Block Size - - 9 - 6 + + 9 + + + 9 + + + 9 + + + 9 + @@ -212,12 +253,21 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -274,12 +324,21 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -356,34 +415,59 @@ Sndcard Buffers - - 9 - 6 + + 9 + + + 9 + + + 9 + + + 9 + - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + - - 3 - 1 + 0 0 @@ -407,12 +491,21 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -458,18 +551,25 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + - - 3 - 1 + 0 0 @@ -493,12 +593,21 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -547,7 +656,7 @@ - In / Out: + Out / In: Qt::AlignCenter @@ -559,18 +668,25 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + - + - - 0 - 0 + 0 0 @@ -590,11 +706,9 @@ - + - - 0 - 0 + 0 0 @@ -624,20 +738,38 @@ Debug - - 9 - 6 + + 9 + + + 9 + + + 9 + + + 9 + - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -662,12 +794,21 @@ - - 0 - 6 + + 0 + + + 0 + + + 0 + + + 0 + @@ -681,9 +822,7 @@ - - 0 - 0 + 0 0 diff --git a/windows/sound.cpp b/windows/sound.cpp index 1580056a..ad5aa82d 100755 --- a/windows/sound.cpp +++ b/windows/sound.cpp @@ -49,7 +49,8 @@ ASIOBufferInfo bufferInfos[2 * NUM_IN_OUT_CHANNELS]; // for input and output b ASIOChannelInfo channelInfos[2 * NUM_IN_OUT_CHANNELS]; bool bASIOPostOutput; ASIOCallbacks asioCallbacks; -int iBufferSize; +int iBufferSizeMono; +int iBufferSizeStereo; // event HANDLE m_ASIOEvent; @@ -81,8 +82,8 @@ bool CSound::Read ( CVector& psData ) // check if device must be opened or reinitialized if ( bChangParamIn ) { - // Reinit sound interface - InitRecordingAndPlayback ( iBufferSize ); + // Reinit sound interface (init recording requires stereo buffer size) + InitRecordingAndPlayback ( iBufferSizeStereo ); // Reset flag bChangParamIn = false; @@ -108,7 +109,7 @@ bool CSound::Read ( CVector& psData ) ASIOMutex.lock(); // get mutex lock { // copy data from sound card in output buffer - for ( i = 0; i < iBufferSize; i++ ) + for ( i = 0; i < iBufferSizeStereo; i++ ) { psData[i] = psSoundcardBuffer[0][i]; } @@ -116,7 +117,7 @@ bool CSound::Read ( CVector& psData ) // move all other data in buffer for ( j = 0; j < iInCurBlockToWrite - 1; j++ ) { - for ( i = 0; i < iBufferSize; i++ ) + for ( i = 0; i < iBufferSizeStereo; i++ ) { psSoundcardBuffer[j][i] = psSoundcardBuffer[j + 1][i]; } @@ -161,8 +162,8 @@ bool CSound::Write ( CVector& psData ) // check if device must be opened or reinitialized if ( bChangParamOut ) { - // reinit sound interface - InitRecordingAndPlayback ( iBufferSize ); + // reinit sound interface (init recording requires stereo buffer size) + InitRecordingAndPlayback ( iBufferSizeStereo ); // reset flag bChangParamOut = false; @@ -174,7 +175,7 @@ bool CSound::Write ( CVector& psData ) if ( iOutCurBlockToWrite < iCurNumSndBufOut ) { // copy stereo data from input in soundcard buffer - for ( int i = 0; i < iBufferSize; i++ ) + for ( int i = 0; i < iBufferSizeStereo; i++ ) { psPlaybackBuffer[iOutCurBlockToWrite][i] = psData[i]; } @@ -222,17 +223,20 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize ) ASIOMutex.lock(); // get mutex lock { + // we need mono buffer size but get stereo buffer size + const int iNewBufferSizeMono = iNewBufferSize / 2; + // calculate "nearest" buffer size and set internal parameter accordingly // first check minimum and maximum values - if ( iNewBufferSize < HWBufferInfo.lMinSize ) + if ( iNewBufferSizeMono < HWBufferInfo.lMinSize ) { - iBufferSize = HWBufferInfo.lMinSize; + iBufferSizeMono = HWBufferInfo.lMinSize; } else { - if ( iNewBufferSize > HWBufferInfo.lMaxSize ) + if ( iNewBufferSizeMono > HWBufferInfo.lMaxSize ) { - iBufferSize = HWBufferInfo.lMaxSize; + iBufferSizeMono = HWBufferInfo.lMaxSize; } else { @@ -244,17 +248,17 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize ) // test loop while ( ( iTrialBufSize <= HWBufferInfo.lMaxSize ) && ( !bSizeFound ) ) { - if ( iTrialBufSize > iNewBufferSize ) + if ( iTrialBufSize > iNewBufferSizeMono ) { // test which buffer size fits better: the old one or the // current one - if ( ( iTrialBufSize - iNewBufferSize ) < ( iNewBufferSize - iLastTrialBufSize ) ) + if ( ( iTrialBufSize - iNewBufferSizeMono ) < ( iNewBufferSizeMono - iLastTrialBufSize ) ) { - iBufferSize = iTrialBufSize; + iBufferSizeMono = iTrialBufSize; } else { - iBufferSize = iLastTrialBufSize; + iBufferSizeMono = iLastTrialBufSize; } // exit while loop @@ -278,9 +282,19 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize ) } } - // create and activate ASIO buffers + // calculate stereo buffer size + iBufferSizeStereo = 2 * iBufferSizeMono; + + // TEST test if requested buffer size is supported by the audio hardware, if not, fire error +if ( iNewBufferSize != iBufferSizeStereo ) +{ + throw CGenErr ( "Required sound card buffer size not allowed by the audio hardware." ); +} + + + // create and activate ASIO buffers (buffer size in samples) ASIOCreateBuffers ( bufferInfos, 2 * NUM_IN_OUT_CHANNELS, - iBufferSize * BYTES_PER_SAMPLE, &asioCallbacks ); + iBufferSizeMono, &asioCallbacks ); // now set all the buffer details for ( i = 0; i < 2 * NUM_IN_OUT_CHANNELS; i++ ) @@ -309,7 +323,7 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize ) delete[] psSoundcardBuffer[i]; } - psSoundcardBuffer[i] = new short[iBufferSize]; + psSoundcardBuffer[i] = new short[iBufferSizeStereo]; } // initialize write block pointer out @@ -323,10 +337,10 @@ void CSound::InitRecordingAndPlayback ( int iNewBufferSize ) delete[] psPlaybackBuffer[j]; } - psPlaybackBuffer[j] = new short[iBufferSize]; + psPlaybackBuffer[j] = new short[iBufferSizeStereo]; // clear new buffer - for ( i = 0; i < iBufferSize; i++ ) + for ( i = 0; i < iBufferSizeStereo; i++ ) { psPlaybackBuffer[j][i] = 0; } @@ -352,6 +366,10 @@ void CSound::Close() // wait for the thread to terminate Sleep ( 500 ); + // stop audio and dispose ASIO buffers + ASIOStop(); + ASIODisposeBuffers(); + // set flag to open devices the next time it is initialized bChangParamIn = true; bChangParamOut = true; @@ -540,55 +558,67 @@ void CSound::bufferSwitch ( long index, ASIOBool processNow ) { if ( bufferInfos[i].isInput == false ) { - // PLAYBACK -------------------------------------------------------- + // PLAYBACK ---------------------------------------------------- if ( iOutCurBlockToWrite > 0 ) { // copy data from sound card in output buffer - for ( iCurSample = 0; iCurSample < iBufferSize; iCurSample++ ) + for ( iCurSample = 0; iCurSample < iBufferSizeMono; iCurSample++ ) { - ((short*) bufferInfos[i].buffers[index])[iCurSample] = - psSoundcardBuffer[0][iCurSample]; + // copy interleaved stereo data in mono sound card buffer + ((short*) bufferInfos[i].buffers[index])[iCurSample] = + psSoundcardBuffer[0][2 * iCurSample + bufferInfos[i].channelNum]; } - - // move all other data in buffer - for ( int j = 0; j < iOutCurBlockToWrite - 1; j++ ) - { - for ( iCurSample = 0; iCurSample < iBufferSize; iCurSample++ ) - { - psPlaybackBuffer[j][iCurSample] = - psPlaybackBuffer[j + 1][iCurSample]; - } - } - - // adjust "current block to write" pointer - iOutCurBlockToWrite--; - } - else - { - // TODO: buffer underrun, inform user somehow...? } } else { - // CAPTURE --------------------------------------------------------- + // CAPTURE ----------------------------------------------------- // first check if buffer is available if ( iInCurBlockToWrite < iCurNumSndBufIn ) { // copy new captured block in thread transfer buffer - for ( iCurSample = 0; iCurSample < iBufferSize; iCurSample++ ) + for ( iCurSample = 0; iCurSample < iBufferSizeMono; iCurSample++ ) { - psSoundcardBuffer[iInCurBlockToWrite][iCurSample] = + // copy mono data interleaved in stereo buffer + psSoundcardBuffer[iInCurBlockToWrite][2 * iCurSample + bufferInfos[i].channelNum] = ((short*) bufferInfos[i].buffers[index])[iCurSample]; } - - iInCurBlockToWrite++; - } - else - { - // TODO: buffer overrun, inform user somehow...? } } } + + + // Manage thread interface buffers for input and output ---------------- + // capture + if ( iInCurBlockToWrite < iCurNumSndBufIn ) + { + iInCurBlockToWrite++; + } + else + { + // TODO: buffer overrun, inform user somehow...? + } + + // playback + if ( iOutCurBlockToWrite > 0 ) + { + // move all other data in playback buffer + for ( int j = 0; j < iOutCurBlockToWrite - 1; j++ ) + { + for ( iCurSample = 0; iCurSample < iBufferSizeStereo; iCurSample++ ) + { + psPlaybackBuffer[j][iCurSample] = + psPlaybackBuffer[j + 1][iCurSample]; + } + } + + // adjust "current block to write" pointer + iOutCurBlockToWrite--; + } + else + { + // TODO: buffer underrun, inform user somehow...? + } } ASIOMutex.unlock();