Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit 9c9d335
Author: Lionel Nicolas <[email protected]>
Date:   Thu Jun 10 03:04:43 2021 -0400

    Fix streaming plugin mutex unlock when disabling mountpoint (meetecho#2690)

commit 2d83e96
Author: Yurii Cherniavskyi <[email protected]>
Date:   Mon Jun 7 16:02:41 2021 +0300

    Fix SIP plugin unhold request docs typo (meetecho#2688)

commit 2cd0118
Author: August Black <[email protected]>
Date:   Mon Jun 7 01:10:49 2021 -0700

    minor adjustment to the audiobridge docs (meetecho#2687)

commit de2117e
Author: nicolasduteil <[email protected]>
Date:   Tue Jun 1 11:26:29 2021 +0200

    fix: [janus_sip] Fix "call_id" property in "missed_call" events (meetecho#2679)

commit 9eeeb38
Author: Alessandro Toppi <[email protected]>
Date:   Mon May 31 15:57:41 2021 +0200

    Fix status vector parsing for incoming twcc feedbacks (resolves meetecho#2677).

commit 8a25f6e
Merge: d3b39b9 394fb48
Author: Alessandro Toppi <[email protected]>
Date:   Fri May 28 13:29:54 2021 +0200

    Merge pull request meetecho#2675 from kmeyerhofer/actions/fix

    GH Actions, fix variable name

commit d3b39b9
Author: Lorenzo Miniero <[email protected]>
Date:   Fri May 28 11:09:30 2021 +0200

    Fixed race condition in VideoRoom

commit 394fb48
Author: Kurt Meyerhofer <[email protected]>
Date:   Thu May 27 14:52:08 2021 -0600

    Fixes variable name.

commit b45cd37
Author: Lorenzo Miniero <[email protected]>
Date:   Thu May 27 18:31:55 2021 +0200

    Clarify that libnice 0.1.18 is recommended

commit 5757a37
Author: Lorenzo Miniero <[email protected]>
Date:   Thu May 27 17:08:17 2021 +0200

    Spatial audio support in AudioBridge via stereo mixing (meetecho#2446)

commit 161fe7a
Author: Luca Barbato <[email protected]>
Date:   Thu May 27 15:29:01 2021 +0200

    Cleanup avformat-based preprocessors (meetecho#2665)

commit 7b010cd
Author: lucylu-star <[email protected]>
Date:   Tue May 25 17:09:40 2021 +0800

    Fixed broken simulcast support in VideoCall plugin (meetecho#2671)

commit 4ae44a4
Author: nicolasduteil <[email protected]>
Date:   Mon May 24 17:57:34 2021 +0200

    feat: support for custom call-id in subscribe request + add 'call_id' property to subscribe & notify related events (meetecho#2664)

commit 4294f20
Author: Lorenzo Miniero <[email protected]>
Date:   Mon May 24 11:02:48 2021 +0200

    Fixed missing macro when using pthread mutexes (fixes meetecho#2666)

commit f22ab0d
Author: Lorenzo Miniero <[email protected]>
Date:   Wed May 19 12:03:32 2021 +0200

    Fixed warning

commit b3f3f17
Author: Alessandro Toppi <[email protected]>
Date:   Tue May 18 12:10:47 2021 +0200

    Remove duplicated flag for fuzzing coverage.

commit 4a7560c
Author: nu774 <[email protected]>
Date:   Fri May 14 00:26:36 2021 +0900

    janus-pp-rec: support HEVC AP(aggregation packet) (meetecho#2662)

commit 5db4be2
Author: Lorenzo Miniero <[email protected]>
Date:   Wed May 12 17:43:43 2021 +0200

    Fixed out of bounds array access

commit 69f56f4
Author: nicolasduteil <[email protected]>
Date:   Tue May 11 14:36:22 2021 +0200

    feat: support for SUBSCRIBE expiry (Expires header) in sip plugin (meetecho#2661)

commit b047ccf
Author: Lorenzo Miniero <[email protected]>
Date:   Mon May 10 09:33:27 2021 +0200

    Fixed types

commit f8e8c5e
Author: Chris Wiggins <[email protected]>
Date:   Mon May 10 19:26:45 2021 +1200

    RabbitMQ Transport Reconnect Logic (meetecho#2651)

commit 280e8e4
Author: Lorenzo Miniero <[email protected]>
Date:   Fri May 7 12:54:30 2021 +0200

    Add per-participant recording options in AudioBridge to join API as well
  • Loading branch information
Kirill committed Jun 10, 2021
1 parent ede1660 commit 69df84b
Show file tree
Hide file tree
Showing 30 changed files with 1,112 additions and 959 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/janus-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
datachannels: ["yes", "no"]
libcurl: ["yes", "no"]
include:
- datachannel: "yes"
- datachannels: "yes"
libcurl: "yes"
deps_from_src: "yes"
janus_config_opts: ""
Expand Down
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,8 @@ janus_pp_rec_SOURCES = \
postprocessing/pp-h264.h \
postprocessing/pp-av1.c \
postprocessing/pp-av1.h \
postprocessing/pp-avformat.c \
postprocessing/pp-avformat.h \
postprocessing/pp-h265.c \
postprocessing/pp-h265.h \
postprocessing/pp-opus.c \
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ To install it, you'll need to satisfy the following dependencies:

* [Jansson](http://www.digip.org/jansson/)
* [libconfig](https://hyperrealm.github.io/libconfig/)
* [libnice](https://libnice.freedesktop.org/) (at least v0.1.16 suggested, master recommended)
* [libnice](https://libnice.freedesktop.org/) (at least v0.1.16 suggested, v0.1.18 recommended)
* [OpenSSL](http://www.openssl.org/) (at least v1.0.1e)
* [libsrtp](https://github.com/cisco/libsrtp) (at least v2.x suggested)
* [usrsctp](https://github.com/sctplab/usrsctp) (only needed if you are interested in Data Channels)
Expand Down
2 changes: 1 addition & 1 deletion conf/janus.eventhandler.rabbitmqevh.jcfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ general: {
#exchange = "janus-exchange"
route_key = "janus-events" # Routing key to use when publishing messages
#exchange_type = "fanout" # Rabbitmq exchange_type can be one of the available types: direct, topic, headers and fanout (fanout by defualt).
#heartbeat = 60 # Defines the seconds without communication that should pass before considering the TCP connection has unreachable.
#heartbeat = 60 # Defines the seconds without communication that should pass before considering the TCP connection unreachable.
#declare_outgoing_queue = true # By default (for backwards compatibility), we declare an outgoing queue. Set this to false to disable that behavior

#ssl_enable = false # Whether ssl support must be enabled
Expand Down
1 change: 1 addition & 0 deletions conf/janus.plugin.audiobridge.jcfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# secret = "<optional password needed for manipulating (e.g. destroying) the room>"
# pin = "<optional password needed for joining the room>"
# sampling_rate = <sampling rate> (e.g., 16000 for wideband mixing)
# spatial_audio = true|false (if true, the mix will be stereo to spatially place users, default=false)
# audiolevel_ext = true|false (whether the ssrc-audio-level RTP extension must
# be negotiated/used or not for new joins, default=true)
# audiolevel_event = true|false (whether to emit event to other users or not, default=false)
Expand Down
1 change: 1 addition & 0 deletions conf/janus.transport.rabbitmq.jcfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ general: {
#queue_durable = false # Whether or not incoming queue should remain after a RabbitMQ reboot
#queue_autodelete = false # Whether or not incoming queue should autodelete after janus disconnects from RabbitMQ
#queue_exclusive = false # Whether or not incoming queue should only allow one subscriber
#heartbeat = 60 # Defines the seconds without communication that should pass before considering the TCP connection unreachable.

#ssl_enabled = false # Whether ssl support must be enabled
#ssl_verify_peer = true # Whether peer verification must be enabled
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ AC_CHECK_LIB([rabbitmq],
AC_DEFINE(HAVE_RABBITMQEVH)
enable_rabbitmq_event_handler=yes
])
AC_CHECK_HEADERS([rabbitmq-c/amqp.h])
],
[
AS_IF([test "x$enable_rabbitmq" = "xyes"],
Expand Down
68 changes: 34 additions & 34 deletions events/janus_rabbitmqevh.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,18 @@

#include <math.h>

/* Latest RabbitMQ-C library changes the library paths from 0.12.0.0 onwards */
#ifdef HAVE_RABBITMQ_C_AMQP_H
#include <rabbitmq-c/amqp.h>
#include <rabbitmq-c/framing.h>
#include <rabbitmq-c/tcp_socket.h>
#include <rabbitmq-c/ssl_socket.h>
#else
#include <amqp.h>
#include <amqp_framing.h>
#include <amqp_tcp_socket.h>
#include <amqp_ssl_socket.h>
#endif

#include "../debug.h"
#include "../config.h"
Expand Down Expand Up @@ -177,7 +185,7 @@ int janus_rabbitmqevh_init(const char *config_path) {
/* Compact, so no spaces between separators */
json_format = JSON_COMPACT | JSON_PRESERVE_ORDER;
} else {
JANUS_LOG(LOG_WARN, "Unsupported JSON format option '%s', using default (indented)\n", item->value);
JANUS_LOG(LOG_WARN, "RabbitMQEventHandler: Unsupported JSON format option '%s', using default (indented)\n", item->value);
json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER;
}
}
Expand Down Expand Up @@ -224,7 +232,7 @@ int janus_rabbitmqevh_init(const char *config_path) {

item = janus_config_get(config, config_general, janus_config_type_item, "heartbeat");
if(item && item->value && janus_string_to_uint16(item->value, &heartbeat) < 0) {
JANUS_LOG(LOG_ERR, "Invalid heartbeat timeout (%s), falling back to default\n", item->value);
JANUS_LOG(LOG_ERR, "RabbitMQEventHandler: Invalid heartbeat timeout (%s), falling back to default (0, disabling heartbeat)\n", item->value);
heartbeat = 0;
}

Expand Down Expand Up @@ -279,9 +287,9 @@ int janus_rabbitmqevh_init(const char *config_path) {
exchange = g_strdup(item->value);
}
if (exchange == NULL) {
JANUS_LOG(LOG_INFO, "RabbitMQ event handler enabled, %s:%d (%s) exchange_type:%s\n", rmqhost, rmqport, route_key,exchange_type);
JANUS_LOG(LOG_INFO, "RabbitMQEventHandler: enabled, %s:%d (%s) exchange_type:%s\n", rmqhost, rmqport, route_key,exchange_type);
} else {
JANUS_LOG(LOG_INFO, "RabbitMQ event handler enabled, %s:%d (%s) exch: (%s) exchange_type:%s\n", rmqhost, rmqport, route_key, exchange,exchange_type);
JANUS_LOG(LOG_INFO, "RabbitMQEventHandler: enabled, %s:%d (%s) exch: (%s) exchange_type:%s\n", rmqhost, rmqport, route_key, exchange,exchange_type);
}

/* Connect */
Expand All @@ -300,7 +308,7 @@ int janus_rabbitmqevh_init(const char *config_path) {
handler_thread = g_thread_try_new("janus rabbitmqevh handler", jns_rmqevh_hdlr, NULL, &error);
if(error != NULL) {
g_atomic_int_set(&initialized, 0);
JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to launch the RabbitMQEventHandler handler thread...\n",
JANUS_LOG(LOG_FATAL, "RabbitMQEventHandler: Got error %d (%s) trying to launch the RabbitMQEventHandler handler thread...\n",
error->code, error->message ? error->message : "??");
g_error_free(error);
goto error;
Expand All @@ -309,7 +317,7 @@ int janus_rabbitmqevh_init(const char *config_path) {
in_thread = g_thread_try_new("janus rabbitmqevh heartbeat handler", jns_rmqevh_hrtbt, NULL, &error);
if(error != NULL) {
g_atomic_int_set(&initialized, 0);
JANUS_LOG(LOG_FATAL, "Got error %d (%s) trying to launch the RabbitMQEventHandler heartbeat thread...\n",
JANUS_LOG(LOG_FATAL, "RabbitMQEventHandler: Got error %d (%s) trying to launch the RabbitMQEventHandler heartbeat thread...\n",
error->code, error->message ? error->message : "??");
g_error_free(error);
goto error;
Expand Down Expand Up @@ -350,16 +358,10 @@ int janus_rabbitmqevh_connect(void) {
JANUS_LOG(LOG_FATAL, "RabbitMQEventHandler: Can't connect to RabbitMQ server: error creating socket...\n");
return -1;
}
if(ssl_verify_peer) {
amqp_ssl_socket_set_verify_peer(socket, 1);
} else {
amqp_ssl_socket_set_verify_peer(socket, 0);
}
if(ssl_verify_hostname) {
amqp_ssl_socket_set_verify_hostname(socket, 1);
} else {
amqp_ssl_socket_set_verify_hostname(socket, 0);
}

amqp_ssl_socket_set_verify_peer(socket, ssl_verify_peer);
amqp_ssl_socket_set_verify_hostname(socket, ssl_verify_hostname);

if(ssl_cacert_file) {
status = amqp_ssl_socket_set_cacert(socket, ssl_cacert_file);
if(status != AMQP_STATUS_OK) {
Expand All @@ -385,7 +387,7 @@ int janus_rabbitmqevh_connect(void) {
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: Connecting to RabbitMQ server...\n");
status = amqp_socket_open(socket, rmqhost, rmqport);
if(status != AMQP_STATUS_OK) {
JANUS_LOG(LOG_FATAL, "Can't connect to RabbitMQ server: error opening socket... (%s)\n", amqp_error_string2(status));
JANUS_LOG(LOG_FATAL, "RabbitMQEventHandler: Can't connect to RabbitMQ server: error opening socket... (%s)\n", amqp_error_string2(status));
return -1;
}
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: Logging in...\n");
Expand All @@ -410,13 +412,13 @@ int janus_rabbitmqevh_connect(void) {
amqp_exchange_declare(rmq_conn, rmq_channel, rmq_exchange, amqp_cstring_bytes(exchange_type), 0, 0, 0, 0, amqp_empty_table);
result = amqp_get_rpc_reply(rmq_conn);
if(result.reply_type != AMQP_RESPONSE_NORMAL) {
JANUS_LOG(LOG_FATAL, "RabbitMQEventHandler: Can't connect to RabbitMQ server: error diclaring exchange... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
JANUS_LOG(LOG_FATAL, "RabbitMQEventHandler: Can't connect to RabbitMQ server: error declaring exchange... %s, %s\n", amqp_error_string2(result.library_error), amqp_method_name(result.reply.id));
return -1;
}
}

if (declare_outgoing_queue) {
JANUS_LOG(LOG_VERB, "Declaring outgoing queue... (%s)\n", route_key);
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: Declaring outgoing queue... (%s)\n", route_key);
amqp_queue_declare(rmq_conn, rmq_channel, amqp_cstring_bytes(route_key), 0, 0, 0, 0, amqp_empty_table);
result = amqp_get_rpc_reply(rmq_conn);
if(result.reply_type != AMQP_RESPONSE_NORMAL) {
Expand All @@ -425,6 +427,8 @@ int janus_rabbitmqevh_connect(void) {
}
}

JANUS_LOG(LOG_INFO, "RabbitMQEventHandler: Connected successfully");

return 0;
}

Expand All @@ -446,9 +450,7 @@ void janus_rabbitmqevh_destroy(void) {
g_async_queue_unref(events);
events = NULL;

if(rmq_conn && rmq_channel) {
amqp_channel_close(rmq_conn, rmq_channel, AMQP_REPLY_SUCCESS);
amqp_connection_close(rmq_conn, AMQP_REPLY_SUCCESS);
if(rmq_conn) {
amqp_destroy_connection(rmq_conn);
}
if(rmq_exchange.bytes)
Expand Down Expand Up @@ -548,7 +550,7 @@ json_t *janus_rabbitmqevh_handle_request(json_t *request) {
if(json_object_get(request, "grouping"))
group_events = json_is_true(json_object_get(request, "grouping"));
} else {
JANUS_LOG(LOG_VERB, "Unknown request '%s'\n", request_text);
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: Unknown request '%s'\n", request_text);
error_code = JANUS_RABBITMQEVH_ERROR_INVALID_REQUEST;
g_snprintf(error_cause, 512, "Unknown request '%s'", request_text);
}
Expand All @@ -570,7 +572,7 @@ json_t *janus_rabbitmqevh_handle_request(json_t *request) {

/* Thread to handle incoming events */
static void *jns_rmqevh_hdlr(void *data) {
JANUS_LOG(LOG_VERB, "Joining RabbitMQEventHandler handler thread\n");
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: joining handler thread\n");
json_t *event = NULL, *output = NULL;
char *event_text = NULL;
int count = 0, max = group_events ? 100 : 1;
Expand All @@ -589,7 +591,7 @@ static void *jns_rmqevh_hdlr(void *data) {
if(created && json_is_integer(created)) {
gint64 then = json_integer_value(created);
gint64 now = janus_get_monotonic_time();
JANUS_LOG(LOG_DBG, "Handled event after %"SCNu64" us\n", now-then);
JANUS_LOG(LOG_DBG, "RabbitMQEventHandler: Handled event after %"SCNu64" us\n", now-then);
}
if(!group_events) {
/* We're done here, we just need a single event */
Expand All @@ -613,7 +615,7 @@ static void *jns_rmqevh_hdlr(void *data) {
/* Since this a simple plugin, it does the same for all events: so just convert to string... */
event_text = json_dumps(output, json_format);
if(event_text == NULL) {
JANUS_LOG(LOG_WARN, "Failed to stringify event, event lost...\n");
JANUS_LOG(LOG_WARN, "RabbitMQEventHandler: Failed to stringify event, event lost...\n");
/* Nothing we can do... get rid of the event */
json_decref(output);
output = NULL;
Expand All @@ -638,14 +640,14 @@ static void *jns_rmqevh_hdlr(void *data) {
json_decref(output);
output = NULL;
}
JANUS_LOG(LOG_VERB, "Leaving RabbitMQEventHandler handler thread\n");
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: leaving handler thread\n");
return NULL;
}


/* Thread to handle heartbeats */
static void *jns_rmqevh_hrtbt(void *data) {
JANUS_LOG(LOG_VERB, "Monitoring RabbitMQ HeartBeat\n");
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: Monitoring RabbitMQ Heartbeat\n");
int waiting_usec = (heartbeat/2) * 1000000;
struct timeval timeout;
timeout.tv_sec = 0;
Expand All @@ -666,15 +668,13 @@ static void *jns_rmqevh_hrtbt(void *data) {
continue;
}

JANUS_LOG(LOG_VERB, "Error on amqp_simple_wait_frame_noblock: %d (%s)\n", res, amqp_error_string2(res));
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: Error on amqp_simple_wait_frame_noblock: %d (%s)\n", res, amqp_error_string2(res));

if(rmq_conn && rmq_channel) {
amqp_channel_close(rmq_conn, rmq_channel, AMQP_REPLY_SUCCESS);
amqp_connection_close(rmq_conn, AMQP_REPLY_SUCCESS);
if(rmq_conn) {
amqp_destroy_connection(rmq_conn);
}
if(!g_atomic_int_get(&stopping)) {
JANUS_LOG(LOG_VERB, "Trying to reconnect with RabbitMQ Server\n");
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: Trying to reconnect\n");
int result = janus_rabbitmqevh_connect();
if(result < 0) {
g_usleep(5000000);
Expand All @@ -688,6 +688,6 @@ static void *jns_rmqevh_hrtbt(void *data) {
}
}

JANUS_LOG(LOG_VERB, "Leaving RabbitMQEventHandler HeartBeat thread\n");
JANUS_LOG(LOG_VERB, "RabbitMQEventHandler: Leaving HeartBeat thread\n");
return NULL;
}
2 changes: 1 addition & 1 deletion fuzzers/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ DEFAULT_CC="clang"
DEFAULT_CCLD=$DEFAULT_CC
DEFAULT_CFLAGS="-O1 -fno-omit-frame-pointer -g -ggdb3 -fsanitize=address,undefined -fsanitize-address-use-after-scope -fno-sanitize-recover=undefined -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
DEFAULT_LDFLAGS="-O1 -fno-omit-frame-pointer -g -ggdb3 -fsanitize=address,undefined -fno-sanitize-recover=undefined -fsanitize-address-use-after-scope"
COVERAGE_CFLAGS="-O1 -fno-omit-frame-pointer -g -ggdb3 -fprofile-instr-generate -fcoverage-mapping -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
COVERAGE_CFLAGS="-O1 -fno-omit-frame-pointer -g -ggdb3 -fprofile-instr-generate -fcoverage-mapping -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
COVERAGE_LDFLAGS="-O1 -fno-omit-frame-pointer -g -ggdb3 -fprofile-instr-generate -fcoverage-mapping -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"

# Janus configure flags
Expand Down
5 changes: 4 additions & 1 deletion html/audiobridgetest.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/5.4.0/bootbox.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/10.6.2/bootstrap-slider.min.js"></script>
<script type="text/javascript" src="janus.js" ></script>
<script type="text/javascript" src="audiobridgetest.js"></script>
<script>
Expand All @@ -25,6 +26,7 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootswatch/3.4.0/cerulean/bootstrap.min.css" type="text/css"/>
<link rel="stylesheet" href="css/demo.css" type="text/css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" type="text/css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/10.6.2/css/bootstrap-slider.css" type="text/css"/>
</head>
<body>

Expand Down Expand Up @@ -80,7 +82,8 @@ <h3>Demo details</h3>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Participants <span class="label label-info hide" id="participant"></span>
<button class="btn-xs btn-danger hide pull-right" autocomplete="off" id="toggleaudio">Mute</button></h3>
<button class="btn-xs btn-danger hide pull-right" autocomplete="off" id="toggleaudio">Mute</button>
<button class="btn-xs btn-primary hide pull-right" autocomplete="off" id="position">Position</button></h3>
</div>
<div class="panel-body">
<ul id="list" class="list-group">
Expand Down
Loading

0 comments on commit 69df84b

Please sign in to comment.