当没有音频硬件设备时,如何从PJSIP获取音频流

当没有音频硬件设备时,如何从PJSIP获取音频流,sip,audio-streaming,pjsip,Sip,Audio Streaming,Pjsip,我想使用PJSIP的C API将传入的音频记录到一个没有硬件声音设备的机器上的文件中 我不确定具体细节,但PJSIP的稀疏文档表明应该这样做 可以通过调用pjsua\u set\u null\u snd\u dev() 在下面的完全功能(Windows偏向)示例中,调用pjmedia_aud_dev_default_param(pjmedia_aud_default_CAPTURE_dev,¶m)返回状态为pjmedia_aud_INVALID_dev 当Linux(Ubuntu14)和

我想使用PJSIP的C API将传入的音频记录到一个没有硬件声音设备的机器上的文件中

我不确定具体细节,但PJSIP的稀疏文档表明应该这样做 可以通过调用
pjsua\u set\u null\u snd\u dev()

在下面的完全功能(Windows偏向)示例中,调用
pjmedia_aud_dev_default_param(pjmedia_aud_default_CAPTURE_dev,¶m)
返回状态为
pjmedia_aud_INVALID_dev

当Linux(Ubuntu14)和Windows10上没有硬件音频设备时,代码会产生相同的错误。 如果安装了硬件音频设备驱动程序,则在两个操作系统上都可以使用完全相同的代码

我在编译PJSIP库时启用了
PJMEDIA\u AUDIO\u DEV\u NULL\u AUDIO
。 在Linux上,模块
snd dummy
的存在没有帮助

调用
pjsua\u set\u null\u snd\u dev()
后,如何从SIP调用访问音频数据流

#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(int,char**)
{
//首先创建pjsua!
pj_status_t status=pjsua_create();
如果(状态!=PJ_成功)
{
fprintf(stderr,“pjsua_创建错误”);
返回-1;
}
//Init pjsua
pjsua_配置cfg;
pjsua_日志记录_配置日志_cfg;
pjsua_配置_默认值(&cfg);
pjsua\u日志记录\u配置\u默认值(&log\u cfg);
log_cfg.console_level=4;
status=pjsua_init(&cfg,&log_cfg,NULL);
如果(状态!=PJ_成功)
{
fprintf(stderr,“pjsua_init error\n”);
返回-1;
}
//主动列出已知的音频设备,以便我们确定没有
pjmedia_aud_dev_info[64];
未签名信息计数=64;
pjsua_enum_aud_devs(信息和信息计数);
fprintf(stderr,“列出已知的声音设备,总计[%u]\n”,信息计数);
for(无符号i=0;iinfo);
param.samples_per_frame=PJMEDIA_PIA_SPF(&wav->info);
param.channel_count=PJMEDIA_PIA_CCNT(&wav->info);
param.bits_per_sample=PJMEDIA_PIA_bits(&wav->info);
状态=pjmedia_aud_stream_create(¶m,&test_rec_cb,&test_play_cb,wav,&strm);
如果(状态!=PJ_成功)
{
fprintf(stderr,“打开声音流时出错”);
返回-1;
}
状态=pjmedia_aud_stream_start(strm);
如果(状态!=PJ_成功)
{
fprintf(标准“启动声音设备时出错”);
返回-1;
}
//花一些时间让被叫方接收并继续录音
睡眠(10000);//睡眠10秒
//清除代码省略
返回0;
}

<> P.>通过加载ALSA模块解决了这个问题。

C++。 查看
/lib/modules/YOUR_KERNEL\u VERSION/modules.dep
,如果有提及

如果有,则使用
modprobe snd dummy


否则,请重新编译内核,将其作为一个模块包含,或者按照上面链接中的安装进行操作。

