[svn-commits] kmoore: branch kmoore/pimp_sip_media r383057 - in /team/kmoore/pimp_sip_media...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Thu Mar 14 11:06:27 CDT 2013
Author: kmoore
Date: Thu Mar 14 11:06:23 2013
New Revision: 383057
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383057
Log:
Add pimp_my_sip SDP/media framework changes
Modified:
team/kmoore/pimp_sip_media/channels/chan_gulp.c
team/kmoore/pimp_sip_media/include/asterisk/res_sip_session.h
team/kmoore/pimp_sip_media/res/res_sip_sdp_audio.c
team/kmoore/pimp_sip_media/res/res_sip_session.c
Modified: team/kmoore/pimp_sip_media/channels/chan_gulp.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/pimp_sip_media/channels/chan_gulp.c?view=diff&rev=383057&r1=383056&r2=383057
==============================================================================
--- team/kmoore/pimp_sip_media/channels/chan_gulp.c (original)
+++ team/kmoore/pimp_sip_media/channels/chan_gulp.c Thu Mar 14 11:06:23 2013
@@ -59,6 +59,35 @@
static const char desc[] = "Gulp SIP Channel";
static const char channel_type[] = "Gulp";
+
+/*!
+ * \brief Positions of various media
+ */
+enum sip_session_media_position {
+ /*! \brief First is audio */
+ SIP_MEDIA_AUDIO = 0,
+ /*! \brief Second is video */
+ SIP_MEDIA_VIDEO,
+ /*! \brief Last is the size for media details */
+ SIP_MEDIA_SIZE,
+};
+
+struct gulp_pvt {
+ struct ast_sip_session *session;
+ struct ast_sip_session_media *media[SIP_MEDIA_SIZE];
+};
+
+static void gulp_pvt_dtor(void *obj)
+{
+ struct gulp_pvt *pvt = obj;
+ int i;
+ ao2_cleanup(pvt->session);
+ pvt->session = NULL;
+ for (i = 0; i < SIP_MEDIA_SIZE; ++i) {
+ ao2_cleanup(pvt->media[i]);
+ pvt->media[i] = NULL;
+ }
+}
/* \brief Asterisk core interaction functions */
static struct ast_channel *gulp_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
@@ -110,14 +139,14 @@
/*! \brief Function called by RTP engine to get local audio RTP peer */
static enum ast_rtp_glue_result gulp_get_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance **instance)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(chan);
-
- if (!session || !session->media[AST_SIP_MEDIA_AUDIO].rtp) {
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+
+ if (!pvt || !pvt->session || !pvt->media[SIP_MEDIA_AUDIO]->rtp) {
return AST_RTP_GLUE_RESULT_FORBID;
}
- ao2_ref(session->media[AST_SIP_MEDIA_AUDIO].rtp, +1);
- *instance = session->media[AST_SIP_MEDIA_AUDIO].rtp;
+ *instance = pvt->media[SIP_MEDIA_AUDIO]->rtp;
+ ao2_ref(*instance, +1);
return AST_RTP_GLUE_RESULT_LOCAL;
}
@@ -146,16 +175,28 @@
{
struct ast_channel *chan;
struct ast_format fmt;
+ struct gulp_pvt *pvt;
+
+ if (!(pvt = ao2_alloc(sizeof(*pvt), gulp_pvt_dtor))) {
+ return NULL;
+ }
if (!(chan = ast_channel_alloc(1, state, "", S_OR(cid_name, ""), "", "", "", linkedid, 0, "Gulp/%s-%.*s", ast_sorcery_object_get_id(session->endpoint),
(int)session->inv_session->dlg->call_id->id.slen, session->inv_session->dlg->call_id->id.ptr))) {
+ ao2_cleanup(pvt);
return NULL;
}
ast_channel_tech_set(chan, &gulp_tech);
ao2_ref(session, +1);
- ast_channel_tech_pvt_set(chan, session);
+ pvt->session = session;
+ /* If res_sip_session is ever updated to create/destroy ast_sip_session_media
+ * during a call such as if multiple same-type stream support is introduced,
+ * these will need to be recaptured as well */
+ pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY);
+ pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY);
+ ast_channel_tech_pvt_set(chan, pvt);
ast_format_cap_copy(ast_channel_nativeformats(chan), session->endpoint->codecs);
ast_codec_choose(&session->endpoint->prefs, session->endpoint->codecs, 1, &fmt);
@@ -195,7 +236,8 @@
/*! \brief Function called by core when we should answer a Gulp session */
static int gulp_answer(struct ast_channel *ast)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(ast);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
if (ast_channel_state(ast) == AST_STATE_UP) {
return 0;
@@ -215,15 +257,20 @@
/*! \brief Function called by core to read any waiting frames */
static struct ast_frame *gulp_read(struct ast_channel *ast)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(ast);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
struct ast_frame *f;
+ struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
+
+ if (!media) {
+ return &ast_null_frame;
+ }
switch (ast_channel_fdno(ast)) {
case 0:
- f = ast_rtp_instance_read(session->media[AST_SIP_MEDIA_AUDIO].rtp, 0);
+ f = ast_rtp_instance_read(media->rtp, 0);
break;
case 1:
- f = ast_rtp_instance_read(session->media[AST_SIP_MEDIA_AUDIO].rtp, 1);
+ f = ast_rtp_instance_read(media->rtp, 1);
break;
default:
f = &ast_null_frame;
@@ -244,11 +291,17 @@
/*! \brief Function called by core to write frames */
static int gulp_write(struct ast_channel *ast, struct ast_frame *frame)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(ast);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
int res = 0;
+ struct ast_sip_session_media *media;
switch (frame->frametype) {
case AST_FRAME_VOICE:
+ media = pvt->media[SIP_MEDIA_AUDIO];
+
+ if (!media) {
+ return 0;
+ }
if (!(ast_format_cap_iscompatible(ast_channel_nativeformats(ast), &frame->subclass.format))) {
char buf[256];
@@ -260,8 +313,8 @@
ast_getformatname(ast_channel_writeformat(ast)));
return 0;
}
- if (session->media[AST_SIP_MEDIA_AUDIO].rtp) {
- res = ast_rtp_instance_write(session->media[AST_SIP_MEDIA_AUDIO].rtp, frame);
+ if (media->rtp) {
+ res = ast_rtp_instance_write(media->rtp, frame);
}
break;
default:
@@ -287,7 +340,8 @@
/*! \brief Function called by core to change the underlying owner channel */
static int gulp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(newchan);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(newchan);
+ struct ast_sip_session *session = pvt->session;
struct fixup_data fix_data;
fix_data.session = session;
fix_data.chan = newchan;
@@ -359,7 +413,8 @@
static int gulp_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
{
int res = 0;
- struct ast_sip_session *session = ast_channel_tech_pvt(ast);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
int response_code = 0;
switch (condition) {
@@ -448,14 +503,18 @@
/*! \brief Function called by core to start a DTMF digit */
static int gulp_digit_begin(struct ast_channel *chan, char digit)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(chan);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(chan);
+ struct ast_sip_session *session = pvt->session;
int res = 0;
+ struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
switch (session->endpoint->dtmf) {
case AST_SIP_DTMF_RFC_4733:
- if (session->media[AST_SIP_MEDIA_AUDIO].rtp) {
- ast_rtp_instance_dtmf_begin(session->media[AST_SIP_MEDIA_AUDIO].rtp, digit);
- }
+ if (!media || !media->rtp) {
+ return -1;
+ }
+
+ ast_rtp_instance_dtmf_begin(media->rtp, digit);
case AST_SIP_DTMF_NONE:
break;
case AST_SIP_DTMF_INBAND:
@@ -471,17 +530,21 @@
/*! \brief Function called by core to stop a DTMF digit */
static int gulp_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(ast);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
int res = 0;
+ struct ast_sip_session_media *media = pvt->media[SIP_MEDIA_AUDIO];
switch (session->endpoint->dtmf) {
case AST_SIP_DTMF_INFO:
/* TODO: Send INFO dtmf here */
break;
case AST_SIP_DTMF_RFC_4733:
- if (session->media[AST_SIP_MEDIA_AUDIO].rtp) {
- ast_rtp_instance_dtmf_end_with_duration(session->media[AST_SIP_MEDIA_AUDIO].rtp, digit, duration);
- }
+ if (!media || !media->rtp) {
+ return -1;
+ }
+
+ ast_rtp_instance_dtmf_end_with_duration(media->rtp, digit, duration);
case AST_SIP_DTMF_NONE:
break;
case AST_SIP_DTMF_INBAND:
@@ -510,7 +573,8 @@
/*! \brief Function called by core to actually start calling a remote party */
static int gulp_call(struct ast_channel *ast, const char *dest, int timeout)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(ast);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
ao2_ref(session, +1);
if (ast_sip_push_task_synchronous(session->serializer, call, session)) {
@@ -597,7 +661,8 @@
pjsip_tx_data *packet = NULL;
struct hangup_data *h_data = data;
struct ast_channel *ast = h_data->chan;
- struct ast_sip_session *session = ast_channel_tech_pvt(ast);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
int cause = h_data->cause;
if (((status = pjsip_inv_end_session(session->inv_session, cause ? cause : 603, NULL, &packet)) == PJ_SUCCESS) && packet) {
@@ -611,7 +676,7 @@
session->channel = NULL;
ast_channel_tech_pvt_set(ast, NULL);
- ao2_cleanup(session);
+ ao2_cleanup(pvt);
ao2_cleanup(h_data);
return 0;
}
@@ -619,7 +684,8 @@
/*! \brief Function called by core to hang up a Gulp session */
static int gulp_hangup(struct ast_channel *ast)
{
- struct ast_sip_session *session = ast_channel_tech_pvt(ast);
+ struct gulp_pvt *pvt = ast_channel_tech_pvt(ast);
+ struct ast_sip_session *session = pvt->session;
int cause = hangup_cause2sip(ast_channel_hangupcause(session->channel));
struct hangup_data *h_data = hangup_data_alloc(cause, ast);
if (!h_data) {
@@ -640,7 +706,7 @@
session->channel = NULL;
ast_channel_tech_pvt_set(ast, NULL);
- ao2_cleanup(session);
+ ao2_cleanup(pvt);
return -1;
}
Modified: team/kmoore/pimp_sip_media/include/asterisk/res_sip_session.h
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/pimp_sip_media/include/asterisk/res_sip_session.h?view=diff&rev=383057&r1=383056&r2=383057
==============================================================================
--- team/kmoore/pimp_sip_media/include/asterisk/res_sip_session.h (original)
+++ team/kmoore/pimp_sip_media/include/asterisk/res_sip_session.h Thu Mar 14 11:06:23 2013
@@ -37,17 +37,7 @@
struct pjmedia_sdp_session;
struct ast_rtp_instance;
-/*!
- * \brief Positions of various media
- */
-enum ast_sip_session_media_position {
- /*! \brief First is audio */
- AST_SIP_MEDIA_AUDIO = 0,
- /*! \brief Second is video */
- AST_SIP_MEDIA_VIDEO,
- /*! \brief Last is the size for media details */
- AST_SIP_MEDIA_SIZE,
-};
+struct ast_sip_session_sdp_handler;
/*!
* \brief A structure containing SIP session media information
@@ -55,8 +45,12 @@
struct ast_sip_session_media {
/*! \brief RTP instance itself */
struct ast_rtp_instance *rtp;
+ /*! \brief SDP handler that setup the RTP */
+ struct ast_sip_session_sdp_handler *handler;
/*! \brief Stream is on hold */
unsigned int held:1;
+ /*! \brief Stream type this session media handles */
+ char stream_type[1];
};
/*!
@@ -81,7 +75,7 @@
/* Datastores added to the session by supplements to the session */
struct ao2_container *datastores;
/* Media streams */
- struct ast_sip_session_media media[AST_SIP_MEDIA_SIZE];
+ struct ao2_container *media;
/* Serializer for tasks relating to this SIP session */
struct ast_taskprocessor *serializer;
};
@@ -166,34 +160,38 @@
/*!
* \brief Set session details based on a stream in an incoming SDP offer or answer
* \param session The session for which the media is being negotiated
+ * \param session_media The media to be setup for this session
* \param sdp The entire SDP. Useful for getting "global" information, such as connections or attributes
* \param stream The stream on which to operate
* \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called.
* \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned.
* \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
*/
- int (*negotiate_incoming_sdp_stream)(struct ast_sip_session *session, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
+ int (*negotiate_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
/*!
* \brief Create an SDP media stream and add it to the outgoing SDP offer or answer
* \param session The session for which media is being added
+ * \param session_media The media to be setup for this session
* \param stream The stream on which to operate
* \retval 0 The stream was not handled by this handler. If there are other registered handlers for this stream type, they will be called.
* \retval <0 There was an error encountered. No further operation will take place and the current negotiation will be abandoned.
* \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
*/
- int (*handle_incoming_sdp_stream)(struct ast_sip_session *session, const struct pjmedia_sdp_session *sdp, struct pjmedia_sdp_media *stream);
+ int (*handle_incoming_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, struct pjmedia_sdp_media *stream);
/*!
* \brief Create an SDP media stream and add it to the outgoing SDP offer or answer
* \param session The session for which media is being added
+ * \param session_media The media to be setup for this session
* \param sdp The entire SDP as currently built
* \retval 0 This handler has no stream to add. If there are other registered handlers for this stream type, they will be called.
* \retval <0 There was an error encountered. No further operation will take place and the current SDP negotiation will be abandoned.
* \retval >0 The handler has a stream to be added to the SDP. No further handler of this stream type will be called.
*/
- int (*create_outgoing_sdp_stream)(struct ast_sip_session *session, struct pjmedia_sdp_session *sdp);
+ int (*create_outgoing_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp);
/*!
* \brief Apply a negotiated SDP media stream
* \param session The session for which media is being applied
+ * \param session_media The media to be setup for this session
* \param local The entire local negotiated SDP
* \param local_stream The local stream which to apply
* \param remote The entire remote negotiated SDP
@@ -202,9 +200,15 @@
* \retval <0 There was an error encountered. No further operation will take place and the current application will be abandoned.
* \retval >0 The stream was handled by this handler. No further handler of this stream type will be called.
*/
- int (*apply_negotiated_sdp_stream)(struct ast_sip_session *session, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
+ int (*apply_negotiated_sdp_stream)(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream);
- /*! Next item int he list. */
+ /*!
+ * \brief Destroy a session_media created by this handler
+ * \param session The session for which media is being destroyed
+ * \param session_media The media to destroy
+ */
+ void (*stream_destroy)(struct ast_sip_session_media *session_media);
+ /*! Next item in the list. */
AST_LIST_ENTRY(ast_sip_session_sdp_handler) next;
};
Modified: team/kmoore/pimp_sip_media/res/res_sip_sdp_audio.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/pimp_sip_media/res/res_sip_sdp_audio.c?view=diff&rev=383057&r1=383056&r2=383057
==============================================================================
--- team/kmoore/pimp_sip_media/res/res_sip_sdp_audio.c (original)
+++ team/kmoore/pimp_sip_media/res/res_sip_sdp_audio.c Thu Mar 14 11:06:23 2013
@@ -53,13 +53,13 @@
static struct ast_sched_context *sched;
/*! \brief Forward declarations for SDP handler functions */
-static int audio_negotiate_incoming_sdp_stream(struct ast_sip_session *session, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
-static int audio_create_outgoing_sdp_stream(struct ast_sip_session *session, struct pjmedia_sdp_session *sdp);
-static int audio_apply_negotiated_sdp_stream(struct ast_sip_session *session, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
+static int audio_negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream);
+static int audio_create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp);
+static int audio_apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream);
/*! \brief Forward declaration for session supplement functions */
-static void audio_session_destroy(struct ast_sip_session *session);
+static void audio_stream_destroy(struct ast_sip_session_media *session_media);
/*! \brief SDP handler for 'audio' media stream */
static struct ast_sip_session_sdp_handler audio_sdp_handler = {
@@ -67,15 +67,11 @@
.negotiate_incoming_sdp_stream = audio_negotiate_incoming_sdp_stream,
.create_outgoing_sdp_stream = audio_create_outgoing_sdp_stream,
.apply_negotiated_sdp_stream = audio_apply_negotiated_sdp_stream,
+ .stream_destroy = audio_stream_destroy,
};
-/*! \brief Session supplement for 'audio' media stream */
-static struct ast_sip_session_supplement audio_session_supplement = {
- .session_destroy = audio_session_destroy,
-};
-
/*! \brief Internal function which creates an RTP instance */
-static int audio_create_rtp(struct ast_sip_session *session, unsigned int ipv6)
+static int audio_create_rtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media, unsigned int ipv6)
{
pj_sockaddr addr;
char hostip[PJ_INET6_ADDRSTRLEN+2];
@@ -91,21 +87,21 @@
return -1;
}
- if (!(session->media[AST_SIP_MEDIA_AUDIO].rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
- return -1;
- }
-
- ast_rtp_instance_set_prop(session->media[AST_SIP_MEDIA_AUDIO].rtp, AST_RTP_PROPERTY_RTCP, 1);
- ast_rtp_instance_set_prop(session->media[AST_SIP_MEDIA_AUDIO].rtp, AST_RTP_PROPERTY_NAT, session->endpoint->rtp_symmetric);
-
- ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->media[AST_SIP_MEDIA_AUDIO].rtp),
- session->media[AST_SIP_MEDIA_AUDIO].rtp, &session->endpoint->prefs);
+ if (!(session_media->rtp = ast_rtp_instance_new("asterisk", sched, &tmp, NULL))) {
+ return -1;
+ }
+
+ ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_RTCP, 1);
+ ast_rtp_instance_set_prop(session_media->rtp, AST_RTP_PROPERTY_NAT, session->endpoint->rtp_symmetric);
+
+ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session_media->rtp),
+ session_media->rtp, &session->endpoint->prefs);
return 0;
}
/*! \brief Function which negotiates an incoming 'audio' stream */
-static int audio_negotiate_incoming_sdp_stream(struct ast_sip_session *session, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
+static int audio_negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *sdp, const struct pjmedia_sdp_media *stream)
{
char host[NI_MAXHOST];
RAII_VAR(struct ast_sockaddr *, addrs, NULL, ast_free_ptr);
@@ -124,7 +120,7 @@
}
/* Using the connection information create an appropriate RTP instance */
- if (!session->media[AST_SIP_MEDIA_AUDIO].rtp && audio_create_rtp(session, ast_sockaddr_is_ipv6(addrs))) {
+ if (!session_media->rtp && audio_create_rtp(session, session_media, ast_sockaddr_is_ipv6(addrs))) {
return -1;
}
@@ -133,7 +129,7 @@
}
/*! \brief Function which creates an outgoing 'audio' stream */
-static int audio_create_outgoing_sdp_stream(struct ast_sip_session *session, struct pjmedia_sdp_session *sdp)
+static int audio_create_outgoing_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, struct pjmedia_sdp_session *sdp)
{
static const pj_str_t STR_AUDIO = { "audio", 5};
static const pj_str_t STR_IN = { "IN", 2 };
@@ -152,7 +148,7 @@
if (!ast_format_cap_has_type(session->endpoint->codecs, AST_FORMAT_TYPE_AUDIO)) {
/* If no audio formats are configured don't add a stream */
return 0;
- } else if (!session->media[AST_SIP_MEDIA_AUDIO].rtp && audio_create_rtp(session, session->endpoint->rtp_ipv6)) {
+ } else if (!session_media->rtp && audio_create_rtp(session, session_media, session->endpoint->rtp_ipv6)) {
return -1;
}
@@ -166,7 +162,7 @@
media->desc.transport = STR_RTP_AVP;
/* Add connection level details */
- ast_rtp_instance_get_local_address(session->media[AST_SIP_MEDIA_AUDIO].rtp, &addr);
+ ast_rtp_instance_get_local_address(session_media->rtp, &addr);
media->conn->net_type = STR_IN;
media->conn->addr_type = (ast_sockaddr_is_ipv6(&addr) && !ast_sockaddr_is_ipv4_mapped(&addr)) ? STR_IP6 : STR_IP4;
pj_strdup2(pool, &media->conn->addr, ast_sockaddr_stringify_addr_remote(&addr));
@@ -178,13 +174,13 @@
struct ast_format format;
int rtp_code;
pjmedia_sdp_rtpmap rtpmap;
- struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session->media[AST_SIP_MEDIA_AUDIO].rtp)->pref;
+ struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session_media->rtp)->pref;
if (!ast_codec_pref_index(&session->endpoint->prefs, index, &format)) {
break;
} else if (AST_FORMAT_GET_TYPE(format.id) != AST_FORMAT_TYPE_AUDIO) {
continue;
- } else if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session->media[AST_SIP_MEDIA_AUDIO].rtp),
+ } else if ((rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp),
1, &format, 0)) == -1) {
return -1;
}
@@ -212,7 +208,7 @@
int rtp_code;
pjmedia_sdp_rtpmap rtpmap;
- if (!(noncodec & index) || (rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session->media[AST_SIP_MEDIA_AUDIO].rtp),
+ if (!(noncodec & index) || (rtp_code = ast_rtp_codecs_payload_code(ast_rtp_instance_get_codecs(session_media->rtp),
0, NULL, index)) == -1) {
continue;
}
@@ -253,7 +249,7 @@
}
/*! \brief Function which applies a negotiated SDP stream */
-static int audio_apply_negotiated_sdp_stream(struct ast_sip_session *session, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
+static int audio_apply_negotiated_sdp_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, const struct pjmedia_sdp_session *local, const struct pjmedia_sdp_media *local_stream,
const struct pjmedia_sdp_session *remote, const struct pjmedia_sdp_media *remote_stream)
{
int format, othercapability = 0;
@@ -267,7 +263,7 @@
struct ast_format fmt;
/* Create an RTP instance if need be */
- if (!session->media[AST_SIP_MEDIA_AUDIO].rtp && audio_create_rtp(session, session->endpoint->rtp_ipv6)) {
+ if (!session_media->rtp && audio_create_rtp(session, session_media, session->endpoint->rtp_ipv6)) {
return -1;
}
@@ -288,7 +284,7 @@
/* Apply connection information to the RTP instance */
ast_sockaddr_set_port(addrs, remote_stream->desc.port);
- ast_rtp_instance_set_remote_address(session->media[AST_SIP_MEDIA_AUDIO].rtp, addrs);
+ ast_rtp_instance_set_remote_address(session_media->rtp, addrs);
ast_rtp_codecs_payloads_initialize(&codecs);
@@ -319,11 +315,11 @@
pj_str_t value = attr->value;
unsigned long framing = pj_strtoul(pj_strltrim(&value));
int codec;
- struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session->media[AST_SIP_MEDIA_AUDIO].rtp)->pref;
+ struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(session_media->rtp)->pref;
for (codec = 0; codec < AST_RTP_MAX_PT; codec++) {
struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(
- session->media[AST_SIP_MEDIA_AUDIO].rtp), codec);
+ session_media->rtp), codec);
if (!format.asterisk_format) {
continue;
@@ -332,8 +328,8 @@
ast_codec_pref_setsize(pref, &format.format, framing);
}
- ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session->media[AST_SIP_MEDIA_AUDIO].rtp),
- session->media[AST_SIP_MEDIA_AUDIO].rtp, pref);
+ ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(session_media->rtp),
+ session_media->rtp, pref);
}
/* Using the configured codecs and the codecs in this SDP we determine the joint formats for *audio only* */
@@ -352,8 +348,8 @@
return -1;
}
- ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session->media[AST_SIP_MEDIA_AUDIO].rtp),
- session->media[AST_SIP_MEDIA_AUDIO].rtp);
+ ast_rtp_codecs_payloads_copy(&codecs, ast_rtp_instance_get_codecs(session_media->rtp),
+ session_media->rtp);
/* Now that we have joint formats for audio remove the existing ones from the channel and add the new ones */
ast_format_cap_copy(cap, ast_channel_nativeformats(session->channel));
@@ -368,25 +364,25 @@
ast_set_read_format(session->channel, ast_channel_readformat(session->channel));
ast_set_write_format(session->channel, ast_channel_writeformat(session->channel));
- ast_channel_set_fd(session->channel, 0, ast_rtp_instance_fd(session->media[AST_SIP_MEDIA_AUDIO].rtp, 0));
- ast_channel_set_fd(session->channel, 1, ast_rtp_instance_fd(session->media[AST_SIP_MEDIA_AUDIO].rtp, 1));
-
- if (session->media[AST_SIP_MEDIA_AUDIO].held && (!ast_sockaddr_isnull(addrs) ||
+ ast_channel_set_fd(session->channel, 0, ast_rtp_instance_fd(session_media->rtp, 0));
+ ast_channel_set_fd(session->channel, 1, ast_rtp_instance_fd(session_media->rtp, 1));
+
+ if (session_media->held && (!ast_sockaddr_isnull(addrs) ||
!pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL))) {
/* The remote side has taken us off hold */
ast_queue_control(session->channel, AST_CONTROL_UNHOLD);
ast_queue_frame(session->channel, &ast_null_frame);
- session->media[AST_SIP_MEDIA_AUDIO].held = 0;
+ session_media->held = 0;
} else if (ast_sockaddr_isnull(addrs) || ast_sockaddr_is_any(addrs) || pjmedia_sdp_media_find_attr2(remote_stream, "sendonly", NULL)) {
/* The remote side has put us on hold */
ast_queue_control_data(session->channel, AST_CONTROL_HOLD, S_OR(session->endpoint->mohsuggest, NULL),
!ast_strlen_zero(session->endpoint->mohsuggest) ? strlen(session->endpoint->mohsuggest) + 1 : 0);
- ast_rtp_instance_stop(session->media[AST_SIP_MEDIA_AUDIO].rtp);
+ ast_rtp_instance_stop(session_media->rtp);
ast_queue_frame(session->channel, &ast_null_frame);
- session->media[AST_SIP_MEDIA_AUDIO].held = 1;
+ session_media->held = 1;
} else {
/* The remote side has not changed state, but make sure the instance is active */
- ast_rtp_instance_activate(session->media[AST_SIP_MEDIA_AUDIO].rtp);
+ ast_rtp_instance_activate(session_media->rtp);
}
ast_rtp_codecs_payloads_destroy(&codecs);
@@ -394,14 +390,14 @@
}
/*! \brief Function which destroys the audio RTP instance when session ends */
-static void audio_session_destroy(struct ast_sip_session *session)
-{
- if (!session->media[AST_SIP_MEDIA_AUDIO].rtp) {
+static void audio_stream_destroy(struct ast_sip_session_media *session_media)
+{
+ if (!session_media->rtp) {
return;
}
- ast_rtp_instance_stop(session->media[AST_SIP_MEDIA_AUDIO].rtp);
- ast_rtp_instance_destroy(session->media[AST_SIP_MEDIA_AUDIO].rtp);
+ ast_rtp_instance_stop(session_media->rtp);
+ ast_rtp_instance_destroy(session_media->rtp);
}
/*!
@@ -426,11 +422,6 @@
goto end;
}
- if (ast_sip_session_register_supplement(&audio_session_supplement)) {
- ast_log(LOG_ERROR, "Unable to register session supplement for audio media stream\n");
- goto end;
- }
-
if (ast_sip_session_register_sdp_handler(&audio_sdp_handler, "audio")) {
ast_log(LOG_ERROR, "Unable to register SDP handler for 'audio' stream type\n");
goto end;
@@ -442,8 +433,6 @@
ast_sched_context_destroy(sched);
}
- ast_sip_session_unregister_supplement(&audio_session_supplement);
-
return AST_MODULE_LOAD_FAILURE;
}
@@ -451,7 +440,6 @@
static int unload_module(void)
{
ast_sip_session_unregister_sdp_handler(&audio_sdp_handler, "audio");
- ast_sip_session_unregister_supplement(&audio_session_supplement);
ast_sched_context_destroy(sched);
return 0;
}
Modified: team/kmoore/pimp_sip_media/res/res_sip_session.c
URL: http://svnview.digium.com/svn/asterisk/team/kmoore/pimp_sip_media/res/res_sip_session.c?view=diff&rev=383057&r1=383056&r2=383057
==============================================================================
--- team/kmoore/pimp_sip_media/res/res_sip_session.c (original)
+++ team/kmoore/pimp_sip_media/res/res_sip_session.c Thu Mar 14 11:06:23 2013
@@ -88,6 +88,23 @@
return strcmp(handler_list1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP;
}
+static int session_media_hash(const void *obj, int flags)
+{
+ const struct ast_sip_session_media *session_media = obj;
+ const char *stream_type = flags & OBJ_KEY ? obj : session_media->stream_type;
+
+ return ast_str_hash(stream_type);
+}
+
+static int session_media_cmp(void *obj, void *arg, int flags)
+{
+ struct ast_sip_session_media *session_media1 = obj;
+ struct ast_sip_session_media *session_media2 = arg;
+ const char *stream_type2 = flags & OBJ_KEY ? arg : session_media2->stream_type;
+
+ return strcmp(session_media1->stream_type, stream_type2) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
int ast_sip_session_register_sdp_handler(struct ast_sip_session_sdp_handler *handler, const char *stream_type)
{
RAII_VAR(struct sdp_handler_list *, handler_list,
@@ -155,9 +172,160 @@
ao2_callback_data(sdp_handlers, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, remove_handler, (void *)stream_type, handler);
}
+static int validate_port_hash(const void *obj, int flags)
+{
+ const int *port = obj;
+ return *port;
+}
+
+static int validate_port_cmp(void *obj, void *arg, int flags)
+{
+ int *port1 = obj;
+ int *port2 = arg;
+
+ return *port1 == *port2 ? CMP_MATCH | CMP_STOP : 0;
+}
+
+struct bundle_assoc {
+ int port;
+ char tag[1];
+};
+
+static int bundle_assoc_hash(const void *obj, int flags)
+{
+ const struct bundle_assoc *assoc = obj;
+ const char *tag = flags & OBJ_KEY ? obj : assoc->tag;
+
+ return ast_str_hash(tag);
+}
+
+static int bundle_assoc_cmp(void *obj, void *arg, int flags)
+{
+ struct bundle_assoc *assoc1 = obj;
+ struct bundle_assoc *assoc2 = arg;
+ const char *tag2 = flags & OBJ_KEY ? arg : assoc2->tag;
+
+ return strcmp(assoc1->tag, tag2) ? 0 : CMP_MATCH | CMP_STOP;
+}
+
+/* return must be ast_freed */
+static pjmedia_sdp_attr *media_get_mid(pjmedia_sdp_media *media)
+{
+ pjmedia_sdp_attr *attr = pjmedia_sdp_media_find_attr2(media, "mid", NULL);
+ if (!attr) {
+ return NULL;
+ }
+
+ return attr;
+}
+
+static int get_bundle_port(const pjmedia_sdp_session *sdp, const char *mid)
+{
+ int i;
+ for (i = 0; i < sdp->media_count; ++i) {
+ pjmedia_sdp_attr *mid_attr = media_get_mid(sdp->media[i]);
+ if (mid_attr && !pj_strcmp2(&mid_attr->value, mid)) {
+ return sdp->media[i]->desc.port;
+ }
+ }
+
+ return -1;
+}
+
+static int validate_incoming_sdp(const pjmedia_sdp_session *sdp)
+{
+ int i;
+ RAII_VAR(struct ao2_container *, portlist, ao2_container_alloc(5, validate_port_hash, validate_port_cmp), ao2_cleanup);
+ RAII_VAR(struct ao2_container *, bundle_assoc_list, ao2_container_alloc(5, bundle_assoc_hash, bundle_assoc_cmp), ao2_cleanup);
+
+ /* check for bundles (for websocket RTP multiplexing, there can be more than one) */
+ for (i = 0; i < sdp->attr_count; ++i) {
+ char *bundle_list;
+ int bundle_port = 0;
+ if (pj_stricmp2(&sdp->attr[i]->name, "group")) {
+ continue;
+ }
+
+ /* check to see if this group is a bundle */
+ if (7 >= sdp->attr[i]->value.slen || pj_strnicmp2(&sdp->attr[i]->value, "bundle ", 7)) {
+ continue;
+ }
+
+ bundle_list = ast_alloca(sdp->attr[i]->value.slen - 6);
+ strncpy(bundle_list, sdp->attr[i]->value.ptr + 7, sdp->attr[i]->value.slen - 7);
+ bundle_list[sdp->attr[i]->value.slen - 7] = '\0';
+ while (bundle_list) {
+ char *item;
+ RAII_VAR(struct bundle_assoc *, assoc, NULL, ao2_cleanup);
+ item = strsep(&bundle_list, " ,");
+ if (!bundle_port) {
+ RAII_VAR(int *, port, ao2_alloc(sizeof(int), NULL), ao2_cleanup);
+ RAII_VAR(int *, port_match, NULL, ao2_cleanup);
+ bundle_port = get_bundle_port(sdp, item);
+ if (bundle_port < 0) {
+ return -1;
+ }
+ port_match = ao2_find(portlist, &bundle_port, OBJ_KEY);
+ if (port_match) {
+ /* bundle port aready consumed by a different bundle */
+ return -1;
+ }
+ *port = bundle_port;
+ ao2_link(portlist, port);
+ }
+ assoc = ao2_alloc(sizeof(*assoc) + strlen(item), NULL);
+ if (!assoc) {
+ return -1;
+ }
+
+ /* safe use of strcpy */
+ strcpy(assoc->tag, item);
+ assoc->port = bundle_port;
+ ao2_link(bundle_assoc_list, assoc);
+ }
+ }
+
+ /* validate all streams */
+ for (i = 0; i < sdp->media_count; ++i) {
+ RAII_VAR(int *, port, ao2_alloc(sizeof(int), NULL), ao2_cleanup);
+ RAII_VAR(int *, port_match, NULL, ao2_cleanup);
+ RAII_VAR(int *, bundle_match, NULL, ao2_cleanup);
+ *port = sdp->media[i]->desc.port;
+ port_match = ao2_find(portlist, port, OBJ_KEY);
+ if (port_match) {
+ RAII_VAR(struct bundle_assoc *, assoc, NULL, ao2_cleanup);
+ pjmedia_sdp_attr *mid = media_get_mid(sdp->media[i]);
+ char *mid_val;
+
+ if (!mid) {
+ /* not part of a bundle */
+ return -1;
+ }
+
+ mid_val = ast_alloca(mid->value.slen + 1);
+ strncpy(mid_val, mid->value.ptr, mid->value.slen);
+ mid_val[mid->value.slen] = '\0';
+
+ assoc = ao2_find(bundle_assoc_list, mid_val, OBJ_KEY);
+ if (!assoc || assoc->port != *port) {
+ /* This port already exists elsewhere in the SDP
+ * and is not an appropriate bundle port, fail
+ * catastrophically */
+ return -1;
+ }
+ }
+ ao2_link(portlist, port);
+ }
+ return 0;
+}
+
static int handle_incoming_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *sdp)
{
int i;
+ if (validate_incoming_sdp(sdp)) {
+ return -1;
+ }
+
for (i = 0; i < sdp->media_count; ++i) {
/* See if there are registered handlers for this media stream type */
char media[20];
@@ -173,15 +341,22 @@
continue;
}
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
- int res = handler->negotiate_incoming_sdp_stream(session, sdp, sdp->media[i]);
+ int res;
+ RAII_VAR(struct ast_sip_session_media *, session_media, NULL, ao2_cleanup);
+ session_media = ao2_find(session->media, handler_list->stream_type, OBJ_KEY);
+ if (!session_media || session_media->handler) {
+ /* There is only one slot for this stream type and it has already been claimed
+ * so it will go unhandled */
+ break;
+ }
+ res = handler->negotiate_incoming_sdp_stream(session, session_media, sdp, sdp->media[i]);
if (res < 0) {
/* Catastrophic failure. Abort! */
return -1;
- } else if (res == 0) {
- /* Not handled yet. Move to the next handler */
- continue;
- } else {
+ }
+ if (res > 0) {
/* Handled by this handler. Move to the next stream */
+ session_media->handler = handler;
break;
}
}
@@ -189,9 +364,21 @@
return 0;
}
-static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)
-{
+struct handle_negotiated_sdp_cb {
+ struct ast_sip_session *session;
+ const pjmedia_sdp_session *local;
+ const pjmedia_sdp_session *remote;
+};
+
+static int handle_negotiated_sdp_session_media(void *obj, void *arg, int flags)
+{
+ struct ast_sip_session_media *session_media = obj;
+ struct handle_negotiated_sdp_cb *callback_data = arg;
+ struct ast_sip_session *session = callback_data->session;
+ const pjmedia_sdp_session *local = callback_data->local;
+ const pjmedia_sdp_session *remote = callback_data->remote;
int i;
+
for (i = 0; i < local->media_count; ++i) {
/* See if there are registered handlers for this media stream type */
char media[20];
@@ -201,26 +388,56 @@
/* We need a null-terminated version of the media string */
ast_copy_pj_str(media, &local->media[i]->desc.media, sizeof(media));
+ /* stream type doesn't match the one we're looking to fill */
+ if (strcasecmp(session_media->stream_type, media)) {
+ continue;
+ }
+
+ handler = session_media->handler;
+ if (handler) {
+ int res = handler->apply_negotiated_sdp_stream(session, session_media, local, local->media[i], remote, remote->media[i]);
+ if (res >= 0) {
+ return CMP_MATCH;
+ }
+ return 0;
+ }
+
handler_list = ao2_find(sdp_handlers, media, OBJ_KEY);
if (!handler_list) {
ast_debug(1, "No registered SDP handlers for media type '%s'\n", media);
continue;
}
AST_LIST_TRAVERSE(&handler_list->list, handler, next) {
- int res = handler->apply_negotiated_sdp_stream(session, local, local->media[i], remote, remote->media[i]);
+ int res = handler->apply_negotiated_sdp_stream(session, session_media, local, local->media[i], remote, remote->media[i]);
if (res < 0) {
/* Catastrophic failure. Abort! */
- return -1;
- } else if (res == 0) {
- /* Not handled yet. Move to the next handler */
- continue;
- } else {
+ return 0;
+ }
+ if (res > 0) {
/* Handled by this handler. Move to the next stream */
- break;
+ session_media->handler = handler;
+ return CMP_MATCH;
}
}
}
- return 0;
+ return CMP_MATCH;
+}
+
+static int handle_negotiated_sdp(struct ast_sip_session *session, const pjmedia_sdp_session *local, const pjmedia_sdp_session *remote)
+{
+ RAII_VAR(struct ao2_iterator *, successful, NULL, ao2_iterator_cleanup);
+ struct handle_negotiated_sdp_cb callback_data = {
+ .session = session,
+ .local = local,
+ .remote = remote,
+ };
+
+ successful = ao2_callback(session->media, OBJ_MULTIPLE, handle_negotiated_sdp_session_media, &callback_data);
+ if (successful && ao2_container_count(successful->c) == ao2_container_count(session->media)) {
+ /* Nothing experienced a catastrophic failure */
+ return 0;
+ }
+ return -1;
}
AST_RWLIST_HEAD_STATIC(session_supplements, ast_sip_session_supplement);
@@ -259,6 +476,7 @@
}
#define DATASTORE_BUCKETS 53
+#define MEDIA_BUCKETS 7
static void session_datastore_destroy(void *obj)
{
@@ -452,6 +670,14 @@
return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
}
+static void session_media_dtor(void *obj)
+{
+ struct ast_sip_session_media *session_media = obj;
+ if (session_media->handler) {
+ session_media->handler->stream_destroy(session_media);
+ }
+}
+
static void session_destructor(void *obj)
{
struct ast_sip_session *session = obj;
@@ -464,8 +690,10 @@
}
ast_free(supplement);
}
+
ast_taskprocessor_unreference(session->serializer);
ao2_cleanup(session->datastores);
+ ao2_cleanup(session->media);
AST_LIST_HEAD_DESTROY(&session->supplements);
ao2_cleanup(session->endpoint);
[... 108 lines stripped ...]
More information about the svn-commits
mailing list