Changeset 545


Ignore:
Timestamp:
Jun 22, 2006 10:31:48 PM (18 years ago)
Author:
bennylp
Message:

Changed siprtp to use timer to schedule transmissions of RTP/RTCP packets

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip-apps/src/samples/siprtp.c

    r540 r545  
    123123    pjmedia_rtcp_session rtcp;              /* incoming RTCP session.   */ 
    124124 
    125     /* Thread: */ 
    126     pj_bool_t            thread_quit_flag;  /* Stop media thread.       */ 
    127     pj_thread_t         *thread;            /* Media thread.            */ 
     125    /* Timer to send RTP and RTCP: */ 
     126    pj_timer_entry       rtp_timer;         /* timer to send RTP pkt.   */ 
     127    pj_timer_entry       rtcp_timer;        /* timer to send RTCP pkt.  */ 
    128128}; 
    129129 
     
    223223static void on_rx_rtcp(void *user_data, const void *pkt, pj_ssize_t size); 
    224224 
     225/* This callback is called when it's time to send RTP packet */ 
     226static void on_tx_rtp( pj_timer_heap_t *timer_heap, 
     227                       struct pj_timer_entry *entry); 
     228 
     229/* This callback is called when it's time to send RTCP packet. */ 
     230static void on_tx_rtcp(pj_timer_heap_t *timer_heap, 
     231                       struct pj_timer_entry *entry); 
     232 
     233 
    225234/* Display error */ 
    226235static void app_perror(const char *sender, const char *title,  
     
    388397     * initialized. 
    389398     */ 
    390     status = pjmedia_endpt_create(&app.cp.factory, NULL, 1, &app.med_endpt); 
     399    status = pjmedia_endpt_create(&app.cp.factory,  
     400                                  pjsip_endpt_get_ioqueue(app.sip_endpt), 1,  
     401                                  &app.med_endpt); 
    391402    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); 
    392403 
     
    408419             * to current port number. 
    409420             */ 
     421            struct media_stream *m = &app.call[i].media[j]; 
    410422            int retry; 
    411423 
    412             app.call[i].media[j].call_index = i; 
    413             app.call[i].media[j].media_index = j; 
     424            m->call_index = i; 
     425            m->media_index = j; 
     426 
     427            m->rtp_timer.user_data = m; 
     428            m->rtp_timer.cb = &on_tx_rtp; 
     429 
     430            m->rtcp_timer.user_data = m; 
     431            m->rtcp_timer.cb = &on_tx_rtcp; 
     432 
    414433 
    415434            status = -1; 
     
    757776 
    758777 
     778#if defined(PJ_WIN32) && PJ_WIN32 != 0 
     779#include <windows.h> 
     780static void boost_priority(void) 
     781{ 
     782    SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS); 
     783    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 
     784} 
     785 
     786#else 
     787#  define boost_priority() 
     788#endif 
     789 
     790 
    759791/* Worker thread for SIP */ 
    760792static int sip_worker_thread(void *arg) 
     
    762794    PJ_UNUSED_ARG(arg); 
    763795 
     796    boost_priority(); 
     797 
    764798    while (!app.thread_quit) { 
    765         pj_time_val timeout = {0, 10}; 
     799        pj_time_val timeout = {0, 1}; 
    766800        pjsip_endpt_handle_events(app.sip_endpt, &timeout); 
    767801    } 
     
    10221056 
    10231057 
    1024 #if defined(PJ_WIN32) && PJ_WIN32 != 0 
    1025 #include <windows.h> 
    1026 static void boost_priority(void) 
    1027 { 
    1028     SetPriorityClass( GetCurrentProcess(), REALTIME_PRIORITY_CLASS); 
    1029     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); 
    1030 } 
    1031  
    1032 #else 
    1033 #  define boost_priority() 
    1034 #endif 
    1035  
    1036  
    10371058/* 
    10381059 * This callback is called by media transport on receipt of RTP packet. 
     
    10781099} 
    10791100 
     1101/* This callback is called when it's time to send RTP packet */ 
     1102static void on_tx_rtp( pj_timer_heap_t *timer_heap, 
     1103                       struct pj_timer_entry *entry) 
     1104{ 
     1105    pj_status_t status; 
     1106    const pjmedia_rtp_hdr *hdr; 
     1107    pj_ssize_t size; 
     1108    int hdrlen; 
     1109    pj_time_val interval; 
     1110    char packet[512]; 
     1111    struct media_stream *strm = entry->user_data; 
     1112 
     1113    PJ_UNUSED_ARG(timer_heap); 
     1114 
     1115    if (!strm->active) 
     1116        return; 
     1117 
     1118    /* Format RTP header */ 
     1119    status = pjmedia_rtp_encode_rtp( &strm->out_sess, strm->si.tx_pt, 
     1120                                     0, /* marker bit */ 
     1121                                     strm->bytes_per_frame,  
     1122                                     strm->samples_per_frame, 
     1123                                     (const void**)&hdr, &hdrlen); 
     1124    if (status == PJ_SUCCESS) { 
     1125 
     1126        //PJ_LOG(4,(THIS_FILE, "\t\tTx seq=%d", pj_ntohs(hdr->seq))); 
     1127 
     1128        /* Copy RTP header to packet */ 
     1129        pj_memcpy(packet, hdr, hdrlen); 
     1130 
     1131        /* Zero the payload */ 
     1132        pj_memset(packet+hdrlen, 0, strm->bytes_per_frame); 
     1133 
     1134        /* Send RTP packet */ 
     1135        size = hdrlen + strm->bytes_per_frame; 
     1136        status = pjmedia_transport_send_rtp(strm->transport,  
     1137                                            packet, size); 
     1138        if (status != PJ_SUCCESS) 
     1139            app_perror(THIS_FILE, "Error sending RTP packet", status); 
     1140 
     1141    } else { 
     1142        pj_assert(!"RTP encode() error"); 
     1143    } 
     1144 
     1145    /* Update RTCP SR */ 
     1146    pjmedia_rtcp_tx_rtp( &strm->rtcp, (pj_uint16_t)strm->bytes_per_frame); 
     1147 
     1148    /* Schedule next send */ 
     1149    interval.sec = 0; 
     1150    interval.msec = strm->samples_per_frame * 1000 / strm->clock_rate; 
     1151    pj_time_val_normalize(&interval); 
     1152 
     1153    pjsip_endpt_schedule_timer(app.sip_endpt, &strm->rtp_timer, &interval); 
     1154} 
     1155 
     1156 
    10801157/* 
    10811158 * This callback is called by media transport on receipt of RTCP packet. 
     
    11021179 
    11031180 
    1104 /*  
    1105  * Media thread  
    1106  * 
    1107  * This is the thread to send and receive both RTP and RTCP packets. 
    1108  */ 
    1109 static int media_thread(void *arg) 
    1110 { 
    1111     enum { RTCP_INTERVAL = 5000, RTCP_RAND = 2000 }; 
    1112     struct media_stream *strm = arg; 
    1113     char packet[1500]; 
    1114     unsigned msec_interval; 
    1115     pj_timestamp freq, next_rtp, next_rtcp; 
    1116  
    1117  
    1118     /* Boost thread priority if necessary */ 
    1119     boost_priority(); 
    1120  
    1121     /* Let things settle */ 
    1122     pj_thread_sleep(1000); 
    1123  
    1124     msec_interval = strm->samples_per_frame * 1000 / strm->clock_rate; 
    1125     pj_get_timestamp_freq(&freq); 
    1126  
    1127     pj_get_timestamp(&next_rtp); 
    1128     next_rtp.u64 += (freq.u64 * msec_interval / 1000); 
    1129  
    1130     next_rtcp = next_rtp; 
    1131     next_rtcp.u64 += (freq.u64 * (RTCP_INTERVAL+(pj_rand()%RTCP_RAND)) / 1000); 
    1132  
    1133  
    1134     while (!strm->thread_quit_flag) { 
    1135         pj_timestamp now, lesser; 
    1136         pj_time_val timeout; 
    1137         pj_bool_t send_rtp, send_rtcp; 
    1138  
    1139         send_rtp = send_rtcp = PJ_FALSE; 
    1140  
    1141         /* Determine how long to sleep */ 
    1142         if (next_rtp.u64 < next_rtcp.u64) { 
    1143             lesser = next_rtp; 
    1144             send_rtp = PJ_TRUE; 
    1145         } else { 
    1146             lesser = next_rtcp; 
    1147             send_rtcp = PJ_TRUE; 
    1148         } 
    1149  
    1150         pj_get_timestamp(&now); 
    1151         if (lesser.u64 <= now.u64) { 
    1152             timeout.sec = timeout.msec = 0; 
    1153             //printf("immediate "); fflush(stdout); 
    1154         } else { 
    1155             pj_uint64_t tick_delay; 
    1156             tick_delay = lesser.u64 - now.u64; 
    1157             timeout.sec = 0; 
    1158             timeout.msec = (pj_uint32_t)(tick_delay * 1000 / freq.u64); 
    1159             pj_time_val_normalize(&timeout); 
    1160  
    1161             //printf("%d:%03d ", timeout.sec, timeout.msec); fflush(stdout); 
    1162         } 
    1163  
    1164         /* Wait for next interval */ 
    1165         //if (timeout.sec!=0 && timeout.msec!=0) { 
    1166             pj_thread_sleep(PJ_TIME_VAL_MSEC(timeout)); 
    1167             if (strm->thread_quit_flag) 
    1168                 break; 
    1169         //} 
    1170  
    1171         pj_get_timestamp(&now); 
    1172  
    1173         if (send_rtp || next_rtp.u64 <= now.u64) { 
    1174             /* 
    1175              * Time to send RTP packet. 
    1176              */ 
    1177             pj_status_t status; 
    1178             const pjmedia_rtp_hdr *hdr; 
    1179             pj_ssize_t size; 
    1180             int hdrlen; 
    1181  
    1182             /* Format RTP header */ 
    1183             status = pjmedia_rtp_encode_rtp( &strm->out_sess, strm->si.tx_pt, 
    1184                                              0, /* marker bit */ 
    1185                                              strm->bytes_per_frame,  
    1186                                              strm->samples_per_frame, 
    1187                                              (const void**)&hdr, &hdrlen); 
    1188             if (status == PJ_SUCCESS) { 
    1189  
    1190                 //PJ_LOG(4,(THIS_FILE, "\t\tTx seq=%d", pj_ntohs(hdr->seq))); 
    1191  
    1192                 /* Copy RTP header to packet */ 
    1193                 pj_memcpy(packet, hdr, hdrlen); 
    1194  
    1195                 /* Zero the payload */ 
    1196                 pj_memset(packet+hdrlen, 0, strm->bytes_per_frame); 
    1197  
    1198                 /* Send RTP packet */ 
    1199                 size = hdrlen + strm->bytes_per_frame; 
    1200                 status = pjmedia_transport_send_rtp(strm->transport,  
    1201                                                     packet, size); 
    1202                 if (status != PJ_SUCCESS) 
    1203                     app_perror(THIS_FILE, "Error sending RTP packet", status); 
    1204  
    1205             } else { 
    1206                 pj_assert(!"RTP encode() error"); 
    1207             } 
    1208  
    1209             /* Update RTCP SR */ 
    1210             pjmedia_rtcp_tx_rtp( &strm->rtcp, (pj_uint16_t)strm->bytes_per_frame); 
    1211  
    1212             /* Schedule next send */ 
    1213             next_rtp.u64 += (msec_interval * freq.u64 / 1000); 
    1214         } 
    1215  
    1216  
    1217         if (send_rtcp || next_rtcp.u64 <= now.u64) { 
    1218             /* 
    1219              * Time to send RTCP packet. 
    1220              */ 
    1221             pjmedia_rtcp_pkt *rtcp_pkt; 
    1222             int rtcp_len; 
    1223             pj_ssize_t size; 
    1224             pj_status_t status; 
    1225  
    1226             /* Build RTCP packet */ 
    1227             pjmedia_rtcp_build_rtcp(&strm->rtcp, &rtcp_pkt, &rtcp_len); 
    1228  
     1181/* This callback is called when it's time to send RTCP packet. */ 
     1182static void on_tx_rtcp(pj_timer_heap_t *timer_heap, 
     1183                       struct pj_timer_entry *entry) 
     1184{ 
     1185    pjmedia_rtcp_pkt *rtcp_pkt; 
     1186    int rtcp_len; 
     1187    pj_ssize_t size; 
     1188    pj_status_t status; 
     1189    pj_time_val interval; 
     1190    struct media_stream *strm = entry->user_data; 
     1191 
     1192    PJ_UNUSED_ARG(timer_heap); 
     1193 
     1194    if (!strm->active) 
     1195        return; 
     1196 
     1197    /* Build RTCP packet */ 
     1198    pjmedia_rtcp_build_rtcp(&strm->rtcp, &rtcp_pkt, &rtcp_len); 
     1199 
     1200    /* Send packet */ 
     1201    size = rtcp_len; 
     1202    status = pjmedia_transport_send_rtcp(strm->transport, 
     1203                                         rtcp_pkt, size); 
     1204    if (status != PJ_SUCCESS) { 
     1205        app_perror(THIS_FILE, "Error sending RTCP packet", status); 
     1206    } 
    12291207     
    1230             /* Send packet */ 
    1231             size = rtcp_len; 
    1232             status = pjmedia_transport_send_rtcp(strm->transport, 
    1233                                                  rtcp_pkt, size); 
    1234             if (status != PJ_SUCCESS) { 
    1235                 app_perror(THIS_FILE, "Error sending RTCP packet", status); 
    1236             } 
    1237              
    1238             /* Schedule next send */ 
    1239             next_rtcp.u64 += (freq.u64 * (RTCP_INTERVAL+(pj_rand()%RTCP_RAND)) / 
    1240                               1000); 
    1241         } 
    1242     } 
    1243  
    1244     return 0; 
    1245 } 
    1246  
     1208    /* Schedule next send */ 
     1209    interval.sec = 5; 
     1210    interval.msec = (pj_rand() % 500); 
     1211    pjsip_endpt_schedule_timer(app.sip_endpt, &strm->rtcp_timer, &interval); 
     1212 
     1213} 
    12471214 
    12481215/* Callback to be called when SDP negotiation is done in the call: */ 
     
    12551222    const pjmedia_sdp_session *local_sdp, *remote_sdp; 
    12561223    struct codec *codec_desc = NULL; 
     1224    pj_time_val interval; 
    12571225    unsigned i; 
    12581226 
     
    12621230 
    12631231    /* If this is a mid-call media update, then destroy existing media */ 
    1264     if (audio->thread != NULL) 
     1232    if (audio->active) 
    12651233        destroy_call_media(call->index); 
    12661234 
     
    13251293    } 
    13261294 
    1327     /* Start media thread. */ 
    1328     audio->thread_quit_flag = 0; 
    1329     status = pj_thread_create( inv->pool, "media", &media_thread, audio, 
    1330                                0, 0, &audio->thread); 
    1331     if (status != PJ_SUCCESS) { 
    1332         app_perror(THIS_FILE, "Error creating media thread", status); 
    1333         return; 
    1334     } 
    1335  
    13361295    /* Set the media as active */ 
    13371296    audio->active = PJ_TRUE; 
     1297 
     1298    /* Immediately schedule to send the first RTP packet. */ 
     1299    audio->rtp_timer.id = 1; 
     1300    interval.sec = interval.msec = 0; 
     1301    pjsip_endpt_schedule_timer(app.sip_endpt, &audio->rtp_timer, &interval); 
     1302 
     1303    /* And schedule the first RTCP packet */ 
     1304    audio->rtcp_timer.id = 1; 
     1305    interval.sec = 4; 
     1306    interval.msec = (pj_rand() % 1000); 
     1307    pjsip_endpt_schedule_timer(app.sip_endpt, &audio->rtcp_timer, &interval); 
    13381308} 
    13391309 
     
    13451315    struct media_stream *audio = &app.call[call_index].media[0]; 
    13461316 
    1347     if (audio->thread) { 
     1317    if (audio->active) { 
    13481318 
    13491319        audio->active = PJ_FALSE; 
    13501320 
    1351         audio->thread_quit_flag = 1; 
    1352         pj_thread_join(audio->thread); 
    1353         pj_thread_destroy(audio->thread); 
    1354         audio->thread = NULL; 
    1355         audio->thread_quit_flag = 0; 
     1321        if (audio->rtp_timer.id) { 
     1322            audio->rtp_timer.id = 0; 
     1323            pjsip_endpt_cancel_timer(app.sip_endpt, &audio->rtp_timer); 
     1324        } 
     1325 
     1326        if (audio->rtcp_timer.id) { 
     1327            audio->rtcp_timer.id = 0; 
     1328            pjsip_endpt_cancel_timer(app.sip_endpt, &audio->rtcp_timer); 
     1329        } 
    13561330 
    13571331        pjmedia_transport_detach(audio->transport, audio); 
     
    16951669     
    16961670    /* Shutting down... */ 
     1671    destroy_media(); 
    16971672    destroy_sip(); 
    1698     destroy_media(); 
    16991673 
    17001674    if (app.pool) { 
Note: See TracChangeset for help on using the changeset viewer.