pjsua\u set\u null\u snd\u dev()用于断开pjsip中的音频流。它必须在结束通话时使用。我不久前解决了这个问题,如果您急需答案,请告诉我,我会发布。@JimmyNJ如果您可以发布答案,我对这个问题的解决方案感兴趣。不,对不起,这不起作用,我尝试了模块问题。并且无法重新编译内核。编译库时是否启用了Alsa支持?我在
PJMEDIA/include/PJMEDIA audiodev/config.h
pjlib/include/pj/config\u site\u sample.h
中设置了
#define PJMEDIA_AUDIO_DEV_HAS_ALSA
为1,我的自动功能选项还包括--enable sound。资料来源:我不久前解决了这个问题,如果您迫切需要答案,请告诉我,我会发布它JimmyNJ 7月30日1:11我也解决了这个问题,并在这里发布了我是如何解决的。我以为你没有解决它,因为这里没有答案?!
#include <pjlib.h>
#include <pjlib-util.h>
#include <pjnath.h>
#include <pjsip.h>
#include <pjsip_ua.h>
#include <pjsip_simple.h>
#include <pjsua-lib/pjsua.h>
#include <pjmedia.h>
#include <pjmedia-codec.h>
#include <pj/log.h>
#include <pj/os.h>

    int main(int, char **)
    {
    // Create pjsua first! 
            pj_status_t status = pjsua_create();
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr,"pjsua_create error\n");
                return -1;
            }

    // Init pjsua 
            pjsua_config cfg;
            pjsua_logging_config log_cfg;

            pjsua_config_default(&cfg);

            pjsua_logging_config_default(&log_cfg);
            log_cfg.console_level = 4;

            status = pjsua_init(&cfg, &log_cfg, NULL);
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr,"pjsua_init error\n");
                return -1;
            }


    // Proactively list known audio devices so we are sure there are NONE
            pjmedia_aud_dev_info info[64];
            unsigned info_count = 64;
            pjsua_enum_aud_devs(info, &info_count);

            fprintf(stderr,"Listing known sound devices, total of [%u]\n", info_count);
            for (unsigned i = 0; i<info_count; ++i)
            {
                fprintf(stderr,"Name [%s]", info[i].name);
            }

    // Add transport
            pjsua_transport_config tcfg;
            pjsua_transport_id trans_id;
            pjsua_transport_config_default(&tcfg);
            tcfg.port = 5060;
            status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &tcfg, &trans_id);
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr, "pjsua_transport_create error\n");
                return -1;
            }

    // Initialization is done, now start pjsua 
            status = pjsua_start();
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr, "pjsua_start error\n");
                return -1;
            }

    // Set NULL sound
            status = pjsua_set_null_snd_dev();
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr, "pjsua_set_null_snd_dev error");
                return -1;
            }

    // Register to a SIP server by creating SIP account, I happen use use Asterisk 
            pjsua_acc_id acc_id;
            fprintf(stderr, "Setting up SIP server registration\n");
            {
                pjsua_acc_config cfg;
                pjsua_acc_config_default(&cfg);
                cfg.id = pj_str("sip:6001@10.0.0.21");
                cfg.reg_uri = cfg.id; // same as ID
                cfg.cred_count = 1;

                cfg.cred_info[0].realm = pj_str("*");
                cfg.cred_info[0].scheme = pj_str("digest"); 
                cfg.cred_info[0].username = pj_str("6001");
                cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
                cfg.cred_info[0].data = pj_str("teddy");

                status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id);
                if (status != PJ_SUCCESS)
                {
                    fprintf(stderr, "pjsua_acc_add error\n");
                    return -1;
                }
            }

            fprintf(stderr, "Waiting for SIP server registration to complete....\n");

            Sleep(2000); // sleep 2 seconds

    // Call extension 9 on my Asterisk server at 10.0.0.21:5060
            pj_str_t sip_target(pj_str("sip:9@10.0.0.21"));
            fprintf(stderr, "Making call to [%s]\n", sip_target.ptr);

            pjsua_call_id call_id;
            status = pjsua_call_make_call(acc_id, &sip_target, 0, NULL, NULL, &call_id);
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr, "pjsua_call_make_call error\n");
                return -1;
            }

            pj_pool_t * pool = nullptr;
            pjmedia_port * wav = nullptr;
            pjmedia_aud_stream *strm = nullptr;
            pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(), "wav-audio", 1000, 1000, NULL);

            if (nullptr == pool)
            {
                fprintf(stderr,"Pool creation failed\n");
                return -1;
            }

    // 8kHz, single channel 16bit MS WAV format file
            status = pjmedia_wav_writer_port_create(pool, "test.wav", 8000, 1, 320, 16, PJMEDIA_FILE_WRITE_PCM, 0, &wav);
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr, "Error creating WAV file\n");
                return -1;
            }

            pjmedia_aud_param param; 
    //////////////////////////////////////////////////////
    // FAILURE HERE : This is the function call which returns PJMEDIA_AUD_INVALID_DEV
    //////////////////////////////////////////////////////
            status = pjmedia_aud_dev_default_param(PJMEDIA_AUD_DEFAULT_CAPTURE_DEV, &param); 
            if (status != PJ_SUCCESS) 
            {
                fprintf(stderr, "pjmedia_aud_dev_default_param()");
                return -1;
            }

            param.dir = PJMEDIA_DIR_CAPTURE;
            param.clock_rate = PJMEDIA_PIA_SRATE(&wav->info);
            param.samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
            param.channel_count = PJMEDIA_PIA_CCNT(&wav->info);
            param.bits_per_sample = PJMEDIA_PIA_BITS(&wav->info);

            status = pjmedia_aud_stream_create(&param, &test_rec_cb, &test_play_cb, wav, &strm);
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr, "Error opening the sound stream");
                return -1;
            }

            status = pjmedia_aud_stream_start(strm);
            if (status != PJ_SUCCESS)
            {
                fprintf(stderr, "Error starting the sound device");
                return -1;
            }

    // Spend some time allowing the called party to pick up and recording to proceed
            Sleep(10000); // sleep 10 seconds

    // Clean up code omitted
    return 0;
    }