@ -1457,9 +1457,7 @@ static const char *kernelize_one(struct rtpengine_target_info *reti, GQueue *out
goto output ;
if ( PS_ISSET2 ( stream , STRICT_SOURCE , MEDIA_HANDOVER ) ) {
mutex_lock ( & stream - > out_lock ) ;
__re_address_translate_ep ( & reti - > expected_src , MEDIA_ISSET ( media , ASYMMETRIC ) ? & stream - > learned_endpoint : & stream - > endpoint ) ;
mutex_unlock ( & stream - > out_lock ) ;
if ( PS_ISSET ( stream , STRICT_SOURCE ) )
reti - > src_mismatch = MSM_DROP ;
else if ( PS_ISSET ( stream , MEDIA_HANDOVER ) )
@ -1599,7 +1597,12 @@ output:
reti - > pt_filter = 1 ;
}
mutex_lock ( & sink - > out_lock ) ;
// XXX nested lock, avoid possible deadlock. should be reworked not to
// require a nested lock
if ( sink ! = stream & & mutex_trylock ( & sink - > lock ) ) {
g_slice_free1 ( sizeof ( * redi ) , redi ) ;
return " " ; // indicate deadlock
}
__re_address_translate_ep ( & redi - > output . dst_addr , & sink - > endpoint ) ;
__re_address_translate_ep ( & redi - > output . src_addr , & sink - > selected_sfd - > socket . local ) ;
@ -1616,7 +1619,8 @@ output:
handler - > out - > kernel ( & redi - > output . encrypt , sink ) ;
mutex_unlock ( & sink - > out_lock ) ;
if ( sink ! = stream )
mutex_unlock ( & sink - > lock ) ;
if ( ! redi - > output . encrypt . cipher | | ! redi - > output . encrypt . hmac ) {
g_slice_free1 ( sizeof ( * redi ) , redi ) ;
@ -1633,25 +1637,33 @@ output:
return NULL ;
}
// helper function for kernelize()
static void kernelize_one_sink_handler ( struct rtpengine_target_info * reti , GQueue * outputs ,
static bool kernelize_one_sink_handler ( struct rtpengine_target_info * reti , GQueue * outputs ,
struct packet_stream * stream , struct sink_handler * sink_handler , GQueue * sinks ,
GList * * payload_types )
{
struct packet_stream * sink = sink_handler - > sink ;
if ( PS_ISSET ( sink , NAT_WAIT ) & & ! PS_ISSET ( sink , RECEIVED ) )
return ;
return true ;
const char * err = kernelize_one ( reti , outputs , stream , sink_handler , & stream - > rtp_sinks ,
payload_types ) ;
if ( err )
if ( err ) {
if ( ! * err )
return false ; // indicate deadlock
ilog ( LOG_WARNING , " No support for kernel packet forwarding available (%s) " , err ) ;
}
return true ;
}
/* called with in_lock held */
void kernelize ( struct packet_stream * stream ) {
/* called with master _lock held */
static void kernelize ( struct packet_stream * stream ) {
struct call * call = stream - > call ;
const char * nk_warn_msg ;
struct call_media * media = stream - > media ;
if ( PS_ISSET ( stream , KERNELIZED ) )
while ( true ) {
LOCK ( & stream - > lock ) ;
// set flag, return if set already
if ( PS_SET ( stream , KERNELIZED ) )
return ;
reset_ps_kernel_stats ( stream ) ;
@ -1660,7 +1672,6 @@ void kernelize(struct packet_stream *stream) {
goto no_kernel ;
if ( ! kernel . is_wanted )
goto no_kernel ;
nk_warn_msg = " interface to kernel module not open " ;
if ( ! kernel . is_open )
goto no_kernel_warn ;
if ( MEDIA_ISSET ( media , GENERATOR ) )
@ -1682,27 +1693,36 @@ void kernelize(struct packet_stream *stream) {
if ( num_sinks = = 0 ) {
// add blackhole kernel rule
const char * err = kernelize_one ( & reti , & outputs , stream , NULL , NULL , & payload_types ) ;
if ( err )
if ( err ) {
if ( ! * err )
goto restart ;
ilog ( LOG_WARNING , " No support for kernel packet forwarding available (%s) " , err ) ;
}
}
else {
for ( GList * l = stream - > rtp_sinks . head ; l ; l = l - > next ) {
struct sink_handler * sh = l - > data ;
if ( sh - > attrs . block_media )
continue ;
kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks ,
bool ok = kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks ,
& payload_types ) ;
if ( ! ok )
goto restart ;
}
for ( GList * l = stream - > rtp_mirrors . head ; l ; l = l - > next ) {
struct sink_handler * sh = l - > data ;
kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks ,
bool ok = kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks ,
& payload_types ) ;
if ( ! ok )
goto restart ;
}
// record number of RTP destinations
unsigned int num_rtp_dests = reti . num_destinations ;
for ( GList * l = stream - > rtcp_sinks . head ; l ; l = l - > next ) {
struct sink_handler * sh = l - > data ;
kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks , NULL ) ;
bool ok = kernelize_one_sink_handler ( & reti , & outputs , stream , sh , & stream - > rtp_sinks , NULL ) ;
if ( ! ok )
goto restart ;
}
reti . num_rtcp_destinations = reti . num_destinations - num_rtp_dests ;
}
@ -1726,15 +1746,25 @@ void kernelize(struct packet_stream *stream) {
}
stream - > kernel_time = rtpe_now . tv_sec ;
PS_SET ( stream , KERNELIZED ) ;
return ;
no_kernel_warn :
ilog ( LOG_WARNING , " No support for kernel packet forwarding available (%s) " , nk_warn_msg ) ;
ilog ( LOG_WARNING , " No support for kernel packet forwarding available "
" (interface to kernel module not open) " ) ;
no_kernel :
PS_SET ( stream , KERNELIZED ) ;
stream - > kernel_time = rtpe_now . tv_sec ;
PS_SET ( stream , NO_KERNEL_SUPPORT ) ;
return ;
restart : // handle detected deadlock
g_list_free ( payload_types ) ;
while ( ( redi = g_queue_pop_head ( & outputs ) ) )
g_slice_free1 ( sizeof ( * redi ) , redi ) ;
// try again, releases stream->lock
}
}
// must be called with appropriate locks (master lock and/or in/out_lock)
@ -1800,9 +1830,6 @@ static void __stream_consume_stats(struct packet_stream *ps, const struct rtpeng
struct sink_handler * sh = l - > data ;
struct packet_stream * sink = sh - > sink ;
if ( mutex_trylock ( & sink - > out_lock ) )
continue ; // will have to skip this
ssrc_ctx = __hunt_ssrc_ctx ( ssrc , sink - > ssrc_out , u ) ;
if ( ! ssrc_ctx )
ssrc_ctx = __hunt_ssrc_ctx ( ssrc_map_out , sink - > ssrc_out , u ) ;
@ -1812,17 +1839,12 @@ static void __stream_consume_stats(struct packet_stream *ps, const struct rtpeng
atomic64_add ( & ssrc_ctx - > packets , stats_info - > ssrc_stats [ u ] . basic_stats . packets ) ;
atomic64_add ( & ssrc_ctx - > octets , stats_info - > ssrc_stats [ u ] . basic_stats . bytes ) ;
}
mutex_unlock ( & sink - > out_lock ) ;
}
for ( GList * l = ps - > rtcp_sinks . head ; l ; l = l - > next ) {
struct sink_handler * sh = l - > data ;
struct packet_stream * sink = sh - > sink ;
if ( mutex_trylock ( & sink - > out_lock ) )
continue ; // will have to skip this
ssrc_ctx = __hunt_ssrc_ctx ( ssrc , sink - > ssrc_out , u ) ;
if ( ! ssrc_ctx )
ssrc_ctx = __hunt_ssrc_ctx ( ssrc_map_out , sink - > ssrc_out , u ) ;
@ -1833,34 +1855,25 @@ static void __stream_consume_stats(struct packet_stream *ps, const struct rtpeng
= stats_info - > last_rtcp_index [ sh - > kernel_output_idx ] [ u ] ;
}
}
mutex_unlock ( & sink - > out_lock ) ;
}
}
}
// must be called with appropriate locks (master lock and/or in_lock)
static void __stream_update_stats ( struct packet_stream * ps , bool have_in_lock ) {
if ( ! have_in_lock )
mutex_lock ( & ps - > in_lock ) ;
// called with master_lock hekd
static void __stream_update_stats ( struct packet_stream * ps ) {
LOCK ( & ps - > lock ) ;
struct rtpengine_command_stats stats_info ;
__re_address_translate_ep ( & stats_info . local , & ps - > selected_sfd - > socket . local ) ;
if ( kernel_update_stats ( & stats_info ) ) {
if ( ! have_in_lock )
mutex_unlock ( & ps - > in_lock ) ;
if ( kernel_update_stats ( & stats_info ) )
return ;
}
__stream_consume_stats ( ps , & stats_info . stats ) ;
if ( ! have_in_lock )
mutex_unlock ( & ps - > in_lock ) ;
}
/* must be called with in_ lock held or call->master_lock held in W */
/* must be called with ps-> lock held or call->master_lock held in W */
void __unkernelize ( struct packet_stream * p , const char * reason ) {
reset_ps_kernel_stats ( p ) ;
@ -1909,9 +1922,8 @@ void __stream_unconfirm(struct packet_stream *ps, const char *reason) {
static void stream_unconfirm ( struct packet_stream * ps , const char * reason ) {
if ( ! ps )
return ;
mutex_lock ( & ps - > in_ lock) ;
LOCK ( & ps - > lock) ;
__stream_unconfirm ( ps , reason ) ;
mutex_unlock ( & ps - > in_lock ) ;
}
static void unconfirm_sinks ( GQueue * q , const char * reason ) {
for ( GList * l = q - > head ; l ; l = l - > next ) {
@ -1922,9 +1934,8 @@ static void unconfirm_sinks(GQueue *q, const char *reason) {
void unkernelize ( struct packet_stream * ps , const char * reason ) {
if ( ! ps )
return ;
mutex_lock ( & ps - > in_ lock) ;
LOCK ( & ps - > lock) ;
__unkernelize ( ps , reason ) ;
mutex_unlock ( & ps - > in_lock ) ;
}
// master lock held in R
@ -1945,7 +1956,7 @@ void media_update_stats(struct call_media *m) {
if ( ! ps - > selected_sfd )
continue ;
__stream_update_stats ( ps , false );
__stream_update_stats ( ps );
}
}
@ -1984,7 +1995,7 @@ err:
return & __sh_noop ;
}
/* must be called with call->master_lock held in R, and in-> in_ lock held */
/* must be called with call->master_lock held in R, and in-> lock held */
// `sh` can be null
static const struct streamhandler * __determine_handler ( struct packet_stream * in , struct sink_handler * sh ) {
const struct transport_protocol * in_proto , * out_proto ;
@ -2091,7 +2102,7 @@ static const char *__stream_ssrc_inout(struct packet_stream *ps, uint32_t ssrc,
static const char * __stream_ssrc_in ( struct packet_stream * in_srtp , uint32_t ssrc_bs ,
struct ssrc_ctx * * ssrc_in_p , struct ssrc_hash * ssrc_hash )
{
return __stream_ssrc_inout ( in_srtp , ntohl ( ssrc_bs ) , & in_srtp - > in_ lock, in_srtp - > ssrc_in ,
return __stream_ssrc_inout ( in_srtp , ntohl ( ssrc_bs ) , & in_srtp - > lock, in_srtp - > ssrc_in ,
& in_srtp - > ssrc_in_idx , 0 , ssrc_in_p , ssrc_hash , SSRC_DIR_INPUT , " ingress " ) ;
}
// check and update output SSRC pointers
@ -2101,12 +2112,12 @@ static const char *__stream_ssrc_out(struct packet_stream *out_srtp, uint32_t ss
bool ssrc_change )
{
if ( ssrc_change )
return __stream_ssrc_inout ( out_srtp , ssrc_in - > ssrc_map_out , & out_srtp - > out_ lock,
return __stream_ssrc_inout ( out_srtp , ssrc_in - > ssrc_map_out , & out_srtp - > lock,
out_srtp - > ssrc_out ,
& out_srtp - > ssrc_out_idx , ntohl ( ssrc_bs ) , ssrc_out_p , ssrc_hash , SSRC_DIR_OUTPUT ,
" egress (mapped) " ) ;
return __stream_ssrc_inout ( out_srtp , ntohl ( ssrc_bs ) , & out_srtp - > out_ lock,
return __stream_ssrc_inout ( out_srtp , ntohl ( ssrc_bs ) , & out_srtp - > lock,
out_srtp - > ssrc_out ,
& out_srtp - > ssrc_out_idx , 0 , ssrc_out_p , ssrc_hash , SSRC_DIR_OUTPUT ,
" egress (direct) " ) ;
@ -2131,14 +2142,13 @@ static int media_demux_protocols(struct packet_handler_ctx *phc) {
}
}
mutex_lock ( & phc - > mp . stream - > in_ lock) ;
LOCK ( & phc - > mp . stream - > lock) ;
int ret = dtls ( phc - > mp . sfd , & phc - > s , & phc - > mp . fsin ) ;
if ( ret = = 1 ) {
phc - > unkernelize = " DTLS connected " ;
phc - > unkernelize_subscriptions = true ;
ret = 0 ;
}
mutex_unlock ( & phc - > mp . stream - > in_lock ) ;
if ( ! ret )
return 0 ;
}
@ -2163,7 +2173,7 @@ static int media_demux_protocols(struct packet_handler_ctx *phc) {
# if RTP_LOOP_PROTECT
// returns: 0 = ok, proceed; -1 = duplicate detected, drop packet
static int media_loop_detect ( struct packet_handler_ctx * phc ) {
mutex_lock ( & phc - > mp . stream - > in_ lock) ;
mutex_lock ( & phc - > mp . stream - > lock) ;
for ( int i = 0 ; i < RTP_LOOP_PACKETS ; i + + ) {
if ( phc - > mp . stream - > lp_buf [ i ] . len ! = phc - > s . len )
@ -2177,7 +2187,7 @@ static int media_loop_detect(struct packet_handler_ctx *phc) {
" to avoid potential loop " ,
RTP_LOOP_MAX_COUNT ,
FMT_M ( endpoint_print_buf ( & phc - > mp . fsin ) ) ) ;
mutex_unlock ( & phc - > mp . stream - > in_ lock) ;
mutex_unlock ( & phc - > mp . stream - > lock) ;
return - 1 ;
}
@ -2191,7 +2201,7 @@ static int media_loop_detect(struct packet_handler_ctx *phc) {
memcpy ( phc - > mp . stream - > lp_buf [ phc - > mp . stream - > lp_idx ] . buf , phc - > s . s , MIN ( phc - > s . len , RTP_LOOP_PROTECT ) ) ;
phc - > mp . stream - > lp_idx = ( phc - > mp . stream - > lp_idx + 1 ) % RTP_LOOP_PACKETS ;
loop_ok :
mutex_unlock ( & phc - > mp . stream - > in_ lock) ;
mutex_unlock ( & phc - > mp . stream - > lock) ;
return 0 ;
}
@ -2310,7 +2320,7 @@ static void media_packet_rtp_out(struct packet_handler_ctx *phc, struct sink_han
static int media_packet_decrypt ( struct packet_handler_ctx * phc )
{
mutex_lock ( & phc - > in_srtp - > in_ lock) ;
mutex_lock ( & phc - > in_srtp - > lock) ;
struct sink_handler * first_sh = phc - > sinks - > length ? phc - > sinks - > head - > data : NULL ;
const struct streamhandler * sh = __determine_handler ( phc - > in_srtp , first_sh ) ;
@ -2331,7 +2341,7 @@ static int media_packet_decrypt(struct packet_handler_ctx *phc)
phc - > mp . payload . len - = ori_s . len - phc - > s . len ;
}
mutex_unlock ( & phc - > in_srtp - > in_ lock) ;
mutex_unlock ( & phc - > in_srtp - > lock) ;
if ( ret = = 1 ) {
phc - > update = true ;
@ -2341,7 +2351,7 @@ static int media_packet_decrypt(struct packet_handler_ctx *phc)
}
static void media_packet_set_encrypt ( struct packet_handler_ctx * phc , struct sink_handler * sh )
{
mutex_lock ( & phc - > in_srtp - > in_ lock) ;
mutex_lock ( & phc - > in_srtp - > lock) ;
__determine_handler ( phc - > in_srtp , sh ) ;
// XXX use an array with index instead of if/else
@ -2351,7 +2361,7 @@ static void media_packet_set_encrypt(struct packet_handler_ctx *phc, struct sink
phc - > encrypt_func = sh - > handler - > out - > rtcp_crypt ;
phc - > rtcp_filter = sh - > handler - > in - > rtcp_filter ;
}
mutex_unlock ( & phc - > in_srtp - > in_ lock) ;
mutex_unlock ( & phc - > in_srtp - > lock) ;
}
int media_packet_encrypt ( rewrite_func encrypt_func , struct packet_stream * out , struct media_packet * mp ) {
@ -2360,7 +2370,7 @@ int media_packet_encrypt(rewrite_func encrypt_func, struct packet_stream *out, s
if ( ! encrypt_func )
return 0x00 ;
mutex_lock ( & out - > out_ lock) ;
LOCK ( & out - > lock) ;
for ( GList * l = mp - > packets_out . head ; l ; l = l - > next ) {
struct codec_packet * p = l - > data ;
@ -2375,8 +2385,6 @@ int media_packet_encrypt(rewrite_func encrypt_func, struct packet_stream *out, s
ret | = 0x01 ;
}
mutex_unlock ( & out - > out_lock ) ;
return ret ;
}
@ -2403,7 +2411,7 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
struct endpoint endpoint ;
bool ret = false ;
mutex_lock ( & phc - > mp . stream - > in_ lock) ;
mutex_lock ( & phc - > mp . stream - > lock) ;
/* we're OK to (potentially) use the source address of this packet as destination
* in the other direction . */
@ -2432,10 +2440,8 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
/* do not pay attention to source addresses of incoming packets for asymmetric streams */
if ( MEDIA_ISSET ( phc - > mp . media , ASYMMETRIC ) | | phc - > mp . stream - > el_flags = = EL_OFF ) {
PS_SET ( phc - > mp . stream , CONFIRMED ) ;
mutex_lock ( & phc - > mp . stream - > out_lock ) ;
if ( MEDIA_ISSET ( phc - > mp . media , ASYMMETRIC ) & & ! phc - > mp . stream - > learned_endpoint . address . family )
phc - > mp . stream - > learned_endpoint = phc - > mp . fsin ;
mutex_unlock ( & phc - > mp . stream - > out_lock ) ;
}
/* confirm sinks for unidirectional streams in order to kernelize */
@ -2451,7 +2457,6 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
/* see if we need to compare the source address with the known endpoint */
if ( PS_ISSET2 ( phc - > mp . stream , STRICT_SOURCE , MEDIA_HANDOVER ) ) {
endpoint = phc - > mp . fsin ;
mutex_lock ( & phc - > mp . stream - > out_lock ) ;
struct endpoint * ps_endpoint = MEDIA_ISSET ( phc - > mp . media , ASYMMETRIC ) ?
& phc - > mp . stream - > learned_endpoint : & phc - > mp . stream - > endpoint ;
@ -2467,8 +2472,6 @@ static bool media_packet_address_check(struct packet_handler_ctx *phc)
goto update_addr ;
}
mutex_unlock ( & phc - > mp . stream - > out_lock ) ;
if ( tmp & & PS_ISSET ( phc - > mp . stream , STRICT_SOURCE ) ) {
ilog ( LOG_INFO | LOG_FLAG_LIMIT , " Drop due to strict-source attribute; "
" got %s%s:%d%s, "
@ -2542,7 +2545,6 @@ confirm_now:
PS_SET ( phc - > mp . stream , CONFIRMED ) ;
update_peerinfo :
mutex_lock ( & phc - > mp . stream - > out_lock ) ;
// if we're during the wait time, check the received address against the previously
// learned address. if they're the same, ignore this packet for learning purposes
if ( ! wait_time | | ! phc - > mp . stream - > learned_endpoint . address . family | |
@ -2561,8 +2563,6 @@ update_peerinfo:
}
}
update_addr :
mutex_unlock ( & phc - > mp . stream - > out_lock ) ;
/* check the destination address of the received packet against what we think our
* local interface to use is */
if ( phc - > mp . stream - > selected_sfd & & phc - > mp . sfd ! = phc - > mp . stream - > selected_sfd ) {
@ -2585,7 +2585,7 @@ update_addr:
}
out :
mutex_unlock ( & phc - > mp . stream - > in_ lock) ;
mutex_unlock ( & phc - > mp . stream - > lock) ;
return ret ;
}
@ -2605,9 +2605,7 @@ static void media_packet_kernel_check(struct packet_handler_ctx *phc) {
if ( ML_ISSET ( phc - > mp . media - > monologue , DTMF_INJECTION_ACTIVE ) )
return ;
mutex_lock ( & phc - > mp . stream - > in_lock ) ;
kernelize ( phc - > mp . stream ) ;
mutex_unlock ( & phc - > mp . stream - > in_lock ) ;
}
@ -2996,19 +2994,19 @@ static int stream_packet(struct packet_handler_ctx *phc) {
if ( ret )
goto next_mirror ;
mutex_lock ( & mirror_sink - > out_ lock) ;
mutex_lock ( & mirror_sink - > lock) ;
if ( ! mirror_sink - > advertised_endpoint . port
| | ( is_addr_unspecified ( & mirror_sink - > advertised_endpoint . address )
& & ! is_trickle_ice_address ( & mirror_sink - > advertised_endpoint ) ) )
{
mutex_unlock ( & mirror_sink - > out_ lock) ;
mutex_unlock ( & mirror_sink - > lock) ;
goto next_mirror ;
}
media_socket_dequeue ( & mirror_phc . mp , mirror_sink ) ;
mutex_unlock ( & mirror_sink - > out_ lock) ;
mutex_unlock ( & mirror_sink - > lock) ;
next_mirror :
media_socket_dequeue ( & mirror_phc . mp , NULL ) ; // just free if anything left
@ -3034,13 +3032,13 @@ next_mirror:
}
}
mutex_lock ( & sink - > out_ lock) ;
mutex_lock ( & sink - > lock) ;
if ( ! sink - > advertised_endpoint . port
| | ( is_addr_unspecified ( & sink - > advertised_endpoint . address )
& & ! is_trickle_ice_address ( & sink - > advertised_endpoint ) ) )
{
mutex_unlock ( & sink - > out_ lock) ;
mutex_unlock ( & sink - > lock) ;
goto next ;
}
@ -3049,18 +3047,18 @@ next_mirror:
else
ret = media_socket_dequeue ( & phc - > mp , NULL ) ;
mutex_unlock ( & sink - > out_ lock) ;
mutex_unlock ( & sink - > lock) ;
if ( ret = = 0 )
goto next ;
err_next :
ilog ( LOG_DEBUG | LOG_FLAG_LIMIT , " Error when sending message. Error: %s " , strerror ( errno ) ) ;
mutex_lock ( & sink - > in_lock ) ;
atomic64_inc ( & sink - > stats_in . errors ) ;
mutex_lock ( & sink - > lock ) ;
if ( sink - > selected_sfd )
atomic64_inc ( & sink - > selected_sfd - > local_intf - > stats . out . errors ) ;
mutex_unlock ( & sink - > in_ lock) ;
mutex_unlock ( & sink - > lock) ;
RTPE_STATS_INC ( errors_user ) ;
goto next ;
@ -3537,7 +3535,7 @@ enum thread_looper_action kernel_stats_updater(void) {
atomic64_set ( & sink - > kernel_stats_out . packets , stats_o - > packets ) ;
atomic64_set ( & sink - > kernel_stats_out . errors , stats_o - > errors ) ;
mutex_lock ( & sink - > out_ lock) ;
mutex_lock ( & sink - > lock) ;
for ( unsigned int u = 0 ; u < G_N_ELEMENTS ( ke - > target . ssrc ) ; u + + ) {
if ( ! ke - > target . ssrc [ u ] ) // end of list
break ;
@ -3565,10 +3563,10 @@ enum thread_looper_action kernel_stats_updater(void) {
update = true ;
}
}
mutex_unlock ( & sink - > out_ lock) ;
mutex_unlock ( & sink - > lock) ;
}
mutex_lock ( & ps - > in_ lock) ;
mutex_lock ( & ps - > lock) ;
for ( unsigned int u = 0 ; u < G_N_ELEMENTS ( ke - > target . ssrc ) ; u + + ) {
if ( ! ke - > target . ssrc [ u ] ) // end of list
@ -3594,7 +3592,7 @@ enum thread_looper_action kernel_stats_updater(void) {
update = true ;
}
}
mutex_unlock ( & ps - > in_ lock) ;
mutex_unlock ( & ps - > lock) ;
}
rwlock_unlock_r ( & sfd - > call - > master_lock ) ;