[pulseaudio-discuss] How to capture one of multiple radios that these radios play at the same time?

Tsai Yu-Chin yorjing at gmail.com
Thu Nov 18 18:29:17 PST 2010


Thank you for your help.
I refer to source code of pavucontrol and I program a simple code below:

///////////////////////////////code//////////////////////////////
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <pulse/pulseaudio.h>
#include <signal.h>

int file_name_length=20;
int record_time=5;
int end=0;

static pa_sample_spec sample_spec = {
    .format = PA_SAMPLE_S16LE,
    .rate = 44100,
    .channels = 2
};

struct thread_data
{
    char *pa_ctx_name;
    char *sink_input_index;

};

void get_monitor_source_index_callback(pa_context *context,const
pa_sink_info *i,int eol,void *userdata);
void get_sink_index_callback(pa_context *context,const
pa_sink_input_info *i,int eol,void *userdata);
void pa_state_callback(pa_context *c, void *userdata);
void read_callback(pa_stream *stream,size_t length,void *userdata);
void alarm_handler(int sig);
void quit(pa_mainloop_api *pa_mlapi,int ret);
void record_thread(void *data);
uint32_t get_monitor_source_index(pa_context *context,pa_mainloop
*pa_ml,uint32_t sink_input_index);

int main(int argc,char *argv[]){
    struct thread_data td;
    pthread_t id;

    td.pa_ctx_name=argv[1];
    td.sink_input_index=argv[2];

    pthread_create(&id,NULL,(void *)record_thread,&td);

    while(!end)
        sleep(1);

    return 0;
}

void record_thread(void *data){
    pa_stream *stream;
    pa_mainloop *pa_ml;
    pa_mainloop_api *pa_mlapi;
    pa_context *context;
    pa_buffer_attr attr;
    int fd;
    int ret=1;
    char msi[16];

    struct thread_data *td=(struct thread_data*)data;

    memset(&attr,0,sizeof(attr));
    attr.fragsize=(uint32_t)-1;
    attr.maxlength=(uint32_t)-1;

    char output_file_name[file_name_length];
    strcpy(output_file_name,(*td).pa_ctx_name);
    strcat(output_file_name,".raw");

    if((fd=open(output_file_name,O_WRONLY|O_TRUNC|O_CREAT,0777))<0){
        printf("Failed to create file\n");
        goto quit;
    }

    pa_ml=pa_mainloop_new();
    pa_mlapi=pa_mainloop_get_api(pa_ml);
    context=pa_context_new(pa_mlapi,(*td).pa_ctx_name);
    pa_context_connect(context,NULL,0,NULL);

    if(!(stream=pa_stream_new(context,(*td).pa_ctx_name,&sample_spec,NULL))){
        printf("Failed to create monitoring stream\n");
        goto quit;
    }

    pa_stream_set_monitor_stream(stream,atoi((*td).sink_input_index));
    pa_stream_set_read_callback(stream,read_callback,&fd);

    uint32_t monitor_source_index=get_monitor_source_index(context,pa_ml,atoi((*td).sink_input_index));
    snprintf(msi,sizeof(msi),"%u",monitor_source_index);

    if(pa_stream_connect_record(stream,msi,&attr,(pa_stream_flags_t)(PA_STREAM_DONT_MOVE|PA_STREAM_PEAK_DETECT))<0){
        printf("Failed to connect monitoring stream\n");
        pa_stream_unref(stream);
        goto quit;
    }

    if(end)
        quit(pa_mlapi,0);


    signal(SIGALRM,alarm_handler);
    alarm(10);

    if(pa_mainloop_run(pa_ml,&ret)<0){
        printf("mainloop run failed.\n");
        goto quit;
    }

quit:
    if(stream)
        pa_stream_unref(stream);

    if(context)
        pa_context_unref(context);

    if(pa_ml){
        pa_signal_done();
        pa_mainloop_free(pa_ml);
    }
}

