Ignore:
Timestamp:
Oct 24, 2011 9:28:13 AM (13 years ago)
Author:
ming
Message:

Re #1395: Backport of PJSIP 1.x branch into PJSIP 2.0 trunk

TODO: ticket #1268 (Option for automatic/manual sending of RTCP SDES/BYE for the stream) for video stream.

Location:
pjproject/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk

  • pjproject/trunk/pjsip-apps/src/samples/pcaputil.c

    r3664 r3841  
    2626"pcaputil [options] INPUT OUTPUT\n" 
    2727"\n" 
    28 "  Convert captured RTP packets in PCAP file to WAV or stream it\n" 
    29 "  to remote destination.\n" 
    30 "\n" 
    31 "INPUT is the PCAP file name/path\n" 
     28"  Convert captured RTP packets in PCAP file to WAV file or play it\n" 
     29"  to audio device.\n" 
     30"\n" 
     31"  INPUT  is the PCAP file name/path.\n" 
     32"  OUTPUT is the WAV file name/path to store the output, or set to \"-\",\n" 
     33"         to play the output to audio device. The program will decode\n" 
     34"         the RTP contents using codec that is available in PJMEDIA,\n" 
     35"         and optionally decrypt the content using the SRTP crypto and\n" 
     36"         keys below.\n" 
    3237"\n" 
    3338"Options to filter packets from PCAP file:\n" 
     
    3843"  --dst-port=port        Only include packets destined to this port number\n" 
    3944"\n" 
    40 "Options for saving to WAV file:\n" 
     45"Options for RTP packet processing:\n" 
    4146"" 
    42 "  OUTPUT is WAV file:    Set output to WAV file. The program will decode the\n" 
    43 "                         RTP contents to the specified WAV file using codec\n" 
    44 "                         that is available in PJMEDIA, and optionally decrypt\n" 
    45 "                         the content using the SRTP crypto and keys below.\n" 
     47"  --codec=codec_id       The codec ID formatted \"name/clock-rate/channel-count\"\n" 
     48"                         must be specified for codec with dynamic PT,\n" 
     49"                         e.g: \"Speex/8000\"\n" 
    4650"  --srtp-crypto=TAG, -c  Set crypto to be used to decrypt SRTP packets. Valid\n" 
    4751"                         tags are: \n" 
     
    5054"  --srtp-key=KEY, -k     Set the base64 key to decrypt SRTP packets.\n" 
    5155"\n" 
     56"Options for playing to audio device:\n" 
     57"" 
     58"  --play-dev-id=dev_id   Audio device ID for playback.\n" 
     59"\n" 
    5260"  Example:\n" 
    5361"    pcaputil file.pcap output.wav\n" 
    5462"    pcaputil -c AES_CM_128_HMAC_SHA1_80 \\\n" 
    55 "              -k VLDONbsbGl2Puqy+0PV7w/uGfpSPKFevDpxGsxN3 \\\n" 
    56 "              file.pcap output.wav\n" 
    57 "\n" 
    58 "Remote streaming is not supported yet." 
     63"             -k VLDONbsbGl2Puqy+0PV7w/uGfpSPKFevDpxGsxN3 \\\n" 
     64"             file.pcap output.wav\n" 
     65"\n" 
    5966; 
    6067 
     
    6774    pjmedia_port        *wav; 
    6875    pjmedia_codec       *codec; 
     76    pjmedia_aud_stream  *aud_strm; 
    6977    unsigned             pt; 
    7078    pjmedia_transport   *srtp; 
     
    7381} app; 
    7482 
    75 static void err_exit(const char *title, pj_status_t status) 
    76 { 
    77     if (status != PJ_SUCCESS) { 
    78         char errmsg[PJ_ERR_MSG_SIZE]; 
    79         pj_strerror(status, errmsg, sizeof(errmsg)); 
    80         printf("Error: %s: %s\n", title, errmsg); 
    81     } else { 
    82         printf("Error: %s\n", title); 
    83     } 
    84  
     83 
     84static void cleanup() 
     85{ 
    8586    if (app.srtp) pjmedia_transport_close(app.srtp); 
    8687    if (app.wav) { 
     
    103104        pjmedia_codec_mgr_dealloc_codec(cmgr, app.codec); 
    104105    } 
     106    if (app.aud_strm) { 
     107        pjmedia_aud_stream_stop(app.aud_strm); 
     108        pjmedia_aud_stream_destroy(app.aud_strm); 
     109    } 
    105110    if (app.mept) pjmedia_endpt_destroy(app.mept); 
    106111    if (app.pool) pj_pool_release(app.pool); 
    107112    pj_caching_pool_destroy(&app.cp); 
    108113    pj_shutdown(); 
    109  
     114} 
     115 
     116static void err_exit(const char *title, pj_status_t status) 
     117{ 
     118    if (status != PJ_SUCCESS) { 
     119        char errmsg[PJ_ERR_MSG_SIZE]; 
     120        pj_strerror(status, errmsg, sizeof(errmsg)); 
     121        printf("Error: %s: %s\n", title, errmsg); 
     122    } else { 
     123        printf("Error: %s\n", title); 
     124    } 
     125    cleanup(); 
    110126    exit(1); 
    111127} 
     
    213229} 
    214230 
    215 static void pcap2wav(const char *wav_filename, const pj_str_t *srtp_crypto, 
     231pjmedia_frame play_frm; 
     232static pj_bool_t play_frm_copied, play_frm_ready; 
     233 
     234static pj_status_t wait_play(pjmedia_frame *f) 
     235{ 
     236    play_frm_copied = PJ_FALSE; 
     237    play_frm = *f; 
     238    play_frm_ready = PJ_TRUE; 
     239    while (!play_frm_copied) { 
     240        pj_thread_sleep(1); 
     241    } 
     242    play_frm_ready = PJ_FALSE; 
     243 
     244    return PJ_SUCCESS; 
     245} 
     246 
     247static pj_status_t play_cb(void *user_data, pjmedia_frame *f) 
     248{ 
     249    PJ_UNUSED_ARG(user_data); 
     250 
     251    if (!play_frm_ready) { 
     252        PJ_LOG(3, ("play_cb()", "Warning! Play frame not ready"));  
     253        return PJ_SUCCESS; 
     254    } 
     255 
     256    pj_memcpy(f->buf, play_frm.buf, play_frm.size); 
     257    f->size = play_frm.size; 
     258 
     259    play_frm_copied = PJ_TRUE; 
     260    return PJ_SUCCESS; 
     261} 
     262 
     263static void pcap2wav(const pj_str_t *codec, 
     264                     const pj_str_t *wav_filename, 
     265                     pjmedia_aud_dev_index dev_id, 
     266                     const pj_str_t *srtp_crypto, 
    216267                     const pj_str_t *srtp_key) 
    217268{ 
     269    const pj_str_t WAV = {".wav", 4}; 
    218270    struct pkt 
    219271    { 
     
    256308    /* Get codec info and param for the specified payload type */ 
    257309    app.pt = pkt0.rtp->pt; 
    258     T( pjmedia_codec_mgr_get_codec_info(cmgr, pkt0.rtp->pt, &ci) ); 
     310    if (app.pt >=0 && app.pt < 96) { 
     311        T( pjmedia_codec_mgr_get_codec_info(cmgr, pkt0.rtp->pt, &ci) ); 
     312    } else { 
     313        unsigned cnt = 2; 
     314        const pjmedia_codec_info *info[2]; 
     315        T( pjmedia_codec_mgr_find_codecs_by_id(cmgr, codec, &cnt,  
     316                                               info, NULL) ); 
     317        if (cnt != 1) 
     318            err_exit("Codec ID must be specified and unique!", 0); 
     319 
     320        ci = info[0]; 
     321    } 
    259322    T( pjmedia_codec_mgr_get_default_param(cmgr, ci, &param) ); 
    260323 
     
    264327    T( pjmedia_codec_open(app.codec, &param) ); 
    265328 
    266     /* Open WAV file */ 
     329    /* Init audio device or WAV file */ 
    267330    samples_per_frame = ci->clock_rate * param.info.frm_ptime / 1000; 
    268     T( pjmedia_wav_writer_port_create(app.pool, wav_filename, 
    269                                       ci->clock_rate, ci->channel_cnt, 
    270                                       samples_per_frame, 
    271                                       param.info.pcm_bits_per_sample, 0, 0, 
    272                                       &app.wav) ); 
     331    if (pj_strcmp2(wav_filename, "-") == 0) { 
     332        pjmedia_aud_param aud_param; 
     333 
     334        /* Open audio device */ 
     335        T( pjmedia_aud_dev_default_param(dev_id, &aud_param) ); 
     336        aud_param.dir = PJMEDIA_DIR_PLAYBACK; 
     337        aud_param.channel_count = ci->channel_cnt; 
     338        aud_param.clock_rate = ci->clock_rate; 
     339        aud_param.samples_per_frame = samples_per_frame; 
     340        T( pjmedia_aud_stream_create(&aud_param, NULL, &play_cb,  
     341                                     NULL, &app.aud_strm) ); 
     342        T( pjmedia_aud_stream_start(app.aud_strm) ); 
     343    } else if (pj_stristr(wav_filename, &WAV)) { 
     344        /* Open WAV file */ 
     345        T( pjmedia_wav_writer_port_create(app.pool, wav_filename->ptr, 
     346                                          ci->clock_rate, ci->channel_cnt, 
     347                                          samples_per_frame, 
     348                                          param.info.pcm_bits_per_sample, 0, 0, 
     349                                          &app.wav) ); 
     350    } else { 
     351        err_exit("invalid output file", PJ_EINVAL); 
     352    } 
    273353 
    274354    /* Loop reading PCAP and writing WAV file */ 
     
    299379            T( pjmedia_codec_decode(app.codec, &frames[i], pcm_frame.size,  
    300380                                     &pcm_frame) ); 
    301             T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); 
     381            if (app.wav) { 
     382                T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); 
     383            } 
     384            if (app.aud_strm) { 
     385                T( wait_play(&pcm_frame) ); 
     386            } 
    302387            samples_cnt += samples_per_frame; 
    303388        } 
     
    322407            } 
    323408 
    324             T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); 
     409            if (app.wav) { 
     410                T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); 
     411            } 
     412            if (app.aud_strm) { 
     413                T( wait_play(&pcm_frame) ); 
     414            } 
    325415            ts_gap -= samples_per_frame; 
    326416        } 
     
    336426int main(int argc, char *argv[]) 
    337427{ 
    338     pj_str_t input, output, wav, srtp_crypto, srtp_key; 
     428    pj_str_t input, output, srtp_crypto, srtp_key, codec; 
     429    pjmedia_aud_dev_index dev_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV; 
    339430    pj_pcap_filter filter; 
    340431    pj_status_t status; 
    341432 
    342     enum { OPT_SRC_IP = 1, OPT_DST_IP, OPT_SRC_PORT, OPT_DST_PORT }; 
     433    enum {  
     434        OPT_SRC_IP = 1, OPT_DST_IP, OPT_SRC_PORT, OPT_DST_PORT, 
     435        OPT_CODEC, OPT_PLAY_DEV_ID 
     436    }; 
    343437    struct pj_getopt_option long_options[] = { 
    344438        { "srtp-crypto",    1, 0, 'c' }, 
     
    348442        { "src-port",       1, 0, OPT_SRC_PORT }, 
    349443        { "dst-port",       1, 0, OPT_DST_PORT }, 
     444        { "codec",          1, 0, OPT_CODEC }, 
     445        { "play-dev-id",    1, 0, OPT_PLAY_DEV_ID }, 
    350446        { NULL, 0, 0, 0} 
    351447    }; 
     
    355451 
    356452    srtp_crypto.slen = srtp_key.slen = 0; 
     453    codec.slen = 0; 
    357454 
    358455    pj_pcap_filter_default(&filter); 
     
    399496            filter.dst_port = pj_htons((pj_uint16_t)atoi(pj_optarg)); 
    400497            break; 
     498        case OPT_CODEC: 
     499            codec = pj_str(pj_optarg); 
     500            break; 
     501        case OPT_PLAY_DEV_ID: 
     502            dev_id = atoi(pj_optarg); 
     503            break; 
    401504        default: 
    402505            puts("Error: invalid option"); 
     
    418521    input = pj_str(argv[pj_optind]); 
    419522    output = pj_str(argv[pj_optind+1]); 
    420     wav = pj_str(".wav"); 
    421523     
    422524    T( pj_init() ); 
     
    431533    T( pj_pcap_set_filter(app.pcap, &filter) ); 
    432534 
    433     if (pj_stristr(&output, &wav)) { 
    434         pcap2wav(output.ptr, &srtp_crypto, &srtp_key); 
    435     } else { 
    436         err_exit("invalid output file", PJ_EINVAL); 
    437     } 
    438  
    439     pjmedia_endpt_destroy(app.mept); 
    440     pj_pool_release(app.pool); 
    441     pj_caching_pool_destroy(&app.cp); 
    442     pj_shutdown(); 
     535    pcap2wav(&codec, &output, dev_id, &srtp_crypto, &srtp_key); 
     536 
     537    cleanup(); 
    443538    return 0; 
    444539} 
Note: See TracChangeset for help on using the changeset viewer.