2020-08-01 07:36:09 +00:00
|
|
|
/* Osmo-CC: helpers to simplify Osmo-CC usage
|
|
|
|
*
|
|
|
|
* (C) 2016 by Andreas Eversberg <jolly@eversberg.eu>
|
|
|
|
* All Rights Reserved
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <inttypes.h>
|
|
|
|
#include "../libtimer/timer.h"
|
|
|
|
#include "../libdebug/debug.h"
|
|
|
|
#include "endpoint.h"
|
|
|
|
#include "helper.h"
|
|
|
|
|
2021-04-02 14:31:43 +00:00
|
|
|
osmo_cc_session_t *osmo_cc_helper_audio_offer(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len), osmo_cc_msg_t *msg, int debug)
|
2020-08-01 07:36:09 +00:00
|
|
|
{
|
|
|
|
osmo_cc_session_t *session;
|
|
|
|
osmo_cc_session_media_t *media;
|
|
|
|
const char *sdp;
|
|
|
|
int i;
|
|
|
|
|
2021-04-02 14:31:43 +00:00
|
|
|
session = osmo_cc_new_session(conf, priv, NULL, NULL, NULL, 0, 0, NULL, NULL, debug);
|
2020-08-01 07:36:09 +00:00
|
|
|
if (!session)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
media = osmo_cc_add_media(session, 0, 0, NULL, osmo_cc_session_media_type_audio, 0, osmo_cc_session_media_proto_rtp, 1, 1, receiver, debug);
|
|
|
|
osmo_cc_rtp_open(media);
|
|
|
|
|
|
|
|
for (i = 0; codecs[i].payload_name; i++)
|
|
|
|
osmo_cc_add_codec(media, codecs[i].payload_name, codecs[i].payload_rate, codecs[i].payload_channels, codecs[i].encoder, codecs[i].decoder, debug);
|
|
|
|
|
|
|
|
sdp = osmo_cc_session_send_offer(session);
|
|
|
|
osmo_cc_add_ie_sdp(msg, sdp);
|
|
|
|
|
|
|
|
return session;
|
|
|
|
}
|
|
|
|
|
2021-04-02 14:31:43 +00:00
|
|
|
const char *osmo_cc_helper_audio_accept(osmo_cc_session_config_t *conf, void *priv, struct osmo_cc_helper_audio_codecs *codecs, void (*receiver)(struct osmo_cc_session_codec *codec, uint16_t sequence_number, uint32_t timestamp, uint8_t *data, int len), osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p, int force_our_codec)
|
2020-08-01 07:36:09 +00:00
|
|
|
{
|
|
|
|
char offer_sdp[65536];
|
|
|
|
const char *accept_sdp;
|
2021-02-27 10:58:07 +00:00
|
|
|
osmo_cc_session_media_t *media, *selected_media;
|
|
|
|
osmo_cc_session_codec_t *codec, *selected_codec, *telephone_event;
|
2020-08-01 07:36:09 +00:00
|
|
|
int rc;
|
2021-02-27 10:58:07 +00:00
|
|
|
int i, selected_codec_i, telephone_event_i;
|
2020-08-01 07:36:09 +00:00
|
|
|
|
|
|
|
if (*session_p) {
|
|
|
|
PDEBUG(DCC, DEBUG_ERROR, "Session already set, please fix!\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
if (*codec_p) {
|
|
|
|
PDEBUG(DCC, DEBUG_ERROR, "Codec already set, please fix!\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SDP IE */
|
|
|
|
rc = osmo_cc_get_ie_sdp(msg, 0, offer_sdp, sizeof(offer_sdp));
|
|
|
|
if (rc < 0) {
|
|
|
|
PDEBUG(DCC, DEBUG_ERROR, "There is no SDP included in setup request.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-04-02 14:31:43 +00:00
|
|
|
*session_p = osmo_cc_session_receive_offer(conf, priv, offer_sdp);
|
2020-08-01 07:36:09 +00:00
|
|
|
if (!*session_p) {
|
|
|
|
PDEBUG(DCC, DEBUG_ERROR, "Failed to parse SDP.\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-02-27 10:58:07 +00:00
|
|
|
selected_media = NULL;
|
2020-08-01 07:36:09 +00:00
|
|
|
osmo_cc_session_for_each_media((*session_p)->media_list, media) {
|
|
|
|
/* only audio */
|
|
|
|
if (media->description.type != osmo_cc_session_media_type_audio)
|
|
|
|
continue;
|
2021-02-27 10:58:07 +00:00
|
|
|
selected_codec_i = -1;
|
|
|
|
selected_codec = NULL;
|
|
|
|
telephone_event_i = -1;
|
|
|
|
telephone_event = NULL;
|
2020-08-01 07:36:09 +00:00
|
|
|
osmo_cc_session_for_each_codec(media->codec_list, codec) {
|
2021-02-27 10:58:07 +00:00
|
|
|
if (!!strcasecmp(codec->payload_name, "telephone-event")) {
|
|
|
|
for (i = 0; codecs[i].payload_name; i++) {
|
|
|
|
if (osmo_cc_session_if_codec(codec, codecs[i].payload_name, codecs[i].payload_rate, codecs[i].payload_channels)) {
|
|
|
|
/* select the first matchting codec or the one we prefer */
|
|
|
|
if (selected_codec_i < 0 || i < selected_codec_i) {
|
|
|
|
selected_codec = codec;
|
|
|
|
selected_codec_i = i;
|
|
|
|
selected_media = media;
|
|
|
|
}
|
|
|
|
/* if we don't force our preferred codec, use the preferred one from the remote */
|
|
|
|
if (!force_our_codec)
|
|
|
|
break;
|
2020-08-01 07:36:09 +00:00
|
|
|
}
|
2021-02-27 10:58:07 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* special case: add telephone-event, if supported */
|
|
|
|
for (i = 0; codecs[i].payload_name; i++) {
|
|
|
|
if (!!strcasecmp(codecs[i].payload_name, "telephone-event"))
|
|
|
|
continue;
|
|
|
|
telephone_event = codec;
|
|
|
|
telephone_event_i = i;
|
|
|
|
break;
|
2020-08-01 07:36:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-27 10:58:07 +00:00
|
|
|
/* codec is selected within this media, we are done */
|
|
|
|
if (selected_codec)
|
|
|
|
break;
|
2020-08-01 07:36:09 +00:00
|
|
|
}
|
|
|
|
if (!selected_codec) {
|
|
|
|
PDEBUG(DCC, DEBUG_ERROR, "No codec found in setup message that we support.\n");
|
|
|
|
osmo_cc_free_session(*session_p);
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-02-27 10:58:07 +00:00
|
|
|
osmo_cc_session_accept_codec(selected_codec, codecs[selected_codec_i].encoder, codecs[selected_codec_i].decoder);
|
|
|
|
if (telephone_event)
|
|
|
|
osmo_cc_session_accept_codec(telephone_event, codecs[telephone_event_i].encoder, codecs[telephone_event_i].decoder);
|
2020-08-01 07:36:09 +00:00
|
|
|
osmo_cc_session_accept_media(selected_media, 0, 0, NULL, 1, 1, receiver);
|
|
|
|
osmo_cc_rtp_open(selected_media);
|
|
|
|
osmo_cc_rtp_connect(selected_media);
|
|
|
|
*codec_p = selected_codec;
|
|
|
|
|
|
|
|
accept_sdp = osmo_cc_session_send_answer(*session_p);
|
|
|
|
if (!accept_sdp) {
|
|
|
|
osmo_cc_free_session(*session_p);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return accept_sdp;
|
|
|
|
}
|
|
|
|
|
|
|
|
int osmo_cc_helper_audio_negotiate(osmo_cc_msg_t *msg, osmo_cc_session_t **session_p, osmo_cc_session_codec_t **codec_p)
|
|
|
|
{
|
|
|
|
char sdp[65536];
|
|
|
|
osmo_cc_session_media_t *media;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!(*session_p)) {
|
|
|
|
PDEBUG(DCC, DEBUG_ERROR, "Session not set, please fix!\n");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* once done, just ignore further messages that reply to setup */
|
|
|
|
if (*codec_p)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* SDP IE */
|
|
|
|
rc = osmo_cc_get_ie_sdp(msg, 0, sdp, sizeof(sdp));
|
|
|
|
if (rc < 0)
|
|
|
|
return 0; // no reply in this message
|
|
|
|
|
|
|
|
rc = osmo_cc_session_receive_answer(*session_p, sdp);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
osmo_cc_session_for_each_media((*session_p)->media_list, media) {
|
|
|
|
/* only audio */
|
|
|
|
if (media->description.type != osmo_cc_session_media_type_audio)
|
|
|
|
continue;
|
|
|
|
/* select first codec, if one was accpeted */
|
|
|
|
if (media->codec_list)
|
|
|
|
*codec_p = media->codec_list;
|
|
|
|
if (*codec_p) {
|
|
|
|
osmo_cc_rtp_connect(media);
|
|
|
|
/* no more media streams */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!(*codec_p)) {
|
|
|
|
PDEBUG(DCC, DEBUG_ERROR, "No codec found in setup reply message that we support.\n");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|