@ -18,7 +18,7 @@ struct janus_session { // "login" session
mutex_t lock ;
mutex_t lock ;
time_t last_act ;
time_t last_act ;
GHashTable * websockets ; / / controlling transports , websocket_conn - > websocket_conn
GHashTable * websockets ; / / controlling transports , websocket_conn - > websocket_conn
GHashTable * handles ; / / handle ID - > handle
GHashTable * handles ; / / handle ID - > 0x1 . handle ID owned by janus_handles
} ;
} ;
struct janus_handle { / / corresponds to a conference participant
struct janus_handle { / / corresponds to a conference participant
uint64_t id ;
uint64_t id ;
@ -38,7 +38,7 @@ struct janus_room {
static mutex_t janus_lock ;
static mutex_t janus_lock ;
static GHashTable * janus_tokens ; / / auth tokens , currently mostly unused
static GHashTable * janus_tokens ; / / auth tokens , currently mostly unused
static GHashTable * janus_sessions ; / / session ID - > session . holds a session reference
static GHashTable * janus_sessions ; / / session ID - > session . holds a session reference
static GHashTable * janus_handles ; / / handle ID - > 0x1 , to test for uniqueness
static GHashTable * janus_handles ; / / handle ID - > handle
static GHashTable * janus_rooms ; / / room ID - > room
static GHashTable * janus_rooms ; / / room ID - > room
static GHashTable * janus_feeds ; / / feed ID - > handle ID
static GHashTable * janus_feeds ; / / feed ID - > handle ID
@ -136,6 +136,7 @@ static void janus_send_ack(struct websocket_message *wm, const char *transaction
}
}
/ / global janus_lock is held
static const char * janus_videoroom_create ( struct janus_session * session , struct janus_handle * handle ,
static const char * janus_videoroom_create ( struct janus_session * session , struct janus_handle * handle ,
JsonBuilder * builder , JsonReader * reader , int * retcode )
JsonBuilder * builder , JsonReader * reader , int * retcode )
{
{
@ -164,14 +165,10 @@ static const char *janus_videoroom_create(struct janus_session *session, struct
}
}
json_reader_end_member ( reader ) ;
json_reader_end_member ( reader ) ;
mutex_lock ( & janus_lock ) ;
if ( room_id ) {
if ( room_id ) {
* retcode = 512 ;
* retcode = 512 ;
if ( g_hash_table_lookup ( janus_rooms , & room_id ) ) {
mutex_unlock ( & janus_lock ) ;
if ( g_hash_table_lookup ( janus_rooms , & room_id ) )
return " Requested room already exists " ;
return " Requested room already exists " ;
}
}
}
while ( 1 ) {
while ( 1 ) {
@ -199,8 +196,6 @@ static const char *janus_videoroom_create(struct janus_session *session, struct
handle - > room = room_id ;
handle - > room = room_id ;
mutex_unlock ( & janus_lock ) ;
ilog ( LOG_INFO , " Created new videoroom with ID % " PRIu64 , room_id ) ;
ilog ( LOG_INFO , " Created new videoroom with ID % " PRIu64 , room_id ) ;
json_builder_set_member_name ( builder , " videoroom " ) ;
json_builder_set_member_name ( builder , " videoroom " ) ;
@ -214,6 +209,7 @@ static const char *janus_videoroom_create(struct janus_session *session, struct
}
}
/ / global janus_lock is held
static const char * janus_videoroom_exists ( struct janus_session * session ,
static const char * janus_videoroom_exists ( struct janus_session * session ,
JsonBuilder * builder , uint64_t room_id )
JsonBuilder * builder , uint64_t room_id )
{
{
@ -221,18 +217,14 @@ static const char *janus_videoroom_exists(struct janus_session *session,
bool exists = false ;
bool exists = false ;
{
LOCK ( & janus_lock ) ;
if ( room_id )
room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
if ( room ) {
struct call * call = call_get ( & room - > call_id ) ;
if ( call ) {
exists = true ;
rwlock_unlock_w ( & call - > master_lock ) ;
obj_put ( call ) ;
}
if ( room_id )
room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
if ( room ) {
struct call * call = call_get ( & room - > call_id ) ;
if ( call ) {
exists = true ;
rwlock_unlock_w ( & call - > master_lock ) ;
obj_put ( call ) ;
}
}
}
}
@ -247,24 +239,21 @@ static const char *janus_videoroom_exists(struct janus_session *session,
}
}
/ / global janus_lock is held
static const char * janus_videoroom_destroy ( struct janus_session * session ,
static const char * janus_videoroom_destroy ( struct janus_session * session ,
JsonBuilder * builder , int * retcode , uint64_t room_id )
JsonBuilder * builder , int * retcode , uint64_t room_id )
{
{
struct janus_room * room = NULL ;
struct janus_room * room = NULL ;
{
LOCK ( & janus_lock ) ;
if ( room_id )
room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
* retcode = 426 ;
if ( ! room )
return " No such room " ;
if ( room_id )
room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
* retcode = 426 ;
if ( ! room )
return " No such room " ;
ilog ( LOG_INFO , " Destroying videoroom with ID % " PRIu64 , room_id ) ;
ilog ( LOG_INFO , " Destroying videoroom with ID % " PRIu64 , room_id ) ;
g_hash_table_remove ( janus_rooms , & room_id ) ;
}
g_hash_table_remove ( janus_rooms , & room_id ) ;
struct call * call = call_get ( & room - > call_id ) ;
struct call * call = call_get ( & room - > call_id ) ;
/ / XXX if call is destroyed separately , room persist - > room should be destroyed too
/ / XXX if call is destroyed separately , room persist - > room should be destroyed too
@ -352,6 +341,7 @@ static void janus_clear_ret_streams(GQueue *q) {
}
}
/ / global janus_lock is held
static const char * janus_videoroom_join ( struct websocket_message * wm , struct janus_session * session ,
static const char * janus_videoroom_join ( struct websocket_message * wm , struct janus_session * session ,
const char * transaction ,
const char * transaction ,
struct janus_handle * handle , JsonBuilder * builder , JsonReader * reader , const char * * successp ,
struct janus_handle * handle , JsonBuilder * builder , JsonReader * reader , const char * * successp ,
@ -382,199 +372,194 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
else
else
return " Invalid 'ptype' " ;
return " Invalid 'ptype' " ;
{
LOCK ( & janus_lock ) ;
struct janus_room * room = NULL ;
if ( room_id )
room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
* retcode = 426 ;
if ( ! room )
return " No such room " ;
* retcode = 436 ;
if ( ! is_pub & & g_hash_table_lookup ( room - > subscribers , & handle - > id ) )
return " User already exists in the room as a subscriber " ;
if ( is_pub & & g_hash_table_lookup ( room - > publishers , & handle - > id ) )
return " User already exists in the room as a publisher " ;
uint64_t feed_id = 0 ; / / set for single feed IDs , otherwise remains 0
AUTO_CLEANUP_INIT ( GString * feed_ids , __g_string_free , g_string_new ( " feeds " ) ) ; / / for log output
AUTO_CLEANUP ( GQueue ret_streams , janus_clear_ret_streams ) = G_QUEUE_INIT ; / / return list for multiple subs
if ( is_pub ) {
/ / random feed ID
while ( 1 ) {
feed_id = janus_random ( ) ;
if ( ! feed_id )
continue ;
if ( g_hash_table_lookup ( janus_feeds , & feed_id ) )
continue ;
break ;
}
struct janus_room * room = NULL ;
if ( room_id )
room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
/ / feed ID points to the handle
g_hash_table_insert ( janus_feeds , uint64_dup ( feed_id ) , uint64_dup ( handle - > id ) ) ;
/ / handle ID points to the feed
g_hash_table_insert ( room - > publishers , uint64_dup ( handle - > id ) , uint64_dup ( feed_id ) ) ;
}
else {
/ / subscriber
AUTO_CLEANUP ( GQueue srcs , call_subscriptions_clear ) = G_QUEUE_INIT ;
AUTO_CLEANUP_NULL ( struct call * call , call_unlock_release ) ;
* retcode = 426 ;
* retcode = 426 ;
if ( ! room )
call = call_get ( & room - > call_id ) ;
if ( ! call )
return " No such room " ;
return " No such room " ;
/ / XXX more granular locking ?
* retcode = 436 ;
if ( ! is_pub & & g_hash_table_lookup ( room - > subscribers , & handle - > id ) )
return " User already exists in the room as a subscriber " ;
if ( is_pub & & g_hash_table_lookup ( room - > publishers , & handle - > id ) )
return " User already exists in the room as a publisher " ;
uint64_t feed_id = 0 ; / / set for single feed IDs , otherwise remains 0
AUTO_CLEANUP_INIT ( GString * feed_ids , __g_string_free , g_string_new ( " feeds " ) ) ; / / for log output
AUTO_CLEANUP ( GQueue ret_streams , janus_clear_ret_streams ) = G_QUEUE_INIT ; / / return list for multiple subs
if ( is_pub ) {
/ / random feed ID
while ( 1 ) {
feed_id = janus_random ( ) ;
if ( ! feed_id )
continue ;
if ( g_hash_table_lookup ( janus_feeds , & feed_id ) )
continue ;
break ;
}
/ / feed ID points to the handle
g_hash_table_insert ( janus_feeds , uint64_dup ( feed_id ) , uint64_dup ( handle - > id ) ) ;
/ / handle ID points to the feed
g_hash_table_insert ( room - > publishers , uint64_dup ( handle - > id ) , uint64_dup ( feed_id ) ) ;
/ / 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 {
/ / subscriber
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 " ;
/ / 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 ) ;
json_reader_end_member ( reader ) ;
/ / handle list of subscriptions if given
if ( json_reader_read_member ( reader , " streams " ) ) {
* retcode = 456 ;
if ( ! json_reader_is_array ( reader ) )
return " Invalid 'message.streams' key (not an array) " ;
int eles = json_reader_count_elements ( reader ) ;
if ( eles < 0 )
return " Invalid 'message.streams' key (invalid array) " ;
for ( int i = 0 ; i < eles ; i + + ) {
if ( ! json_reader_read_element ( reader , i ) )
return " Invalid 'message.streams' key (cannot read element) " ;
if ( ! json_reader_is_object ( reader ) )
return " Invalid 'message.streams' key (contains not an object) " ;
if ( ! json_reader_read_member ( reader , " feed " ) )
return " Invalid 'message.streams' key (doesn't contain 'feed') " ;
uint64_t fid = jr_str_int ( reader ) ; / / leave ` feed_id ` zero
if ( ! fid )
return " Invalid 'message.streams' key (contains invalid 'feed') " ;
const char * ret = janus_videoroom_join_sub ( handle , room , retcode , fid ,
call , & srcs ) ;
if ( ret )
if ( ret )
return ret ;
return ret ;
}
json_reader_end_member ( reader ) ;
/ / handle list of subscriptions if given
if ( json_reader_read_member ( reader , " streams " ) ) {
* retcode = 456 ;
if ( ! json_reader_is_array ( reader ) )
return " Invalid 'message.streams' key (not an array) " ;
int eles = json_reader_count_elements ( reader ) ;
if ( eles < 0 )
return " Invalid 'message.streams' key (invalid array) " ;
for ( int i = 0 ; i < eles ; i + + ) {
if ( ! json_reader_read_element ( reader , i ) )
return " Invalid 'message.streams' key (cannot read element) " ;
if ( ! json_reader_is_object ( reader ) )
return " Invalid 'message.streams' key (contains not an object) " ;
if ( ! json_reader_read_member ( reader , " feed " ) )
return " Invalid 'message.streams' key (doesn't contain 'feed') " ;
uint64_t fid = jr_str_int ( reader ) ; / / leave ` feed_id ` zero
if ( ! fid )
return " Invalid 'message.streams' key (contains invalid 'feed') " ;
const char * ret = janus_videoroom_join_sub ( handle , room , retcode , fid ,
call , & srcs ) ;
if ( ret )
return ret ;
json_reader_end_member ( reader ) ;
json_reader_end_element ( reader ) ;
g_string_append_printf ( feed_ids , " % " PRIu64 " , " , fid ) ;
uint64_t * fidp = g_slice_alloc ( sizeof ( * fidp ) ) ;
* fidp = fid ;
g_queue_push_tail ( & ret_streams , fidp ) ;
}
}
json_reader_end_member ( reader ) ;
json_reader_end_member ( reader ) ;
json_reader_end_element ( reader ) ;
* retcode = 456 ;
if ( ! srcs . length )
return " No feeds to subscribe to given " ;
AUTO_CLEANUP_GBUF ( dest_handle_buf ) ;
dest_handle_buf = g_strdup_printf ( " % " PRIu64 , handle - > id ) ;
str dest_handle_str ;
str_init ( & dest_handle_str , dest_handle_buf ) ;
struct call_monologue * dest_ml = call_get_or_create_monologue ( call , & dest_handle_str ) ;
AUTO_CLEANUP ( struct sdp_ng_flags flags , call_ng_free_flags ) ;
call_ng_flags_init ( & flags , OP_REQUEST ) ;
/ / set all WebRTC - specific attributes
flags . transport_protocol = & transport_protocols [ PROTO_UDP_TLS_RTP_SAVPF ] ;
flags . ice_option = ICE_FORCE ;
flags . trickle_ice = 1 ;
flags . generate_mid = 1 ;
flags . rtcp_mux_offer = 1 ;
flags . rtcp_mux_require = 1 ;
flags . no_rtcp_attr = 1 ;
flags . sdes_off = 1 ;
flags . rtcp_mirror = 1 ;
int ret = monologue_subscribe_request ( & srcs , dest_ml , & flags ) ;
if ( ret )
return " Subscribe error " ;
/ / 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 ) ;
g_string_append_printf ( feed_ids , " % " PRIu64 " , " , fid ) ;
uint64_t * fidp = g_slice_alloc ( sizeof ( * fidp ) ) ;
* fidp = fid ;
g_queue_push_tail ( & ret_streams , fidp ) ;
}
}
else
ret = sdp_create ( jsep_sdp_out , dest_ml , & flags ) ;
}
json_reader_end_member ( reader ) ;
if ( ! dest_ml - > janus_session )
dest_ml - > janus_session = obj_get ( session ) ;
* retcode = 456 ;
if ( ! srcs . length )
return " No feeds to subscribe to given " ;
if ( ret )
return " Error generating SDP " ;
* jsep_type_out = " offer " ;
AUTO_CLEANUP_GBUF ( dest_handle_buf ) ;
dest_handle_buf = g_strdup_printf ( " % " PRIu64 , handle - > id ) ;
str dest_handle_str ;
str_init ( & dest_handle_str , dest_handle_buf ) ;
struct call_monologue * dest_ml = call_get_or_create_monologue ( call , & dest_handle_str ) ;
AUTO_CLEANUP ( struct sdp_ng_flags flags , call_ng_free_flags ) ;
call_ng_flags_init ( & flags , OP_REQUEST ) ;
/ / set all WebRTC - specific attributes
flags . transport_protocol = & transport_protocols [ PROTO_UDP_TLS_RTP_SAVPF ] ;
flags . ice_option = ICE_FORCE ;
flags . trickle_ice = 1 ;
flags . generate_mid = 1 ;
flags . rtcp_mux_offer = 1 ;
flags . rtcp_mux_require = 1 ;
flags . no_rtcp_attr = 1 ;
flags . sdes_off = 1 ;
flags . rtcp_mirror = 1 ;
int ret = monologue_subscribe_request ( & srcs , dest_ml , & flags ) ;
if ( ret )
return " Subscribe error " ;
/ / 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 ( ! dest_ml - > janus_session )
dest_ml - > janus_session = obj_get ( session ) ;
if ( ret )
return " Error generating SDP " ;
* jsep_type_out = " offer " ;
}
handle - > room = room_id ;
handle - > room = room_id ;
/ / single or multiple feed IDs ?
if ( feed_id )
g_string_printf ( feed_ids , " feed % " PRIu64 , feed_id ) ;
else if ( feed_ids - > len > = 2 ) / / truncate trailing " , "
g_string_truncate ( feed_ids , feed_ids - > len - 2 ) ;
/ / single or multiple feed IDs ?
if ( feed_id )
g_string_printf ( feed_ids , " feed % " PRIu64 , feed_id ) ;
else if ( feed_ids - > len > = 2 ) / / truncate trailing " , "
g_string_truncate ( feed_ids , feed_ids - > len - 2 ) ;
ilog ( LOG_INFO , " Handle % " PRIu64 " has joined room % " PRIu64 " as %s (%s) " ,
handle - > id , room_id ,
is_pub ? " publisher " : " subscriber " , feed_ids - > str ) ;
ilog ( LOG_INFO , " Handle % " PRIu64 " has joined room % " PRIu64 " as %s (%s) " ,
handle - > id , room_id ,
is_pub ? " publisher " : " subscriber " , feed_ids - > str ) ;
* successp = " event " ;
* successp = " event " ;
if ( is_pub ) {
json_builder_set_member_name ( builder , " videoroom " ) ;
json_builder_add_string_value ( builder , " joined " ) ;
json_builder_set_member_name ( builder , " room " ) ;
json_builder_add_int_value ( builder , room_id ) ;
if ( is_pub ) {
json_builder_set_member_name ( builder , " videoroom " ) ;
json_builder_add_string_value ( builder , " joined " ) ;
json_builder_set_member_name ( builder , " room " ) ;
json_builder_add_int_value ( builder , room_id ) ;
json_builder_set_member_name ( builder , " id " ) ;
json_builder_add_int_value ( builder , feed_id ) ;
json_builder_set_member_name ( builder , " publishers " ) ;
janus_publishers_list ( builder , room , feed_id ) ;
}
else {
/ / subscriber
json_builder_set_member_name ( builder , " videoroom " ) ;
json_builder_add_string_value ( builder , " attached " ) ;
json_builder_set_member_name ( builder , " room " ) ;
json_builder_add_int_value ( builder , room_id ) ;
/ / output format : single feed ID or multiple ?
if ( feed_id ) {
json_builder_set_member_name ( builder , " id " ) ;
json_builder_set_member_name ( builder , " id " ) ;
json_builder_add_int_value ( builder , feed_id ) ;
json_builder_add_int_value ( builder , feed_id ) ;
json_builder_set_member_name ( builder , " publishers " ) ;
janus_publishers_list ( builder , room , feed_id ) ;
}
}
else {
else {
/ / subscriber
json_builder_set_member_name ( builder , " videoroom " ) ;
json_builder_add_string_value ( builder , " attached " ) ;
json_builder_set_member_name ( builder , " room " ) ;
json_builder_add_int_value ( builder , room_id ) ;
/ / output format : single feed ID or multiple ?
if ( feed_id ) {
json_builder_set_member_name ( builder , " id " ) ;
json_builder_add_int_value ( builder , feed_id ) ;
}
else {
json_builder_set_member_name ( builder , " streams " ) ;
json_builder_begin_array ( builder ) ;
uint64_t idx = 0 ;
for ( GList * l = ret_streams . head ; l ; l = l - > next ) {
uint64_t * fidp = l - > data ;
json_builder_begin_object ( builder ) ;
json_builder_set_member_name ( builder , " mindex " ) ;
json_builder_add_int_value ( builder , idx + + ) ;
json_builder_set_member_name ( builder , " feed_id " ) ;
json_builder_add_int_value ( builder , * fidp ) ;
json_builder_end_object ( builder ) ;
}
json_builder_end_array ( builder ) ;
json_builder_set_member_name ( builder , " streams " ) ;
json_builder_begin_array ( builder ) ;
uint64_t idx = 0 ;
for ( GList * l = ret_streams . head ; l ; l = l - > next ) {
uint64_t * fidp = l - > data ;
json_builder_begin_object ( builder ) ;
json_builder_set_member_name ( builder , " mindex " ) ;
json_builder_add_int_value ( builder , idx + + ) ;
json_builder_set_member_name ( builder , " feed_id " ) ;
json_builder_add_int_value ( builder , * fidp ) ;
json_builder_end_object ( builder ) ;
}
}
json_builder_end_array ( builder ) ;
}
}
}
}
@ -582,11 +567,10 @@ static const char *janus_videoroom_join(struct websocket_message *wm, struct jan
}
}
/ / global janus_lock is held
static void janus_notify_publishers ( struct websocket_message * wm , uint64_t room_id , uint64_t except ,
static void janus_notify_publishers ( struct websocket_message * wm , uint64_t room_id , uint64_t except ,
uint64_t session_id )
uint64_t session_id )
{
{
LOCK ( & janus_lock ) ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
if ( ! room )
if ( ! room )
return ;
return ;
@ -631,6 +615,7 @@ static void janus_notify_publishers(struct websocket_message *wm, uint64_t room_
}
}
/ / global janus_lock is held
static const char * janus_videoroom_configure ( struct websocket_message * wm , struct janus_session * session ,
static const char * janus_videoroom_configure ( struct websocket_message * wm , struct janus_session * session ,
const char * jsep_type , const char * jsep_sdp ,
const char * jsep_type , const char * jsep_sdp ,
const char * transaction ,
const char * transaction ,
@ -682,21 +667,17 @@ static const char *janus_videoroom_configure(struct websocket_message *wm, struc
AUTO_CLEANUP_NULL ( struct call * call , call_unlock_release ) ;
AUTO_CLEANUP_NULL ( struct call * call , call_unlock_release ) ;
{
LOCK ( & janus_lock ) ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
* retcode = 426 ;
if ( ! room )
return " No such room " ;
call = call_get ( & room - > call_id ) ;
/ / XXX if call is destroyed separately , room persists - > room should be destroyed too
if ( ! call )
return " No such room " ;
* retcode = 512 ;
if ( ! g_hash_table_lookup ( room - > publishers , & handle - > id ) )
return " Not a publisher " ;
}
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
* retcode = 426 ;
if ( ! room )
return " No such room " ;
call = call_get ( & room - > call_id ) ;
/ / XXX if call is destroyed separately , room persists - > room should be destroyed too
if ( ! call )
return " No such room " ;
* retcode = 512 ;
if ( ! g_hash_table_lookup ( room - > publishers , & handle - > id ) )
return " Not a publisher " ;
AUTO_CLEANUP_GBUF ( handle_buf ) ;
AUTO_CLEANUP_GBUF ( handle_buf ) ;
handle_buf = g_strdup_printf ( " % " PRIu64 , handle - > id ) ;
handle_buf = g_strdup_printf ( " % " PRIu64 , handle - > id ) ;
@ -796,6 +777,7 @@ static const char *janus_videoroom_configure(struct websocket_message *wm, struc
}
}
/ / global janus_lock is held
static const char * janus_videoroom_start ( struct websocket_message * wm , struct janus_session * session ,
static const char * janus_videoroom_start ( struct websocket_message * wm , struct janus_session * session ,
const char * jsep_type , const char * jsep_sdp ,
const char * jsep_type , const char * jsep_sdp ,
const char * transaction ,
const char * transaction ,
@ -837,46 +819,42 @@ static const char *janus_videoroom_start(struct websocket_message *wm, struct ja
AUTO_CLEANUP_NULL ( struct call * call , call_unlock_release ) ;
AUTO_CLEANUP_NULL ( struct call * call , call_unlock_release ) ;
{
LOCK ( & janus_lock ) ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
* retcode = 426 ;
if ( ! room )
return " No such room " ;
call = call_get ( & room - > call_id ) ;
if ( ! call )
return " No such room " ;
* retcode = 456 ;
if ( ! g_hash_table_lookup ( room - > subscribers , & handle - > id ) )
return " Not a subscriber " ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
* retcode = 426 ;
if ( ! room )
return " No such room " ;
call = call_get ( & room - > call_id ) ;
if ( ! call )
return " No such room " ;
* retcode = 456 ;
if ( ! g_hash_table_lookup ( room - > subscribers , & handle - > id ) )
return " Not a subscriber " ;
* retcode = 512 ;
uint64_t * feed_handle = g_hash_table_lookup ( janus_feeds , & feed_id ) ;
if ( ! feed_handle )
return " No such feed exists " ;
* retcode = 512 ;
uint64_t * feed_handle = g_hash_table_lookup ( janus_feeds , & feed_id ) ;
if ( ! feed_handle )
return " No such feed exists " ;
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 " ;
/ / XXX verify that dest_ml is subscribed to source_ml
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 " ;
/ / XXX verify that dest_ml is subscribed to source_ml
AUTO_CLEANUP_GBUF ( dest_handle_buf ) ;
dest_handle_buf = g_strdup_printf ( " % " PRIu64 , handle - > id ) ;
str dest_handle_str ;
str_init ( & dest_handle_str , dest_handle_buf ) ;
struct call_monologue * dest_ml = call_get_monologue ( call , & dest_handle_str ) ;
if ( ! dest_ml )
return " Subscriber not found " ;
AUTO_CLEANUP_GBUF ( dest_handle_buf ) ;
dest_handle_buf = g_strdup_printf ( " % " PRIu64 , handle - > id ) ;
str dest_handle_str ;
str_init ( & dest_handle_str , dest_handle_buf ) ;
struct call_monologue * dest_ml = call_get_monologue ( call , & dest_handle_str ) ;
if ( ! dest_ml )
return " Subscriber not found " ;
int ret = monologue_subscribe_answer ( dest_ml , & flags , & streams ) ;
if ( ret )
return " Failed to process subscription answer " ;
}
int ret = monologue_subscribe_answer ( dest_ml , & flags , & streams ) ;
if ( ret )
return " Failed to process subscription answer " ;
* successp = " event " ;
* successp = " event " ;
json_builder_set_member_name ( builder , " videoroom " ) ;
json_builder_set_member_name ( builder , " videoroom " ) ;
@ -890,7 +868,8 @@ static const char *janus_videoroom_start(struct websocket_message *wm, struct ja
}
}
/ / session is locked , which also locks handle
/ / global janus_lock is held
/ / TODO : more granular locking
static const char * janus_videoroom ( struct websocket_message * wm , struct janus_session * session ,
static const char * janus_videoroom ( struct websocket_message * wm , struct janus_session * session ,
const char * jsep_type , const char * jsep_sdp ,
const char * jsep_type , const char * jsep_sdp ,
const char * transaction ,
const char * transaction ,
@ -1175,16 +1154,15 @@ const char *janus_attach(JsonReader *reader, JsonBuilder *builder, struct janus_
handle_id = handle - > id = janus_random ( ) ;
handle_id = handle - > id = janus_random ( ) ;
if ( g_hash_table_lookup ( janus_handles , & handle - > id ) )
if ( g_hash_table_lookup ( janus_handles , & handle - > id ) )
continue ;
continue ;
g_hash_table_insert ( janus_handles , & handle - > id , ( void * ) 0x1 ) ;
g_hash_table_insert ( janus_handles , & handle - > id , handle ) ;
break ;
break ;
}
}
mutex_unlock ( & janus_lock ) ;
mutex_unlock ( & janus_lock ) ;
mutex_lock ( & session - > lock ) ;
mutex_lock ( & session - > lock ) ;
assert ( g_hash_table_lookup ( session - > handles , & handle_id ) = = NULL ) ;
assert ( g_hash_table_lookup ( session - > handles , & handle_id ) = = NULL ) ;
g_hash_table_insert ( session - > handles , & handle - > id , handle ) ;
g_hash_table_insert ( session - > handles , & handle - > id , ( void * ) 0x1 ) ;
mutex_unlock ( & session - > lock ) ;
mutex_unlock ( & session - > lock ) ;
/ / handle is now owned by session
json_builder_set_member_name ( builder , " data " ) ;
json_builder_set_member_name ( builder , " data " ) ;
json_builder_begin_object ( builder ) ; / / {
json_builder_begin_object ( builder ) ; / / {
@ -1209,26 +1187,37 @@ const char *janus_detach(struct websocket_message *wm, JsonReader *reader, JsonB
uint64_t room_id = 0 ;
uint64_t room_id = 0 ;
/ / remove handle from session first as the handle ID in the hash is owned by the
/ / janus_handle object , which is owned by janus_handles
{
{
LOCK ( & session - > lock ) ;
LOCK ( & session - > lock ) ;
struct janus_handle * handle = g_hash_table_lookup ( session - > handles , & handle_id ) ;
void * exists = g_hash_table_lookup ( session - > handles , & handle_id ) ;
* retcode = 463 ;
* retcode = 463 ;
if ( ! handl e)
if ( ! exists )
return " Could not detach handle from plugin " ;
return " Could not detach handle from plugin " ;
room_id = handle - > room ;
/ / destroy handle
g_hash_table_remove ( session - > handles , & handle_id ) ;
g_hash_table_remove ( session - > handles , & handle_id ) ;
g_slice_free1 ( sizeof ( * handle ) , handle ) ;
}
}
LOCK ( & janus_lock ) ;
struct janus_handle * handle = g_hash_table_lookup ( janus_handles , & handle_id ) ;
* retcode = 463 ;
if ( ! handle | | handle - > session ! = session - > id )
return " Could not detach handle from plugin " ;
room_id = handle - > room ;
/ / destroy handle
g_hash_table_remove ( janus_handles , & handle_id ) ;
g_slice_free1 ( sizeof ( * handle ) , handle ) ;
if ( ! room_id )
if ( ! room_id )
return NULL ;
return NULL ;
LOCK ( & janus_lock ) ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
if ( ! room )
if ( ! room )
return NULL ;
return NULL ;
@ -1384,12 +1373,12 @@ const char *janus_message(struct websocket_message *wm, JsonReader *reader, Json
char * jsep_type_out = NULL ;
char * jsep_type_out = NULL ;
str jsep_sdp_out = STR_NULL ;
str jsep_sdp_out = STR_NULL ;
mutex_lock ( & session - > lock ) ;
LOCK ( & janus_ lock) ;
struct janus_handle * handle = g_hash_table_lookup ( session - > handles , & handle_id ) ;
struct janus_handle * handle = g_hash_table_lookup ( janus_ handles, & handle_id ) ;
const char * err = NULL ;
const char * err = NULL ;
if ( ! handle ) {
if ( ! handle | | handle - > session ! = session - > id ) {
* retcode = 457 ;
* retcode = 457 ;
err = " No plugin handle given or invalid handle " ;
err = " No plugin handle given or invalid handle " ;
}
}
@ -1398,8 +1387,6 @@ const char *janus_message(struct websocket_message *wm, JsonReader *reader, Json
builder , reader , successp , retcode , & jsep_type_out ,
builder , reader , successp , retcode , & jsep_type_out ,
& jsep_sdp_out ) ;
& jsep_sdp_out ) ;
mutex_unlock ( & session - > lock ) ;
json_builder_end_object ( builder ) ; / / }
json_builder_end_object ( builder ) ; / / }
json_builder_end_object ( builder ) ; / / }
json_builder_end_object ( builder ) ; / / }
@ -1474,23 +1461,16 @@ const char *janus_trickle(JsonReader *reader, struct janus_session *session, uin
/ / fetch call and monologue
/ / fetch call and monologue
uint64_t room_id = 0 ;
AUTO_CLEANUP_NULL ( struct call * call , call_unlock_release ) ;
{
{
LOCK ( & session - > lock ) ;
LOCK ( & janus_ lock) ;
struct janus_handle * handle = g_hash_table_lookup ( session - > handles , & handle_id ) ;
struct janus_handle * handle = g_hash_table_lookup ( janus_ handles, & handle_id ) ;
if ( ! handle )
if ( ! handle | | ! handle - > room | | handle - > session ! = session - > id )
return " Unhandled request method " ;
return " Unhandled request method " ;
room_id = handle - > room ;
}
AUTO_CLEANUP_NULL ( struct call * call , call_unlock_release ) ;
{
LOCK ( & janus_lock ) ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & room_id ) ;
struct janus_room * room = g_hash_table_lookup ( janus_rooms , & handle - > room ) ;
* retcode = 426 ;
* retcode = 426 ;
if ( ! room )
if ( ! room )