Q: Simultaneous record/playing with OpenAL using threads I've been trying to write a simple threaded audio capture/playback application (using OpenAL) as a precursor to attempting a voice chat application.
I currently have the Capture & "Write" (save / playback) functions on separate threads and when saving the data to a wav file everything behaves correctly. The problem occurs when trying to play back the data that has been captured.
I am attempting to do this a byte at a time, so there is minimal data being passed around. However I get no playback. When I am trying to assign the data from the capture buffer vector to the buffer to be played I get an error of AL_INVALID_NAME. I have done some looking around and I believe that this is possibly thread related regarding how the buffer is being written to/read from, but I'm not 100% sure as what I have found is vague.
The code is given below, and I was wondering if anyone could shed some light on the problem I am having. Thanks in advance.
#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;
}

