Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions api.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,166 @@ switch_status_t apiJoin(const char *pUrl, const char *pSecret,
return result;
}

/* Join and configure in one request: join body + jsep offer (room id + SDP offer in same message) */
switch_status_t apiJoinAndConfigure(const char *pUrl, const char *pSecret,
const janus_id_t serverId, const janus_id_t senderId, const janus_id_t roomId, const char *pRoomIdStr,
const char *pDisplay, const char *pPin, const char *pToken, const char *callId,
const switch_bool_t muted, switch_bool_t record, const char *pRecordingFile,
const char *pType, const char *pSdp) {
message_t request, *pResponse = NULL;
switch_status_t result = SWITCH_STATUS_SUCCESS;

cJSON *pJsonRequest = NULL;
cJSON *pJsonResponse = NULL;
char *pTransactionId = generateTransactionId();
char url[1024];

switch_assert(pUrl);
switch_assert(pType);
switch_assert(pSdp);

(void) memset((void *) &request, 0, sizeof(request));
request.pType = "message";
request.serverId = serverId;
request.pTransactionId = pTransactionId;
request.pSecret = pSecret;

request.pJsonBody = cJSON_CreateObject();
if (request.pJsonBody == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create body\n");
result = SWITCH_STATUS_FALSE;
goto done;
}

if (cJSON_AddStringToObject(request.pJsonBody, "request", "join") == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (body.request)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}

if (pRoomIdStr && *pRoomIdStr != '\0') {
if (cJSON_AddStringToObject(request.pJsonBody, "room", pRoomIdStr) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (body.room)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
} else if (cJSON_AddNumberToObject(request.pJsonBody, "room", roomId) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create number (body.room)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}

if (pPin) {
if (cJSON_AddStringToObject(request.pJsonBody, "pin", pPin) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (body.pin)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
}

if (pDisplay) {
if (cJSON_AddStringToObject(request.pJsonBody, "display", pDisplay) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (body.display)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
}

if (pToken) {
if (cJSON_AddStringToObject(request.pJsonBody, "token", pToken) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (body.token)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
}

if (callId) {
if (cJSON_AddStringToObject(request.pJsonBody, "opaque_id", callId) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (body.opaque_id)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
}

/* configure params in same body */
if (cJSON_AddBoolToObject(request.pJsonBody, "muted", (cJSON_bool) muted) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create boolean (body.muted)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
if (cJSON_AddBoolToObject(request.pJsonBody, "record", (cJSON_bool) record) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create boolean (body.record)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
if (pRecordingFile) {
if (cJSON_AddStringToObject(request.pJsonBody, "filename", pRecordingFile) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (body.filename)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
}

/* jsep: offer SDP */
request.pJsonJsep = cJSON_CreateObject();
if (request.pJsonJsep == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create jsep\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
if (cJSON_AddStringToObject(request.pJsonJsep, "type", pType) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (jsep.type)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
if (cJSON_AddFalseToObject(request.pJsonJsep, "trickle") == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create jsep.trickle\n");
result = SWITCH_STATUS_FALSE;
goto done;
}
if (cJSON_AddStringToObject(request.pJsonJsep, "sdp", pSdp) == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create string (jsep.sdp)\n");
result = SWITCH_STATUS_FALSE;
goto done;
}

if (!(pJsonRequest = encode(request))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot create request\n");
result = SWITCH_STATUS_FALSE;
goto done;
}

if (snprintf(url, sizeof(url), "%s/%" SWITCH_UINT64_T_FMT "/%" SWITCH_UINT64_T_FMT, pUrl, serverId, senderId) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Could not generate URL\n");
result = SWITCH_STATUS_FALSE;
goto done;
}

DEBUG(SWITCH_CHANNEL_LOG, "Sending join-and-configure HTTP request\n");
pJsonResponse = httpPost(url, HTTP_POST_TIMEOUT, pJsonRequest);

if (!(pResponse = decode(pJsonResponse))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid response\n");
result = SWITCH_STATUS_FALSE;
goto done;
}

if (!pResponse->pType || strcmp("ack", pResponse->pType) ||
!pResponse->pTransactionId || strcmp(pTransactionId, pResponse->pTransactionId)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Value mismatch\n");
result = SWITCH_STATUS_FALSE;
goto done;
}

done:
cJSON_Delete(pJsonRequest);
cJSON_Delete(pJsonResponse);
switch_safe_free(pResponse);
switch_safe_free(pTransactionId);

return result;
}

switch_status_t apiConfigure(const char *pUrl, const char *pSecret,
const janus_id_t serverId, const janus_id_t senderId, const switch_bool_t muted,
switch_bool_t record, const char *pRecordingFile,
Expand Down
9 changes: 7 additions & 2 deletions api.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,13 @@
janus_id_t apiGetServerId(const char *pUrl, const char *pSecret);
switch_status_t apiClaimServerId(const char *pUrl, const char *pSecret, const janus_id_t serverId);
janus_id_t apiGetSenderId(const char *pUrl, const char *pSecret, const janus_id_t serverId, const char *callId);
janus_id_t apiCreateRoom(const char *pUrl, const char *pSecret, const janus_id_t serverId, const janus_id_t senderId, const janus_id_t roomId, const char *pDescription, switch_bool_t record, const char *pRecordingFile, const char *pPin);
switch_status_t apiJoin(const char *pUrl, const char *pSecret, const janus_id_t serverId, const janus_id_t senderId, const janus_id_t roomId, const char *pDisplay, const char *pPin, const char *pToken, const char *callId);
janus_id_t apiCreateRoom(const char *pUrl, const char *pSecret, const janus_id_t serverId, const janus_id_t senderId, const janus_id_t roomId, const char *pRoomIdStr, const char *pDescription, switch_bool_t record, const char *pRecordingFile, const char *pPin);
switch_status_t apiJoin(const char *pUrl, const char *pSecret, const janus_id_t serverId, const janus_id_t senderId, const janus_id_t roomId, const char *pRoomIdStr, const char *pDisplay, const char *pPin, const char *pToken, const char *callId);
switch_status_t apiJoinAndConfigure(const char *pUrl, const char *pSecret,
const janus_id_t serverId, const janus_id_t senderId, const janus_id_t roomId, const char *pRoomIdStr,
const char *pDisplay, const char *pPin, const char *pToken, const char *callId,
const switch_bool_t muted, switch_bool_t record, const char *pRecordingFile,
const char *pType, const char *pSdp);
switch_status_t apiConfigure(const char *pUrl, const char *pSecret,
const janus_id_t serverId, const janus_id_t senderId, const switch_bool_t muted,
switch_bool_t record, const char *pRecordingFile,
Expand Down
167 changes: 108 additions & 59 deletions mod_janus.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ typedef enum {
TFLAG_HANGUP = (1 << 5),
TFLAG_LINEAR = (1 << 6),
TFLAG_CODEC = (1 << 7),
TFLAG_BREAK = (1 << 8)
TFLAG_BREAK = (1 << 8),
TFLAG_JOIN_AND_CONFIGURE = (1 << 9)
} TFLAGS;

struct private_object {
Expand Down Expand Up @@ -135,75 +136,78 @@ switch_status_t joined(janus_id_t serverId, janus_id_t senderId, janus_id_t room
switch_channel_set_variable(channel, "media_webrtc", "true");
switch_channel_set_flag(channel, CF_AUDIO);

if (switch_core_session_get_partner(session, &partner_session) == SWITCH_STATUS_SUCCESS) {
switch_channel_t *partner_channel = switch_core_session_get_channel(partner_session);
// forces the B-leg to use the same codec of A-leg and set rfc2833 flags for DTMF to work
// passed by originate flag use-bridged-channel-codec
if (switch_channel_var_true(channel, "janus-use-bridged-channel-codec")) {
// required to force Freeswitch to add telephone-event in sdp to Janus
/* When join-and-configure was used, SDP offer was sent with join; skip configure path */
if (!switch_test_flag(tech_pvt, TFLAG_JOIN_AND_CONFIGURE)) {
if (switch_core_session_get_partner(session, &partner_session) == SWITCH_STATUS_SUCCESS) {
switch_channel_t *partner_channel = switch_core_session_get_channel(partner_session);
// forces the B-leg to use the same codec of A-leg and set rfc2833 flags for DTMF to work
// passed by originate flag use-bridged-channel-codec
if (switch_channel_var_true(channel, "janus-use-bridged-channel-codec")) {
// required to force Freeswitch to add telephone-event in sdp to Janus
tech_pvt->mparams.te = 101;
tech_pvt->mparams.recv_te = 101;
// make sure DTMF input is pass trough and with no delays
switch_channel_set_flag(channel, CF_PASS_RFC2833);

const char *partner_codec = switch_channel_get_variable(partner_channel, "ep_codec_string");
const char *partner_dtmf_type = switch_channel_get_variable(partner_channel, "dtmf_type");

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Using codec from A-Leg: %s\n", partner_codec);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Using DTMF Type from A-Leg: %s\n", partner_dtmf_type);

switch_channel_set_variable(channel, "dtmf_type", partner_dtmf_type);
switch_channel_set_variable(channel, "absolute_codec_string", switch_channel_get_variable(partner_channel, partner_codec));
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Using codec from janus.conf.xml: %s\n", pServer->codec_string);
switch_channel_set_variable(channel, "absolute_codec_string", pServer->codec_string);
}
switch_core_session_rwunlock(partner_session);
} else if (switch_channel_var_true(channel, "janus-use-bridged-channel-codec")) {
// Make sure that telephone-event is added to the SDP towards Janus
tech_pvt->mparams.te = 101;
tech_pvt->mparams.recv_te = 101;
// make sure DTMF input is pass trough and with no delays
switch_channel_set_flag(channel, CF_PASS_RFC2833);

const char *partner_codec = switch_channel_get_variable(partner_channel, "ep_codec_string");
const char *partner_dtmf_type = switch_channel_get_variable(partner_channel, "dtmf_type");

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Using codec from A-Leg: %s\n", partner_codec);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Using DTMF Type from A-Leg: %s\n", partner_dtmf_type);

switch_channel_set_variable(channel, "dtmf_type", partner_dtmf_type);
switch_channel_set_variable(channel, "absolute_codec_string", switch_channel_get_variable(partner_channel, partner_codec));
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Using codec from janus.conf.xml: %s\n", pServer->codec_string);
switch_channel_set_variable(channel, "absolute_codec_string", pServer->codec_string);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Using default DTMF Type: rfc2833 \n");
switch_channel_set_variable(channel, "dtmf_type", "rfc2833");
}
switch_core_session_rwunlock(partner_session);
} else if (switch_channel_var_true(channel, "janus-use-bridged-channel-codec")) {
// Make sure that telephone-event is added to the SDP towards Janus
tech_pvt->mparams.te = 101;
tech_pvt->mparams.recv_te = 101;
// make sure DTMF input is pass trough and with no delays
switch_channel_set_flag(channel, CF_PASS_RFC2833);

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Using default DTMF Type: rfc2833 \n");
switch_channel_set_variable(channel, "dtmf_type", "rfc2833");
}

switch_core_media_prepare_codecs(session, SWITCH_TRUE);
switch_core_media_prepare_codecs(session, SWITCH_TRUE);

switch_core_session_set_ice(session);
switch_core_session_set_ice(session);

for (unsigned int i = 0; i < pServer->cand_acl_count; i ++) {
switch_core_media_add_ice_acl(session, SWITCH_MEDIA_TYPE_AUDIO, pServer->cand_acl[i]);
}

if (switch_core_media_choose_ports(session, SWITCH_TRUE, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot choose ports\n");
switch_channel_hangup(channel, SWITCH_CAUSE_NETWORK_OUT_OF_ORDER);
return SWITCH_STATUS_FALSE;
}

switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0);

//switch_channel_set_flag(channel, CF_REQ_MEDIA);
//switch_channel_set_flag(channel, CF_MEDIA_ACK);
//switch_channel_set_flag(channel, CF_MEDIA_SET);
for (unsigned int i = 0; i < pServer->cand_acl_count; i ++) {
switch_core_media_add_ice_acl(session, SWITCH_MEDIA_TYPE_AUDIO, pServer->cand_acl[i]);
}

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Generated SDP=%s\n", tech_pvt->mparams.local_sdp_str);
if (switch_core_media_choose_ports(session, SWITCH_TRUE, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot choose ports\n");
switch_channel_hangup(channel, SWITCH_CAUSE_NETWORK_OUT_OF_ORDER);
return SWITCH_STATUS_FALSE;
}

if (apiConfigure(pServer->pUrl,
pServer->pSecret,
tech_pvt->serverId,
tech_pvt->senderId,
switch_channel_var_true(channel, "janus-start-muted"),
switch_channel_var_true(channel, "janus-user-record"),
switch_channel_get_variable(channel, "janus-user-record-file"),
"offer",
tech_pvt->mparams.local_sdp_str,
tech_pvt->callId) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to configure\n");
switch_channel_hangup(channel, SWITCH_CAUSE_NETWORK_OUT_OF_ORDER);
switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0);

//switch_channel_set_flag(channel, CF_REQ_MEDIA);
//switch_channel_set_flag(channel, CF_MEDIA_ACK);
//switch_channel_set_flag(channel, CF_MEDIA_SET);

switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Generated SDP=%s\n", tech_pvt->mparams.local_sdp_str);

if (apiConfigure(pServer->pUrl,
pServer->pSecret,
tech_pvt->serverId,
tech_pvt->senderId,
switch_channel_var_true(channel, "janus-start-muted"),
switch_channel_var_true(channel, "janus-user-record"),
switch_channel_get_variable(channel, "janus-user-record-file"),
"offer",
tech_pvt->mparams.local_sdp_str,
tech_pvt->callId) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to configure\n");
switch_channel_hangup(channel, SWITCH_CAUSE_NETWORK_OUT_OF_ORDER);
}
}

switch_channel_mark_ring_ready(channel);
Expand Down Expand Up @@ -660,6 +664,51 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)
return SWITCH_STATUS_NOTFOUND;
}

if (switch_channel_var_true(channel, "janus-join-and-configure")) {
/* Combine join and configure: generate SDP before join, send one request with room + offer */
if (pServer->codec_string) {
switch_channel_set_variable(channel, "absolute_codec_string", pServer->codec_string);
}
switch_channel_set_variable(channel, "dtmf_type", "rfc2833");
tech_pvt->mparams.te = 101;
tech_pvt->mparams.recv_te = 101;

switch_core_media_prepare_codecs(session, SWITCH_TRUE);
switch_core_session_set_ice(session);
for (unsigned int i = 0; i < pServer->cand_acl_count; i++) {
switch_core_media_add_ice_acl(session, SWITCH_MEDIA_TYPE_AUDIO, pServer->cand_acl[i]);
}
if (switch_core_media_choose_ports(session, SWITCH_TRUE, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot choose ports (join-and-configure)\n");
switch_channel_hangup(channel, SWITCH_CAUSE_NETWORK_OUT_OF_ORDER);
return SWITCH_STATUS_FALSE;
}
switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0);

if (apiJoinAndConfigure(
pServer->pUrl,
pServer->pSecret,
tech_pvt->serverId,
tech_pvt->senderId,
tech_pvt->roomId,
tech_pvt->pRoomIdStr,
tech_pvt->pDisplay,
switch_channel_get_variable(channel, "janus-room-pin"),
switch_channel_get_variable(channel, "janus-user-token"),
tech_pvt->callId,
switch_channel_var_true(channel, "janus-start-muted"),
switch_channel_var_true(channel, "janus-user-record"),
switch_channel_get_variable(channel, "janus-user-record-file"),
"offer",
tech_pvt->mparams.local_sdp_str) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Failed to join-and-configure\n");
switch_channel_hangup(channel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
return SWITCH_STATUS_FALSE;
}
switch_set_flag_locked(tech_pvt, TFLAG_JOIN_AND_CONFIGURE);
return SWITCH_STATUS_SUCCESS;
}

if (apiJoin(
pServer->pUrl,
pServer->pSecret,
Expand Down