4

I am trying to create a voice chat program using OpenAL. The networking side of things seems to be ok but I'll take advice on that =]

The problem I am having at the moment is trying to playback captured audio data from the mic. I followed the code found here to get mic input and echo it to the speakers.

This works OK but I can't seem to playback the fully captured audio after the capturing has finished.

When some sound has been captured I store it on a list like so...

for (int i = 0; i < CAP_SIZE; i++)
{
    playbackBuffer.push_back( buffer[i] );
}

and then after the capturing has finished I have tried (and failed) to use the following code to play that audio back

ALuint  playbackSource;
alGenSources(1, &playbackSource);
errorCode = alGetError();

ALuint tempPlayback;
alBufferData(tempPlayback, AL_FORMAT_MONO16, &playbackBuffer.front(), playbackBuffer.size()*sizeof(ALuint), FREQ);

// Attach the playback buffer to the new playback source
alSourcei(playbackSource, AL_BUFFER, tempPlayback);
alSourcePlay(playbackSource);

ALint sState = 0;
do
{
    alGetSourcei(playbackSource, AL_SOURCE_STATE, &sState);
}
while ((sState == AL_PLAYING));

When debugging I can see that playbackBuffer has a lot of data in it and there is a split second of noise played at this point but nowhere near that which was captured.

EDIT: I have added the line

alGenBuffers(1, &tempPlayback);

after creating the tempPlayback and before the call to alBufferData(...) and this now plays for the correct amount of time but all I hear is a high-pitched noise the whole way through.

Community
  • 1
  • 1
Ralara
  • 559
  • 4
  • 19

3 Answers3

6

Here's a really simple program that captures audio for 5 seconds, pauses, then captures 5 more seconds of audio, and finally plays it all back (I used it to debug a problem with capture one time).

It worked on mint 13 linux laptop. Mint is like ubuntu 12.04

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h>
#include <AL/al.h> 
#include <AL/alc.h> 
#include <sys/time.h>
#include <ctime> 

int main(void) 
{ 
const ALCchar *   devices; 
const ALCchar *         ptr; 
ALCdevice *       mainDev; 
ALCcontext *      mainContext; 
ALCdevice *       captureDev; 
ALubyte           captureBuffer[1048576]; 
ALubyte           *captureBufPtr; 
ALint             samplesAvailable; 
ALint             samplesCaptured; 
time_t            currentTime; 
time_t            lastTime; 
ALuint            buffer; 
ALuint            source; 
ALint             playState; 
int               i; 

// Print the list of capture devices 
printf("Available playback devices:\n");

devices = alcGetString(NULL, ALC_DEVICE_SPECIFIER); 
ptr = devices; 
//while (ptr[0] != NULL)
while (*ptr)
{ 
   printf("   %s\n", ptr); 
   ptr += strlen(ptr) + 1; 
} 

// Open a playback device and create a context first 
printf("Opening playback device:\n"); 
mainDev = alcOpenDevice(NULL); 
if (mainDev == NULL) 
{ 
  printf("Unable to open playback device!\n"); 
  exit(1); 
} 
devices = alcGetString(mainDev, ALC_DEVICE_SPECIFIER); 
printf("   opened device '%s'\n", devices); 
mainContext = alcCreateContext(mainDev, NULL); 
if (mainContext == NULL) 
{ 
  printf("Unable to create playback context!\n"); 
  exit(1); 
} 
printf("   created playback context\n"); 

// Make the playback context current 
alcMakeContextCurrent(mainContext); 
alcProcessContext(mainContext); 

// Print the list of capture devices 

printf("Available capture devices:\n"); 
devices = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); 
ptr = devices; 

//while (ptr[0] != NULL)
while (*ptr)
{ 
   printf("   %s\n", ptr); 
   ptr += strlen(ptr) + 1; 
}

// Open the default device 
printf("Opening capture device:\n"); 
captureDev = alcCaptureOpenDevice(NULL, 8000, AL_FORMAT_MONO16, 800); 
if (captureDev == NULL) 
{  
  printf("   Unable to open device!\n"); 
  exit(1); 
} 
devices = alcGetString(captureDev, ALC_CAPTURE_DEVICE_SPECIFIER); 
printf("   opened device %s\n", devices); 

// Wait for three seconds to prompt the user 
for (i = 3; i > 0; i--) 
{ 
  printf("Starting capture in %d...\r", i); 
  fflush(stdout); 
  lastTime = time(NULL); 
  currentTime = lastTime; 
  while (currentTime == lastTime) 
  { 
     currentTime = time(NULL); 
     usleep(100000); 
  } 
} 

