c++sippjsippcm

pjsip capture and play pcm data


I have some embedded Devices that have no audio device by default. They communicate with each other via a FPGA. So my question is, how do I capture/play back audio from pjsip in pcm in order to send/receive it with the FPGA?

I know that there is pjmedia_mem_player_create() and pjmedia_mem_capture_create() but I can't seem to find any good info towards using these functions.

I tried the following piece of code, but an assertion failed cause one of the function's parameter is "empty".

Error:

pjmedia_mem_capture_create: Assertion `pool && buffer && size && clock_rate && channel_count && samples_per_frame && bits_per_sample && p_port' failed.

Note: I'm mainly using pjsua2 for everything else like registrations, transports etc. Also the default audio is set to null with ep.audDevManager().setNullDev(); as without this, making/receiving a call would simply fail?!

void MyCall::onCallMediaState(OnCallMediaStateParam &prm){
CallInfo ci = getInfo();

pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
pj_pool_t *pool = pj_pool_create(&cp.factory, "POOLNAME", 2000, 2000, NULL);

void *buffer;
pjmedia_port *prt;

#define CLOCK_RATE 8000
#define CHANELS 1
#define SAMPLES_PER_FRAME 480
#define BITS_PER_SAMPLE 16

pjmedia_mem_capture_create( pool, //Pool
                            buffer, //Buffer
                            2000, //Buffer Size
                            CLOCK_RATE, 
                            CHANELS, 
                            SAMPLES_PER_FRAME, 
                            BITS_PER_SAMPLE, 
                            0, //Options
                            &prt); //The return port}

UPDATE

The assertion failed cause the buffer variable doesn't have any memory allocated to it. Allocate with twice the amount of samples per frame to have sufficient memory.

 buffer = pj_pool_zalloc(pool, 960);

Also a callback needs to be registered with pjmedia_mem_capture_set_eof_cb2() (The two at the end is necessary for PJSIP 2.10 or later) Apparently from there the buffer can be used. Just that my implementation atm doesn't execute the callback.


Solution

  • Looks like I found the solution, I have modified your code and wrote a simple code in C with pjsua API to dump every frame to file. Sorry for mess, I'm not proficient in C:

    pjsua_call_info ci;
    pjsua_call_get_info(call_id, &ci);
    pjsua_conf_port_info cpi;
    pjsua_conf_get_port_info(ci.conf_slot, &cpi);
    
    pj_pool_t *pool = pjsua_pool_create("POOLNAME", 2000, 2000);
    pjmedia_port *prt;
    uint buf_size = cpi.bits_per_sample*cpi.samples_per_frame/8;
    void *buffer = pj_pool_zalloc(pool, buf_size);
    pjsua_conf_port_id port_id;
    
    pjmedia_mem_capture_create( pool,
                                buffer,
                                buf_size,
                                cpi.clock_rate,
                                cpi.channel_count,
                                cpi.samples_per_frame,
                                cpi.bits_per_sample,
                                0,
                                &prt);
    pjmedia_mem_capture_set_eof_cb(prt, buffer, dump_incoming_frames);
    pjsua_conf_add_port(pool, prt, &port_id);
    pjsua_conf_connect(ci.conf_slot, port_id); //connect port with conference
    
    ///////dumping frames///
    static pj_status_t dump_incoming_frames(pjmedia_port * port, void * usr_data){
       pj_size_t buf_size = pjmedia_mem_capture_get_size(port);
       char * data = usr_data;
       ...
       fwrite(data,sizeof(data[0]),buf_size,fptr);
       ...
    }
    

    Documenation says pjmedia_mem_capture_set_eof_cb is deprecated but I couldn't make work pjmedia_mem_capture_set_eof_cb2, buf_size is 0 for every call of dump_incoming_frames so just left with deprecated function. I also succeed the same result with creating custom port.

    I hope you can modify it easily to your C++/pjsua2 code

    UPD: I have modified the PJSIP and packed audio in-out streaming into proper PJSUA2/Media classes so it can be called from Python. Full code is here.