我一直在尝试编写一个简单的线程音频捕获/回放应用程序(使用OpenAL)作为尝试语音聊天应用程序的先驱。
我目前拥有Capture&在单独的线程上“写”(保存/回放)函数,当将数据保存到wav文件时,一切都表现正常。尝试播放已捕获的数据时会出现此问题。
我试图一次一个字节,所以传递的数据很少。但是我没有回放。当我尝试将捕获缓冲区向量中的数据分配给要播放的缓冲区时,我收到AL_INVALID_NAME错误。我已经做了一些环顾四周,我相信这可能是关于如何写入/读取缓冲区的线程相关,但我不是100%肯定,因为我发现的是模糊的。
下面给出了代码,我想知道是否有人可以解释我遇到的问题。提前谢谢。
#include <iostream>
#include <conio.h>
#include <Windows.h>
#include <vector>
using std::vector;
#include <al.h>
#include <alc.h>
#include <AL\alut.h>
#define SAMPLE_RATE 22050
#define BUFFER_SIZE 4410
vector<ALbyte> bufferVector;
CRITICAL_SECTION bufferAccess;
ALint iDataSize = 0;
bool isCapturing = true;
ALuint buffer;
ALuint source;
// Each source has several properties, see the code for examples. Here we store position and velocity of
// the sound source above (x, y & z)
ALfloat sourcePos[3] = { 0.0, 0.0, 0.0 };
ALfloat sourceVel[3] = { 0.0, 0.0, 0.0 };
// There is always assumed to be a listener in an OpenAL application. We don't need a specific listener
// variable. However, listeners also have properties (examples in code). Here we store the position and
// velocity of the listener
ALfloat listenerPos[3] = { 0.0, 0.0, 0.0 };
ALfloat listenerVel[3] = { 0.0, 0.0, 0.0 };
// The listener may be at an angle (which may affect the perception of sound). Here we store the
// orientation of the listener. The first three values are the facing direction (x, y, z) of the
// listener - called "at" in the documentation. The next three values are the upward direction
// of the listener, called "up". These vectors can be extracted from a world or view matrix
// NOTE: OpenAL (like OpenGL) uses a right-handed system for 3D coordinates. To convert from the
// left-handed system we have used, we must negate all Z values (facing direction has -ve Z below)
ALfloat listenerOri[6] = { 0.0, 0.0, -1.0,
0.0, 1.0, 0.0 };
typedef struct
{
char szRIFF[4];
long lRIFFSize;
char szWave[4];
char szFmt[4];
long lFmtSize;
WAVEFORMATEX wfex;
char szData[4];
long lDataSize;
} WAVEHEADER;
struct SInfo
{
ALCdevice* mDevice;
};
DWORD WINAPI CaptureThread( LPVOID context )
{
SInfo info = *((SInfo*)context);
ALint samplesAvailable;
ALbyte ALBuffer[BUFFER_SIZE];
WAVEHEADER sWaveHeader;
// Prepare a WAVE file header for the captured data
sprintf(sWaveHeader.szRIFF, "RIFF");
sWaveHeader.lRIFFSize = 0;
sprintf(sWaveHeader.szWave, "WAVE");
sprintf(sWaveHeader.szFmt, "fmt ");
sWaveHeader.lFmtSize = sizeof(WAVEFORMATEX);
sWaveHeader.wfex.nChannels = 1;
sWaveHeader.wfex.wBitsPerSample = 16;
sWaveHeader.wfex.wFormatTag = WAVE_FORMAT_PCM;
sWaveHeader.wfex.nSamplesPerSec = SAMPLE_RATE;
sWaveHeader.wfex.nBlockAlign = sWaveHeader.wfex.nChannels * sWaveHeader.wfex.wBitsPerSample / 8;
sWaveHeader.wfex.nAvgBytesPerSec = sWaveHeader.wfex.nSamplesPerSec * sWaveHeader.wfex.nBlockAlign;
sWaveHeader.wfex.cbSize = 0;
sprintf(sWaveHeader.szData, "data");
sWaveHeader.lDataSize = 0;
alcCaptureStart( info.mDevice );
//** Capture audio til a key is hit.
while( !_kbhit() )
{
//** Find out how many samples have been captured.
alcGetIntegerv( info.mDevice, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &samplesAvailable );
printf( "Samples available: %d\r", samplesAvailable );
//** When there is enough data to fill the buffer size, grab the data.
if( samplesAvailable > ( BUFFER_SIZE / sWaveHeader.wfex.nBlockAlign ) )
{
//** Consume the samples
alcCaptureSamples( info.mDevice, ALBuffer, BUFFER_SIZE / sWaveHeader.wfex.nBlockAlign );
for( int i = 0; i < BUFFER_SIZE; i++ )
{
EnterCriticalSection( &bufferAccess );
bufferVector.push_back( ALBuffer[i] );
LeaveCriticalSection( &bufferAccess );
}
//** Accumulate the amount of data recorded.
iDataSize += BUFFER_SIZE;
}
}
isCapturing = false;
return S_OK;
}
DWORD WINAPI WriteThread( LPVOID context )
{
//FILE* pFile;
//WAVEHEADER sWaveHeader;
//// Create / open a file for the captured data
//pFile = fopen( "Capture.wav", "wb");
//// Prepare a WAVE file header for the captured data
//sprintf(sWaveHeader.szRIFF, "RIFF");
//sWaveHeader.lRIFFSize = 0;
//sprintf(sWaveHeader.szWave, "WAVE");
//sprintf(sWaveHeader.szFmt, "fmt ");
//sWaveHeader.lFmtSize = sizeof(WAVEFORMATEX);
//sWaveHeader.wfex.nChannels = 1;
//sWaveHeader.wfex.wBitsPerSample = 16;
//sWaveHeader.wfex.wFormatTag = WAVE_FORMAT_PCM;
//sWaveHeader.wfex.nSamplesPerSec = SAMPLE_RATE;
//sWaveHeader.wfex.nBlockAlign = sWaveHeader.wfex.nChannels * sWaveHeader.wfex.wBitsPerSample / 8;
//sWaveHeader.wfex.nAvgBytesPerSec = sWaveHeader.wfex.nSamplesPerSec * sWaveHeader.wfex.nBlockAlign;
//sWaveHeader.wfex.cbSize = 0;
//sprintf(sWaveHeader.szData, "data");
//sWaveHeader.lDataSize = 0;
//fwrite(&sWaveHeader, sizeof(WAVEHEADER), 1, pFile);
// Write the audio data to a file
while( isCapturing || !bufferVector.empty() )
{
if( bufferVector.empty() )
continue;
//fwrite( &bufferVector[0], sizeof( ALbyte ), 1, pFile );
//buffer = bufferVector[0];
alBufferData( buffer, AL_FORMAT_MONO16, (ALvoid*)bufferVector[0], sizeof(ALbyte), SAMPLE_RATE );
ALenum errorEnum = alGetError();
if ( errorEnum == AL_INVALID_NAME )
{
printf( "\nAL_INVALID_NAME\n" );
}
alGenSources( 1, &source );
// Set the properties of the source. The full list of available properties can be found in the documentation
// The last characters of each function name indicate the type of the second parameter (int, float, float vector etc.)
alSourcei ( source, AL_BUFFER, buffer ); // Attach a buffer to the source (identify which sound to play)
alSourcef ( source, AL_PITCH, 1.0f ); // Pitch multiplier, doubling the pitch shifts the sound up 1 octave, halving
// the pitch shifts it down 1 octave. Will also shorten/lengthen the sound
alSourcef ( source, AL_GAIN, 1.0f ); // Effectively the volume of the sound - 0.0 = silent, 1.0 = as recorded. May
// be able to increase volume over 1, but depends on sound
alSourcefv( source, AL_POSITION, sourcePos ); // Position of sound relative to listener affects how it is reproduced through speakers
alSourcefv( source, AL_VELOCITY, sourceVel ); // Velocity of sound relative to listener can cause Doppler effect
alSourcei ( source, AL_LOOPING, AL_FALSE ); // Whether to loop the sound or just stop when it finishes
//****************
// Listener
// Set the properties of the listener. These are all the available listener properties
alListenerfv( AL_POSITION, listenerPos ); // Position, velocity and orientation of listener affect sound...
alListenerfv( AL_VELOCITY, listenerVel ); // ...reproduction as noted above
alListenerfv( AL_ORIENTATION, listenerOri );
alListenerf ( AL_GAIN, 1.0f ); // "Master" gain / volume. Controls overall loudness of all sounds
EnterCriticalSection( &bufferAccess );
bufferVector.erase( bufferVector.begin() );
LeaveCriticalSection( &bufferAccess );
alSourcePlay( source );
}
// Fill in Size information in Wave Header
//fseek(pFile, 4, SEEK_SET);
//ALint iSize = iDataSize + sizeof(WAVEHEADER) - 8;
//fwrite(&iSize, 4, 1, pFile);
//fseek(pFile, 42, SEEK_SET);
//fwrite(&iDataSize, 4, 1, pFile);
//fclose(pFile);
return S_OK;
}
int main()
{
//** Initialise OpenAL
alutInit( 0, 0 );
SInfo info;
info.mDevice = alcCaptureOpenDevice( NULL, SAMPLE_RATE, AL_FORMAT_MONO16, BUFFER_SIZE);
InitializeCriticalSection( &bufferAccess );
HANDLE capThread = CreateThread( NULL, NULL, &CaptureThread, &info, NULL, NULL );
HANDLE writeThread = CreateThread( NULL, NULL, &WriteThread, NULL, NULL, NULL );
WaitForSingleObject( capThread, INFINITE );
WaitForSingleObject( writeThread, INFINITE );
DeleteCriticalSection( &bufferAccess );
system("pause");
alutExit();
return 0;
}