/* The oSIP library implements the Session Initiation Protocol (SIP -rfc3261-) Copyright (C) 2001,2002,2003,2004,2005 Aymeric MOIZARD jack@atosc.org This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef __ICC #pragma warning (disable:810 869 1418 981) #endif #include #include #include #include /* internal include */ /** * Initialize negotiation facility.. * @param config The element to work on. */ int osip_rfc3264_init (struct osip_rfc3264 **config) { osip_rfc3264_t *cnf; *config = NULL; cnf = (osip_rfc3264_t *) osip_malloc (sizeof (osip_rfc3264_t)); if (cnf == NULL) return -1; memset (cnf, 0, sizeof (osip_rfc3264_t)); *config = cnf; return 0; } /** * Free negotiation facility. * @param config The element to work on. */ void osip_rfc3264_free (struct osip_rfc3264 *config) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; int i; if (config == NULL) return; for (i = 0; i < MAX_AUDIO_CODECS; i++) { if (cnf->audio_medias[i] != NULL) { sdp_media_free (cnf->audio_medias[i]); cnf->audio_medias[i] = NULL; } } for (i = 0; i < MAX_VIDEO_CODECS; i++) { if (cnf->video_medias[i] != NULL) { sdp_media_free (cnf->video_medias[i]); cnf->video_medias[i] = NULL; } } for (i = 0; i < MAX_T38_CODECS; i++) { if (cnf->t38_medias[i] != NULL) { sdp_media_free (cnf->t38_medias[i]); cnf->t38_medias[i] = NULL; } } for (i = 0; i < MAX_APP_CODECS; i++) { if (cnf->app_medias[i] != NULL) { sdp_media_free (cnf->app_medias[i]); cnf->app_medias[i] = NULL; } } osip_free (cnf); } /** * Test if a media exist in the configuration. * @param config The element to work on. * @param pos The index of the media element. */ int osip_rfc3264_endof_media (struct osip_rfc3264 *config, int pos) { if (config == NULL) return -1; return 0; } /** * Get a media from the configuration. * @param config The element to work on. * @param pos The index of the media element to get. */ sdp_media_t * osip_rfc3264_get (struct osip_rfc3264 * config, int pos) { if (config == NULL) return NULL; return NULL; } /** * Remove a media from the configuration. * @param config The element to work on. * @param pos The index of the media element to remove. */ int osip_rfc3264_remove (struct osip_rfc3264 *config, int pos) { if (config == NULL) return -1; return 0; } /** * Remove all medias from the configuration. * @param config The element to work on. */ int osip_rfc3264_reset_media (struct osip_rfc3264 *config) { if (config == NULL) return -1; return 0; } /** * Add a media (for audio) in the configuration. * @param config The element to work on. * @param med The media element to add. * @param pos The index of the media element to add. */ int osip_rfc3264_add_audio_media (struct osip_rfc3264 *config, sdp_media_t * med, int pos) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; if (config == NULL) return -1; if (pos >= MAX_AUDIO_CODECS) return -1; if (pos == -1) { for (pos = 0; pos < MAX_AUDIO_CODECS && cnf->audio_medias[pos] != NULL; pos++) { } } if (pos >= MAX_AUDIO_CODECS) return -1; /* no space left */ cnf->audio_medias[pos] = med; return 0; } /** * Remove a media in the configuration. * @param config The element to work on. * @param pos The index of the media element to remove. */ int osip_rfc3264_del_audio_media (struct osip_rfc3264 *config, int pos) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; if (config == NULL) return -1; if (pos >= MAX_AUDIO_CODECS) return -1; sdp_media_free (cnf->audio_medias[pos]); cnf->audio_medias[pos] = NULL; return 0; } /** * Add a media (for video) in the configuration. * @param config The element to work on. * @param med The media element to add. * @param pos The index of the media element to add. */ int osip_rfc3264_add_video_media (struct osip_rfc3264 *config, sdp_media_t * med, int pos) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; if (config == NULL) return -1; if (pos >= MAX_VIDEO_CODECS) return -1; if (pos == -1) { for (pos = 0; pos < MAX_VIDEO_CODECS && cnf->video_medias[pos] != NULL; pos++) { } } if (pos >= MAX_VIDEO_CODECS) return -1; /* no space left */ cnf->video_medias[pos] = med; return 0; } /** * Remove a media in the configuration. * @param config The element to work on. * @param pos The index of the media element to remove. */ int osip_rfc3264_del_video_media (struct osip_rfc3264 *config, int pos) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; if (config == NULL) return -1; if (pos >= MAX_VIDEO_CODECS) return -1; sdp_media_free (cnf->video_medias[pos]); cnf->video_medias[pos] = NULL; return 0; } /** * Add a media (for t38) in the configuration. * @param config The element to work on. * @param med The media element to add. * @param pos The index of the media element to add. */ int osip_rfc3264_add_t38_media (struct osip_rfc3264 *config, sdp_media_t * med, int pos) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; if (config == NULL) return -1; if (pos >= MAX_T38_CODECS) return -1; if (pos == -1) { for (pos = 0; pos < MAX_T38_CODECS && cnf->t38_medias[pos] != NULL; pos++) { } } if (pos >= MAX_T38_CODECS) return -1; /* no space left */ cnf->t38_medias[pos] = med; return 0; } /** * Remove a media in the configuration. * @param config The element to work on. * @param pos The index of the media element to remove. */ int osip_rfc3264_del_t38_media (struct osip_rfc3264 *config, int pos) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; if (config == NULL) return -1; if (pos >= MAX_T38_CODECS) return -1; sdp_media_free (cnf->t38_medias[pos]); cnf->t38_medias[pos] = NULL; return 0; } /** * Search for support of a special codec. * @param config The element to work on. * @param payload The payload to find. * @param rtpmap The rtpmap for the payload. */ sdp_media_t * osip_rfc3264_find_audio (struct osip_rfc3264 * config, char *payload, char *rtpmap) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; int i; if (config == NULL) return NULL; if (rtpmap == NULL) { for (i = 0; i < MAX_AUDIO_CODECS; i++) { if (cnf->audio_medias[i] != NULL) { sdp_media_t *med = cnf->audio_medias[i]; char *str = (char *) osip_list_get (med->m_payloads, 0); /* static payload?: only compare payload number */ if (strlen (str) == strlen (payload) && 0 == osip_strcasecmp (str, payload)) return med; } } return NULL; } for (i = 0; i < MAX_AUDIO_CODECS; i++) { if (cnf->audio_medias[i] != NULL) { sdp_media_t *med = cnf->audio_medias[i]; int pos = 0; while (!osip_list_eol (med->a_attributes, pos)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); if (0 == osip_strcasecmp ("rtpmap", attr->a_att_field) && attr->a_att_value != NULL) { char *tmp = strchr (attr->a_att_value, ' '); char *tmp2 = strchr (rtpmap, ' '); if (tmp != NULL && tmp2 != NULL) { if (0 == osip_strcasecmp (tmp, tmp2)) return med; } } pos++; } } } return NULL; } /** * Search for support of a special codec. * @param config The element to work on. * @param payload The payload to find. * @param rtpmap The rtpmap for the payload. */ sdp_media_t * osip_rfc3264_find_video (struct osip_rfc3264 * config, char *payload, char *rtpmap) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; int i; if (config == NULL) return NULL; if (rtpmap == NULL) { for (i = 0; i < MAX_VIDEO_CODECS; i++) { if (cnf->video_medias[i] != NULL) { sdp_media_t *med = cnf->video_medias[i]; char *str = (char *) osip_list_get (med->m_payloads, 0); /* static payload?: only compare payload number */ if (strlen (str) == strlen (payload) && 0 == osip_strcasecmp (str, payload)) return med; } } return NULL; } for (i = 0; i < MAX_VIDEO_CODECS; i++) { if (cnf->video_medias[i] != NULL) { sdp_media_t *med = cnf->video_medias[i]; int pos = 0; while (!osip_list_eol (med->a_attributes, pos)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); if (0 == osip_strcasecmp ("rtpmap", attr->a_att_field) && attr->a_att_value != NULL) { char *tmp = strchr (attr->a_att_value, ' '); char *tmp2 = strchr (rtpmap, ' '); if (tmp != NULL && tmp2 != NULL) { if (0 == osip_strcasecmp (tmp, tmp2)) return med; } } pos++; } } } return NULL; } /** * Search for support of a special codec. * @param config The element to work on. * @param payload The payload to find. */ sdp_media_t * osip_rfc3264_find_t38 (struct osip_rfc3264 * config, char *payload) { //osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; if (config == NULL) return NULL; return NULL; } /** * Search for support of a special codec. * @param config The element to work on. * @param payload The payload to find. */ sdp_media_t * osip_rfc3264_find_app (struct osip_rfc3264 * config, char *payload) { // osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; if (config == NULL) return NULL; return NULL; } /** * Compare remote sdp packet against local supported media. * Only one media line is checked. * * @param config The element to work on. * @param remote_sdp The remote SDP packet. * @param audio_tab The local list of media supported by both side. * @param video_tab The local list of media supported by both side. * @param t38_tab The local list of media supported by both side. * @param app_tab The local list of media supported by both side. * @param pos_media The position of the media line to match. */ int osip_rfc3264_match (struct osip_rfc3264 *config, sdp_message_t * remote_sdp, sdp_media_t * audio_tab[], sdp_media_t * video_tab[], sdp_media_t * t38_tab[], sdp_media_t * app_tab[], int pos_media) { sdp_media_t *remote_med; int pos; audio_tab[0] = NULL; video_tab[0] = NULL; t38_tab[0] = NULL; app_tab[0] = NULL; if (config == NULL) return -1; pos = 0; while (!sdp_message_endof_media (remote_sdp, pos)) { if (pos_media == 0) { remote_med = osip_list_get (remote_sdp->m_medias, pos); if (remote_med->m_media != NULL && 0 == osip_strcasecmp (remote_med->m_media, "audio")) { osip_rfc3264_match_audio (config, remote_sdp, remote_med, audio_tab); } else if (remote_med->m_media != NULL && 0 == osip_strcasecmp (remote_med->m_media, "video")) { osip_rfc3264_match_video (config, remote_sdp, remote_med, video_tab); } else if (remote_med->m_media != NULL && 0 == osip_strcasecmp (remote_med->m_media, "image")) { osip_rfc3264_match_t38 (config, remote_sdp, remote_med, t38_tab); } else if (remote_med->m_media != NULL && 0 == osip_strcasecmp (remote_med->m_media, "application")) { osip_rfc3264_match_app (config, remote_sdp, remote_med, app_tab); } return 0; } remote_med = NULL; pos++; pos_media--; } return -1; } /** * Compare remote sdp packet against local supported media for audio. * @param config The element to work on. * @param remote_sdp The remote SDP packet. * @param remote_med The remote Media SDP line. * @param audio_tab The local list of media supported by both side. */ int osip_rfc3264_match_audio (struct osip_rfc3264 *config, sdp_message_t * remote_sdp, sdp_media_t * remote_med, sdp_media_t * audio_tab[]) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; int num = 0; int pos; audio_tab[0] = NULL; if (cnf == NULL) return -1; /* search for the audio media line */ pos = 0; while (!osip_list_eol (remote_med->m_payloads, pos)) { char *payload = (char *) osip_list_get (remote_med->m_payloads, pos); sdp_media_t *local_med; char *rtpmap = NULL; int posattr = 0; /* search for the rtpmap associated to the payload */ while (!osip_list_eol (remote_med->a_attributes, posattr)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (remote_med->a_attributes, posattr); if (0 == osip_strncasecmp (attr->a_att_field, "rtpmap", 6)) { if (attr->a_att_value != NULL && 0 == osip_strncasecmp (attr->a_att_value, payload, strlen (payload))) { /* TODO check if it was not like 101: == 10 */ rtpmap = attr->a_att_value; break; } } posattr++; } local_med = osip_rfc3264_find_audio (config, payload, rtpmap); if (local_med != NULL) { /* found a supported codec? */ audio_tab[num] = local_med; num++; } /* search for support of this codec in local media list */ pos++; } audio_tab[num] = NULL; return 0; } /** * Compare remote sdp packet against local supported media for video. * @param config The element to work on. * @param remote_sdp The remote SDP packet. * @param remote_med The remote Media SDP line. * @param video_tab The local list of media supported by both side. */ int osip_rfc3264_match_video (struct osip_rfc3264 *config, sdp_message_t * remote_sdp, sdp_media_t * remote_med, sdp_media_t * video_tab[]) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; int num = 0; int pos; video_tab[0] = NULL; if (cnf == NULL) return -1; /* search for the video media line */ pos = 0; while (!osip_list_eol (remote_med->m_payloads, pos)) { char *payload = (char *) osip_list_get (remote_med->m_payloads, pos); sdp_media_t *local_med; char *rtpmap = NULL; int posattr = 0; /* search for the rtpmap associated to the payload */ while (!osip_list_eol (remote_med->a_attributes, posattr)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (remote_med->a_attributes, posattr); if (0 == osip_strncasecmp (attr->a_att_field, "rtpmap", 6)) { if (attr->a_att_value != NULL && 0 == osip_strncasecmp (attr->a_att_value, payload, strlen (payload))) { /* TODO check if it was not like 101: == 10 */ rtpmap = attr->a_att_value; break; } } posattr++; } local_med = osip_rfc3264_find_video (config, payload, rtpmap); if (local_med != NULL) { /* found a supported codec? */ video_tab[num] = local_med; num++; } /* search for support of this codec in local media list */ pos++; } video_tab[num] = NULL; return 0; } /** * Compare remote sdp packet against local supported media for t38. * @param config The element to work on. * @param remote_sdp The remote SDP packet. * @param remote_med The remote Media SDP line. * @param t38_tab The local list of media supported by both side. */ int osip_rfc3264_match_t38 (struct osip_rfc3264 *config, sdp_message_t * remote_sdp, sdp_media_t * remote_med, sdp_media_t * t38_tab[]) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; t38_tab[0] = NULL; if (cnf == NULL) return -1; return 0; } /** * Compare remote sdp packet against local supported media for application. * @param config The element to work on. * @param remote_sdp The remote SDP packet. * @param remote_med The remote Media SDP line. * @param app_tab The local list of media supported by both side. */ int osip_rfc3264_match_app (struct osip_rfc3264 *config, sdp_message_t * remote_sdp, sdp_media_t * remote_med, sdp_media_t * app_tab[]) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; app_tab[0] = NULL; if (cnf == NULL) return -1; return 0; } /** * Prepare an uncomplete answer. * @param config The element to work on. * @param remote_sdp The remote SDP packet. * @param local_sdp The local SDP packet to prepare. * @param length The local SDP packet's length. */ int osip_rfc3264_prepare_answer (struct osip_rfc3264 *config, sdp_message_t * remote_sdp, char *local_sdp, int length) { int pos, pos2; if (config == NULL) return -1; if (remote_sdp == NULL) return -1; if (osip_list_size (remote_sdp->t_descrs) > 0) #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (local_sdp, 4096, "v=0\r\n\ o=userX 20000001 20000001 IN IP4 TOREPLACE\r\n\ s=-\r\n\ c=IN IP4 TOREPLACE\r\n"); #else snprintf (local_sdp, 4096, "v=0\r\n\ o=userX 20000001 20000001 IN IP4 TOREPLACE\r\n\ s=-\r\n\ c=IN IP4 TOREPLACE\r\n"); #endif /* Fill t= (and r=) fields */ pos = 0; while (!osip_list_eol (remote_sdp->t_descrs, pos)) { char tmp[100]; sdp_time_descr_t *td; td = (sdp_time_descr_t *) osip_list_get (remote_sdp->t_descrs, pos); if (td->t_start_time != NULL && td->t_stop_time != NULL) #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (tmp, 100, "t=%s %s\r\n", td->t_start_time, td->t_stop_time); #else snprintf (tmp, 100, "t=%s %s\r\n", td->t_start_time, td->t_stop_time); #endif else #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (tmp, 100, "t=0 0\r\n"); #else snprintf (tmp, 100, "t=0 0\r\n"); #endif if ((int) (strlen (local_sdp) + strlen (tmp) + 1) < length) { strcat (local_sdp, tmp); pos2 = 0; while (!osip_list_eol (td->r_repeats, pos2)) { char *str = (char *) osip_list_get (td->r_repeats, pos2); if ((int) (strlen (local_sdp) + strlen (str) + 5 + 1) < length) { strcat (local_sdp, "r="); strcat (local_sdp, str); strcat (local_sdp, "\r\n"); } else return -1; pos2++; } } else return -1; pos++; } pos = 0; while (!osip_list_eol (remote_sdp->m_medias, pos)) { int posattr = 0; char tmp[200]; char tmp2[200]; char inactive = 'X'; sdp_media_t *med; #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (tmp2, 199, "\r\n"); #else snprintf (tmp2, 199, "\r\n"); #endif med = (sdp_media_t *) osip_list_get (remote_sdp->m_medias, pos); /* search for the rtpmap associated to the payload */ while (!osip_list_eol (med->a_attributes, posattr)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (med->a_attributes, posattr); if (strlen (attr->a_att_field) == 8 && attr->a_att_value == NULL) { if (0 == osip_strncasecmp (attr->a_att_field, "sendonly", 8)) { #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (tmp2, 199, "\r\na=recvonly\r\n"); #else snprintf (tmp2, 199, "\r\na=recvonly\r\n"); #endif break; } else if (0 == osip_strncasecmp (attr->a_att_field, "recvonly", 8)) { #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (tmp2, 199, "\r\na=sendonly\r\n"); #else snprintf (tmp2, 199, "\r\na=sendonly\r\n"); #endif break; } else if (0 == osip_strncasecmp (attr->a_att_field, "sendrecv", 8)) { break; } else if (0 == osip_strncasecmp (attr->a_att_field, "inactive", 8)) { #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (tmp2, 199, "\r\na=inactive\r\n"); #else snprintf (tmp2, 199, "\r\na=inactive\r\n"); #endif inactive = '0'; break; } } posattr++; } if (med->m_media != NULL && med->m_proto != NULL && med->m_number_of_port == NULL) { #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (tmp, 199, "m=%s %c %s ", med->m_media, inactive, med->m_proto); #else snprintf (tmp, 199, "m=%s %c %s ", med->m_media, inactive, med->m_proto); #endif } else if (med->m_media != NULL && med->m_proto != NULL && med->m_number_of_port != NULL) { #if !defined __PALMOS__ && (defined WIN32 || defined _WIN32_WCE) _snprintf (tmp, 199, "m=%s %c %s/%s ", med->m_media, inactive, med->m_proto, med->m_number_of_port); #else snprintf (tmp, 199, "m=%s %c %s/%s ", med->m_media, inactive, med->m_proto, med->m_number_of_port); #endif } else return -1; if ((int) (strlen (local_sdp) + strlen (tmp) + 1) < length) strcat (local_sdp, tmp); else return -1; if ((int) (strlen (local_sdp) + strlen (tmp2) + 1) < length) strcat (local_sdp, tmp2); else return -1; pos++; } return 0; } /** * Agree to support a specific codec. * This method should be called for each codec returned by * osip_rfc3264_match(...) that the calle agree to support. * * @param config The element to work on. * @param remote_sdp The remote SDP packet. * @param local_sdp The local SDP packet to complete. * @param med One of the media returned by osip_rfc3264_match. * @param mline The position of the media line to complete. */ int osip_rfc3264_complete_answer (struct osip_rfc3264 *config, sdp_message_t * remote_sdp, sdp_message_t * local_sdp, sdp_media_t * med, int mline) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; sdp_media_t *remote_med = NULL; sdp_media_t *local_med = NULL; int pos; if (cnf == NULL) return -1; if (remote_sdp == NULL) return -1; if (med == NULL) return -1; if (mline < 0) return -1; if (local_sdp == NULL) return -1; pos = 0; while (!osip_list_eol (remote_sdp->m_medias, pos)) { remote_med = (sdp_media_t *) osip_list_get (remote_sdp->m_medias, pos); local_med = (sdp_media_t *) osip_list_get (local_sdp->m_medias, pos); if (pos == mline) break; remote_med = NULL; local_med = NULL; pos++; } if (remote_med == NULL) return -1; pos = 0; while (!osip_list_eol (med->a_attributes, pos)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); if (0 == osip_strcasecmp ("rtpmap", attr->a_att_field) && attr->a_att_value != NULL) { sdp_attribute_t *mattr; char *tmp; /* fill the m= line */ tmp = (char *) osip_list_get (med->m_payloads, 0); if (tmp != NULL) osip_list_add (local_med->m_payloads, osip_strdup (tmp), -1); else return -1; sdp_attribute_init (&mattr); mattr->a_att_field = osip_strdup (attr->a_att_field); mattr->a_att_value = osip_strdup (attr->a_att_value); /* fill the a= line */ osip_list_add (local_med->a_attributes, mattr, -1); return 0; } } return -1; /* no rtpmap found? It is mandatory in audio and video media */ } /** * Agree to support a specific codec. * This method should be called for each codec returned by * osip_rfc3264_match(...) * * @param config The element to work on. * @param med One of the media returned by osip_rfc3264_match * @param remote_sdp The remote SDP packet. * @param local_sdp The local SDP packet to prepare. */ int osip_rfc3264_accept_codec (struct osip_rfc3264 *config, sdp_media_t * med, sdp_message_t * remote_sdp, sdp_message_t * local_sdp) { if (config == NULL) return -1; return 0; } /* #ifdef RFC3264_DEBUG */ /** * List supported codecs. (for debugging purpose only) * * @param config The element to work on. */ int __osip_rfc3264_print_codecs (struct osip_rfc3264 *config) { osip_rfc3264_t *cnf = (osip_rfc3264_t *) config; int i, pos; if (config == NULL) return -1; fprintf (stdout, "Audio codecs Supported:\n"); for (i = 0; i < MAX_AUDIO_CODECS; i++) { if (cnf->audio_medias[i] != NULL) { sdp_media_t *med = cnf->audio_medias[i]; char *str = (char *) osip_list_get (med->m_payloads, 0); fprintf (stdout, "\tm=%s %s %s %s\n", med->m_media, med->m_port, med->m_proto, str); pos = 0; while (!osip_list_eol (med->a_attributes, pos)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); fprintf (stdout, "\ta=%s:%s\n", attr->a_att_field, attr->a_att_value); pos++; } fprintf (stdout, "\n"); } } fprintf (stdout, "Video codecs Supported:\n"); for (i = 0; i < MAX_VIDEO_CODECS; i++) { if (cnf->video_medias[i] != NULL) { sdp_media_t *med = cnf->video_medias[i]; char *str = (char *) osip_list_get (med->m_payloads, 0); fprintf (stdout, "\tm=%s %s %s %s\n", med->m_media, med->m_port, med->m_proto, str); pos = 0; while (!osip_list_eol (med->a_attributes, pos)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); fprintf (stdout, "\ta=%s:%s\n", attr->a_att_field, attr->a_att_value); pos++; } fprintf (stdout, "\n"); } } fprintf (stdout, "t38 configs Supported:\n"); for (i = 0; i < MAX_T38_CODECS; i++) { if (cnf->t38_medias[i] != NULL) { sdp_media_t *med = cnf->t38_medias[i]; fprintf (stdout, "m=%s %s %s X\n", med->m_media, med->m_port, med->m_proto); pos = 0; while (!osip_list_eol (med->a_attributes, pos)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); fprintf (stdout, "\ta=%s:%s\n", attr->a_att_field, attr->a_att_value); pos++; } fprintf (stdout, "\n"); } } fprintf (stdout, "Application config Supported:\n"); for (i = 0; i < MAX_APP_CODECS; i++) { if (cnf->app_medias[i] != NULL) { sdp_media_t *med = cnf->app_medias[i]; fprintf (stdout, "m=%s %s %s X\n", med->m_media, med->m_port, med->m_proto); pos = 0; while (!osip_list_eol (med->a_attributes, pos)) { sdp_attribute_t *attr = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); fprintf (stdout, "\ta=%s:%s\n", attr->a_att_field, attr->a_att_value); pos++; } fprintf (stdout, "\n"); } } return 0; } /* #endif */