Changeset 3588


Ignore:
Timestamp:
Jun 20, 2011 3:54:49 AM (13 years ago)
Author:
nanang
Message:

Re #1308:

  • Updated pcap parser component to skip trailer bytes that may exist in some network layers (was raising assertion).
  • Updated pcaputil app to allow dynamic payload type codecs.
  • Updated pcaputil app to be able to play decoded frames directly to audio device, instead of writing to WAV file.
Location:
pjproject/branches/1.x
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/1.x/pjlib-util/src/pjlib-util/pcap.c

    r3553 r3588  
    369369        *udp_payload_size = sz; 
    370370 
     371        // Some layers may have trailer, e.g: link eth2. 
    371372        /* Check that we've read all the packets */ 
    372         PJ_ASSERT_RETURN(sz_read == rec_incl, PJ_EBUG); 
     373        //PJ_ASSERT_RETURN(sz_read == rec_incl, PJ_EBUG); 
     374 
     375        /* Skip trailer */ 
     376        while (sz_read < rec_incl) { 
     377            sz = rec_incl - sz_read; 
     378            status = read_file(file, &tmp.eth, &sz); 
     379            if (status != PJ_SUCCESS) { 
     380                TRACE_((file->obj_name, "Error reading trailer: %d", status)); 
     381                return status; 
     382            } 
     383            sz_read += sz; 
     384        } 
    373385 
    374386        return PJ_SUCCESS; 
  • pjproject/branches/1.x/pjsip-apps/src/samples/pcaputil.c

    r3553 r3588  
    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    { 
     
    254306#endif  /* PJMEDIA_HAS_L16_CODEC */ 
    255307 
     308#if PJMEDIA_HAS_INTEL_IPP 
     309    T( pjmedia_codec_ipp_init(app.mept) ); 
     310#endif 
     311 
    256312    /* Create SRTP transport is needed */ 
    257313#if PJMEDIA_HAS_SRTP 
     
    278334    /* Get codec info and param for the specified payload type */ 
    279335    app.pt = pkt0.rtp->pt; 
    280     T( pjmedia_codec_mgr_get_codec_info(cmgr, pkt0.rtp->pt, &ci) ); 
     336    if (app.pt >=0 && app.pt < 96) { 
     337        T( pjmedia_codec_mgr_get_codec_info(cmgr, pkt0.rtp->pt, &ci) ); 
     338    } else { 
     339        unsigned cnt = 2; 
     340        const pjmedia_codec_info *info[2]; 
     341        T( pjmedia_codec_mgr_find_codecs_by_id(cmgr, codec, &cnt,  
     342                                               info, NULL) ); 
     343        if (cnt != 1) 
     344            err_exit("Codec ID must be specified and unique!", 0); 
     345 
     346        ci = info[0]; 
     347    } 
    281348    T( pjmedia_codec_mgr_get_default_param(cmgr, ci, &param) ); 
    282349 
     
    286353    T( app.codec->op->open(app.codec, &param) ); 
    287354 
    288     /* Open WAV file */ 
     355    /* Init audio device or WAV file */ 
    289356    samples_per_frame = ci->clock_rate * param.info.frm_ptime / 1000; 
    290     T( pjmedia_wav_writer_port_create(app.pool, wav_filename, 
    291                                       ci->clock_rate, ci->channel_cnt, 
    292                                       samples_per_frame, 
    293                                       param.info.pcm_bits_per_sample, 0, 0, 
    294                                       &app.wav) ); 
     357    if (pj_strcmp2(wav_filename, "-") == 0) { 
     358        pjmedia_aud_param aud_param; 
     359 
     360        /* Open audio device */ 
     361        T( pjmedia_aud_dev_default_param(dev_id, &aud_param) ); 
     362        aud_param.dir = PJMEDIA_DIR_PLAYBACK; 
     363        aud_param.channel_count = ci->channel_cnt; 
     364        aud_param.clock_rate = ci->clock_rate; 
     365        aud_param.samples_per_frame = samples_per_frame; 
     366        T( pjmedia_aud_stream_create(&aud_param, NULL, &play_cb,  
     367                                     NULL, &app.aud_strm) ); 
     368        T( pjmedia_aud_stream_start(app.aud_strm) ); 
     369    } else if (pj_stristr(wav_filename, &WAV)) { 
     370        /* Open WAV file */ 
     371        T( pjmedia_wav_writer_port_create(app.pool, wav_filename->ptr, 
     372                                          ci->clock_rate, ci->channel_cnt, 
     373                                          samples_per_frame, 
     374                                          param.info.pcm_bits_per_sample, 0, 0, 
     375                                          &app.wav) ); 
     376    } else { 
     377        err_exit("invalid output file", PJ_EINVAL); 
     378    } 
    295379 
    296380    /* Loop reading PCAP and writing WAV file */ 
     
    321405            T( app.codec->op->decode(app.codec, &frames[i], pcm_frame.size,  
    322406                                     &pcm_frame) ); 
    323             T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); 
     407            if (app.wav) { 
     408                T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); 
     409            } 
     410            if (app.aud_strm) { 
     411                T( wait_play(&pcm_frame) ); 
     412            } 
    324413            samples_cnt += samples_per_frame; 
    325414        } 
     
    344433            } 
    345434 
    346             T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); 
     435            if (app.wav) { 
     436                T( pjmedia_port_put_frame(app.wav, &pcm_frame) ); 
     437            } 
     438            if (app.aud_strm) { 
     439                T( wait_play(&pcm_frame) ); 
     440            } 
    347441            ts_gap -= samples_per_frame; 
    348442        } 
     
    358452int main(int argc, char *argv[]) 
    359453{ 
    360     pj_str_t input, output, wav, srtp_crypto, srtp_key; 
     454    pj_str_t input, output, srtp_crypto, srtp_key, codec; 
     455    pjmedia_aud_dev_index dev_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV; 
    361456    pj_pcap_filter filter; 
    362457    pj_status_t status; 
    363458 
    364     enum { OPT_SRC_IP = 1, OPT_DST_IP, OPT_SRC_PORT, OPT_DST_PORT }; 
     459    enum {  
     460        OPT_SRC_IP = 1, OPT_DST_IP, OPT_SRC_PORT, OPT_DST_PORT, 
     461        OPT_CODEC, OPT_PLAY_DEV_ID 
     462    }; 
    365463    struct pj_getopt_option long_options[] = { 
    366464        { "srtp-crypto",    1, 0, 'c' }, 
     
    370468        { "src-port",       1, 0, OPT_SRC_PORT }, 
    371469        { "dst-port",       1, 0, OPT_DST_PORT }, 
     470        { "codec",          1, 0, OPT_CODEC }, 
     471        { "play-dev-id",    1, 0, OPT_PLAY_DEV_ID }, 
    372472        { NULL, 0, 0, 0} 
    373473    }; 
     
    377477 
    378478    srtp_crypto.slen = srtp_key.slen = 0; 
     479    codec.slen = 0; 
    379480 
    380481    pj_pcap_filter_default(&filter); 
     
    421522            filter.dst_port = pj_htons((pj_uint16_t)atoi(pj_optarg)); 
    422523            break; 
     524        case OPT_CODEC: 
     525            codec = pj_str(pj_optarg); 
     526            break; 
     527        case OPT_PLAY_DEV_ID: 
     528            dev_id = atoi(pj_optarg); 
     529            break; 
    423530        default: 
    424531            puts("Error: invalid option"); 
     
    440547    input = pj_str(argv[pj_optind]); 
    441548    output = pj_str(argv[pj_optind+1]); 
    442     wav = pj_str(".wav"); 
    443549     
    444550    T( pj_init() ); 
     
    453559    T( pj_pcap_set_filter(app.pcap, &filter) ); 
    454560 
    455     if (pj_stristr(&output, &wav)) { 
    456         pcap2wav(output.ptr, &srtp_crypto, &srtp_key); 
    457     } else { 
    458         err_exit("invalid output file", PJ_EINVAL); 
    459     } 
    460  
    461     pjmedia_endpt_destroy(app.mept); 
    462     pj_pool_release(app.pool); 
    463     pj_caching_pool_destroy(&app.cp); 
    464     pj_shutdown(); 
     561    pcap2wav(&codec, &output, dev_id, &srtp_crypto, &srtp_key); 
     562 
     563    cleanup(); 
    465564    return 0; 
    466565} 
Note: See TracChangeset for help on using the changeset viewer.