c ++ - Samtidig optagelse/afspilning med OpenAL ved hjælp af tråde

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har forsøgt at skrive et enkelt trådløst lydoptagelses-/afspilningsprogram (ved hjælp af OpenAL) som en forløber for at prøve en talechatapplikation.


Jeg har for øjeblikket Capture & 'Skriv' (gem/afspil) funktioner på separate tråde, og når data gemmes til en wav-fil, virker alt korrekt. Problemet opstår, når du forsøger at afspille de data, der er blevet taget.


Jeg forsøger at gøre dette til en byte ad gangen, så der er minimalt data, der sendes rundt. Men jeg får ingen afspilning. Når jeg forsøger at tildele dataene fra capture buffer-vektoren til bufferen, der skal afspilles, får jeg en fejl på AL\_INVALID\_NAME. Jeg har gjort nogle kigger rundt, og jeg tror, ​​at dette muligvis er trådrelateret med hensyn til, hvordan bufferen bliver skrevet til/læs fra, men jeg er ikke 100\% sikker på, at hvad jeg har fundet er vagt.


Koden er angivet nedenfor, og jeg spekulerede på, om nogen kunne kaste lys over det problem, jeg har. Tak på forhånd.


#include <iostream>
#include <conio.h>
#include <Windows.h>
#include <vector>
using std::vector;

#include <al.h>
#include <alc.h>
#include <ALalut.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
", 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( "
AL\_INVALID\_NAME
" );
    }

    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;
}

Bedste reference