printf("Starting capture NOW!\n"); 
fflush(stdout); 
lastTime = currentTime; 

// Capture (roughly) five seconds of audio 
alcCaptureStart(captureDev); 
samplesCaptured = 0; 
captureBufPtr = captureBuffer; 
while (currentTime < (lastTime + 5)) 
{ 
  // Get the number of samples available 
  alcGetIntegerv(captureDev, ALC_CAPTURE_SAMPLES, 1, &samplesAvailable); 

  // Copy the samples to our capture buffer 
  if (samplesAvailable > 0) 
  { 
     alcCaptureSamples(captureDev, captureBufPtr, samplesAvailable); 
     samplesCaptured += samplesAvailable; 
     printf("Captured %d samples (adding %d)\r", samplesCaptured, 
        samplesAvailable); 
     fflush(stdout); 

     // Advance the buffer (two bytes per sample * number of samples) 
     captureBufPtr += samplesAvailable * 2; 
  } 

  // Wait for a bit 
  usleep(10000); 

  // Update the clock 
  currentTime = time(NULL); 
} 
printf("\nPausing capture.\n"); 
alcCaptureStop(captureDev); 

// Wait for three seconds to prompt the user 
for (i = 3; i > 0; i--) 
{ 
  printf("Resuming capture in %d...\r", i); 
  fflush(stdout); 
  lastTime = time(NULL); 
  currentTime = lastTime; 
  while (currentTime == lastTime) 
  { 
     currentTime = time(NULL); 
     usleep(100000); 
  } 
} 

printf("Resuming capture NOW!\n"); 
fflush(stdout); 
lastTime = currentTime; 

// Capture (roughly) five seconds of audio 
alcCaptureStart(captureDev); 
while (currentTime < (lastTime + 5)) 
{ 
  // Get the number of samples available 
  alcGetIntegerv(captureDev, ALC_CAPTURE_SAMPLES, 1, &samplesAvailable); 

  // Copy the samples to our capture buffer 
  if (samplesAvailable > 0) 
  { 
     alcCaptureSamples(captureDev, captureBufPtr, samplesAvailable); 
     samplesCaptured += samplesAvailable; 
     printf("Captured %d samples (adding %d)\r", samplesCaptured, 
        samplesAvailable); 
     fflush(stdout); 

     // Advance the buffer (two bytes per sample * number of samples) 
     captureBufPtr += samplesAvailable * 2; 
  } 

  // Wait for a bit 
  usleep(10000); 

  // Update the clock 
  currentTime = time(NULL); 
} 

printf("\nDone capturing.\n"); 
alcCaptureStop(captureDev); 

// Play back the captured data 
printf("Starting playback...\n"); 
fflush(stdout); 

// Generate an OpenAL buffer for the captured data 
alGenBuffers(1, &buffer); 
alGenSources(1, &source); 
alBufferData(buffer, AL_FORMAT_MONO16, captureBuffer,samplesCaptured*2, 8000); 
alSourcei(source, AL_BUFFER, buffer); 
alSourcePlay(source); 

// Wait for the source to stop playing 
playState = AL_PLAYING; 
while (playState == AL_PLAYING) 
{ 
  printf("  source %d is playing...\r", source); 
  fflush(stdout); 
  alGetSourcei(source, AL_SOURCE_STATE, &playState); 
  usleep(100000); 
} 
printf("\nDone with playback.\n"); 
fflush(stdout); 

// Shut down OpenAL 
alDeleteSources(1, &source); 
alDeleteBuffers(1, &buffer); 
alcMakeContextCurrent(NULL); 
alcCloseDevice(mainDev); 
alcCaptureCloseDevice(captureDev); 
}

Compile with this:

g++ p.cpp -lalut -lopenal -o p
Kate Gregory
  • 18,808
  • 8
  • 56
  • 85
keghn
  • 61
  • 1
  • 2
0
// Compile as: g++ p.cpp -lalut -lopenal -o p
//runs on ubuntu linux for around 2 seconds
#include <AL/al.h>    // OpenAL header files
#include <AL/alc.h>

//#include "stdafx.h"
#include <iostream>
#include <stdio.h>
//#include <windows.h>
//#include <al.h>
//#include <alc.h>


