Hi,
as first: I'm not a professional at this topic and I'm really trying my
best, but now I'm stuck and don't know what to do.
I want to modify my program, which is using PjSIP to create and do a
wav-file-record, to perform a memory_capture to a buffer - this requires
a existing call-conference - i guess (otherwise I will get error 70004).
The easy-to-use function "pjsua_recorder_create()" does all by itself
and i can get in a very simple way a plain old recorder to file. After
copy-and-pasting (i choosed this snippet from "pjsua_aud.c", because it
needs only little modifications to work with the memory_capture) THIS
code...
```
PJ_DEF(pj_status_t) pjsua_recorder_create( const pj_str_t *filename,
unsigned enc_type,
void *enc_param,
pj_ssize_t max_size,
unsigned options,
pjsua_recorder_id *p_id)
{
enum Format
{
FMT_UNKNOWN,
FMT_WAV,
FMT_MP3,
};
unsigned slot, file_id;
char path[PJ_MAXPATH];
pj_str_t ext;
int file_format;
pj_pool_t *pool = NULL;
pjmedia_port *port;
pj_status_t status = PJ_SUCCESS;
/* Filename must present */
PJ_ASSERT_RETURN(filename != NULL, PJ_EINVAL);
/* Don't support max_size at present */
PJ_ASSERT_RETURN(max_size == 0 || max_size == -1, PJ_EINVAL);
/* Don't support encoding type at present */
PJ_ASSERT_RETURN(enc_type == 0, PJ_EINVAL);
PJ_LOG(4,(THIS_FILE, "Creating recorder %.*s..",
(int)filename->slen, filename->ptr));
pj_log_push_indent();
if (pjsua_var.rec_cnt >= PJ_ARRAY_SIZE(pjsua_var.recorder)) {
pj_log_pop_indent();
return PJ_ETOOMANY;
}
/* Determine the file format */
ext.ptr = filename->ptr + filename->slen - 4;
ext.slen = 4;
if (pj_stricmp2(&ext, ".wav") == 0)
file_format = FMT_WAV;
else if (pj_stricmp2(&ext, ".mp3") == 0)
file_format = FMT_MP3;
else {
PJ_LOG(1,(THIS_FILE, "pjsua_recorder_create() error: unable to "
"determine file format for %.*s",
(int)filename->slen, filename->ptr));
pj_log_pop_indent();
return PJ_ENOTSUP;
}
PJSUA_LOCK();
for (file_id=0; file_id<PJ_ARRAY_SIZE(pjsua_var.recorder); ++file_id) {
if (pjsua_var.recorder[file_id].port == NULL)
break;
}
if (file_id == PJ_ARRAY_SIZE(pjsua_var.recorder)) {
/* This is unexpected */
pj_assert(0);
status = PJ_EBUG;
goto on_return;
}
pj_memcpy(path, filename->ptr, filename->slen);
path[filename->slen] = '\0';
pool = pjsua_pool_create(get_basename(path,
(unsigned)filename->slen), 1000,
1000);
if (!pool) {
status = PJ_ENOMEM;
goto on_return;
}
if (file_format == FMT_WAV) {
status = pjmedia_wav_writer_port_create(pool, path,
pjsua_var.media_cfg.clock_rate,
pjsua_var.mconf_cfg.channel_count,
pjsua_var.mconf_cfg.samples_per_frame,
pjsua_var.mconf_cfg.bits_per_sample,
options, 0, &port);
} else {
PJ_UNUSED_ARG(enc_param);
port = NULL;
status = PJ_ENOTSUP;
}
if (status != PJ_SUCCESS) {
pjsua_perror(THIS_FILE, "Unable to open file for recording", status);
goto on_return;
}
status = pjmedia_conf_add_port(pjsua_var.mconf, pool,
port, filename, &slot);
if (status != PJ_SUCCESS) {
pjmedia_port_destroy(port);
goto on_return;
}
pjsua_var.recorder[file_id].port = port;
pjsua_var.recorder[file_id].slot = slot;
pjsua_var.recorder[file_id].pool = pool;
if (p_id) *p_id = file_id;
++pjsua_var.rec_cnt;
PJSUA_UNLOCK();
PJ_LOG(4,(THIS_FILE, "Recorder created, id=%d, slot=%d", file_id,
slot));
pj_log_pop_indent();
return PJ_SUCCESS;
on_return:
PJSUA_UNLOCK();
if (pool) pj_pool_release(pool);
pj_log_pop_indent();
return status;
}
```
...(of the normal recorder-to-file) to my program (and modified it) - it
create a 44 bytes big file and thats it. I guess my problem is, that my
modified version uses a new instance of a pjmedia_conf* (createt by
pjmedia_conf_create()), which is not connected with the incoming call.
So my questions are:
- How I can bind an existing call (e.g. with its call_info) to a new
conference (conf)?
- Or how can I get the default "pjsua_var.mconf" to use it inside the
mem_capture or at least with this extracted code snippet?
- Or has anyone a good snippet with an example of the usage of PjSIP
calls with mem_capture? This here is a good example of the
high-level-recorder-to-wav function:
"http://binerry.de/post/29180946733/raspberry-pi-caller-and-answering-machine"
- but I would love to see a code snippet with the direct source code of
the easy-to-use-function, so I can simply modify it to work with the
mem_capture.
- Can *anyone* explain me, how PjSIP-Conference/Media structures work
(How to use ports, what are the slots - what can I get from the "normal"
call_info - structures)? I've read the documentation really often, but I
don't know what I'm doing wrong...
Btw this is my modified version - yeah I know it is dirty...
```
void VoIP_client::record_wav_start(string filename_out) {
//Update call_info
pjsua_call_get_info(this->call_id, &this->call_info);
pj_str_t rec_file;
pj_status_t status = PJ_ENOTFOUND;
VoIP::voip_log->log_msg("[VoIP] [REC] Creating recorder for " +
string(this->call_info.remote_info.ptr), LOG_DEBUG);
// Create recorder for call
//status = pjsua_recorder_create(pj_cstr(&rec_file,
filename_out.c_str()), 0, NULL, 0, 0, &this->recorder_id);
{
const pj_str_t *filename = pj_cstr(&rec_file,
filename_out.c_str());
unsigned options = 0;
unsigned pjsua_var_rec_cnt;
pjmedia_port * pjsua_var_recorder_0_port;
unsigned pjsua_var_recorder_0_slot;
pj_pool_t * pjsua_var_recorder_0_pool;
pjmedia_conf * pjsua_var_mconf;
enum Format {
FMT_UNKNOWN,
FMT_WAV,
FMT_MP3,
};
unsigned slot, file_id;
char path[PJ_MAXPATH];
pj_str_t ext;
int file_format;
pj_pool_t *pool = NULL;
pjmedia_port *port;
pj_status_t statust = PJ_SUCCESS;
/* Filename must present */
//PJ_ASSERT_RETURN(filename != NULL, PJ_EINVAL);
/* Don't support max_size at present */
//PJ_ASSERT_RETURN(max_size == 0 || max_size == -1, PJ_EINVAL);
/* Don't support encoding type at present */
//PJ_ASSERT_RETURN(enc_type == 0, PJ_EINVAL);
PJ_LOG(4, ("", "Creating recorder %.*s..",
(int) filename->slen, filename->ptr));
pj_log_push_indent();
//if (pjsua_var_rec_cnt >= PJ_ARRAY_SIZE(pjsua_var.recorder)) {
// pj_log_pop_indent();
// return PJ_ETOOMANY;
// }
/* Determine the file format */
ext.ptr = filename->ptr + filename->slen - 4;
ext.slen = 4;
if (pj_stricmp2(&ext, ".wav") == 0)
file_format = FMT_WAV;
else if (pj_stricmp2(&ext, ".mp3") == 0)
file_format = FMT_MP3;
else {
PJ_LOG(1, ("", "pjsua_recorder_create() error: unable to "
"determine file format for %.*s",
(int) filename->slen, filename->ptr));
pj_log_pop_indent();
exit(PJ_ENOTSUP);
}
//for (file_id = 0; file_id <
PJ_ARRAY_SIZE(pjsua_var.recorder); ++file_id) {
// if (pjsua_var_recorder_0_port == NULL)
// break;
//}
//if (file_id == PJ_ARRAY_SIZE(pjsua_var.recorder)) {
// /* This is unexpected */
// pj_assert(0);
// status = PJ_EBUG;
// goto on_return;
//}
pj_memcpy(path, filename->ptr, filename->slen);
path[filename->slen] = '\0';
pool = pjsua_pool_create("pool1", 1000,
1000);
if (!pool) {
statust = PJ_ENOMEM;
goto on_return;
}
if (file_format == FMT_WAV) {
statust = pjmedia_wav_writer_port_create(pool, path,
8000, //pjsua_var.media_cfg.clock_rate,
1, //pjsua_var.mconf_cfg.channel_count,
160, //pjsua_var.mconf_cfg.samples_per_frame,
16, //pjsua_var.mconf_cfg.bits_per_sample,
options, 0, &port);
} else {
port = NULL;
exit(PJ_ENOTSUP);
}
if (statust != PJ_SUCCESS) {
pjsua_perror("", "Unable to open file for recording", status);
goto on_return;
}
status = pjmedia_conf_create(
pool,
1 /*Phone*/ + 1 /*Sound device*/,
8000 /*8kHz clock rate*/,
1 /*Channel count*/,
160 /*samples_per_frame*/,
16 /*bits_per_sample*/,
PJMEDIA_CONF_NO_DEVICE /* options */,
&pjsua_var_mconf /* result */);
if (status != PJ_SUCCESS)
VoIP::voip_log->log_msg("[VoIP] Error on creating
conference for client " + string(this->call_info.remote_info.ptr) + ": "
+ to_string(status), LOG_ERROR);
statust = pjmedia_conf_add_port(pjsua_var_mconf, pool, port,
filename, &slot);
if (statust != PJ_SUCCESS) {
pjmedia_port_destroy(port);
goto on_return;
}
pjsua_var_recorder_0_port = port;
pjsua_var_recorder_0_slot = slot;
pjsua_var_recorder_0_pool = pool;
//if (p_id) *p_id = file_id;
//++pjsua_var.rec_cnt;
PJ_LOG(4, ("", "Recorder created, id=%d, slot=%d", file_id, slot));
pj_log_pop_indent();
status = PJ_SUCCESS;
on_return:
if (pool) pj_pool_release(pool);
pj_log_pop_indent();
//exit(statust);
}
if (status != PJ_SUCCESS)
VoIP::voip_log->log_msg("[VoIP] [REC] Error recording answer" +
to_string(status), LOG_ERROR);
//Connect recorder with a new virtual phone conference
pjsua_conf_port_id rec_port =
pjsua_recorder_get_conf_port(this->recorder_id);
pjsua_conf_connect(this->call_info.conf_slot, rec_port);
VoIP::voip_log->log_msg("[VoIP] [REC] Created a recorder for " +
string(this->call_info.remote_info.ptr), LOG_DEBUG);
}
```
Thank to anyone who can help or at least understands waht i want and
where i fail.
Simonmicro
_______________________________________________
Visit our blog: http://blog.pjsip.org
pjsip mailing list
pjsip@xxxxxxxxxxxxxxx
http://lists.pjsip.org/mailman/listinfo/pjsip_lists.pjsip.org