Changeset 169


Ignore:
Timestamp:
Feb 9, 2006 2:01:40 PM (18 years ago)
Author:
bennylp
Message:

Updated with new jitter buffer, and statistics in pjsua

Location:
pjproject/trunk
Files:
17 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjmedia/include/pjmedia/errno.h

    r162 r169  
    277277 
    278278 
     279/************************************************************ 
     280 * JITTER BUFFER 
     281 ***********************************************************/ 
     282 
     283 
    279284PJ_END_DECL 
    280285 
  • pjproject/trunk/pjmedia/include/pjmedia/jbuf.h

    r121 r169  
    3131 */ 
    3232 
    33 #include <pj/types.h> 
     33#include <pjmedia/types.h> 
    3434 
    3535 
     
    3737 
    3838 
    39 /** 
    40  * Opaque declaration of internal frame type used by jitter buffer.  
    41  */ 
    42 struct pj_jbframe; 
     39enum pjmedia_jb_frame_type  
     40{ 
     41    PJMEDIA_JB_MISSING_FRAME   = 0, 
     42    PJMEDIA_JB_NORMAL_FRAME    = 1, 
     43    PJMEDIA_JB_ZERO_FRAME      = 2, 
     44}; 
    4345 
    4446 
    45 /** 
    46  * Miscelaneous operation result/status.  
    47  */  
    48 typedef enum jb_op_status 
    49 { 
    50     PJ_JB_STATUS_TOO_OLD = -2,          /** The packet is too old. */ 
    51     PJ_JB_STATUS_TOO_SOON = -3,         /** The packet is too soon. */ 
    52     PJ_JB_STATUS_FRAME_NULL = -4,       /** No packet can be retrieved */ 
    53     PJ_JB_STATUS_FRAME_MISSING = -5,    /** The specified packet is missing/lost */ 
    54 } jb_op_status; 
     47#define PJMEDIA_JB_DEFAULT_INIT_PREFETCH    15 
    5548 
    5649 
    57 /* 
    58  * Frame list, container abstraction for ordered list with fixed maximum 
    59  * size. It is used internally by the jitter buffer. 
    60  */   
    61 typedef struct pj_jbframelist 
    62 { 
    63     unsigned            head, count, maxcount; 
    64     struct pj_jbframe  *frames; 
    65 } pj_jbframelist; 
    66  
    67  
    68 /** 
    69  * Jitter buffer implementation. 
    70  */  
    71 typedef struct pj_jitter_buffer 
    72 { 
    73     pj_jbframelist  lst;            /** The frame list. */ 
    74     int             level;          /** Current, real-time jitter level. */ 
    75     int             max_level;      /** Maximum level for the period.    */ 
    76     unsigned        prefetch;       /** Prefetch count currently used. */ 
    77     unsigned        get_cnt;        /** Number of get operation during prefetch state. */ 
    78     unsigned        min;            /** Minimum jitter size, in packets. */ 
    79     unsigned        max;            /** Maximum jitter size, in packets. */ 
    80     pj_uint32_t     lastseq;        /** Last sequence number put to jitter buffer. */ 
    81     unsigned        upd_count;      /** Internal counter to manage update interval. */ 
    82     int             state;          /** Jitter buffer state (1==operational) */ 
    83     int             last_op;        /** Last jitter buffer operation. */ 
    84 } pj_jitter_buffer; 
    85  
    86  
    87 /** 
    88  * Initialize jitter buffer with the specified parameters. 
    89  * This function will allocate internal frame buffer from the specified pool. 
    90  * @param jb The jitter buffer to be initialized. 
    91  * @param pool Pool where memory will be allocated for the frame buffer. 
    92  * @param min The minimum value of jitter buffer, in packets. 
    93  * @param max The maximum value of jitter buffer, in packets. 
    94  * @param maxcount The maximum number of delay, in packets, which must be 
    95  *                 greater than max. 
    96  * @return PJ_SUCCESS on success. 
    97  */ 
    98 PJ_DECL(pj_status_t) pj_jb_init(pj_jitter_buffer *jb, pj_pool_t *pool,  
    99                                 unsigned min, unsigned max, unsigned maxcount); 
    100  
    101 /** 
    102  * Reset jitter buffer according to the parameters specified when the jitter 
    103  * buffer was initialized. Any packets currently in the buffer will be  
    104  * discarded. 
    105  */ 
    106 PJ_DECL(void) pj_jb_reset(pj_jitter_buffer *jb); 
    107  
    108 /** 
    109  * Put a pointer to the buffer with the specified sequence number. The pointer 
    110  * normally points to a buffer held by application, and this pointer will be 
    111  * returned later on when pj_jb_get() is called. The jitter buffer will not try 
    112  * to interpret the content of this pointer. 
    113  * @return: 
    114  *   - PJ_SUCCESS on success. 
    115  *   - PJ_JB_STATUS_TOO_OLD when the packet is too old. 
    116  *   - PJ_JB_STATUS_TOO_SOON when the packet is too soon. 
    117  */ 
    118 PJ_DECL(pj_status_t) pj_jb_put( pj_jitter_buffer *jb, pj_uint32_t extseq, void *buf ); 
    119  
    120 /** 
    121  * Get the earliest data from the jitter buffer. ONLY when the operation succeeds, 
    122  * the function returns both sequence number and a pointer in the parameters. 
    123  * This returned data corresponds to sequence number and pointer that were 
    124  * given to jitter buffer in the previous pj_jb_put operation. 
    125  * @return  
    126  *  - PJ_SUCCESS on success 
    127  *  - PJ_JB_STATUS_FRAME_NULL when there is no frames to be returned. 
    128  *  - PJ_JB_STATUS_FRAME_MISSING if the jitter buffer detects that the packet  
    129  *     is lost. Application may run packet concealment algorithm when it  
    130  *     receives this status. 
    131  */ 
    132 PJ_DECL(pj_status_t) pj_jb_get( pj_jitter_buffer *jb, pj_uint32_t *extseq, void **buf ); 
     50PJ_DECL(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool,  
     51                                        int frame_size,  
     52                                        int initial_prefetch,  
     53                                        int max_count, 
     54                                        pjmedia_jbuf **p_jb); 
     55PJ_DECL(pj_status_t) pjmedia_jbuf_destroy(pjmedia_jbuf *jb); 
     56PJ_DECL(pj_status_t) pjmedia_jbuf_put_frame(pjmedia_jbuf *jb,  
     57                                            const void *frame,  
     58                                            pj_size_t frame_size,  
     59                                            int frame_seq); 
     60PJ_DECL(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb,  
     61                                             void *frame,  
     62                                             char *p_frame_type); 
     63PJ_DECL(unsigned)    pjmedia_jbuf_get_prefetch_size(pjmedia_jbuf *jb); 
     64PJ_DECL(unsigned)    pjmedia_jbuf_get_current_size(pjmedia_jbuf *jb); 
    13365 
    13466 
  • pjproject/trunk/pjmedia/include/pjmedia/session.h

    r162 r169  
    4040 
    4141/** 
     42 * Session info, retrieved from a session by calling 
     43 * #pjmedia_session_get_info(). 
     44 */ 
     45struct pjmedia_session_info 
     46{ 
     47    unsigned            stream_cnt; 
     48    pjmedia_stream_info stream_info[PJSDP_MAX_MEDIA]; 
     49}; 
     50 
     51 
     52/** 
    4253 * Create new session offering based on the local and remote SDP. 
    4354 * The session will start immediately. 
     
    6475                                             const pjmedia_sdp_session *rem_sdp, 
    6576                                             pjmedia_session **p_session ); 
     77 
     78 
     79/** 
     80 * Get session info. 
     81 * 
     82 * @param session       The session which info is being queried. 
     83 * @param info          Pointer to receive session info. 
     84 * 
     85 * @return              PJ_SUCCESS on success. 
     86 */ 
     87PJ_DECL(pj_status_t) pjmedia_session_get_info( pjmedia_session *session, 
     88                                               pjmedia_session_info *info ); 
    6689 
    6790 
     
    138161 * 
    139162 * @param session       The media session. 
    140  * @param count         On input, specifies the number of elements in 
    141  *                      the array. On output, the number will be filled 
    142  *                      with number of streams in the session. 
    143  * @param stat          Array of stream statistics. 
     163 * @param index         Stream index. 
     164 * @param stat          Stream statistic. 
    144165 * 
    145166 * @return              PJ_SUCCESS on success. 
    146167 */ 
    147 PJ_DECL(pj_status_t) pjmedia_session_get_stat(const pjmedia_session *session, 
    148                                               unsigned *count, 
    149                                               pjmedia_stream_stat stat[]); 
    150  
    151 /** 
    152  * Get individual stream statistics. The stream statistic shows various 
    153  * indicators such as packet count, packet lost, jitter, delay, etc. 
    154  * 
    155  * @param s             The media session. 
    156  * @param index         The stream index. 
    157  * @param stat          Stream statistics. 
    158  * 
    159  * @return              PJ_SUCCESS on success. 
    160  */ 
    161 PJ_DECL(pj_status_t) pjmedia_session_get_stream_stat(const pjmedia_session *s, 
     168PJ_DECL(pj_status_t) pjmedia_session_get_stream_stat(pjmedia_session *session, 
    162169                                                     unsigned index, 
    163170                                                     pjmedia_stream_stat *stat); 
  • pjproject/trunk/pjmedia/include/pjmedia/types.h

    r162 r169  
    167167 
    168168/** 
     169 * Media session info. 
     170 */ 
     171typedef struct pjmedia_session_info pjmedia_session_info; 
     172 
     173/** 
    169174 * Forward declaration for SDP attribute (sdp.h) 
    170175 */ 
     
    206211typedef struct pjmedia_sdp_neg pjmedia_sdp_neg; 
    207212 
     213/** 
     214 * Types of frame returned from jitter buffer (jbuf.h). 
     215 */ 
     216typedef enum pjmedia_jb_frame_type pjmedia_jb_frame_type; 
     217 
     218/** 
     219 * Opaque declaration for jitter buffer. 
     220 */ 
     221typedef struct pjmedia_jbuf pjmedia_jbuf; 
    208222 
    209223#endif  /* __PJMEDIA_TYPES_H__ */ 
  • pjproject/trunk/pjmedia/src/pjmedia/jbuf.c

    r129 r169  
    1818 */ 
    1919#include <pjmedia/jbuf.h> 
    20 #include <pj/log.h> 
     20#include <pjmedia/errno.h> 
    2121#include <pj/pool.h> 
    2222#include <pj/assert.h> 
     
    2424 
    2525 
    26 /* 
    27  * At the current state, this is basicly an ugly jitter buffer. 
    28  * It worked before by observing level, bit it doesn't work. 
    29  * Then I used the size, which makes the level obsolete. 
    30  * That's why it's ugly! 
    31  */ 
    32  
    33 #define MAX_SEQ_RANGE   1000    /* Range in which sequence is considered still within session */ 
    34 #define UPDATE_DURATION 20      /* Number of frames retrieved before jitter is updated */ 
    35  
    36 #define THIS_FILE   "jbuf" 
    37  
    38 /* Individual frame in the frame list. */  
    39 struct pj_jbframe 
    40 { 
    41     pj_uint32_t  extseq; 
    42     void        *buf; 
     26 
     27struct jb_framelist 
     28{ 
     29    char        *flist_buffer; 
     30    int         *flist_frame_type; 
     31    unsigned     flist_frame_size; 
     32    unsigned     flist_max_count; 
     33    unsigned     flist_empty; 
     34    unsigned     flist_head; 
     35    unsigned     flist_tail; 
     36    unsigned     flist_origin; 
    4337}; 
    4438 
    4539 
    46 /* Jitter buffer state. */  
    47 typedef enum jb_state_t 
    48 { 
    49     JB_PREFETCH, 
    50     JB_NORMAL, 
    51 } jb_state_t; 
    52  
    53  
    54 /* Jitter buffer last operation. */  
    55 typedef enum jb_op_t 
    56 { 
    57     JB_PUT, 
    58     JB_GET, 
    59 } jb_op_t; 
    60  
    61  
    62 /* Short name for convenience. */  
    63 typedef struct pj_jitter_buffer JB; 
    64  
    65  
    66 /* Initialize framelist. */  
    67 static pj_status_t 
    68 pj_framelist_init( pj_jbframelist *lst, pj_pool_t *pool, unsigned maxcount ) 
    69 { 
    70     PJ_LOG(5, (THIS_FILE, "..pj_frame_list_init [lst=%p], maxcount=%d", lst, maxcount)); 
    71  
    72     pj_memset(lst, 0, sizeof(*lst)); 
    73     lst->maxcount = maxcount; 
    74     lst->frames = pj_pool_calloc( pool, maxcount, sizeof(*lst->frames) ); 
    75     if (lst->frames == NULL) { 
    76         PJ_LOG(1,(THIS_FILE, "Unable to allocate frame list!")); 
    77         return -1; 
    78     } 
    79     return 0;     
    80 } 
    81  
    82 /* Reset framelist. */ 
    83 static void  
    84 pj_framelist_reset( pj_jbframelist *lst ) 
    85 { 
    86     PJ_LOG(6, (THIS_FILE, "..pj_frame_list_reset [lst=%p]", lst)); 
    87  
    88     lst->count = 0; 
    89     lst->head = 0; 
    90     lst->frames[0].extseq = 0; 
    91 } 
    92  
    93 /* Put a buffer with the specified sequence into the ordered list. */  
    94 static int  
    95 pj_framelist_put( pj_jbframelist *lst, pj_uint32_t extseq, void *buf ) 
    96 { 
    97     unsigned pos = (unsigned)-1; 
    98     pj_uint32_t startseq = lst->frames[lst->head].extseq; 
    99  
    100     if (lst->count == 0) { 
    101         /* Empty list. Initialize frame list. */ 
    102         PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_put [lst=%p], empty, seq=%u@pos=%d",  
    103                    lst, extseq, lst->head)); 
    104  
    105         lst->head = 0; 
    106         lst->count = 1; 
    107         lst->frames[0].buf = buf; 
    108         lst->frames[0].extseq = extseq; 
    109         return 0; 
     40typedef struct jb_framelist jb_framelist; 
     41 
     42struct pjmedia_jbuf 
     43{ 
     44    jb_framelist    jb_framelist; 
     45    pj_size_t       jb_frame_size;        // frame size  
     46    pj_size_t       jb_max_count;         // max frames in the jitter framelist->flist_buffer 
     47 
     48    int             jb_level;             // delay between source & destination 
     49                                          // (calculated according of the number of get/put operations) 
     50    int             jb_last_level;        // last delay  
     51    int             jb_last_jitter;       // last jitter calculated 
     52    int             jb_max_hist_jitter;   // max jitter during the last jitter calculations 
     53    int             jb_stable_hist;       // num of times the delay has been lower then the prefetch num 
     54    int             jb_last_op;           // last operation executed on the framelist->flist_buffer (put/get) 
     55    int             jb_last_seq_no;       // seq no. of the last frame inserted to the framelist->flist_buffer 
     56    int             jb_prefetch;          // no. of frame to insert before removing some 
     57                                          // (at the beginning of the framelist->flist_buffer operation) 
     58    int             jb_prefetch_cnt;      // prefetch counter 
     59    int             jb_status;            // status is 'init' until the first 'put' operation 
     60 
     61 
     62}; 
     63 
     64 
     65#define JB_STATUS_INITIALIZING  0 
     66#define JB_STATUS_PROCESSING    1 
     67 
     68#define PJ_ABS(x)       ((x > 0) ? (x) : -(x)) 
     69#define PJ_MAX(x, y)    ((x > y) ? (x) : (y)) 
     70#define PJ_MIN(x, y)    ((x < y) ? (x) : (y)) 
     71 
     72 
     73 
     74static pj_status_t jb_framelist_init( pj_pool_t *pool, 
     75                                      jb_framelist *framelist, 
     76                                      unsigned frame_size, 
     77                                      unsigned max_count)  
     78{ 
     79    PJ_ASSERT_RETURN(pool && framelist, PJ_EINVAL); 
     80 
     81    pj_memset(framelist, 0, sizeof(jb_framelist)); 
     82 
     83    framelist->flist_frame_size = frame_size; 
     84    framelist->flist_max_count = max_count; 
     85    framelist->flist_buffer = pj_pool_zalloc(pool, 
     86                                             framelist->flist_frame_size *  
     87                                             framelist->flist_max_count); 
     88 
     89    framelist->flist_frame_type = pj_pool_zalloc(pool,  
     90                                                 sizeof(framelist->flist_frame_type[0]) *  
     91                                                 framelist->flist_max_count); 
     92 
     93    framelist->flist_empty = 1; 
     94    framelist->flist_head = framelist->flist_tail = framelist->flist_origin = 0; 
     95 
     96    return PJ_SUCCESS; 
     97 
     98} 
     99 
     100static pj_status_t jb_framelist_destroy(jb_framelist *framelist)  
     101{ 
     102    PJ_UNUSED_ARG(framelist); 
     103    return PJ_SUCCESS; 
     104} 
     105 
     106 
     107static unsigned jb_framelist_size(jb_framelist *framelist)  
     108{ 
     109    if (framelist->flist_tail == framelist->flist_head) { 
     110        return framelist->flist_empty ? 0 : framelist->flist_max_count; 
     111    } else { 
     112        return (framelist->flist_tail - framelist->flist_head +  
     113                framelist->flist_max_count) % framelist->flist_max_count; 
     114    } 
     115} 
     116 
     117 
     118static pj_bool_t jb_framelist_get(jb_framelist *framelist, 
     119                                  void *frame, 
     120                                  pjmedia_jb_frame_type *p_type)  
     121{ 
     122    if (!framelist->flist_empty) { 
     123        pj_memcpy(frame,  
     124                  framelist->flist_buffer + framelist->flist_head * framelist->flist_frame_size, 
     125                  framelist->flist_frame_size); 
     126        *p_type = (pjmedia_jb_frame_type) framelist->flist_frame_type[framelist->flist_head]; 
     127 
     128        pj_memset(framelist->flist_buffer + framelist->flist_head * framelist->flist_frame_size, 
     129                  0, framelist->flist_frame_size); 
     130        framelist->flist_frame_type[framelist->flist_head] = 0; 
     131 
     132        framelist->flist_origin++; 
     133        framelist->flist_head = ++framelist->flist_head % framelist->flist_max_count; 
     134        if (framelist->flist_head == framelist->flist_tail)  
     135            framelist->flist_empty = PJ_TRUE; 
    110136         
    111     } else if (extseq < startseq) { 
    112         /* The sequence number is lower than our oldest packet. This can mean 
    113            two things: 
    114             - old packet has been receieved, or 
    115             - the sequence number has wrapped around. 
    116          */   
    117         if (startseq + lst->maxcount <= extseq) { 
    118             /* The sequence number has wrapped around, but it is beyond 
    119                the capacity of the list (i.e. too soon). 
    120              */ 
    121             PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_SOON! [lst=%p] seq=%u, startseq=%d",  
    122                        lst, extseq, startseq)); 
    123             return PJ_JB_STATUS_TOO_SOON; 
    124  
    125         } else if (startseq-extseq > lst->maxcount && startseq+lst->maxcount > extseq) { 
    126             /* The sequence number has wrapped around, and it is still inside 
    127                the 'window' of the framelist. 
    128              */ 
    129             pos = extseq - startseq; 
     137        return PJ_TRUE; 
     138 
     139    } else { 
     140        pj_memset(frame, 0, framelist->flist_frame_size); 
     141        return PJ_FALSE; 
     142    } 
     143} 
     144 
     145 
     146static void jb_framelist_remove_head( jb_framelist *framelist, 
     147                                      unsigned count)  
     148{ 
     149    unsigned cur_size; 
     150 
     151    cur_size = jb_framelist_size(framelist); 
     152    if (count > cur_size)  
     153        count = cur_size; 
     154 
     155    if (count) { 
     156        // may be done in two steps if overlapping 
     157        unsigned step1,step2; 
     158        unsigned tmp = framelist->flist_head+count; 
     159 
     160        if (tmp > framelist->flist_max_count) { 
     161            step1 = framelist->flist_max_count - framelist->flist_head; 
     162            step2 = count-step1; 
    130163        } else { 
    131             /* The new frame is too old. */ 
    132             PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_OLD! [lst=%p] seq=%u, startseq=%d",  
    133                        lst, extseq, startseq)); 
    134             return PJ_JB_STATUS_TOO_OLD; 
     164            step1 = count; 
     165            step2 = 0; 
    135166        } 
    136          
    137     } else if (extseq > startseq + lst->maxcount) { 
    138         /* Two possibilities here. Either: 
    139             - packet is really too soon, or 
    140             - sequence number of startseq has just wrapped around, and old packet 
    141               which hasn't wrapped is received. 
    142          */ 
    143         if (extseq < MAX_SEQ_RANGE /*approx 20 seconds with 50 fps*/) { 
    144             PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_SOON! [lst=%p] seq=%u, startseq=%d",  
    145                        lst, extseq, startseq)); 
    146             return PJ_JB_STATUS_TOO_SOON; 
    147         } else { 
    148             PJ_LOG(5, (THIS_FILE, "    ..pj_frame_list_put TOO_OLD! [lst=%p] seq=%u, startseq=%d",  
    149                        lst, extseq, startseq)); 
    150             return PJ_JB_STATUS_TOO_OLD; 
     167 
     168        pj_memset(framelist->flist_buffer + framelist->flist_head * framelist->flist_frame_size, 
     169                  0, 
     170                  step1*framelist->flist_frame_size); 
     171        pj_memset(framelist->flist_frame_type+framelist->flist_head, 
     172                  0, 
     173                  step1*sizeof(framelist->flist_frame_type[0])); 
     174 
     175        if (step2) { 
     176            pj_memset(framelist->flist_buffer, 
     177                      0, 
     178                      step2*framelist->flist_frame_size); 
     179            pj_memset(framelist->flist_frame_type, 
     180                      0, 
     181                      step2*sizeof(framelist->flist_frame_type[0])); 
    151182        } 
    152     }  
    153  
    154     /* The new frame is within the framelist capacity. 
    155        Calculate position where to put it in the list. 
    156      */ 
    157     if (pos == (unsigned)-1) 
    158         pos = ((extseq - startseq) + lst->head) % lst->maxcount; 
    159  
    160     pj_assert(pos < lst->maxcount); 
    161      
    162     /* Update count only if we're not overwriting existing frame. */ 
    163     if (lst->frames[pos].buf == NULL) 
    164         ++lst->count; 
    165  
    166     lst->frames[pos].buf = buf; 
    167     lst->frames[pos].extseq = extseq; 
    168  
    169     PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_put [lst=%p] seq=%u, startseq=%d, head=%d, pos=%d",  
    170                lst, extseq, startseq, lst->head, pos)); 
    171     return 0; 
    172 } 
    173  
    174 /* Get the first element of the list. */  
    175 static int  
    176 pj_framelist_get( pj_jbframelist *lst, pj_uint32_t *extseq, void **buf ) 
    177 { 
    178     if (lst->count == 0) { 
    179         /* Empty. */ 
    180         *buf = NULL; 
    181         *extseq = 0; 
    182         PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_get [lst=%p], empty!", lst)); 
    183         return -1; 
    184          
    185     } else { 
    186         *buf = lst->frames[lst->head].buf; 
    187         *extseq = lst->frames[lst->head].extseq; 
    188         lst->frames[lst->head].buf = NULL; 
    189  
    190         PJ_LOG(6, (THIS_FILE, "    ..pj_frame_list_get [lst=%p] seq=%u, head=%d",  
    191                    lst, *extseq, lst->head)); 
    192  
    193         lst->head = (lst->head + 1) % lst->maxcount; 
    194         --lst->count; 
    195         return 0; 
    196     } 
    197 } 
    198  
    199  
    200 /***************************************************************************** 
    201  * Reset jitter buffer.  
    202  **************************************************************************** 
    203 */ 
    204 PJ_DEF(void) pj_jb_reset(JB *jb) 
    205 { 
    206     PJ_LOG(6, (THIS_FILE, "pj_jb_reset [jb=%p]", jb)); 
    207  
    208     jb->level = jb->max_level = 1; 
    209     jb->prefetch = jb->min; 
    210     jb->get_cnt = 0; 
    211     jb->lastseq = 0; 
    212     jb->state = JB_PREFETCH; 
    213     jb->upd_count = 0; 
    214     jb->last_op = -1; 
    215     pj_framelist_reset( &jb->lst ); 
    216 } 
    217  
    218  
    219 /***************************************************************************** 
    220  * Create jitter buffer. 
    221  ***************************************************************************** 
    222  */  
    223 PJ_DEF(pj_status_t) pj_jb_init( pj_jitter_buffer *jb, pj_pool_t *pool,  
    224                                 unsigned min, unsigned max, unsigned maxcount) 
    225 { 
     183 
     184        // update pointers 
     185        framelist->flist_origin += count; 
     186        framelist->flist_head = (framelist->flist_head+count) % framelist->flist_max_count; 
     187        if (framelist->flist_head == framelist->flist_tail)  
     188            framelist->flist_empty = PJ_TRUE; 
     189    } 
     190} 
     191 
     192 
     193static pj_bool_t jb_framelist_put_at(jb_framelist *framelist, 
     194                                     unsigned index, 
     195                                     const void *frame, 
     196                                     unsigned frame_size)  
     197{ 
     198    unsigned where; 
     199 
     200    // too late 
     201    if (index < framelist->flist_origin)  
     202        return PJ_FALSE; 
     203 
     204    // too soon 
     205    if ((index > (framelist->flist_origin + framelist->flist_max_count - 1)) && !framelist->flist_empty)  
     206        return PJ_FALSE; 
     207 
     208    assert(frame_size <= framelist->flist_frame_size); 
     209 
     210    if (!framelist->flist_empty) { 
     211        unsigned cur_size; 
     212 
     213        where = (index - framelist->flist_origin + framelist->flist_head) % framelist->flist_max_count; 
     214 
     215        // update framelist->flist_tail pointer 
     216        cur_size = jb_framelist_size(framelist); 
     217        if (index >= framelist->flist_origin + cur_size) { 
     218            unsigned diff = (index - (framelist->flist_origin + cur_size)); 
     219            framelist->flist_tail = (framelist->flist_tail + diff + 1) % framelist->flist_max_count; 
     220        } 
     221    } else { 
     222        where = framelist->flist_tail; 
     223        framelist->flist_origin = index; 
     224        framelist->flist_tail = (++framelist->flist_tail % framelist->flist_max_count); 
     225        framelist->flist_empty = PJ_FALSE; 
     226    } 
     227 
     228    pj_memcpy(framelist->flist_buffer + where * framelist->flist_frame_size,  
     229              frame, frame_size); 
     230 
     231    framelist->flist_frame_type[where] = PJMEDIA_JB_NORMAL_FRAME; 
     232 
     233    return PJ_TRUE; 
     234} 
     235 
     236 
     237 
     238enum pjmedia_jb_op 
     239{ 
     240    JB_OP_INIT  = -1, 
     241    JB_OP_PUT   = 1, 
     242    JB_OP_GET   = 2 
     243}; 
     244 
     245 
     246PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool,  
     247                                        int frame_size,  
     248                                        int initial_prefetch,  
     249                                        int max_count, 
     250                                        pjmedia_jbuf **p_jb) 
     251{ 
     252    pjmedia_jbuf *jb; 
    226253    pj_status_t status; 
    227254 
    228     if (maxcount <= max) { 
    229         maxcount = max * 5 / 4; 
    230         PJ_LOG(3,(THIS_FILE, "Jitter buffer maximum count was adjusted.")); 
    231     } 
    232  
    233     jb->min = min; 
    234     jb->max = max; 
    235  
    236     status = pj_framelist_init( &jb->lst, pool, maxcount ); 
     255    jb = pj_pool_zalloc(pool, sizeof(pjmedia_jbuf)); 
     256 
     257    status = jb_framelist_init(pool, &jb->jb_framelist, frame_size, max_count); 
    237258    if (status != PJ_SUCCESS) 
    238259        return status; 
    239260 
    240     pj_jb_reset(jb); 
    241  
    242     PJ_LOG(4, (THIS_FILE, "pj_jb_init success [jb=%p], min=%d, max=%d, maxcount=%d",  
    243                           jb, min, max, maxcount)); 
     261    jb->jb_frame_size    = frame_size; 
     262    jb->jb_last_seq_no   = -1; 
     263    jb->jb_level         = 0; 
     264    jb->jb_last_level    = 0; 
     265    jb->jb_last_jitter   = 0; 
     266    jb->jb_last_op       = JB_OP_INIT; 
     267    jb->jb_prefetch      = PJ_MIN(initial_prefetch, max_count*4/5); 
     268    jb->jb_prefetch_cnt  = 0; 
     269    jb->jb_stable_hist   = 0; 
     270    jb->jb_status        = JB_STATUS_INITIALIZING; 
     271    jb->jb_max_hist_jitter = 0; 
     272    jb->jb_max_count     = max_count; 
     273 
     274    *p_jb = jb; 
    244275    return PJ_SUCCESS; 
    245276} 
    246277 
    247278 
    248 /***************************************************************************** 
    249  * Put a packet to the jitter buffer. 
    250  ***************************************************************************** 
    251  */  
    252 PJ_DEF(pj_status_t) pj_jb_put( JB *jb, pj_uint32_t extseq, void *buf ) 
    253 { 
    254     unsigned distance; 
    255     int status; 
     279PJ_DEF(pj_status_t) pjmedia_jbuf_destroy(pjmedia_jbuf *jb) 
     280{ 
     281    return jb_framelist_destroy(&jb->jb_framelist); 
     282} 
     283 
     284 
     285static void jbuf_calculate_jitter(pjmedia_jbuf *jb) 
     286{ 
     287    enum { STABLE_HISTORY_LIMIT = (500/20) }; 
     288 
     289    jb->jb_last_jitter = PJ_ABS(jb->jb_level-jb->jb_last_level); 
     290    jb->jb_last_level = jb->jb_level; 
     291    jb->jb_max_hist_jitter = PJ_MAX(jb->jb_max_hist_jitter,jb->jb_last_jitter); 
    256292     
    257     PJ_LOG(6, (THIS_FILE, "==> pj_jb_put [jb=%p], seq=%u, buf=%p", jb, extseq, buf)); 
    258  
    259     if (jb->lastseq == 0) 
    260         jb->lastseq = extseq - 1; 
    261  
    262     /* Calculate distance between this packet and last received packet 
    263        to detect long jump (indicating probably remote has just been 
    264        restarted. 
    265      */ 
    266     distance = (extseq > jb->lastseq) ? extseq - jb->lastseq : jb->lastseq - extseq; 
    267     if (distance > MAX_SEQ_RANGE) { 
    268         /* Distance is out of range, reset jitter while maintaining current jitter 
    269            level. 
    270          */ 
    271         int old_level = jb->level; 
    272         int old_prefetch = jb->prefetch; 
    273  
    274         PJ_LOG(4, (THIS_FILE, "    ..[jb=%p] distance out of range, resetting", jb)); 
    275  
    276         pj_jb_reset(jb); 
    277         jb->level = old_level; 
    278         jb->prefetch = old_prefetch; 
    279         distance = 1; 
    280         jb->lastseq = extseq - 1; 
    281     } 
    282      
    283     jb->lastseq = extseq; 
    284  
    285     status = pj_framelist_put( &jb->lst, extseq, buf ); 
    286     if (status == PJ_JB_STATUS_TOO_OLD) 
    287         return -1; 
    288  
    289     if (status == PJ_JB_STATUS_TOO_SOON) { 
    290         /* TODO: discard old packets.. */ 
    291         /* No, don't do it without putting a way to inform application so that 
    292            it can free the memory */ 
    293     } 
    294  
    295  
    296     if (jb->last_op != JB_PUT) { 
    297         if (jb->state != JB_PREFETCH) 
    298             jb->level--; 
    299     } else { 
    300         jb->level++; 
    301     } 
    302  
    303     if ((int)jb->lst.count > jb->max_level) 
    304         jb->max_level++; 
    305  
    306     jb->last_op = JB_PUT; 
    307     return 0; 
    308 } 
    309  
    310  
    311 /* 
    312  * Update jitter buffer algorithm. 
    313  */ 
    314 static void jb_update(JB *jb, int apply, int log_info) 
    315 { 
    316     unsigned abs_level = jb->max_level > 0 ? jb->max_level : -jb->max_level; 
    317     unsigned new_prefetch; 
    318  
    319     /* Update prefetch count */ 
    320     if (abs_level > jb->prefetch) 
    321         new_prefetch = (jb->prefetch + abs_level*9 + 1) / 10; 
    322     else { 
    323         new_prefetch = (jb->prefetch*4 + abs_level) / 5; 
    324         pj_assert(new_prefetch <= jb->prefetch); 
    325     } 
    326  
    327     if (log_info) { 
    328         PJ_LOG(5, (THIS_FILE, "    ..jb_update [jb=%p], level=%d, max_level=%d, old_prefetch=%d, new_prefetch=%d",  
    329                               jb, jb->level, jb->max_level, jb->prefetch, new_prefetch)); 
    330     } else { 
    331         PJ_LOG(6, (THIS_FILE, "    ..jb_update [jb=%p], level=%d, max_level=%d, old_prefetch=%d, new_prefetch=%d",  
    332                               jb, jb->level, jb->max_level, jb->prefetch, new_prefetch)); 
    333     } 
    334  
    335     if (new_prefetch < jb->min) new_prefetch = jb->min; 
    336     if (new_prefetch > jb->max) new_prefetch = jb->max; 
    337  
    338     /* If jitter buffer is empty, set state to JB_PREFETCH, taking care of the 
    339        new prefetch setting. 
    340      */ 
    341     if (jb->lst.count == 0) { 
    342         jb->state = JB_PREFETCH; 
    343         jb->get_cnt = 0; 
    344     } else { 
    345         /* Check if delay is too long, which in this case probably better to 
    346            discard some frames.. 
    347          */ 
    348         /* No, don't do it without putting a way to inform application so that 
    349            it can free the memory */ 
    350     } 
    351  
    352  
    353     if (apply) { 
    354         jb->prefetch = new_prefetch; 
    355         if (jb->max_level > 0) 
    356             jb->max_level--; 
    357     } else { 
    358         jb->level = new_prefetch; 
    359     } 
    360 } 
    361  
    362  
    363 /***************************************************************************** 
    364  * Get the oldest frame from jitter buffer. 
    365  ***************************************************************************** 
    366  */  
    367 PJ_DEF(pj_status_t) pj_jb_get( JB *jb, pj_uint32_t *extseq, void **buf ) 
    368 { 
    369     pj_status_t status; 
    370      
    371     PJ_LOG(6, (THIS_FILE, "<== pj_jb_get [jb=%p]", jb)); 
    372  
    373     /* 
    374      * Check whether we're ready to give frame. When we're in JB_PREFETCH state, 
    375      * only give frames only when: 
    376      *  - the buffer has enough frames in it (jb->list.count > jb->prefetch), OR 
    377      *  - after 'prefetch' attempts, there's still no frame, which in this 
    378      *    case PJ_JB_STATUS_FRAME_NULL will be returned by the next check. 
    379      */ 
    380     if (jb->state == JB_PREFETCH && jb->lst.count <= jb->prefetch && jb->get_cnt < jb->prefetch) { 
    381         jb->get_cnt++;    
    382         jb->last_op = JB_GET; 
    383         PJ_LOG(5, (THIS_FILE, "    ..[jb=%p] bufferring...", jb)); 
    384         return PJ_JB_STATUS_FRAME_NULL; 
    385     } 
    386  
    387     /* Attempt to get one frame from the list. */ 
    388     status = pj_framelist_get( &jb->lst, extseq, buf ); 
    389     if (status != 0) { 
    390         PJ_LOG(6, (THIS_FILE, "    ..[jb=%p] no packet!", jb)); 
    391         status = jb->lst.count ? PJ_JB_STATUS_FRAME_MISSING : PJ_JB_STATUS_FRAME_NULL; 
    392         jb_update(jb, 1, 0); 
    393         return status; 
    394     } 
    395  
    396     /* Force state to NORMAL */ 
    397     jb->state = JB_NORMAL; 
    398  
    399     /* Increase level only when last operation is GET. 
    400      * This is to prevent level from increasing during silence period, which 
    401      * no packets is receieved. 
    402      */ 
    403     if (jb->last_op != JB_GET) { 
    404         int apply; 
    405  
    406         //jb->level++; 
    407         jb->last_op = JB_GET; 
    408  
    409         apply = (++jb->upd_count > UPDATE_DURATION); 
    410         if (apply) 
    411             jb->upd_count = 0; 
    412  
    413         jb_update(jb, apply, apply); 
    414     } 
    415  
    416     PJ_LOG(6, (THIS_FILE, "    ..[jb=%p] seq=%u, level=%d, prefetch=%d, size=%u, delay=%d",  
    417                           jb, *extseq, jb->level, jb->prefetch, jb->lst.count, 
    418                           jb->lastseq - *extseq)); 
    419     return 0; 
    420 } 
    421  
    422  
     293    if (jb->jb_last_jitter< jb->jb_prefetch) { 
     294        jb->jb_stable_hist += jb->jb_last_jitter; 
     295        if (jb->jb_stable_hist > STABLE_HISTORY_LIMIT) { 
     296            int seq_diff = (jb->jb_prefetch - jb->jb_max_hist_jitter)/3; 
     297            if (seq_diff<1) seq_diff = 1; 
     298 
     299            jb->jb_prefetch -= seq_diff; 
     300            if (jb->jb_prefetch < 1) jb->jb_prefetch = 1; 
     301 
     302            jb->jb_stable_hist = 0; 
     303            jb->jb_max_hist_jitter = 0; 
     304        } 
     305    } else { 
     306        jb->jb_prefetch = PJ_MIN(jb->jb_last_jitter,(int)(jb->jb_max_count*4/5)); 
     307        jb->jb_stable_hist = 0; 
     308        jb->jb_max_hist_jitter = 0; 
     309    } 
     310} 
     311 
     312static void jbuf_update(pjmedia_jbuf *jb, int oper) 
     313{ 
     314    if(jb->jb_last_op != oper) { 
     315        jbuf_calculate_jitter(jb); 
     316        jb->jb_last_op = oper; 
     317    } 
     318} 
     319 
     320PJ_DEF(pj_status_t) pjmedia_jbuf_put_frame(pjmedia_jbuf *jb,  
     321                                           const void *frame,  
     322                                           pj_size_t frame_size,  
     323                                           int frame_seq) 
     324{ 
     325    pj_size_t min_frame_size; 
     326    int seq_diff; 
     327 
     328    if (jb->jb_last_seq_no == -1)       { 
     329        jb->jb_last_seq_no = frame_seq - 1; 
     330    } 
     331 
     332    seq_diff = frame_seq - jb->jb_last_seq_no; 
     333    jb->jb_last_seq_no = PJ_MAX(jb->jb_last_seq_no, frame_seq); 
     334    if (seq_diff > 0) jb->jb_level += seq_diff; 
     335 
     336    if(jb->jb_status == JB_STATUS_INITIALIZING) { 
     337        jb->jb_status = JB_STATUS_PROCESSING; 
     338        jb->jb_level = 0; 
     339        jb->jb_last_level = 0; 
     340        jb->jb_last_jitter = 0; 
     341    } else { 
     342        jbuf_update(jb, JB_OP_PUT); 
     343    } 
     344 
     345    min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size); 
     346    if (seq_diff > 0) { 
     347 
     348        while (!jb_framelist_put_at(&jb->jb_framelist,frame_seq,frame,min_frame_size)) { 
     349            jb_framelist_remove_head(&jb->jb_framelist,PJ_MAX(jb->jb_max_count/4,1)); 
     350        } 
     351 
     352        if (jb->jb_prefetch_cnt < jb->jb_prefetch)       
     353            jb->jb_prefetch_cnt += seq_diff; 
     354 
     355    } 
     356    else 
     357    { 
     358        jb_framelist_put_at(&jb->jb_framelist,frame_seq,frame,min_frame_size); 
     359    } 
     360 
     361    return PJ_SUCCESS; 
     362} 
     363 
     364PJ_DEF(pj_status_t) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb,  
     365                                            void *frame,  
     366                                            char *p_frame_type) 
     367{ 
     368    pjmedia_jb_frame_type ftype; 
     369 
     370    jb->jb_level--; 
     371 
     372    jbuf_update(jb, JB_OP_GET); 
     373 
     374    if (jb_framelist_size(&jb->jb_framelist) == 0) { 
     375        jb->jb_prefetch_cnt = 0; 
     376    } 
     377 
     378    if ((jb->jb_prefetch_cnt < jb->jb_prefetch) || !jb_framelist_get(&jb->jb_framelist,frame,&ftype)) { 
     379        pj_memset(frame, 0, jb->jb_frame_size); 
     380        *p_frame_type = PJMEDIA_JB_ZERO_FRAME; 
     381        return PJ_SUCCESS; 
     382    } 
     383 
     384    if (ftype == PJMEDIA_JB_NORMAL_FRAME) { 
     385        *p_frame_type   = PJMEDIA_JB_NORMAL_FRAME; 
     386    } else { 
     387        *p_frame_type   = PJMEDIA_JB_MISSING_FRAME; 
     388    } 
     389 
     390    return PJ_SUCCESS; 
     391} 
     392 
     393PJ_DEF(unsigned) pjmedia_jbuf_get_prefetch_size(pjmedia_jbuf *jb) 
     394{ 
     395    return jb->jb_prefetch; 
     396} 
     397 
     398PJ_DEF(unsigned) pjmedia_jbuf_get_current_size(pjmedia_jbuf *jb) 
     399{ 
     400    return jb_framelist_size(&jb->jb_framelist); 
     401} 
     402 
     403 
  • pjproject/trunk/pjmedia/src/pjmedia/session.c

    r164 r169  
    234234 
    235235    /* 
    236      * Now create the stream! 
     236     * Now create and start the stream! 
    237237     */ 
    238238    for (i=0; i<(int)stream_cnt; ++i) { 
     
    241241                                       &session->stream_info[i], 
    242242                                       &session->stream[i]); 
     243        if (status == PJ_SUCCESS) 
     244            status = pjmedia_stream_start(session->stream[i]); 
     245 
    243246        if (status != PJ_SUCCESS) { 
    244247 
     
    260263 
    261264 
     265/* 
     266 * Get session info. 
     267 */ 
     268PJ_DEF(pj_status_t) pjmedia_session_get_info( pjmedia_session *session, 
     269                                              pjmedia_session_info *info ) 
     270{ 
     271    PJ_ASSERT_RETURN(session && info, PJ_EINVAL); 
     272 
     273    info->stream_cnt = session->stream_cnt; 
     274    pj_memcpy(info->stream_info, session->stream_info, 
     275              session->stream_cnt * sizeof(pjmedia_stream_info)); 
     276 
     277    return PJ_SUCCESS; 
     278} 
     279 
     280 
    262281/** 
    263282 * Destroy media session. 
     
    369388 * Get statistics 
    370389 */ 
    371 PJ_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  */ 
    386 PJ_DEF(pj_status_t) pjmedia_session_get_stream_stat( const pjmedia_session *s, 
     390PJ_DEF(pj_status_t) pjmedia_session_get_stream_stat( pjmedia_session *session, 
    387391                                                     unsigned index, 
    388392                                                     pjmedia_stream_stat *stat) 
    389393{ 
    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  
     394    PJ_ASSERT_RETURN(session && stat && index < session->stream_cnt,  
     395                     PJ_EINVAL); 
     396 
     397    return pjmedia_stream_get_stat(session->stream[index], stat); 
     398} 
     399 
     400 
  • pjproject/trunk/pjmedia/src/pjmedia/stream.c

    r164 r169  
    4040#define PJMEDIA_MAX_MTU                 1500 
    4141 
    42 struct jb_frame 
    43 { 
    44     unsigned size; 
    45     void    *buf; 
    46 }; 
    47  
    48 #define pj_fifobuf_alloc(fifo,size)     malloc(size) 
    49 #define pj_fifobuf_unalloc(fifo,buf)    free(buf) 
    50 #define pj_fifobuf_free(fifo, buf)      free(buf) 
    5142 
    5243 
     
    8980    pjmedia_codec_mgr       *codec_mgr;     /**< Codec manager instance.    */ 
    9081    pjmedia_codec           *codec;         /**< Codec instance being used. */ 
    91  
     82    pj_size_t                frame_size;    /**< Size of encoded frame.     */ 
    9283    pj_mutex_t              *jb_mutex; 
    93     pj_jitter_buffer         jb;            /**< Jitter buffer.             */ 
    94  
    95     pj_sock_t                rtp_sock;      /**< RTP socket.                */ 
    96     pj_sock_t                rtcp_sock;     /**< RTCP socket.               */ 
    97     pj_sockaddr_in           dst_addr;      /**< Destination RTP address.   */ 
     84    pjmedia_jbuf            *jb;            /**< Jitter buffer.             */ 
     85 
     86    pjmedia_sock_info        skinfo;        /**< Transport info.            */ 
     87    pj_sockaddr_in           rem_rtp_addr;  /**< Remote RTP address.        */ 
     88    pj_sockaddr_in           rem_rtcp_addr; /**< Remote RTCP address.       */ 
    9889 
    9990    pj_rtcp_session          rtcp;          /**< RTCP for incoming RTP.     */ 
     
    118109    pjmedia_channel *channel = user_data; 
    119110    pjmedia_stream *stream = channel->stream; 
    120     struct jb_frame *jb_frame; 
    121     void *p; 
    122     pj_uint32_t extseq; 
     111    char frame_type; 
    123112    pj_status_t status; 
    124113    struct pjmedia_frame frame_in, frame_out; 
     
    134123 
    135124    /* Get frame from jitter buffer. */ 
    136     status = pj_jb_get(&stream->jb, &extseq, &p); 
     125    status = pjmedia_jbuf_get_frame(stream->jb, channel->out_pkt, 
     126                                    &frame_type); 
    137127 
    138128    /* Unlock jitter buffer mutex. */ 
    139129    pj_mutex_unlock( stream->jb_mutex ); 
    140130 
    141     jb_frame = p; 
    142     if (status != PJ_SUCCESS || jb_frame == NULL) { 
     131    if (status != PJ_SUCCESS || frame_type == PJMEDIA_JB_ZERO_FRAME || 
     132        frame_type == PJMEDIA_JB_MISSING_FRAME)  
     133    { 
    143134        pj_memset(frame, 0, size); 
    144135        return 0; 
    145136    } 
    146137 
     138 
    147139    /* Decode */ 
    148     frame_in.buf = jb_frame->buf; 
    149     frame_in.size = jb_frame->size; 
     140    frame_in.buf = channel->out_pkt; 
     141    frame_in.size = stream->frame_size; 
    150142    frame_in.type = PJMEDIA_FRAME_TYPE_AUDIO;  /* ignored */ 
    151143    frame_out.buf = channel->pcm_buf; 
     
    156148 
    157149        pj_memset(frame, 0, size); 
    158         pj_fifobuf_free (&channel->fifobuf, jb_frame); 
    159150        return 0; 
    160151    } 
     
    168159 
    169160    pj_memcpy(frame, frame_out.buf, size); 
    170     pj_fifobuf_free (&channel->fifobuf, jb_frame); 
    171161 
    172162    return 0; 
     
    239229    /* Send. */ 
    240230    sent = frame_out.size+sizeof(pj_rtp_hdr); 
    241     status = pj_sock_sendto(stream->rtp_sock, channel->out_pkt, &sent, 0,  
    242                             &stream->dst_addr, sizeof(stream->dst_addr)); 
     231    status = pj_sock_sendto(stream->skinfo.rtp_sock, channel->out_pkt, &sent, 0,  
     232                            &stream->rem_rtp_addr, sizeof(stream->rem_rtp_addr)); 
    243233    if (status != PJ_SUCCESS) 
    244234        return status; 
     
    261251    pjmedia_channel *channel = stream->dec; 
    262252 
     253 
    263254    while (!stream->quit_flag) { 
    264         pj_ssize_t len, size; 
     255        pj_ssize_t len; 
    265256        const pj_rtp_hdr *hdr; 
    266257        const void *payload; 
    267258        unsigned payloadlen; 
    268259        int status; 
    269         struct jb_frame *jb_frame; 
    270260 
    271261        /* Wait for packet. */ 
     
    274264 
    275265        PJ_FD_ZERO (&fds); 
    276         PJ_FD_SET (stream->rtp_sock, &fds); 
     266        PJ_FD_SET (stream->skinfo.rtp_sock, &fds); 
    277267        timeout.sec = 0; 
    278268        timeout.msec = 1; 
    279269 
    280270        /* Wait with timeout. */ 
    281         status = pj_sock_select(stream->rtp_sock, &fds, NULL, NULL, &timeout); 
    282         if (status != 1) 
     271        status = pj_sock_select(FD_SETSIZE, &fds, NULL, NULL, &timeout); 
     272        if (status < 0) { 
     273            char errmsg[PJ_ERR_MSG_SIZE]; 
     274            pj_strerror(pj_get_netos_error(), errmsg, sizeof(errmsg)); 
     275            TRACE_((THIS_FILE, "Jitter buffer select() error: %s", 
     276                    errmsg)); 
     277            pj_thread_sleep(500); 
     278            continue; 
     279        } else if (status == 0) 
    283280            continue; 
    284281 
    285282        /* Get packet from socket. */ 
    286283        len = channel->in_pkt_size; 
    287         status = pj_sock_recv(stream->rtp_sock, channel->in_pkt, &len, 0); 
     284        status = pj_sock_recv(stream->skinfo.rtp_sock,  
     285                              channel->in_pkt, &len, 0); 
    288286        if (len < 1 || status != PJ_SUCCESS) { 
    289287            if (pj_get_netos_error() == PJ_STATUS_FROM_OS(OSERR_ECONNRESET)) { 
     
    326324        stream->stat.dec.bytes += len; 
    327325 
    328         /* Copy to FIFO buffer. */ 
    329         size = payloadlen+sizeof(struct jb_frame); 
    330         jb_frame = pj_fifobuf_alloc (&channel->fifobuf, size); 
    331         if (jb_frame == NULL) { 
    332             TRACE_((THIS_FILE, "Unable to allocate %d bytes FIFO buffer",  
    333                     size)); 
    334             continue; 
    335         } 
    336  
    337         /* Copy the payload */ 
    338         jb_frame->size = payloadlen; 
    339         jb_frame->buf = ((char*)jb_frame) + sizeof(struct jb_frame); 
    340         pj_memcpy (jb_frame->buf, payload, payloadlen); 
    341  
    342326        /* Put to jitter buffer. */ 
    343327        pj_mutex_lock( stream->jb_mutex ); 
    344         status = pj_jb_put(&stream->jb, pj_ntohs(hdr->seq), jb_frame); 
     328        status = pjmedia_jbuf_put_frame(stream->jb, payload, payloadlen, pj_ntohs(hdr->seq)); 
    345329        pj_mutex_unlock( stream->jb_mutex ); 
    346330 
    347331        if (status != 0) { 
    348             pj_fifobuf_unalloc (&channel->fifobuf, jb_frame); 
    349              
    350332            TRACE_((THIS_FILE,  
    351333                    "Jitter buffer put() has returned error status %d",  
     
    486468    stream->dir = info->dir; 
    487469    stream->codec_mgr = pjmedia_endpt_get_codec_mgr(endpt); 
     470    stream->skinfo = info->sock_info; 
     471    stream->rem_rtp_addr = info->rem_addr; 
     472 
     473    PJ_TODO(INITIALIZE_RTCP_REMOTE_ADDRESS); 
    488474 
    489475    /* Create mutex to protect jitter buffer: */ 
     
    516502 
    517503 
     504    /* Get the frame size: */ 
     505 
     506    stream->frame_size = (codec_param.avg_bps / 8) * codec_param.ptime / 1000; 
     507 
     508 
    518509    /* Init RTCP session: */ 
    519510 
     
    521512 
    522513 
    523     /* Init jitter buffer: */ 
    524  
    525     status = pj_jb_init(&stream->jb, pool,  
    526                         info->jb_min, info->jb_max, info->jb_maxcnt); 
     514    /* Create jitter buffer: */ 
     515 
     516    status = pjmedia_jbuf_create(pool, stream->frame_size, 15, 100, 
     517                                 &stream->jb); 
    527518    if (status != PJ_SUCCESS) 
    528519        goto err_cleanup; 
     
    533524    status = pj_thread_create(pool, "decode",  
    534525                              &jitter_buffer_thread, stream, 
    535                               0, 0, &stream->thread); 
     526                              0, PJ_THREAD_SUSPENDED, &stream->thread); 
    536527    if (status != PJ_SUCCESS) 
    537528        goto err_cleanup; 
     
    553544        goto err_cleanup; 
    554545 
     546    /* Resume jitter buffer thread. */ 
     547    status = pj_thread_resume( stream->thread ); 
     548    if (status != PJ_SUCCESS) 
     549        goto err_cleanup; 
    555550 
    556551    /* Success! */ 
  • pjproject/trunk/pjsip/include/pjsip-ua/sip_inv.h

    r163 r169  
    200200PJ_DECL(pjsip_module*) pjsip_inv_usage_instance(void); 
    201201 
     202 
     203/** 
     204 * Dump user agent contents (e.g. all dialogs). 
     205 */ 
     206PJ_DECL(void) pjsip_inv_usage_dump(void); 
    202207 
    203208 
  • pjproject/trunk/pjsip/include/pjsip/sip_ua_layer.h

    r135 r169  
    7474 
    7575/** 
     76 * Dump user agent contents (e.g. all dialogs). 
     77 */ 
     78PJ_DEF(void) pjsip_ua_dump(void); 
     79 
     80/** 
    7681 * Get the endpoint instance of a user agent module. 
    7782 * 
  • pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c

    r163 r169  
    321321 
    322322 
     323 
    323324/* 
    324325 * Return the invite session for the specified dialog. 
  • pjproject/trunk/pjsip/src/pjsip/sip_dialog.c

    r160 r169  
    930930 
    931931        to->tag = dlg->local.info->tag; 
     932 
     933        if (dlg->state == PJSIP_DIALOG_STATE_NULL) 
     934            dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED; 
    932935    } 
    933936} 
     
    10981101 
    10991102    /* Create UAS transaction for this request. */ 
    1100     if (pjsip_rdata_get_tsx(rdata) == NULL) { 
     1103    if (pjsip_rdata_get_tsx(rdata) == NULL &&  
     1104        rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD)  
     1105    { 
    11011106        status = pjsip_tsx_create_uas(dlg->ua, rdata, &tsx); 
    11021107        PJ_ASSERT_ON_FAIL(status==PJ_SUCCESS,{goto on_return;}); 
     
    12811286} 
    12821287 
    1283  
  • pjproject/trunk/pjsip/src/pjsip/sip_transport.c

    r163 r169  
    10451045    pj_lock_acquire(mgr->lock); 
    10461046 
     1047#if defined(PJ_DEBUG) && PJ_DEBUG!=0 
     1048    PJ_LOG(3,(THIS_FILE, " Outstanding transmit buffers: %d", 
     1049              pj_atomic_get(mgr->tdata_counter))); 
     1050#endif 
     1051 
    10471052    itr = pj_hash_first(mgr->table, &itr_val); 
    10481053    if (itr) { 
  • pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c

    r160 r169  
    721721 
    722722 
     723#if PJ_LOG_MAX_LEVEL >= 3 
     724static void print_dialog( const char *title, 
     725                          pjsip_dialog *dlg, char *buf, pj_size_t size) 
     726{ 
     727    int len; 
     728    char userinfo[128]; 
     729 
     730    len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo)); 
     731    if (len < 1) 
     732        pj_native_strcpy(userinfo, "<--uri too long-->"); 
     733    else 
     734        userinfo[len] = '\0'; 
     735     
     736    len = pj_snprintf(buf, size, "%s[%s]  %s", 
     737                      title, 
     738                      (dlg->state==PJSIP_DIALOG_STATE_NULL ? " - " : 
     739                                                             "est"), 
     740                      userinfo); 
     741    if (len < 1 || len >= (int)size) { 
     742        pj_native_strcpy(buf, "<--uri too long-->"); 
     743    } else 
     744        buf[len] = '\0'; 
     745} 
     746#endif 
     747 
     748/* 
     749 * Dump user agent contents (e.g. all dialogs). 
     750 */ 
     751PJ_DEF(void) pjsip_ua_dump(void) 
     752{ 
     753#if PJ_LOG_MAX_LEVEL >= 3 
     754    pj_hash_iterator_t itbuf, *it; 
     755    char dlginfo[128]; 
     756 
     757    pj_mutex_lock(mod_ua.mutex); 
     758 
     759    PJ_LOG(3, (THIS_FILE, "Number of dialog sets: %u", pj_hash_count(mod_ua.dlg_table))); 
     760    PJ_LOG(3, (THIS_FILE, "Dumping dialog sets:")); 
     761 
     762    it = pj_hash_first(mod_ua.dlg_table, &itbuf); 
     763    for (; it != NULL; it = pj_hash_next(mod_ua.dlg_table, it))  { 
     764        struct dlg_set *dlg_set; 
     765        pjsip_dialog *dlg; 
     766        const char *title; 
     767 
     768        dlg_set = pj_hash_this(mod_ua.dlg_table, it); 
     769        if (!dlg_set || pj_list_empty(&dlg_set->dlg_list)) continue; 
     770 
     771        /* First dialog in dialog set. */ 
     772        dlg = dlg_set->dlg_list.next; 
     773        if (dlg->role == PJSIP_ROLE_UAC) 
     774            title = "  [out] "; 
     775        else 
     776            title = "  [in]  "; 
     777 
     778        print_dialog(title, dlg, dlginfo, sizeof(dlginfo)); 
     779        PJ_LOG(3,(THIS_FILE, "%s", dlginfo)); 
     780 
     781        /* Next dialog in dialog set (forked) */ 
     782        dlg = dlg->next; 
     783        while (dlg != (pjsip_dialog*) &dlg_set->dlg_list) { 
     784            print_dialog("    [forked] ", dlg, dlginfo, sizeof(dlginfo)); 
     785            dlg = dlg->next; 
     786        } 
     787    } 
     788 
     789    pj_mutex_unlock(mod_ua.mutex); 
     790#endif 
     791} 
     792 
  • pjproject/trunk/pjsip/src/pjsua/main.c

    r167 r169  
    2626static pjsip_inv_session *inv_session; 
    2727 
     28static const char *inv_state_names[] = 
     29{ 
     30    "NULL      ", 
     31    "CALLING   ", 
     32    "INCOMING  ", 
     33    "EARLY     ", 
     34    "CONNECTING", 
     35    "CONFIRMED ", 
     36    "DISCONNCTD", 
     37    "TERMINATED", 
     38}; 
     39 
    2840/* 
    2941 * Notify UI when invite state has changed. 
     
    3143void pjsua_ui_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) 
    3244{ 
    33     const char *state_names[] = 
    34     { 
    35         "NULL", 
    36         "CALLING", 
    37         "INCOMING", 
    38         "EARLY", 
    39         "CONNECTING", 
    40         "CONFIRMED", 
    41         "DISCONNECTED", 
    42         "TERMINATED", 
    43     }; 
    44  
    4545    PJ_UNUSED_ARG(e); 
    4646 
    47     PJ_LOG(3,(THIS_FILE, "INVITE session state changed to %s", state_names[inv->state])); 
     47    PJ_LOG(3,(THIS_FILE, "INVITE session state changed to %s",  
     48              inv_state_names[inv->state])); 
    4849 
    4950    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) { 
     
    5859} 
    5960 
     61 
     62static void print_invite_session(const char *title, 
     63                                 struct pjsua_inv_data *inv_data,  
     64                                 char *buf, pj_size_t size) 
     65{ 
     66    int len; 
     67    pjsip_inv_session *inv = inv_data->inv; 
     68    pjsip_dialog *dlg = inv->dlg; 
     69    char userinfo[128]; 
     70 
     71    /* Dump invite sesion info. */ 
     72 
     73    len = pjsip_hdr_print_on(dlg->remote.info, userinfo, sizeof(userinfo)); 
     74    if (len < 1) 
     75        pj_native_strcpy(userinfo, "<--uri too long-->"); 
     76    else 
     77        userinfo[len] = '\0'; 
     78     
     79    len = pj_snprintf(buf, size, "%s[%s] %s", 
     80                      title, 
     81                      inv_state_names[inv->state], 
     82                      userinfo); 
     83    if (len < 1 || len >= (int)size) { 
     84        pj_native_strcpy(buf, "<--uri too long-->"); 
     85        len = 18; 
     86    } else 
     87        buf[len] = '\0'; 
     88} 
     89 
     90static void dump_media_session(pjmedia_session *session) 
     91{ 
     92    unsigned i; 
     93    pjmedia_session_info info; 
     94 
     95    pjmedia_session_get_info(session, &info); 
     96 
     97    for (i=0; i<info.stream_cnt; ++i) { 
     98        pjmedia_stream_stat strm_stat; 
     99        const char *rem_addr; 
     100        int rem_port; 
     101        const char *dir; 
     102 
     103        pjmedia_session_get_stream_stat(session, i, &strm_stat); 
     104        rem_addr = pj_inet_ntoa(info.stream_info[i].rem_addr.sin_addr); 
     105        rem_port = pj_ntohs(info.stream_info[i].rem_addr.sin_port); 
     106 
     107        if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING) 
     108            dir = "sendonly"; 
     109        else if (info.stream_info[i].dir == PJMEDIA_DIR_DECODING) 
     110            dir = "recvonly"; 
     111        else if (info.stream_info[i].dir == PJMEDIA_DIR_ENCODING_DECODING) 
     112            dir = "sendrecv"; 
     113        else 
     114            dir = "inactive"; 
     115 
     116         
     117        PJ_LOG(3,(THIS_FILE,  
     118                  "%s[Media strm#%d] %.*s, %s, peer=%s:%d", 
     119                  "               ", 
     120                  i, 
     121                  info.stream_info[i].fmt.encoding_name.slen, 
     122                  info.stream_info[i].fmt.encoding_name.ptr, 
     123                  dir, 
     124                  rem_addr, rem_port)); 
     125        PJ_LOG(3,(THIS_FILE,  
     126                  "%s tx {pkt=%u, bytes=%u} rx {pkt=%u, bytes=%u}", 
     127                  "                             ", 
     128                  strm_stat.enc.pkt, strm_stat.enc.bytes, 
     129                  strm_stat.dec.pkt, strm_stat.dec.bytes)); 
     130 
     131    } 
     132} 
     133 
     134/* 
     135 * Dump application states. 
     136 */ 
     137static void pjsua_dump(void) 
     138{ 
     139    struct pjsua_inv_data *inv_data; 
     140    char buf[128]; 
     141    unsigned log_decor; 
     142 
     143    log_decor = pj_log_get_decor(); 
     144    pj_log_set_decor(PJ_LOG_HAS_NEWLINE); 
     145 
     146    pjsip_endpt_dump(pjsua.endpt, 1); 
     147    pjsip_ua_dump(); 
     148 
     149    /* Dump all invite sessions: */ 
     150    PJ_LOG(3,(THIS_FILE, "Dumping invite sessions:")); 
     151 
     152    if (pj_list_empty(&pjsua.inv_list)) { 
     153 
     154        PJ_LOG(3,(THIS_FILE, "  - no sessions -")); 
     155 
     156    } else { 
     157 
     158        inv_data = pjsua.inv_list.next; 
     159 
     160        while (inv_data != &pjsua.inv_list) { 
     161 
     162            print_invite_session("  ", inv_data, buf, sizeof(buf)); 
     163            PJ_LOG(3,(THIS_FILE, "%s", buf)); 
     164 
     165            if (inv_data->session) 
     166                dump_media_session(inv_data->session); 
     167 
     168            inv_data = inv_data->next; 
     169        } 
     170    } 
     171 
     172    pj_log_set_decor(log_decor); 
     173} 
     174 
     175 
     176/* 
     177 * Show a bit of help. 
     178 */ 
    60179static void ui_help(void) 
    61180{ 
     
    63182    puts("Console keys:"); 
    64183    puts("  m    Make a call/another call"); 
     184    puts("  d    Dump application states"); 
    65185    puts("  a    Answer incoming call"); 
    66186    puts("  h    Hangup current call"); 
     
    122242            break; 
    123243 
     244 
     245        case 'd': 
     246            pjsua_dump(); 
     247            break; 
    124248 
    125249        case 'a': 
  • pjproject/trunk/pjsip/src/pjsua/pjsua.h

    r167 r169  
    3737 
    3838PJ_BEGIN_DECL 
     39 
     40 
     41/**  
     42 * Structure to be attached to all dialog.  
     43 * Given a dialog "dlg", application can retrieve this structure 
     44 * by accessing dlg->mod_data[pjsua.mod.id]. 
     45 */ 
     46struct pjsua_inv_data 
     47{ 
     48    PJ_DECL_LIST_MEMBER(struct pjsua_inv_data); 
     49 
     50    pjsip_inv_session   *inv; 
     51    pjmedia_session     *session; 
     52}; 
     53 
     54 
    3955 
    4056/* PJSUA application variables. */ 
     
    110126    char            *log_filename;  /**< Log filename.                  */ 
    111127 
     128    /* List of invite sessions: */ 
     129 
     130    struct pjsua_inv_data inv_list; 
    112131}; 
    113132 
     
    116135extern struct pjsua pjsua; 
    117136 
    118  
    119 /**  
    120  * Structure to be attached to all dialog.  
    121  * Given a dialog "dlg", application can retrieve this structure 
    122  * by accessing dlg->mod_data[pjsua.mod.id]. 
    123  */ 
    124 struct pjsua_inv_data 
    125 { 
    126     pjmedia_session *session; 
    127 }; 
    128137 
    129138 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_core.c

    r167 r169  
    7676 
    7777    pj_list_init(&pjsua.route_set); 
     78 
     79    /* Init invite session list: */ 
     80 
     81    pj_list_init(&pjsua.inv_list); 
    7882} 
    7983 
  • pjproject/trunk/pjsip/src/pjsua/pjsua_inv.c

    r167 r169  
    7979 
    8080    inv_data = pj_pool_zalloc( dlg->pool, sizeof(struct pjsua_inv_data)); 
     81    inv_data->inv = inv; 
    8182    dlg->mod_data[pjsua.mod.id] = inv_data; 
    8283 
     
    110111        goto on_error; 
    111112    } 
     113 
     114    /* Add invite session to the list. */ 
     115     
     116    pj_list_push_back(&pjsua.inv_list, inv_data); 
    112117 
    113118 
     
    215220 
    216221            inv_data = pj_pool_zalloc(dlg->pool, sizeof(struct pjsua_inv_data)); 
     222            inv_data->inv = inv; 
    217223            dlg->mod_data[pjsua.mod.id] = inv_data; 
     224 
     225            pj_list_push_back(&pjsua.inv_list, inv_data); 
    218226 
    219227 
     
    245253 
    246254        inv_data = inv->dlg->mod_data[pjsua.mod.id]; 
     255 
     256        pj_assert(inv_data != NULL); 
     257 
    247258        if (inv_data && inv_data->session) { 
    248259            pjmedia_session_destroy(inv_data->session); 
     
    252263        } 
    253264 
     265        if (inv_data) { 
     266 
     267            pj_list_erase(inv_data); 
     268 
     269        } 
    254270    } 
    255271 
Note: See TracChangeset for help on using the changeset viewer.