using namespace std;
int main()
{




ALCdevice *dev[2];
ALCcontext *ctx;
ALuint source, buffers[3];
char data[5000];
ALuint buf;
ALint val;

    float ttotal;
    unsigned int ccount;
    long int c1ount;
    c1ount =0;

dev[0] = alcOpenDevice(NULL);
ctx = alcCreateContext(dev[0], NULL);
alcMakeContextCurrent(ctx);

alGenSources(1, &source);
alGenBuffers(3, buffers);

/* Setup some initial silent data to play out of the source */
alBufferData(buffers[0], AL_FORMAT_MONO16, data, sizeof(data), 22050);
alBufferData(buffers[1], AL_FORMAT_MONO16, data, sizeof(data), 22050);
alBufferData(buffers[2], AL_FORMAT_MONO16, data, sizeof(data), 22050);
alSourceQueueBuffers(source, 3, buffers);

/* If you don't need 3D spatialization, this should help processing time */
alDistanceModel(AL_NONE); 

dev[1] = alcCaptureOpenDevice(NULL, 22050, AL_FORMAT_MONO16, sizeof(data)/2); //22050 mean 22.050 samples per     second. or 44100 for 44.1 per second.

/* Start playback and capture, and enter the audio loop */
alSourcePlay(source);
alcCaptureStart(dev[1]);    //starts ring buffer

while(1) 
{
    /* Check if any queued buffers are finished */
    alGetSourcei(source, AL_BUFFERS_PROCESSED, &val);
    if(val <= 0)
        continue;

    /* Check how much audio data has been captured (note that 'val' is the
    * number of frames, not bytes) */
    alcGetIntegerv(dev[1], ALC_CAPTURE_SAMPLES, 1, &val);

    /* Read the captured audio */
    alcCaptureSamples(dev[1], data, val);


        //***** Process/filter captured data here *****//


c1ount = c1ount +1;
if(c1ount >= 33){
          break;
         }


        //for (int ii=0;ii<val;++ii) {
        //  data[ii]*=0.1; // Make it quieter
        //}
    //***** end Process/filter captured data here *****//

    /* Pop the oldest finished buffer, fill it with the new capture data,
    then re-queue it to play on the source */
    alSourceUnqueueBuffers(source, 1, &buf);
    alBufferData(buf, AL_FORMAT_MONO16, data, val*2 /* bytes here, not
    frames */, 22050);
    alSourceQueueBuffers(source, 1, &buf);

    /* Make sure the source is still playing */
    alGetSourcei(source, AL_SOURCE_STATE, &val);

    if(val != AL_PLAYING)
    {

        alSourcePlay(source);
    }
}

cout<< "fgggggggg\n";


/* Shutdown and cleanup */
alcCaptureStop(dev[1]);
alcCaptureCloseDevice(dev[1]);

alSourceStop(source);
alDeleteSources(1, &source);
alDeleteBuffers(3, buffers);
alDeleteBuffers(1, &buf);

alcMakeContextCurrent(NULL);
alcDestroyContext(ctx);
alcCloseDevice(dev[0]); 

return 0;

}

keghn
  • 1
  • Thanks for your response but I feel I may have not explained myself properly. I got the code in the link I posted to work, which plays the sound at the same time as recording, what I need is to store the recorded sound and then when recording has finished then play it. As mentioned the final outcome of this project will be a voice chat style program, so I am planning on recording a chunk of audio, sending that chunk across the network while recording the next and then that chunk will be played back on the other side. Again, thanks for the help though. – Ralara Apr 02 '12 at 07:59
0

The only programs that record from the microphone that I could find on the web are the one you started with and the one i sent to you. I am kind of going in the same direction you are. the I code sent you is the one I am trying to modify. And I go it from stackoverflow. I found the code we want in a twisted BASIC programing language, but I am no good a the language. the link is:

 http://www.blitzbasic.com/Community/posts.php?topic=90830

If you can get it to work that would be great. And even better, if it
could be change over to c/c++.

I have been looking for microphone capture programs for around two
years. Waiting for some thing simple to come along.
So now I am focusing on the these programs to figure how they work
with debugger and test subroutines figure out the dynamics of freealut.
because I do not see any thing simple comming along any time soon.
OpenAL is the only software I cold get to work.  the documentation
provided by Creative web site is good referance for some one who is
already an expert with the software.
I could not get FBOD, alas, SDL,  Allegro4, or OSS to work because
of a lack of working examples, or no good information.

Good luck.

   keghn
keghn
  • 1
  • Didn't manage to get either of those working like I wanted still =\ on the good side I have managed to get something working using the TeamSpeak 3 sdk [link](http://www.teamspeak.com/), it handles the capturing/networking/playback side of things very well and the documentation is helpful as well. It's free for hobbyists to use (not sure if that covers yourself) but requires a license for commercial use. – Ralara Apr 04 '12 at 08:26