|
|
|
@ -304,6 +304,37 @@ static void janus_publishers_list(JsonBuilder *builder, struct janus_room *room, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static const char *janus_videoroom_join_sub(struct janus_handle *handle, struct janus_room *room, int *retcode, |
|
|
|
uint64_t feed_id, struct call *call, GQueue *srcs) |
|
|
|
{ |
|
|
|
// does the feed actually exist? get the feed handle |
|
|
|
*retcode = 512; |
|
|
|
uint64_t *feed_handle = g_hash_table_lookup(janus_feeds, &feed_id); |
|
|
|
if (!feed_handle) |
|
|
|
return "No such feed exists"; |
|
|
|
if (!g_hash_table_lookup(room->publishers, feed_handle)) |
|
|
|
return "No such feed handle exists"; |
|
|
|
|
|
|
|
// handle ID points to the subscribed feed |
|
|
|
g_hash_table_insert(room->subscribers, uint64_dup(handle->id), uint64_dup(feed_id)); |
|
|
|
|
|
|
|
// add the subscription |
|
|
|
AUTO_CLEANUP_GBUF(source_handle_buf); |
|
|
|
source_handle_buf = g_strdup_printf("%" PRIu64, *feed_handle); |
|
|
|
str source_handle_str; |
|
|
|
str_init(&source_handle_str, source_handle_buf); |
|
|
|
struct call_monologue *source_ml = call_get_monologue(call, &source_handle_str); |
|
|
|
if (!source_ml) |
|
|
|
return "Feed not found"; |
|
|
|
|
|
|
|
struct call_subscription *cs = g_slice_alloc0(sizeof(*cs)); |
|
|
|
cs->monologue = source_ml; |
|
|
|
g_queue_push_tail(srcs, cs); |
|
|
|
|
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static const char *janus_videoroom_join(struct websocket_message *wm, struct janus_session *session, |
|
|
|
const char *transaction, |
|
|
|
struct janus_handle *handle, JsonBuilder *builder, JsonReader *reader, const char **successp, |
|
|
|
@ -372,39 +403,28 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan |
|
|
|
} |
|
|
|
else { |
|
|
|
// subscriber |
|
|
|
// get the feed ID |
|
|
|
*retcode = 456; |
|
|
|
if (!json_reader_read_member(reader, "feed")) |
|
|
|
return "JSON object does not contain 'message.feed' key"; |
|
|
|
feed_id = jr_str_int(reader); |
|
|
|
if (!feed_id) |
|
|
|
return "JSON object does not contain 'message.feed' key"; |
|
|
|
|
|
|
|
// does the feed actually exist? get the feed handle |
|
|
|
*retcode = 512; |
|
|
|
uint64_t *feed_handle = g_hash_table_lookup(janus_feeds, &feed_id); |
|
|
|
if (!feed_handle) |
|
|
|
return "No such feed exists"; |
|
|
|
if (!g_hash_table_lookup(room->publishers, feed_handle)) |
|
|
|
return "No such feed handle exists"; |
|
|
|
|
|
|
|
// handle ID points to the subscribed feed |
|
|
|
g_hash_table_insert(room->subscribers, uint64_dup(handle->id), uint64_dup(feed_id)); |
|
|
|
|
|
|
|
// add the subscription |
|
|
|
AUTO_CLEANUP(GQueue srcs, call_subscriptions_clear) = G_QUEUE_INIT; |
|
|
|
AUTO_CLEANUP_NULL(struct call *call, call_unlock_release); |
|
|
|
*retcode = 426; |
|
|
|
call = call_get(&room->call_id); |
|
|
|
if (!call) |
|
|
|
return "No such room"; |
|
|
|
|
|
|
|
AUTO_CLEANUP_GBUF(source_handle_buf); |
|
|
|
source_handle_buf = g_strdup_printf("%" PRIu64, *feed_handle); |
|
|
|
str source_handle_str; |
|
|
|
str_init(&source_handle_str, source_handle_buf); |
|
|
|
struct call_monologue *source_ml = call_get_monologue(call, &source_handle_str); |
|
|
|
if (!source_ml) |
|
|
|
return "Feed not found"; |
|
|
|
// get single feed ID if there is one |
|
|
|
if (json_reader_read_member(reader, "feed")) { |
|
|
|
*retcode = 456; |
|
|
|
feed_id = jr_str_int(reader); |
|
|
|
if (!feed_id) |
|
|
|
return "JSON object contains invalid 'message.feed' key"; |
|
|
|
const char *ret = janus_videoroom_join_sub(handle, room, retcode, feed_id, |
|
|
|
call, &srcs); |
|
|
|
if (ret) |
|
|
|
return ret; |
|
|
|
} |
|
|
|
else |
|
|
|
return "JSON object does not contain 'message.feed' key"; |
|
|
|
json_reader_end_member(reader); |
|
|
|
|
|
|
|
AUTO_CLEANUP_GBUF(dest_handle_buf); |
|
|
|
dest_handle_buf = g_strdup_printf("%" PRIu64, handle->id); |
|
|
|
@ -426,19 +446,21 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan |
|
|
|
flags.sdes_off = 1; |
|
|
|
flags.rtcp_mirror = 1; |
|
|
|
|
|
|
|
AUTO_CLEANUP(GQueue srcs, call_subscriptions_clear) = G_QUEUE_INIT; |
|
|
|
|
|
|
|
struct call_subscription *cs = g_slice_alloc0(sizeof(*cs)); |
|
|
|
cs->monologue = source_ml; |
|
|
|
g_queue_push_tail(&srcs, cs); |
|
|
|
|
|
|
|
int ret = monologue_subscribe_request(&srcs, dest_ml, &flags); |
|
|
|
if (ret) |
|
|
|
return "Subscribe error"; |
|
|
|
|
|
|
|
struct sdp_chopper *chopper = sdp_chopper_new(&source_ml->last_in_sdp); |
|
|
|
ret = sdp_replace(chopper, &source_ml->last_in_sdp_parsed, dest_ml, &flags); |
|
|
|
sdp_chopper_destroy_ret(chopper, jsep_sdp_out); |
|
|
|
// create SDP: if there's only one subscription, we can use the original |
|
|
|
// SDP, otherwise we generate a new one |
|
|
|
if (srcs.length == 1) { |
|
|
|
struct call_subscription *cs = srcs.head->data; |
|
|
|
struct call_monologue *source_ml = cs->monologue; |
|
|
|
struct sdp_chopper *chopper = sdp_chopper_new(&source_ml->last_in_sdp); |
|
|
|
ret = sdp_replace(chopper, &source_ml->last_in_sdp_parsed, dest_ml, &flags); |
|
|
|
sdp_chopper_destroy_ret(chopper, jsep_sdp_out); |
|
|
|
} |
|
|
|
else |
|
|
|
ret = sdp_create(jsep_sdp_out, dest_ml, &flags); |
|
|
|
|
|
|
|
if (ret) |
|
|
|
return "Error generating SDP"; |
|
|
|
|