title: Simultaneous record/playing with OpenAL using threads
body: <p>I've been trying to write a simple threaded audio capture/playback application (using OpenAL) as a precursor to attempting a voice chat application.</p>
  
  <p>I currently have the Capture &amp; "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.</p>
  
  <p>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.</p>
  
  <p>The code is given below, and I was wondering if anyone could shed some light on the problem I am having. Thanks in advance.</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;conio.h&gt;
  #include &lt;Windows.h&gt;
  #include &lt;vector&gt;
  using std::vector;
  
  #include &lt;al.h&gt;
  #include &lt;alc.h&gt;
  #include &lt;AL\alut.h&gt;
  
  #define SAMPLE_RATE 22050
  #define BUFFER_SIZE 4410
  
  vector&lt;ALbyte&gt; 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 &amp; 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), &amp;samplesAvailable );
  
      printf( "Samples available: %d\r", samplesAvailable );
  
      //** When there is enough data to fill the buffer size, grab the data.
      if( samplesAvailable &gt; ( BUFFER_SIZE / sWaveHeader.wfex.nBlockAlign ) )
      {
          //** Consume the samples
          alcCaptureSamples( info.mDevice, ALBuffer, BUFFER_SIZE / sWaveHeader.wfex.nBlockAlign );
  
          for( int i = 0; i &lt; BUFFER_SIZE; i++ )
          {
              EnterCriticalSection( &amp;bufferAccess );
              bufferVector.push_back( ALBuffer[i] );
              LeaveCriticalSection( &amp;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(&amp;sWaveHeader, sizeof(WAVEHEADER), 1, pFile);
  
  // Write the audio data to a file
  while( isCapturing  || !bufferVector.empty() )
  {
      if( bufferVector.empty() )
          continue;
  
      //fwrite( &amp;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, &amp;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( &amp;bufferAccess );
      bufferVector.erase( bufferVector.begin() );
      LeaveCriticalSection( &amp;bufferAccess );
  
      alSourcePlay( source );
  }
  
  // Fill in Size information in Wave Header
  //fseek(pFile, 4, SEEK_SET);
  //ALint iSize = iDataSize + sizeof(WAVEHEADER) - 8;
  //fwrite(&amp;iSize, 4, 1, pFile);
  //fseek(pFile, 42, SEEK_SET);
  //fwrite(&amp;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( &amp;bufferAccess );
  
      HANDLE capThread = CreateThread( NULL, NULL, &amp;CaptureThread, &amp;info, NULL, NULL );
      HANDLE writeThread = CreateThread( NULL, NULL, &amp;WriteThread, NULL, NULL, NULL );
  
      WaitForSingleObject( capThread, INFINITE );
      WaitForSingleObject( writeThread, INFINITE );
  
      DeleteCriticalSection( &amp;bufferAccess );
  
      system("pause");
      alutExit();
      return 0;
  }
  </code></pre>