-2

I have used the simple C code of pulse audio for playback and record and it worked fine. But when I converted it to C++ it doesn't work. I am pasting both the codes. Please help. The C++ code doesn't show any error but doesn't playback any sound. But C++ code plays the recorded sound. N.B: I am using 64 bit CentOS 6.2

C++ Code:

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>

#include "pulse/simple.h"
#include "pulse/error.h"
using namespace std;
#define BUFSIZE 32
int error;

/* The Sample format to use */


class AudioCapt
{

public: 
    AudioCapt();
    void RecordSound(int argc,char *argv[],pa_simple *s_in,pa_sample_spec &ss,pa_simple *s_out,uint8_t buf[],ssize_t r);
    void PlaybackSound(int argc, char*argv[],pa_simple *s_out,pa_sample_spec &ss,uint8_t buf[],ssize_t r);
};




void AudioCapt::RecordSound(int argc, char*argv[],pa_simple *s_in,pa_sample_spec &ss,pa_simple *s_out,uint8_t buf[],ssize_t r)
{

printf("Audio Capturing \n");
  if (!(s_in = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) {
    fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
}

    if (pa_simple_read(s_in, buf, sizeof(buf), &error) < 0) {
        fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno));
}
printf("Buffer :::: %d\n",buf[0]);

}

void AudioCapt::PlaybackSound(int argc, char*argv[],pa_simple *s_out,pa_sample_spec &ss,uint8_t buf[],ssize_t r)
{
printf("Audio PlayBack \n");
printf("Play Buffer::: %d\n",buf[0]);
if (!(s_out = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL,  &error))) {
    fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
}

    /* ... and play it (Modified) */
   if (pa_simple_write(s_out, buf, sizeof(buf), &error) < 0) {
       fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
}

/* Make sure that every single sample was played */
if (pa_simple_drain(s_out, &error) < 0) {
    fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error));
}
}

int main(int argc, char * argv[])
{

pa_sample_spec ss;
ss.format = PA_SAMPLE_S16LE;
ss.rate = 44100;
    ss.channels = 2;

pa_simple *s_in, *s_out = NULL;

AudioCapt *m_pMyObject;

for(;;)
{ 
uint8_t buf[BUFSIZE];
    ssize_t r;
m_pMyObject->RecordSound(argc,argv,s_in,ss,s_out,buf,r);
m_pMyObject->PlaybackSound(argc,argv,s_out,ss,buf,r);
}   
return 0;
}

C Code:

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include <pulse/simple.h>
#include <pulse/error.h>

#define BUFSIZE 32

int main(int argc, char*argv[]) {

/* The Sample format to use */
static const pa_sample_spec ss = {
    .format = PA_SAMPLE_S16LE,
    .rate = 44100,
    .channels = 2
};

pa_simple *s_in, *s_out = NULL;
int ret = 1;
int error;


/* Create a new playback stream */
if (!(s_out = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, NULL, &error))) {
    fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
    goto finish;
}

  if (!(s_in = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error))) {
    fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
    goto finish;
}

for (;;) {
    uint8_t buf[BUFSIZE];
    ssize_t r;

#if 1
    pa_usec_t latency;

    if ((latency = pa_simple_get_latency(s_in, &error)) == (pa_usec_t) -1) {
        fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error));
        goto finish;
    }

    fprintf(stderr, "In:  %0.0f usec    \r\n", (float)latency);

    if ((latency = pa_simple_get_latency(s_out, &error)) == (pa_usec_t) -1) {
        fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error));
        goto finish;
    }

    fprintf(stderr, "Out: %0.0f usec    \r\n", (float)latency);
 #endif

    if (pa_simple_read(s_in, buf, sizeof(buf), &error) < 0) {

        fprintf(stderr, __FILE__": read() failed: %s\n", strerror(errno));
        goto finish;
    }
printf("Buffer :::: %d\n",buf[0]);

    /* ... and play it */
    if (pa_simple_write(s_out, buf, sizeof(buf), &error) < 0) {
        fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error));
        goto finish;
    }
}

/* Make sure that every single sample was played */
if (pa_simple_drain(s_out, &error) < 0) {
    fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error));
    goto finish;
}

ret = 0;

finish:

if (s_in)
    pa_simple_free(s_in);
if (s_out)
    pa_simple_free(s_out);

return ret;
}
Naseef Chowdhury
  • 2,357
  • 3
  • 28
  • 52

2 Answers2

2

In RecordSound and PlaybackSound you're initializing temporary variables with pa_simple_new. This value is lost once function returns, and you passing NULL to next one.

keltar
  • 17,711
  • 2
  • 37
  • 42
  • what should be the solution? – Naseef Chowdhury Jan 30 '13 at 03:58
  • something like void RecordSound(int argc,char *argv[],pa_simple *&s_in,pa_sample_spec &ss,pa_simple *&s_out,uint8_t buf[],ssize_t r); should do the trick (making s_in and s_out references to pointers), and the same for second function. However, this is kinda wrong design. These object should be either created by separate functions or be part of your class. – keltar Jan 30 '13 at 04:10
  • Not what i meant. You have class with two functions that, for some reason, creates new objects. If it isn't something you're willing to change - than these functions should either store these pointers within AudioCapt (btw, just noticed - you haven't initialized m_pMyObject. it works for your specific case, because you don't accessing any object data and don't calling virtual functions, but it still wrong and will fall in anything not that trivial) or these functions should return pointer to created objects. – keltar Jan 30 '13 at 04:39
  • I am still not getting you. Will you change my code to help me? – Naseef Chowdhury Jan 30 '13 at 05:07
  • I already told - to make it working, just make s_in and s_out references ('pa_simple *&s_in' instead of 'pa_simple *s_in', same for s_out). It should suffice. Everything else is just recommendations, but they highly depends on the reasons why you decided to use C++ instead of C, - which for sure not my business. – keltar Jan 30 '13 at 05:40
  • I want to include this audio file into a C++ project as audio engine. That's why I want to convert it into C++. – Naseef Chowdhury Jan 30 '13 at 07:03
1

I would suggest turning on compiler checks and fixing all errors and warnings issued by your compiler on this code.

To start, m_pMyObject is never initialized, so using it in the call to RecordSound will mean passing an uninitialized value as "this" to the method. This is generally a bad thing to do.

In RecordSound and PlaybackSound, you use size(buf) to tell the library how many bytes to read/write. The parameter buf is a pointer to uint8_t. So the compiler fills in the size of the pointer (probably 8 on a 64-bit machine). In these methods you should use the parameter you have for the size. In the calls, pass sizeof(buf) to that parameter.

I don't know how many streams the library can create before running out of memory/resources. Each call to RecordSound creates a recording stream, and the PlaybackSound creates a playback stream. These streams are never freed.

So to summarize, If using the uninitialized value to call the RecordSound method does not cause the program to crash, it will create a recording stream and record a couple samples, then it will create a playback stream and play back those two samples. Then it will try doing all this again.