uint32_t get_monitor_source_index(pa_context *context,pa_mainloop
*pa_ml,uint32_t sink_input_index){
    pa_operation *pa_op;
    uint32_t sink_index;
    uint32_t monitor_source_index;
    int state = 0;
    int pa_ready = 0;


    pa_context_set_state_callback(context, pa_state_callback, &pa_ready);

    for (;;) {
        if (pa_ready == 0) {
            pa_mainloop_iterate(pa_ml, 1, NULL);
            continue;
        }

        if (pa_ready == 2) {
            pa_context_disconnect(context);
            pa_context_unref(context);
            pa_mainloop_free(pa_ml);
            return -1;
        }

        switch (state) {
            case 0:
                pa_op = pa_context_get_sink_input_info(context,
                        sink_input_index,
                        get_sink_index_callback,
                        &sink_index
                        );

                printf("Getting sink index...\n");
                state++;
            break;

            case 1:
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
		    pa_operation_unref(pa_op);

                    pa_op = pa_context_get_sink_info_by_index(context,
                        sink_index,
                        get_monitor_source_index_callback,
                        &monitor_source_index
                        );

                    printf("Getting monitor source index...\n");
                    state++;
                }
            break;

            case 2:
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    pa_operation_unref(pa_op);

                    return monitor_source_index;
                }
            break;

            default:
                fprintf(stderr, "in state %d\n", state);
                return -1;
        }

        pa_mainloop_iterate(pa_ml, 1, NULL);
    }
}

void get_monitor_source_index_callback(pa_context *context,const
pa_sink_info *i,int eol,void *userdata){
    uint32_t *monitor_source_index=userdata;

    if (eol > 0) {
        printf("Get monitor source index complete...\nmonitor source
index=%d\n\n",*(monitor_source_index));
        return;
    }

    *(monitor_source_index)=i->monitor_source;
}

void get_sink_index_callback(pa_context *context,const
pa_sink_input_info *i,int eol,void *userdata){
    uint32_t *sink_index=userdata;

    if (eol > 0) {
        printf("Get Sink index complete...\nsink index=%d\n\n",*(sink_index));
        return;
    }

    *(sink_index)=i->sink;
}

void pa_state_callback(pa_context *c, void *userdata) {
        pa_context_state_t state;
        int *pa_ready = userdata;

        state = pa_context_get_state(c);
        switch  (state) {
                case PA_CONTEXT_UNCONNECTED:
                case PA_CONTEXT_CONNECTING:
                case PA_CONTEXT_AUTHORIZING:
                case PA_CONTEXT_SETTING_NAME:
                default:
                        break;
                case PA_CONTEXT_FAILED:
                case PA_CONTEXT_TERMINATED:
                        *pa_ready = 2;
                        break;
                case PA_CONTEXT_READY:
                        *pa_ready = 1;
                        break;
        }
}

void read_callback(pa_stream *stream,size_t length,void *userdata){
    const void *data;
    int *fd=userdata;

    if(pa_stream_peek(stream,&data,&length)<0){
        printf("Failed to read data from stream\n");
        return;
    }

    if (write(*fd,data,length)<=0) {
        printf("Failed to write data into file\n");
        return;
    }

    pa_stream_drop(stream);
}

void quit(pa_mainloop_api *pa_mlapi,int ret){
    assert(pa_mlapi);
    pa_mlapi->quit(pa_mlapi,ret);
}

void alarm_handler(int sig){
    end=1;
}
///////////////////////////////////////////////////////////////////

As before, it captures audio which combination of all radios.
How can I revise this code to capture audio which is from a single radio?
Thanks for your help again.

2010/11/19 Colin Guthrie <gmane at colin.guthr.ie>:
> 'Twas brillig, and Tsai Yu-Chin at 18/11/10 23:09 did gyre and gimble:
>> Excuse me.
>> When I play 3 radios at the same time,
>> how to capture one of them using PulseAudio?
>> Using Asynchronous API?
>>
>> I study PulseAudio Volume Control of PulsaAudio Device Chooser Project,
>> but I capture one audio which combine 3 radios.
>>
>> How can I capture one audio which is from one of three radios?
>
> Have a look at the pavucontrol source. It uses a sink input monitor to
> draw the vumeters on the "Playback" tab. This should allow you to locate
> the stream you want to record and open it's monitor.
>
> I've not done this myself, but I suspect that the code itself will lead
> the way. Let me know if you get stuck and I'll try and look it up for you.
>
> Col
>
> --
>
> Colin Guthrie
> gmane(at)colin.guthr.ie
> http://colin.guthr.ie/
>
> Day Job:
>  Tribalogic Limited [http://www.tribalogic.net/]
> Open Source:
>  Mageia Contributor [http://www.mageia.org/]
>  PulseAudio Hacker [http://www.pulseaudio.org/]
>  Trac Hacker [http://trac.edgewall.org/]
>
> _______________________________________________
> pulseaudio-discuss mailing list
> pulseaudio-discuss at mail.0pointer.de
> https://tango.0pointer.de/mailman/listinfo/pulseaudio-discuss
>



More information about the pulseaudio-discuss mailing list