|
|
|
@ -871,6 +871,9 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) { |
|
|
|
case CSH_LOOKUP("single-codec"): |
|
|
|
out->single_codec = 1; |
|
|
|
break; |
|
|
|
case CSH_LOOKUP("allow-transcoding"): |
|
|
|
out->allow_transcoding = 1; |
|
|
|
break; |
|
|
|
case CSH_LOOKUP("inject-DTMF"): |
|
|
|
out->inject_dtmf = 1; |
|
|
|
break; |
|
|
|
@ -907,7 +910,7 @@ static void call_ng_flags_flags(struct sdp_ng_flags *out, str *s, void *dummy) { |
|
|
|
&out->codec_except)) |
|
|
|
return; |
|
|
|
#ifdef WITH_TRANSCODING |
|
|
|
if (out->opmode == OP_OFFER) { |
|
|
|
if (out->opmode == OP_OFFER || out->opmode == OP_REQUEST || out->opmode == OP_PUBLISH) { |
|
|
|
if (call_ng_flags_prefix(out, s, "transcode-", call_ng_flags_codec_list, |
|
|
|
&out->codec_transcode)) |
|
|
|
return; |
|
|
|
@ -957,9 +960,11 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu |
|
|
|
bencode_dictionary_get_str(input, "from-tag", &out->from_tag); |
|
|
|
bencode_dictionary_get_str(input, "to-tag", &out->to_tag); |
|
|
|
bencode_dictionary_get_str(input, "via-branch", &out->via_branch); |
|
|
|
bencode_dictionary_get_str(input, "label", &out->label); |
|
|
|
bencode_get_alt(input, "label", "from-label", &out->label); |
|
|
|
bencode_get_alt(input, "to-label", "set-label", &out->set_label); |
|
|
|
bencode_dictionary_get_str(input, "address", &out->address); |
|
|
|
bencode_get_alt(input, "sdp", "SDP", &out->sdp); |
|
|
|
bencode_dictionary_get_str(input, "interface", &out->interface); |
|
|
|
|
|
|
|
diridx = 0; |
|
|
|
if ((list = bencode_dictionary_get_expect(input, "direction", BENCODE_LIST))) { |
|
|
|
@ -1145,7 +1150,7 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu |
|
|
|
call_ng_flags_list(out, dict, "offer", call_ng_flags_codec_list, &out->codec_offer); |
|
|
|
call_ng_flags_list(out, dict, "except", call_ng_flags_str_ht, &out->codec_except); |
|
|
|
#ifdef WITH_TRANSCODING |
|
|
|
if (opmode == OP_OFFER) { |
|
|
|
if (opmode == OP_OFFER || opmode == OP_REQUEST || opmode == OP_PUBLISH) { |
|
|
|
call_ng_flags_list(out, dict, "transcode", call_ng_flags_codec_list, &out->codec_transcode); |
|
|
|
call_ng_flags_list(out, dict, "mask", call_ng_flags_codec_list, &out->codec_mask); |
|
|
|
call_ng_flags_list(out, dict, "set", call_ng_flags_str_ht_split, &out->codec_set); |
|
|
|
@ -2044,6 +2049,12 @@ found: |
|
|
|
__monologue_unkernelize(*monologue); |
|
|
|
} |
|
|
|
|
|
|
|
// for generic ops, handle set-label here if given |
|
|
|
if (opmode == OP_OTHER && flags->set_label.len && *monologue) { |
|
|
|
call_str_cpy(*call, &(*monologue)->label, &flags->set_label); |
|
|
|
g_hash_table_replace((*call)->labels, &(*monologue)->label, *monologue); |
|
|
|
} |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
@ -2460,6 +2471,174 @@ found_sink: |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const char *call_publish_ng(bencode_item_t *input, bencode_item_t *output) { |
|
|
|
AUTO_CLEANUP(struct sdp_ng_flags flags, call_ng_free_flags); |
|
|
|
AUTO_CLEANUP(GQueue parsed, sdp_free) = G_QUEUE_INIT; |
|
|
|
AUTO_CLEANUP(GQueue streams, sdp_streams_free) = G_QUEUE_INIT; |
|
|
|
AUTO_CLEANUP(str sdp_in, str_free_dup) = STR_NULL; |
|
|
|
AUTO_CLEANUP(str sdp_out, str_free_dup) = STR_NULL; |
|
|
|
|
|
|
|
call_ng_process_flags(&flags, input, OP_PUBLISH); |
|
|
|
|
|
|
|
if (!flags.sdp.s) |
|
|
|
return "No SDP body in message"; |
|
|
|
if (!flags.call_id.s) |
|
|
|
return "No call-id in message"; |
|
|
|
if (!flags.from_tag.s) |
|
|
|
return "No from-tag in message"; |
|
|
|
|
|
|
|
str_init_dup_str(&sdp_in, &flags.sdp); |
|
|
|
|
|
|
|
if (sdp_parse(&sdp_in, &parsed, &flags)) |
|
|
|
return "Failed to parse SDP"; |
|
|
|
if (sdp_streams(&parsed, &streams, &flags)) |
|
|
|
return "Incomplete SDP specification"; |
|
|
|
|
|
|
|
struct call *call = call_get_or_create(&flags.call_id, false, false); |
|
|
|
struct call_monologue *ml = call_get_or_create_monologue(call, &flags.from_tag); |
|
|
|
|
|
|
|
int ret = monologue_publish(ml, &streams, &flags); |
|
|
|
if (ret) |
|
|
|
ilog(LOG_ERR, "Publish error"); // XXX close call? handle errors? |
|
|
|
|
|
|
|
ret = sdp_create(&sdp_out, ml, &flags); |
|
|
|
if (!ret) { |
|
|
|
save_last_sdp(ml, &sdp_in, &parsed, &streams); |
|
|
|
bencode_buffer_destroy_add(output->buffer, g_free, sdp_out.s); |
|
|
|
bencode_dictionary_add_str(output, "sdp", &sdp_out); |
|
|
|
sdp_out = STR_NULL; // ownership passed to output |
|
|
|
} |
|
|
|
|
|
|
|
rwlock_unlock_w(&call->master_lock); |
|
|
|
obj_put(call); |
|
|
|
|
|
|
|
if (!ret) |
|
|
|
return NULL; |
|
|
|
return "Failed to create SDP"; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const char *call_subscribe_request_ng(bencode_item_t *input, bencode_item_t *output) { |
|
|
|
const char *err = NULL; |
|
|
|
AUTO_CLEANUP(struct sdp_ng_flags flags, call_ng_free_flags); |
|
|
|
char rand_buf[65]; |
|
|
|
AUTO_CLEANUP_NULL(struct call *call, call_unlock_release); |
|
|
|
struct call_monologue *source_ml; |
|
|
|
|
|
|
|
// get source monologue |
|
|
|
err = media_block_match(&call, &source_ml, &flags, input, OP_REQUEST); |
|
|
|
if (err) |
|
|
|
return err; |
|
|
|
|
|
|
|
if (flags.sdp.len) |
|
|
|
ilog(LOG_INFO, "Subscribe-request with SDP received - ignoring SDP"); |
|
|
|
|
|
|
|
if (!source_ml) |
|
|
|
return "No call participant specified"; |
|
|
|
if (!source_ml->last_in_sdp.len || !source_ml->last_in_sdp_parsed.length) |
|
|
|
return "No SDP known for this from-tag"; |
|
|
|
|
|
|
|
// the `label=` option was possibly used above to select the from-tag -- |
|
|
|
// switch it out with `to-label=` or `set-label=` for monologue_subscribe_request |
|
|
|
// below which sets the label based on `label` for a newly created monologue |
|
|
|
flags.label = flags.set_label; |
|
|
|
|
|
|
|
// get destination monologue |
|
|
|
if (!flags.to_tag.len) { |
|
|
|
// generate one |
|
|
|
flags.to_tag = STR_CONST_INIT(rand_buf); |
|
|
|
rand_hex_str(flags.to_tag.s, flags.to_tag.len / 2); |
|
|
|
} |
|
|
|
struct call_monologue *dest_ml = call_get_or_create_monologue(call, &flags.to_tag); |
|
|
|
|
|
|
|
struct sdp_chopper *chopper = sdp_chopper_new(&source_ml->last_in_sdp); |
|
|
|
bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper); |
|
|
|
|
|
|
|
int ret = monologue_subscribe_request(source_ml, dest_ml, &flags); |
|
|
|
if (ret) |
|
|
|
return "Failed to request subscription"; |
|
|
|
|
|
|
|
ret = sdp_replace(chopper, &source_ml->last_in_sdp_parsed, dest_ml, &flags); |
|
|
|
if (ret) |
|
|
|
return "Failed to rewrite SDP"; |
|
|
|
|
|
|
|
if (chopper->output->len) |
|
|
|
bencode_dictionary_add_string_len(output, "sdp", chopper->output->str, chopper->output->len); |
|
|
|
bencode_dictionary_add_str_dup(output, "from-tag", &source_ml->tag); |
|
|
|
bencode_dictionary_add_str_dup(output, "to-tag", &dest_ml->tag); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const char *call_subscribe_answer_ng(bencode_item_t *input, bencode_item_t *output) { |
|
|
|
const char *err = NULL; |
|
|
|
AUTO_CLEANUP(struct sdp_ng_flags flags, call_ng_free_flags); |
|
|
|
AUTO_CLEANUP(GQueue parsed, sdp_free) = G_QUEUE_INIT; |
|
|
|
AUTO_CLEANUP(GQueue streams, sdp_streams_free) = G_QUEUE_INIT; |
|
|
|
AUTO_CLEANUP_NULL(struct call *call, call_unlock_release); |
|
|
|
struct call_monologue *source_ml; |
|
|
|
|
|
|
|
// get source monologue |
|
|
|
err = media_block_match(&call, &source_ml, &flags, input, OP_REQ_ANSWER); |
|
|
|
if (err) |
|
|
|
return err; |
|
|
|
|
|
|
|
if (!source_ml) |
|
|
|
return "No call participant specified"; |
|
|
|
if (!flags.to_tag.s) |
|
|
|
return "No to-tag in message"; |
|
|
|
if (!flags.sdp.len) |
|
|
|
return "No SDP body in message"; |
|
|
|
|
|
|
|
// get destination monologue |
|
|
|
struct call_monologue *dest_ml = call_get_monologue(call, &flags.to_tag); |
|
|
|
if (!dest_ml) |
|
|
|
return "To-tag not found"; |
|
|
|
|
|
|
|
if (sdp_parse(&flags.sdp, &parsed, &flags)) |
|
|
|
return "Failed to parse SDP"; |
|
|
|
if (sdp_streams(&parsed, &streams, &flags)) |
|
|
|
return "Incomplete SDP specification"; |
|
|
|
|
|
|
|
int ret = monologue_subscribe_answer(source_ml, dest_ml, &flags, &streams); |
|
|
|
if (ret) |
|
|
|
return "Failed to process subscription answer"; |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const char *call_unsubscribe_ng(bencode_item_t *input, bencode_item_t *output) { |
|
|
|
const char *err = NULL; |
|
|
|
AUTO_CLEANUP(struct sdp_ng_flags flags, call_ng_free_flags); |
|
|
|
AUTO_CLEANUP_NULL(struct call *call, call_unlock_release); |
|
|
|
struct call_monologue *source_ml; |
|
|
|
|
|
|
|
// get source monologue |
|
|
|
err = media_block_match(&call, &source_ml, &flags, input, OP_OTHER); |
|
|
|
if (err) |
|
|
|
return err; |
|
|
|
|
|
|
|
if (!source_ml) |
|
|
|
return "No call participant specified"; |
|
|
|
if (!flags.to_tag.s) |
|
|
|
return "No to-tag in message"; |
|
|
|
|
|
|
|
// get destination monologue |
|
|
|
struct call_monologue *dest_ml = call_get_or_create_monologue(call, &flags.to_tag); |
|
|
|
if (!dest_ml) |
|
|
|
return "To-tag not found"; |
|
|
|
|
|
|
|
int ret = monologue_unsubscribe(source_ml, dest_ml, &flags); |
|
|
|
if (ret) |
|
|
|
return "Failed to unsubscribe"; |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void call_interfaces_free() { |
|
|
|
if (info_re) { |
|
|
|
pcre_free(info_re); |
|
|
|
|