Вопрос

I'm trying to capture a microphone signal in "real-time" using PulseAudio. The program is written in C and uses the PulseAudio Simple API for that. Unfortunately my requested audio buffer does not contain any signal. Either there's a problem in my code or the device source just does not get recognized. I ran some tests outside my program with gstreamer's pulsesrc and pulsesink which worked. I also tested the following command which also worked:

parec -d alsa_input.usb-041e_30d3_121023000184-00-U0x41e0x30d3.analog-mono | sox -t raw -r 44100 -sLb 16 -c 2 - /home/roos/Arbeitsfläche/pulsetest.wav

and on my second card it worked, too:

parec -d alsa_input.usb-Creative_Technology_Ltd_Sound_Blaster_X-Fi_Go__Pro_00173634-00-Pro_1.analog-stereo | sox -t raw -r 44100 -sLb 16 -c 2 - /home/roos/Arbeitsfläche/pulsetest.wav

Here's the code that's supposed to work:

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <math.h>

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

#define BUFSIZE 1024
#define SAMPLE_BITS 16

/* A simple routine calling UNIX write() in a loop */
static ssize_t loop_write(int fd, const uint8_t *data, size_t size) 
{
    int i = 0;
    for (i = 0; i < size; i += 2)
    {
        // put two bytes into one __signed__ integer
        int16_t val = data[i] + ((uint32_t)data[i+1] << 8);
        printf("%d", val);
    }

        return size;
}

int main(int argc, char*argv[]) 
{
    char *device = "alsa_output.usb-Creative_Technology_Ltd_Sound_Blaster_X-Fi_Go__Pro_00173634-00-Pro_1.analog-stereo";

    // The sample type to use
    static const pa_sample_spec ss = {
    .format = PA_SAMPLE_S16LE,
    .rate = 44100,
    .channels = 2
    };
    pa_simple *s = NULL;
    int ret = 1;
    int error;

    // Create the recording stream 
    if (!(s = 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];

    // Record some data ...
    if (pa_simple_read(s, buf, sizeof(buf), &error) < 0) {
        fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error));
        goto finish;
    }

    // And write it to STDOUT
    if (loop_write(STDOUT_FILENO, buf, sizeof(buf)) != sizeof(buf)) {
        fprintf(stderr, __FILE__": write() failed: %s\n", strerror(errno));
        goto finish;
    }
    }

    ret = 0;

finish:

    if (s)
    pa_simple_free(s);

    return 0;
}

The method "ssize_t loop_write" receives the buffer and because it's a 16 bit little endian byte array I combine two bytes into one singed 16 bit integer. This means the amplitude (represented by the variable "val") should be between 0 and 32768. But as of now it's all 0. So the two main concerns I have are the device source (which imo seems more likely) and my conversion to an integer value.

Do you have any advice on that? Thank you in advance!

EDIT/UPDATE: Ok, I don't know what I did - but if I pass a specific device I'm getting the following message now:

pa_simple_new() failed: Connection refused

When I pass NULL it's working for the default soundcard. Still working with the command line commands I previously described. Any clue what this might be all about?

Это было полезно?

Решение

Ok, just figured it out - quite a silly error made by me.

I passed the device to the first function parameter instead of the fourth.

So do this

if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, device, "record", &ss, NULL, NULL, &error)))

instead of this

if (!(s = pa_simple_new(device, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, NULL, &error)))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top