Ignore:
Timestamp:
Feb 8, 2006 10:43:39 PM (19 years ago)
Author:
bennylp
Message:

Finished new pjmedia rewrite

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/src/pjmedia/session.c

    r121 r159  
    1818 */ 
    1919#include <pjmedia/session.h> 
     20#include <pjmedia/errno.h> 
    2021#include <pj/log.h> 
    2122#include <pj/os.h>  
     
    2324#include <pj/string.h> 
    2425#include <pj/assert.h> 
    25  
    26  
    27 typedef struct pj_media_stream_desc 
    28 { 
    29     pj_media_stream_info    info; 
    30     pj_media_stream_t      *enc_stream, *dec_stream; 
    31 } pj_media_stream_desc; 
    32  
    33 struct pj_media_session_t 
     26#include <pj/ctype.h> 
     27 
     28 
     29struct pjmedia_session 
    3430{ 
    3531    pj_pool_t              *pool; 
    36     pj_med_mgr_t           *mediamgr; 
     32    pjmedia_endpt          *endpt; 
    3733    unsigned                stream_cnt; 
    38     pj_media_stream_desc   *stream_desc[PJSDP_MAX_MEDIA]; 
     34    pjmedia_stream_info     stream_info[PJSDP_MAX_MEDIA]; 
     35    pjmedia_stream         *stream[PJSDP_MAX_MEDIA]; 
    3936}; 
    4037 
    4138#define THIS_FILE               "session.c" 
    4239 
    43 #define PJ_MEDIA_SESSION_SIZE   (48*1024) 
    44 #define PJ_MEDIA_SESSION_INC    1024 
     40#define PJMEDIA_SESSION_SIZE    (48*1024) 
     41#define PJMEDIA_SESSION_INC     1024 
    4542 
    4643static const pj_str_t ID_AUDIO = { "audio", 5}; 
     
    5047static const pj_str_t ID_RTP_AVP = { "RTP/AVP", 7 }; 
    5148static const pj_str_t ID_SDP_NAME = { "pjmedia", 7 }; 
    52  
    53 static void session_init (pj_media_session_t *ses) 
    54 { 
    55     pj_memset (ses, 0, sizeof(pj_media_session_t)); 
    56 } 
    57  
    58  
    59 /** 
    60  * Create new session offering. 
    61  */ 
    62 PJ_DEF(pj_media_session_t*)  
    63 pj_media_session_create (pj_med_mgr_t *mgr, const pj_media_sock_info *sock_info) 
    64 { 
    65     pj_pool_factory *pf; 
     49static const pj_str_t ID_RTPMAP = { "rtpmap", 6 }; 
     50 
     51static const pj_str_t STR_INACTIVE = { "inactive", 8 }; 
     52static const pj_str_t STR_SENDRECV = { "sendrecv", 8 }; 
     53static const pj_str_t STR_SENDONLY = { "sendonly", 8 }; 
     54static const pj_str_t STR_RECVONLY = { "recvonly", 8 }; 
     55 
     56 
     57/* 
     58 * Create stream info from SDP media line. 
     59 */ 
     60static pj_status_t create_stream_info_from_sdp(pj_pool_t *pool, 
     61                                               pjmedia_stream_info *si, 
     62                                               const pjmedia_sdp_conn *local_conn, 
     63                                               const pjmedia_sdp_conn *rem_conn, 
     64                                               const pjmedia_sdp_media *local_m, 
     65                                               const pjmedia_sdp_media *rem_m) 
     66{ 
     67    const pjmedia_sdp_attr *attr; 
     68    pjmedia_sdp_rtpmap *rtpmap; 
     69    pj_status_t status; 
     70 
     71 
     72    /* Validate arguments: */ 
     73 
     74    PJ_ASSERT_RETURN(pool && si && local_conn && rem_conn && 
     75                     local_m && rem_m, PJ_EINVAL); 
     76 
     77    /* Reset: */ 
     78 
     79    pj_memset(si, 0, sizeof(*si)); 
     80 
     81    /* Media type: */ 
     82 
     83    if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) == 0) { 
     84 
     85        si->type = PJMEDIA_TYPE_AUDIO; 
     86 
     87    } else if (pj_stricmp(&local_m->desc.media, &ID_VIDEO) == 0) { 
     88 
     89        si->type = PJMEDIA_TYPE_VIDEO; 
     90 
     91    } else { 
     92 
     93        si->type = PJMEDIA_TYPE_UNKNOWN; 
     94 
     95    } 
     96 
     97    /* Media direction: */ 
     98 
     99    if (local_m->desc.port == 0 ||  
     100        pj_inet_addr(&local_conn->addr).s_addr==0 || 
     101        pj_inet_addr(&rem_conn->addr).s_addr==0 || 
     102        pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL) 
     103    { 
     104        /* Inactive stream. */ 
     105 
     106        si->dir = PJMEDIA_DIR_NONE; 
     107 
     108    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) { 
     109 
     110        /* Send only stream. */ 
     111 
     112        si->dir = PJMEDIA_DIR_ENCODING; 
     113 
     114    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) { 
     115 
     116        /* Recv only stream. */ 
     117 
     118        si->dir = PJMEDIA_DIR_DECODING; 
     119 
     120    } else { 
     121 
     122        /* Send and receive stream. */ 
     123 
     124        si->dir = PJMEDIA_DIR_ENCODING_DECODING; 
     125 
     126    } 
     127 
     128 
     129    /* Set remote address: */ 
     130 
     131    si->rem_addr.sin_family = PJ_AF_INET; 
     132    si->rem_addr.sin_port = pj_htons(rem_m->desc.port); 
     133    if (pj_inet_aton(&rem_conn->addr, &si->rem_addr.sin_addr) == 0) { 
     134 
     135        /* Invalid IP address. */ 
     136        return PJMEDIA_EINVALIDIP; 
     137    } 
     138 
     139    /* For this version of PJMEDIA, send and receive media must use 
     140     * the same codec. 
     141     */ 
     142    if (pj_strcmp(&local_m->desc.fmt[0], &rem_m->desc.fmt[0]) != 0) 
     143        return PJMEDIA_EASYMCODEC; 
     144 
     145 
     146    /* And codec must be numeric! */ 
     147    if (!pj_isdigit(*local_m->desc.fmt[0].ptr)) 
     148        return PJMEDIA_EINVALIDPT; 
     149 
     150    /* Find rtpmap for the first codec.  
     151     * For this version of PJMEDIA, we do not support static payload 
     152     * type without rtpmap. 
     153     */ 
     154    attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, NULL); 
     155    if (attr == NULL) 
     156        return PJMEDIA_EMISSINGRTPMAP; 
     157 
     158    status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap); 
     159    if (status != PJ_SUCCESS) 
     160        return status; 
     161 
     162    /* Build codec format info: */ 
     163 
     164    si->fmt.type = si->type; 
     165    si->fmt.pt = pj_strtoul(&local_m->desc.fmt[0]); 
     166    pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name); 
     167    si->fmt.sample_rate = rtpmap->clock_rate; 
     168 
     169    /* Leave SSRC to zero. */ 
     170 
     171    /* Leave jitter buffer parameter. */ 
     172     
     173    return PJ_SUCCESS; 
     174} 
     175 
     176 
     177/** 
     178 * Create new session. 
     179 */ 
     180PJ_DEF(pj_status_t) pjmedia_session_create( pjmedia_endpt *endpt,  
     181                                            unsigned stream_cnt, 
     182                                            const pjmedia_sock_info skinfo[], 
     183                                            const pjmedia_sdp_session *local_sdp, 
     184                                            const pjmedia_sdp_session *rem_sdp, 
     185                                            pjmedia_session **p_session ) 
     186{ 
    66187    pj_pool_t *pool; 
    67     pj_media_session_t *session; 
    68     pj_media_stream_desc *sd; 
    69     unsigned i, codec_cnt; 
    70     pj_codec_mgr *cm; 
    71     const pj_codec_id *codecs[PJSDP_MAX_FMT]; 
    72  
    73     pf = pj_med_mgr_get_pool_factory(mgr); 
    74  
    75     pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL); 
    76     if (!pool) 
    77         return NULL; 
    78  
    79     session = pj_pool_alloc(pool, sizeof(pj_media_session_t)); 
    80     if (!session) 
    81         return NULL; 
    82  
    83     session_init (session); 
    84  
     188    pjmedia_session *session; 
     189    int i; /* Must be signed */ 
     190    pj_status_t status; 
     191 
     192    /* Verify arguments. */ 
     193    PJ_ASSERT_RETURN(endpt && stream_cnt && skinfo && 
     194                     local_sdp && rem_sdp && p_session, PJ_EINVAL); 
     195 
     196    /* Create pool for the session. */ 
     197    pool = pjmedia_endpt_create_pool( endpt, "session",  
     198                                      PJMEDIA_SESSION_SIZE,  
     199                                      PJMEDIA_SESSION_INC); 
     200    PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); 
     201 
     202    session = pj_pool_zalloc(pool, sizeof(pjmedia_session)); 
    85203    session->pool = pool; 
    86     session->mediamgr = mgr; 
    87  
    88     /* Create first stream  */ 
    89     sd = pj_pool_calloc (pool, 1, sizeof(pj_media_stream_desc)); 
    90     if (!sd) 
    91         return NULL; 
    92  
    93     sd->info.type = ID_AUDIO; 
    94     sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING; 
    95     sd->info.transport = ID_RTP_AVP; 
    96     pj_memcpy(&sd->info.sock_info, sock_info, sizeof(*sock_info)); 
    97  
    98     /* Enum audio codecs. */ 
    99     sd->info.fmt_cnt = 0; 
    100     cm = pj_med_mgr_get_codec_mgr (mgr); 
    101     codec_cnt = pj_codec_mgr_enum_codecs(cm, PJSDP_MAX_FMT, codecs); 
    102     if (codec_cnt > PJSDP_MAX_FMT) codec_cnt = PJSDP_MAX_FMT; 
    103     for (i=0; i<codec_cnt; ++i) { 
    104         if (codecs[i]->type != PJ_MEDIA_TYPE_AUDIO) 
    105             continue; 
    106  
    107         sd->info.fmt[sd->info.fmt_cnt].pt = codecs[i]->pt; 
    108         sd->info.fmt[sd->info.fmt_cnt].sample_rate = codecs[i]->sample_rate; 
    109         pj_strdup (pool, &sd->info.fmt[sd->info.fmt_cnt].encoding_name, &codecs[i]->encoding_name); 
    110         ++sd->info.fmt_cnt; 
    111     } 
    112  
    113     session->stream_desc[session->stream_cnt++] = sd; 
    114  
    115     return session; 
    116 } 
    117  
    118 static int sdp_check (const pjsdp_session_desc *sdp) 
    119 { 
    120     int has_conn = 0; 
     204    session->endpt = endpt; 
     205    session->stream_cnt = stream_cnt; 
     206     
     207    /* Stream count is the lower number of stream_cnt or SDP m= lines count */ 
     208    if (stream_cnt < local_sdp->media_count) 
     209        stream_cnt = local_sdp->media_count; 
     210 
     211    /*  
     212     * Create streams:  
     213     */ 
     214    for (i=0; i<(int)stream_cnt; ++i) { 
     215 
     216        pjmedia_stream_info *si = &session->stream_info[i]; 
     217        const pjmedia_sdp_media *local_m = local_sdp->media[i]; 
     218        const pjmedia_sdp_media *rem_m = rem_sdp->media[i]; 
     219        pjmedia_sdp_conn *local_conn, *rem_conn; 
     220 
     221        /* Build stream info based on media line in local SDP */ 
     222        local_conn = local_m->conn ? local_m->conn : local_sdp->conn; 
     223        rem_conn = rem_m->conn ? rem_m->conn : rem_sdp->conn; 
     224 
     225        status = create_stream_info_from_sdp(session->pool, si, 
     226                                             local_conn, rem_conn, 
     227                                             local_m, rem_m); 
     228        if (status != PJ_SUCCESS) 
     229            return status; 
     230 
     231        /* Assign sockinfo */ 
     232        si->sock_info = skinfo[i]; 
     233    } 
     234 
     235    /* 
     236     * Now create the stream! 
     237     */ 
     238    for (i=0; i<(int)stream_cnt; ++i) { 
     239 
     240        status = pjmedia_stream_create(endpt, session->pool, 
     241                                       &session->stream_info[i], 
     242                                       &session->stream[i]); 
     243        if (status != PJ_SUCCESS) { 
     244 
     245            for ( --i; i>=0; ++i) { 
     246                pjmedia_stream_destroy(session->stream[i]); 
     247            } 
     248 
     249            pj_pool_release(session->pool); 
     250            return status; 
     251        } 
     252    } 
     253 
     254 
     255    /* Done. */ 
     256 
     257    *p_session = session; 
     258    return PJ_SUCCESS; 
     259} 
     260 
     261 
     262/** 
     263 * Destroy media session. 
     264 */ 
     265PJ_DEF(pj_status_t) pjmedia_session_destroy (pjmedia_session *session) 
     266{ 
    121267    unsigned i; 
    122268 
    123     if (sdp->conn) 
    124         has_conn = 1; 
    125  
    126     if (sdp->media_count == 0) { 
    127         PJ_LOG(4,(THIS_FILE, "SDP check failed: no media stream definition")); 
    128         return -1; 
    129     } 
    130  
    131     for (i=0; i<sdp->media_count; ++i) { 
    132         pjsdp_media_desc *m = sdp->media[i]; 
    133  
    134         if (!m) { 
    135             pj_assert(0); 
    136             return -1; 
    137         } 
    138  
    139         if (m->desc.fmt_count == 0) { 
    140             PJ_LOG(4,(THIS_FILE, "SDP check failed: no format listed in media stream")); 
    141             return -1; 
    142         } 
    143  
    144         if (!has_conn && m->conn == NULL) { 
    145             PJ_LOG(4,(THIS_FILE, "SDP check failed: no connection information for media")); 
    146             return -1; 
    147         } 
    148     } 
    149  
    150     return 0; 
    151 } 
    152  
    153 /* 
    154  * Create local stream definition that matches SDP received from peer. 
    155  */ 
    156 static pj_media_stream_desc*  
    157 create_stream_from_sdp (pj_pool_t *pool, pj_med_mgr_t *mgr, const pjsdp_conn_info *conn, 
    158                         const pjsdp_media_desc *m, const pj_media_sock_info *sock_info) 
    159 { 
    160     pj_media_stream_desc *sd; 
    161  
    162     sd = pj_pool_calloc (pool, 1, sizeof(pj_media_stream_desc)); 
    163     if (!sd) { 
    164         PJ_LOG(2,(THIS_FILE, "No memory to allocate stream descriptor")); 
    165         return NULL; 
    166     } 
    167  
    168     if (pj_stricmp(&conn->net_type, &ID_IN)==0 &&  
    169         pj_stricmp(&conn->addr_type, &ID_IP4)==0 && 
    170         pj_stricmp(&m->desc.media, &ID_AUDIO)==0 && 
    171         pj_stricmp(&m->desc.transport, &ID_RTP_AVP) == 0)  
    172     { 
    173         /* 
    174          * Got audio stream. 
    175          */ 
    176         unsigned i, codec_cnt; 
    177         pj_codec_mgr *cm; 
    178         const pj_codec_id *codecs[PJSDP_MAX_FMT]; 
    179  
    180         sd->info.type = ID_AUDIO; 
    181         sd->info.transport = ID_RTP_AVP; 
    182         pj_memcpy(&sd->info.sock_info, sock_info, sizeof(*sock_info)); 
    183         sd->info.rem_port = m->desc.port; 
    184         pj_strdup (pool, &sd->info.rem_addr, &conn->addr); 
    185  
    186         /* Enum audio codecs. */ 
    187         sd->info.fmt_cnt = 0; 
    188         cm = pj_med_mgr_get_codec_mgr (mgr); 
    189         codec_cnt = pj_codec_mgr_enum_codecs (cm, PJSDP_MAX_FMT, codecs); 
    190         if (codec_cnt > PJSDP_MAX_FMT) codec_cnt = PJSDP_MAX_FMT; 
    191  
    192         /* Find just one codec which we can support. */ 
    193         for (i=0; i<m->desc.fmt_count && sd->info.fmt_cnt == 0; ++i) { 
    194             unsigned j, fmt_i; 
    195  
    196             /* For static payload, just match payload type. */ 
    197             /* Else match clock rate and encoding name. */ 
    198             fmt_i = pj_strtoul(&m->desc.fmt[i]); 
    199             if (fmt_i < PJ_RTP_PT_DYNAMIC) { 
    200                 for (j=0; j<codec_cnt; ++j) { 
    201                     if (codecs[j]->pt == fmt_i) { 
    202                         sd->info.fmt_cnt = 1; 
    203                         sd->info.fmt[0].type = PJ_MEDIA_TYPE_AUDIO; 
    204                         sd->info.fmt[0].pt = codecs[j]->pt; 
    205                         sd->info.fmt[0].sample_rate = codecs[j]->sample_rate; 
    206                         pj_strdup (pool, &sd->info.fmt[0].encoding_name, &codecs[j]->encoding_name); 
    207                         break; 
    208                     } 
    209                 } 
    210             } else { 
    211  
    212                 /* Find the rtpmap for the payload type. */ 
    213                 const pjsdp_rtpmap_attr *rtpmap = pjsdp_media_desc_find_rtpmap (m, fmt_i); 
    214  
    215                 /* Don't accept the media if no rtpmap for dynamic PT. */ 
    216                 if (rtpmap == NULL) { 
    217                     PJ_LOG(4,(THIS_FILE, "SDP: No rtpmap found for payload id %d", m->desc.fmt[i])); 
    218                     continue; 
    219                 } 
    220  
    221                 /* Check whether we can take this codec. */ 
    222                 for (j=0; j<codec_cnt; ++j) { 
    223                     if (rtpmap->clock_rate == codecs[j]->sample_rate &&  
    224                         pj_stricmp(&rtpmap->encoding_name, &codecs[j]->encoding_name) == 0) 
    225                     { 
    226                         sd->info.fmt_cnt = 1; 
    227                         sd->info.fmt[0].type = PJ_MEDIA_TYPE_AUDIO; 
    228                         sd->info.fmt[0].pt = codecs[j]->pt; 
    229                         sd->info.fmt[0].sample_rate = codecs[j]->sample_rate; 
    230                         sd->info.fmt[0].encoding_name = codecs[j]->encoding_name; 
    231                         break; 
    232                     } 
    233                 } 
    234             } 
    235         } 
    236  
    237         /* Match codec and direction. */ 
    238         if (sd->info.fmt_cnt == 0 || m->desc.port == 0 ||  
    239             pjsdp_media_desc_has_attr(m, PJSDP_ATTR_INACTIVE))  
    240         { 
    241             sd->info.dir = PJ_MEDIA_DIR_NONE; 
    242         } 
    243         else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_RECV_ONLY)) { 
    244             sd->info.dir = PJ_MEDIA_DIR_ENCODING; 
    245         } 
    246         else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_SEND_ONLY)) { 
    247             sd->info.dir = PJ_MEDIA_DIR_DECODING; 
    248         } 
    249         else { 
    250             sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING; 
    251         } 
    252  
    253     } else { 
    254         /* Unsupported media stream. */ 
    255         unsigned fmt_num; 
    256         const pjsdp_rtpmap_attr *rtpmap = NULL; 
    257  
    258         pj_strdup(pool, &sd->info.type, &m->desc.media); 
    259         pj_strdup(pool, &sd->info.transport, &m->desc.transport); 
    260         pj_memset(&sd->info.sock_info, 0, sizeof(*sock_info)); 
    261         pj_strdup (pool, &sd->info.rem_addr, &conn->addr); 
    262         sd->info.rem_port = m->desc.port; 
    263  
    264         /* Just put one format and rtpmap, so that we don't have to make  
    265          * special exception when we convert this stream to SDP. 
    266          */ 
    267  
    268         /* Find the rtpmap for the payload type. */ 
    269         fmt_num = pj_strtoul(&m->desc.fmt[0]); 
    270         rtpmap = pjsdp_media_desc_find_rtpmap (m, fmt_num); 
    271  
    272         sd->info.fmt_cnt = 1; 
    273         if (pj_stricmp(&m->desc.media, &ID_VIDEO)==0) { 
    274             sd->info.fmt[0].type = PJ_MEDIA_TYPE_VIDEO; 
    275             sd->info.fmt[0].pt = fmt_num; 
    276             if (rtpmap) { 
    277                 pj_strdup (pool, &sd->info.fmt[0].encoding_name,  
    278                            &rtpmap->encoding_name); 
    279                 sd->info.fmt[0].sample_rate = rtpmap->clock_rate; 
    280             } 
    281         } else { 
    282             sd->info.fmt[0].type = PJ_MEDIA_TYPE_UNKNOWN; 
    283             pj_strdup(pool, &sd->info.fmt[0].encoding_name, &m->desc.fmt[0]); 
    284         } 
     269    PJ_ASSERT_RETURN(session, PJ_EINVAL); 
     270 
     271    for (i=0; i<session->stream_cnt; ++i) { 
    285272         
    286         sd->info.dir = PJ_MEDIA_DIR_NONE; 
    287     } 
    288  
    289     return sd; 
    290 } 
    291  
    292 /** 
    293  * Create new session based on peer's offering. 
    294  */ 
    295 PJ_DEF(pj_media_session_t*)  
    296 pj_media_session_create_from_sdp (pj_med_mgr_t *mgr, const pjsdp_session_desc *sdp, 
    297                                   const pj_media_sock_info *sock_info) 
    298 { 
    299     pj_pool_factory *pf; 
    300     pj_pool_t *pool; 
    301     pj_media_session_t *session; 
     273        pjmedia_stream_destroy(session->stream[i]); 
     274 
     275    } 
     276 
     277    pj_pool_release (session->pool); 
     278 
     279    return PJ_SUCCESS; 
     280} 
     281 
     282 
     283/** 
     284 * Activate all stream in media session. 
     285 * 
     286 */ 
     287PJ_DEF(pj_status_t) pjmedia_session_resume(pjmedia_session *session, 
     288                                           pjmedia_dir dir) 
     289{ 
    302290    unsigned i; 
    303291 
    304     if (sdp_check(sdp) != 0) 
    305         return NULL; 
    306  
    307     pf = pj_med_mgr_get_pool_factory(mgr); 
    308     pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL); 
    309     if (!pool) 
    310         return NULL; 
    311  
    312     session = pj_pool_alloc(pool, sizeof(pj_media_session_t)); 
    313     if (!session) { 
    314         PJ_LOG(3,(THIS_FILE, "No memory to create media session descriptor")); 
    315         pj_pool_release (pool); 
    316         return NULL; 
    317     } 
    318  
    319     session_init (session); 
    320  
    321     session->pool = pool; 
    322     session->mediamgr = mgr; 
    323  
    324     /* Enumerate each media stream and create our peer. */ 
    325     for (i=0; i<sdp->media_count; ++i) { 
    326         const pjsdp_conn_info *conn; 
    327         const pjsdp_media_desc *m; 
    328         pj_media_stream_desc *sd; 
    329  
    330         m = sdp->media[i]; 
    331         conn = m->conn ? m->conn : sdp->conn; 
    332  
    333         /* 
    334          * Bug: 
    335          *  the sock_info below is used by more than one 'm' lines 
    336          */ 
    337         PJ_TODO(SUPPORT_MORE_THAN_ONE_SDP_M_LINES) 
    338  
    339         sd = create_stream_from_sdp (pool, mgr, conn, m, sock_info); 
    340         pj_assert (sd); 
    341  
    342         session->stream_desc[session->stream_cnt++] = sd; 
    343     } 
    344  
    345     return session; 
    346 } 
    347  
    348 /** 
    349  * Duplicate session. The new session is inactive. 
    350  */ 
    351 PJ_DEF(pj_media_session_t*) 
    352 pj_media_session_clone (const pj_media_session_t *rhs) 
    353 { 
    354     pj_pool_factory *pf; 
    355     pj_pool_t *pool; 
    356     pj_media_session_t *session; 
     292    PJ_ASSERT_RETURN(session, PJ_EINVAL); 
     293 
     294    for (i=0; i<session->stream_cnt; ++i) { 
     295        pjmedia_session_resume_stream(session, i, dir); 
     296    } 
     297 
     298    return PJ_SUCCESS; 
     299} 
     300 
     301 
     302/** 
     303 * Suspend receipt and transmission of all stream in media session. 
     304 * 
     305 */ 
     306PJ_DEF(pj_status_t) pjmedia_session_pause(pjmedia_session *session, 
     307                                          pjmedia_dir dir) 
     308{ 
    357309    unsigned i; 
    358310 
    359     pf = pj_med_mgr_get_pool_factory(rhs->mediamgr); 
    360     pool = pj_pool_create( pf, "session", PJ_MEDIA_SESSION_SIZE, PJ_MEDIA_SESSION_INC, NULL); 
    361     if (!pool) { 
    362         return NULL; 
    363     } 
    364  
    365     session = pj_pool_alloc (pool, sizeof(*session)); 
    366     if (!session) { 
    367         PJ_LOG(3,(THIS_FILE, "No memory to create media session descriptor")); 
    368         pj_pool_release (pool); 
    369         return NULL; 
    370     } 
    371  
    372     session->pool = pool; 
    373     session->mediamgr = rhs->mediamgr; 
    374     session->stream_cnt = rhs->stream_cnt; 
    375  
    376     for (i=0; i<rhs->stream_cnt; ++i) { 
    377         pj_media_stream_desc *sd1 = pj_pool_alloc (session->pool, sizeof(pj_media_stream_desc)); 
    378         const pj_media_stream_desc *sd2 = rhs->stream_desc[i]; 
    379  
    380         if (!sd1) { 
    381             PJ_LOG(3,(THIS_FILE, "No memory to create media stream descriptor")); 
    382             pj_pool_release (pool); 
    383             return NULL; 
    384         } 
    385  
    386         session->stream_desc[i] = sd1; 
    387         sd1->enc_stream = sd1->dec_stream = NULL; 
    388         pj_strdup (pool, &sd1->info.type, &sd2->info.type); 
    389         sd1->info.dir = sd2->info.dir; 
    390         pj_strdup (pool, &sd1->info.transport, &sd2->info.transport); 
    391         pj_memcpy(&sd1->info.sock_info, &sd2->info.sock_info, sizeof(pj_media_sock_info)); 
    392         pj_strdup (pool, &sd1->info.rem_addr, &sd2->info.rem_addr); 
    393         sd1->info.rem_port = sd2->info.rem_port; 
    394         sd1->info.fmt_cnt = sd2->info.fmt_cnt; 
    395         pj_memcpy (sd1->info.fmt, sd2->info.fmt, sizeof(sd2->info.fmt)); 
    396     } 
    397  
    398     return session; 
    399 } 
    400  
    401 /** 
    402  * Create SDP description from the session. 
    403  */ 
    404 PJ_DEF(pjsdp_session_desc*) 
    405 pj_media_session_create_sdp (const pj_media_session_t *session, pj_pool_t *pool, 
    406                              pj_bool_t only_first_fmt) 
    407 { 
    408     pjsdp_session_desc *sdp; 
    409     pj_time_val tv; 
     311    PJ_ASSERT_RETURN(session, PJ_EINVAL); 
     312 
     313    for (i=0; i<session->stream_cnt; ++i) { 
     314        pjmedia_session_pause_stream(session, i, dir); 
     315    } 
     316 
     317    return PJ_SUCCESS; 
     318} 
     319 
     320 
     321/** 
     322 * Suspend receipt and transmission of individual stream in media session. 
     323 */ 
     324PJ_DEF(pj_status_t) pjmedia_session_pause_stream( pjmedia_session *session, 
     325                                                  unsigned index, 
     326                                                  pjmedia_dir dir) 
     327{ 
     328    PJ_ASSERT_RETURN(session && index < session->stream_cnt, PJ_EINVAL); 
     329 
     330    return pjmedia_stream_pause(session->stream[index], dir); 
     331} 
     332 
     333 
     334/** 
     335 * Activate individual stream in media session. 
     336 * 
     337 */ 
     338PJ_DEF(pj_status_t) pjmedia_session_resume_stream( pjmedia_session *session, 
     339                                                   unsigned index, 
     340                                                   pjmedia_dir dir) 
     341{ 
     342    PJ_ASSERT_RETURN(session && index < session->stream_cnt, PJ_EINVAL); 
     343 
     344    return pjmedia_stream_resume(session->stream[index], dir); 
     345} 
     346 
     347/** 
     348 * Enumerate media stream in the session. 
     349 */ 
     350PJ_DEF(pj_status_t) pjmedia_session_enum_streams(const pjmedia_session *session, 
     351                                                 unsigned *count,  
     352                                                 pjmedia_stream_info info[]) 
     353{ 
    410354    unsigned i; 
    411     pj_media_sock_info *c_addr = NULL; 
    412  
    413     if (session->stream_cnt == 0) { 
    414         pj_assert(0); 
    415         return NULL; 
    416     } 
    417  
    418     sdp = pj_pool_calloc (pool, 1, sizeof(pjsdp_session_desc)); 
    419     if (!sdp) { 
    420         PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP session descriptor")); 
    421         return NULL; 
    422     } 
    423  
    424     pj_gettimeofday(&tv); 
    425  
    426     sdp->origin.user = pj_str("-"); 
    427     sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL; 
    428     sdp->origin.net_type = ID_IN; 
    429     sdp->origin.addr_type = ID_IP4; 
    430     sdp->origin.addr = *pj_gethostname(); 
    431  
    432     sdp->name = ID_SDP_NAME; 
    433  
    434     /* If all media addresses are the same, then put the connection 
    435      * info in the session level, otherwise put it in media stream 
    436      * level. 
    437      */ 
    438     for (i=0; i<session->stream_cnt; ++i) { 
    439         if (c_addr == NULL) { 
    440             c_addr = &session->stream_desc[i]->info.sock_info; 
    441         } else if (c_addr->rtp_addr_name.sin_addr.s_addr != session->stream_desc[i]->info.sock_info.rtp_addr_name.sin_addr.s_addr) 
    442         { 
    443             c_addr = NULL; 
    444             break; 
    445         } 
    446     } 
    447  
    448     if (c_addr) { 
    449         /* All addresses are the same, put connection info in session level. */ 
    450         sdp->conn = pj_pool_alloc (pool, sizeof(pjsdp_conn_info)); 
    451         if (!sdp->conn) { 
    452             PJ_LOG(2,(THIS_FILE, "No memory to allocate SDP connection info")); 
    453             return NULL; 
    454         } 
    455  
    456         sdp->conn->net_type = ID_IN; 
    457         sdp->conn->addr_type = ID_IP4; 
    458         pj_strdup2 (pool, &sdp->conn->addr, pj_inet_ntoa(c_addr->rtp_addr_name.sin_addr)); 
    459     } 
    460  
    461     sdp->time.start = sdp->time.stop = 0; 
    462     sdp->attr_count = 0; 
    463  
    464     /* Create each media. */ 
    465     sdp->media_count = 0; 
    466     for (i=0; i<session->stream_cnt; ++i) { 
    467         const pj_media_stream_desc *sd = session->stream_desc[i]; 
    468         pjsdp_media_desc *m; 
    469         unsigned j; 
    470         unsigned fmt_cnt; 
    471         pjsdp_attr *attr; 
    472  
    473         m = pj_pool_calloc (pool, 1, sizeof(pjsdp_media_desc)); 
    474         if (!m) { 
    475             PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP media stream descriptor")); 
    476             return NULL; 
    477         } 
    478  
    479         sdp->media[sdp->media_count++] = m; 
    480  
    481         pj_strdup (pool, &m->desc.media, &sd->info.type); 
    482         m->desc.port = pj_ntohs(sd->info.sock_info.rtp_addr_name.sin_port); 
    483         m->desc.port_count = 1; 
    484         pj_strdup (pool, &m->desc.transport, &sd->info.transport); 
    485  
    486         /* Add format and rtpmap for each codec. */ 
    487         m->desc.fmt_count = 0; 
    488         m->attr_count = 0; 
    489         fmt_cnt = sd->info.fmt_cnt; 
    490         if (fmt_cnt > 0 && only_first_fmt) 
    491             fmt_cnt = 1; 
    492         for (j=0; j<fmt_cnt; ++j) { 
    493             pjsdp_rtpmap_attr *rtpmap; 
    494             pj_str_t *fmt = &m->desc.fmt[m->desc.fmt_count++]; 
    495  
    496             if (sd->info.fmt[j].type==PJ_MEDIA_TYPE_UNKNOWN) { 
    497                 pj_strdup(pool, fmt, &sd->info.fmt[j].encoding_name); 
    498             } else { 
    499                 fmt->ptr = pj_pool_alloc(pool, 8); 
    500                 fmt->slen = pj_utoa(sd->info.fmt[j].pt, fmt->ptr); 
    501  
    502                 rtpmap = pj_pool_calloc(pool, 1, sizeof(pjsdp_rtpmap_attr)); 
    503                 if (rtpmap) { 
    504                     m->attr[m->attr_count++] = (pjsdp_attr*)rtpmap; 
    505                     rtpmap->type = PJSDP_ATTR_RTPMAP; 
    506                     rtpmap->payload_type = sd->info.fmt[j].pt; 
    507                     rtpmap->clock_rate = sd->info.fmt[j].sample_rate; 
    508                     pj_strdup (pool, &rtpmap->encoding_name, &sd->info.fmt[j].encoding_name); 
    509                 } else { 
    510                     PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP rtpmap descriptor")); 
    511                 } 
    512             } 
    513         } 
    514  
    515         /* If we don't have connection info in session level, create one. */ 
    516         if (sdp->conn == NULL) { 
    517             m->conn = pj_pool_alloc (pool, sizeof(pjsdp_conn_info)); 
    518             if (m->conn) { 
    519                 m->conn->net_type = ID_IN; 
    520                 m->conn->addr_type = ID_IP4; 
    521                 pj_strdup2 (pool, &m->conn->addr, pj_inet_ntoa(sd->info.sock_info.rtp_addr_name.sin_addr)); 
    522             } else { 
    523                 PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP media connection info")); 
    524                 return NULL; 
    525             } 
    526         } 
    527  
    528         /* Add additional attribute to the media stream. */ 
    529         attr = pj_pool_alloc(pool, sizeof(pjsdp_attr)); 
    530         if (!attr) { 
    531             PJ_LOG(3,(THIS_FILE, "No memory to allocate SDP attribute")); 
    532             return NULL; 
    533         } 
    534         m->attr[m->attr_count++] = attr; 
    535  
    536         switch (sd->info.dir) { 
    537         case PJ_MEDIA_DIR_NONE: 
    538             attr->type = PJSDP_ATTR_INACTIVE; 
    539             break; 
    540         case PJ_MEDIA_DIR_ENCODING: 
    541             attr->type = PJSDP_ATTR_SEND_ONLY; 
    542             break; 
    543         case PJ_MEDIA_DIR_DECODING: 
    544             attr->type = PJSDP_ATTR_RECV_ONLY; 
    545             break; 
    546         case PJ_MEDIA_DIR_ENCODING_DECODING: 
    547             attr->type = PJSDP_ATTR_SEND_RECV; 
    548             break; 
    549         } 
    550     } 
    551  
    552     return sdp; 
    553 } 
    554  
    555 /** 
    556  * Update session with SDP answer from peer. 
    557  */ 
    558 PJ_DEF(pj_status_t) 
    559 pj_media_session_update (pj_media_session_t *session,  
    560                          const pjsdp_session_desc *sdp) 
    561 { 
    562     unsigned i; 
    563     unsigned count; 
    564  
    565     /* Check SDP */ 
    566     if (sdp_check (sdp) != 0) { 
    567         return -1; 
    568     } 
    569  
    570     /* If the media stream count doesn't match, only update one. */ 
    571     if (session->stream_cnt != sdp->media_count) { 
    572         PJ_LOG(3,(THIS_FILE, "pj_media_session_update : " 
    573                  "SDP media count mismatch! (rmt=%d, lcl=%d)", 
    574                  sdp->media_count, session->stream_cnt)); 
    575         count = (session->stream_cnt < sdp->media_count) ? 
    576             session->stream_cnt : sdp->media_count; 
    577     } else { 
    578         count = session->stream_cnt; 
    579     } 
    580  
    581     for (i=0; i<count; ++i) { 
    582         pj_media_stream_desc *sd = session->stream_desc[i]; 
    583         const pjsdp_media_desc *m = sdp->media[i]; 
    584         const pjsdp_conn_info *conn; 
    585         unsigned j; 
    586  
    587         /* Check that the session is not active. */ 
    588         pj_assert (sd->enc_stream == NULL && sd->dec_stream == NULL); 
    589  
    590         conn = m->conn ? m->conn : sdp->conn; 
    591         pj_assert(conn); 
    592  
    593         /* Update remote address. */ 
    594         sd->info.rem_port = m->desc.port; 
    595         pj_strdup (session->pool, &sd->info.rem_addr, &conn->addr); 
    596  
    597         /* Select one active codec according to what peer wants. */ 
    598         for (j=0; j<sd->info.fmt_cnt; ++j) { 
    599             unsigned fmt_0 = pj_strtoul(&m->desc.fmt[0]); 
    600             if (sd->info.fmt[j].pt == fmt_0) { 
    601                 pj_codec_id temp; 
    602  
    603                 /* Put active format to the front. */ 
    604                 if (j == 0) 
    605                     break; 
    606  
    607                 pj_memcpy(&temp, &sd->info.fmt[0], sizeof(temp)); 
    608                 pj_memcpy(&sd->info.fmt[0], &sd->info.fmt[j], sizeof(temp)); 
    609                 pj_memcpy(&sd->info.fmt[j], &temp, sizeof(temp)); 
    610                 break; 
    611             } 
    612         } 
    613  
    614         if (j == sd->info.fmt_cnt) { 
    615             /* Peer has answered SDP with new codec, which doesn't exist 
    616              * in the offer! 
    617              * Mute this media. 
    618              */ 
    619             PJ_LOG(3,(THIS_FILE, "Peer has answered SDP with new codec!")); 
    620             sd->info.dir = PJ_MEDIA_DIR_NONE; 
    621             continue; 
    622         } 
    623  
    624         /* Check direction. */ 
    625         if (m->desc.port == 0 || pjsdp_media_desc_has_attr(m, PJSDP_ATTR_INACTIVE)) { 
    626             sd->info.dir = PJ_MEDIA_DIR_NONE; 
    627         } 
    628         else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_RECV_ONLY)) { 
    629             sd->info.dir = PJ_MEDIA_DIR_ENCODING; 
    630         } 
    631         else if (pjsdp_media_desc_has_attr(m, PJSDP_ATTR_SEND_ONLY)) { 
    632             sd->info.dir = PJ_MEDIA_DIR_DECODING; 
    633         } 
    634         else { 
    635             sd->info.dir = PJ_MEDIA_DIR_ENCODING_DECODING; 
    636         } 
    637     } 
    638  
    639     return 0; 
    640 } 
    641  
    642 /** 
    643  * Enumerate media streams in the session. 
    644  */ 
    645 PJ_DEF(unsigned) 
    646 pj_media_session_enum_streams (const pj_media_session_t *session,  
    647                                unsigned count, const pj_media_stream_info *info[]) 
    648 { 
    649     unsigned i; 
    650  
    651     if (count > session->stream_cnt) 
    652         count = session->stream_cnt; 
    653  
    654     for (i=0; i<count; ++i) { 
    655         info[i] = &session->stream_desc[i]->info; 
    656     } 
    657  
    658     return session->stream_cnt; 
     355 
     356    PJ_ASSERT_RETURN(session && count && *count && info, PJ_EINVAL); 
     357 
     358    if (*count > session->stream_cnt) 
     359        *count = session->stream_cnt; 
     360 
     361    for (i=0; i<*count; ++i) { 
     362        pj_memcpy(&info[i], &session->stream[i], sizeof(pjmedia_stream_info)); 
     363    } 
     364 
     365    return PJ_SUCCESS; 
    659366} 
    660367 
     
    662369 * Get statistics 
    663370 */ 
    664 PJ_DEF(pj_status_t) 
    665 pj_media_session_get_stat (const pj_media_session_t *session, unsigned index, 
    666                            pj_media_stream_stat *tx_stat, 
    667                            pj_media_stream_stat *rx_stat) 
    668 { 
    669     pj_media_stream_desc *sd; 
    670     int stat_cnt = 0; 
    671  
    672     if (index >= session->stream_cnt) { 
    673         pj_assert(0); 
    674         return -1; 
    675     } 
    676      
    677     sd = session->stream_desc[index]; 
    678  
    679     if (sd->enc_stream && tx_stat) { 
    680         pj_media_stream_get_stat (sd->enc_stream, tx_stat); 
    681         ++stat_cnt; 
    682     } else if (tx_stat) { 
    683         pj_memset (tx_stat, 0, sizeof(*tx_stat)); 
    684     } 
    685  
    686     if (sd->dec_stream && rx_stat) { 
    687         pj_media_stream_get_stat (sd->dec_stream, rx_stat); 
    688         ++stat_cnt; 
    689     } else if (rx_stat) { 
    690         pj_memset (rx_stat, 0, sizeof(*rx_stat)); 
    691     } 
    692  
    693     return stat_cnt ? 0 : -1; 
    694 } 
    695  
    696 /** 
    697  * Modify stream, only when stream is inactive. 
    698  */ 
    699 PJ_DEF(pj_status_t) 
    700 pj_media_session_modify_stream (pj_media_session_t *session, unsigned index, 
    701                                 unsigned modify_flag, const pj_media_stream_info *info) 
    702 { 
    703     pj_media_stream_desc *sd; 
    704  
    705     if (index >= session->stream_cnt) { 
    706         pj_assert(0); 
    707         return -1; 
    708     } 
    709      
    710     sd = session->stream_desc[index]; 
    711  
    712     if (sd->enc_stream || sd->dec_stream) { 
    713         pj_assert(0); 
    714         return -1; 
    715     } 
    716  
    717     if (modify_flag & PJ_MEDIA_STREAM_MODIFY_DIR) { 
    718         sd->info.dir = info->dir; 
    719     } 
    720  
    721     return 0; 
    722 } 
    723  
    724 /** 
    725  * Activate media session. 
    726  */ 
    727 PJ_DEF(pj_status_t) 
    728 pj_media_session_activate (pj_media_session_t *session) 
    729 { 
    730     unsigned i; 
    731     pj_status_t status = 0; 
    732  
    733     for (i=0; i<session->stream_cnt; ++i) { 
    734         pj_status_t rc; 
    735         rc = pj_media_session_activate_stream (session, i); 
    736         if (status == 0) 
    737             status = rc; 
    738     } 
    739     return status; 
    740 } 
    741  
    742 /** 
    743  * Activate individual stream in media session. 
    744  */ 
    745 PJ_DEF(pj_status_t) 
    746 pj_media_session_activate_stream (pj_media_session_t *session, unsigned index) 
    747 { 
    748     pj_media_stream_desc *sd; 
    749     pj_media_stream_create_param scp; 
    750     pj_status_t status; 
    751     pj_time_val tv; 
    752  
    753     if (index < 0 || index >= session->stream_cnt) { 
    754         pj_assert(0); 
    755         return -1; 
    756     } 
    757  
    758     sd = session->stream_desc[index]; 
    759  
    760     if (sd->enc_stream || sd->dec_stream) { 
    761         /* Stream already active. */ 
    762         pj_assert(0); 
    763         return 0; 
    764     } 
    765  
    766     pj_gettimeofday(&tv); 
    767  
    768     /* Initialize parameter to create stream. */ 
    769     pj_memset (&scp, 0, sizeof(scp)); 
    770     scp.codec_id = &sd->info.fmt[0]; 
    771     scp.mediamgr = session->mediamgr; 
    772     scp.dir = sd->info.dir; 
    773     scp.rtp_sock = sd->info.sock_info.rtp_sock; 
    774     scp.rtcp_sock = sd->info.sock_info.rtcp_sock; 
    775     scp.remote_addr = pj_pool_calloc (session->pool, 1, sizeof(pj_sockaddr_in)); 
    776     pj_sockaddr_in_init(scp.remote_addr, &sd->info.rem_addr, sd->info.rem_port); 
    777     scp.ssrc = tv.sec; 
    778     scp.jb_min = 1; 
    779     scp.jb_max = 15; 
    780     scp.jb_maxcnt = 16; 
    781  
    782     /* Build the stream! */ 
    783     status = pj_media_stream_create (session->pool, &sd->enc_stream, &sd->dec_stream, &scp); 
    784  
    785     if (status==0 && sd->enc_stream) { 
    786         status = pj_media_stream_start (sd->enc_stream); 
    787         if (status != 0) 
    788             goto on_error; 
    789     } 
    790     if (status==0 && sd->dec_stream) { 
    791         status = pj_media_stream_start (sd->dec_stream); 
    792         if (status != 0) 
    793             goto on_error; 
    794     } 
    795     return status; 
    796  
    797 on_error: 
    798     if (sd->enc_stream) { 
    799         pj_media_stream_destroy (sd->enc_stream); 
    800         sd->enc_stream = NULL; 
    801     } 
    802     if (sd->dec_stream) { 
    803         pj_media_stream_destroy (sd->dec_stream); 
    804         sd->dec_stream = NULL; 
    805     } 
    806     return status; 
    807 } 
    808  
    809 /** 
    810  * Destroy media session. 
    811  */ 
    812 PJ_DEF(pj_status_t) 
    813 pj_media_session_destroy (pj_media_session_t *session) 
    814 { 
    815     unsigned i; 
    816  
    817     if (!session) 
    818         return -1; 
    819  
    820     for (i=0; i<session->stream_cnt; ++i) { 
    821         pj_media_stream_desc *sd = session->stream_desc[i]; 
    822  
    823         if (sd->enc_stream) { 
    824             pj_media_stream_destroy (sd->enc_stream); 
    825             sd->enc_stream = NULL; 
    826         } 
    827         if (sd->dec_stream) { 
    828             pj_media_stream_destroy (sd->dec_stream); 
    829             sd->dec_stream = NULL; 
    830         } 
    831     } 
    832     pj_pool_release (session->pool); 
    833     return 0; 
    834 } 
    835  
     371PJ_DEF(pj_status_t) pjmedia_session_get_stat(const pjmedia_session *session,  
     372                                             unsigned *count, 
     373                                             pjmedia_stream_stat stat[]) 
     374{ 
     375    PJ_ASSERT_RETURN(session && count && *count && stat, PJ_EINVAL); 
     376 
     377    *count = 0; 
     378    pj_memset(stat, 0, *count * sizeof(pjmedia_stream_stat)); 
     379    return PJ_EINVALIDOP; 
     380} 
     381 
     382 
     383/** 
     384 * Get individual stream statistic. 
     385 */ 
     386PJ_DEF(pj_status_t) pjmedia_session_get_stream_stat( const pjmedia_session *s, 
     387                                                     unsigned index, 
     388                                                     pjmedia_stream_stat *stat) 
     389{ 
     390    PJ_ASSERT_RETURN(s && index < s->stream_cnt && stat, PJ_EINVAL); 
     391    pj_memset(stat, 0, sizeof(pjmedia_stream_stat)); 
     392    return PJ_EINVALIDOP; 
     393} 
     394 
     395 
Note: See TracChangeset for help on using the changeset viewer.