📄 streamutil.c
字号:
/* $Id: streamutil.c 974 2007-02-19 01:13:53Z bennylp $ */
/*
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/**
* \page page_pjmedia_samples_streamutil_c Samples: Remote Streaming
*
* This example mainly demonstrates how to stream media file to remote
* peer using RTP.
*
* This file is pjsip-apps/src/samples/streamutil.c
*
* \includelineno streamutil.c
*/
static const char *desc =
" streamutil \n"
" \n"
" PURPOSE: \n"
" Demonstrate how to use pjmedia stream component to transmit/receive \n"
" RTP packets to/from sound device. \n"
"\n"
"\n"
" USAGE: \n"
" streamutil [options] \n"
"\n"
"\n"
" Options:\n"
" --codec=CODEC Set the codec name. \n"
" --local-port=PORT Set local RTP port (default=4000) \n"
" --remote=IP:PORT Set the remote peer. If this option is set, \n"
" the program will transmit RTP audio to the \n"
" specified address. (default: recv only) \n"
" --play-file=WAV Send audio from the WAV file instead of from \n"
" the sound device. \n"
" --record-file=WAV Record incoming audio to WAV file instead of \n"
" playing it to sound device. \n"
" --send-recv Set stream direction to bidirectional. \n"
" --send-only Set stream direction to send only \n"
" --recv-only Set stream direction to recv only (default) \n"
"\n"
;
#include <pjlib.h>
#include <pjlib-util.h>
#include <pjmedia.h>
#include <pjmedia-codec.h>
#include <stdlib.h> /* atoi() */
#include <stdio.h>
#include "util.h"
#define THIS_FILE "stream.c"
/* Prototype */
static void print_stream_stat(pjmedia_stream *stream);
/*
* Register all codecs.
*/
static pj_status_t init_codecs(pjmedia_endpt *med_endpt)
{
pj_status_t status;
/* To suppress warning about unused var when all codecs are disabled */
PJ_UNUSED_ARG(status);
#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
status = pjmedia_codec_g711_init(med_endpt);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
#endif
#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC!=0
status = pjmedia_codec_gsm_init(med_endpt);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
#endif
#if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0
status = pjmedia_codec_speex_init(med_endpt, 0, -1, -1);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
#endif
#if defined(PJMEDIA_HAS_L16_CODEC) && PJMEDIA_HAS_L16_CODEC!=0
status = pjmedia_codec_l16_init(med_endpt, 0);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
#endif
return PJ_SUCCESS;
}
/*
* Create stream based on the codec, dir, remote address, etc.
*/
static pj_status_t create_stream( pj_pool_t *pool,
pjmedia_endpt *med_endpt,
const pjmedia_codec_info *codec_info,
pjmedia_dir dir,
pj_uint16_t local_port,
const pj_sockaddr_in *rem_addr,
pjmedia_stream **p_stream )
{
pjmedia_stream_info info;
pjmedia_transport *transport;
pj_status_t status;
/* Reset stream info. */
pj_bzero(&info, sizeof(info));
/* Initialize stream info formats */
info.type = PJMEDIA_TYPE_AUDIO;
info.dir = dir;
pj_memcpy(&info.fmt, codec_info, sizeof(pjmedia_codec_info));
info.tx_pt = codec_info->pt;
info.ssrc = pj_rand();
/* Copy remote address */
pj_memcpy(&info.rem_addr, rem_addr, sizeof(pj_sockaddr_in));
/* Create media transport */
status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
0, &transport);
if (status != PJ_SUCCESS)
return status;
/* Now that the stream info is initialized, we can create the
* stream.
*/
status = pjmedia_stream_create( med_endpt, pool, &info,
transport, NULL, p_stream);
if (status != PJ_SUCCESS) {
app_perror(THIS_FILE, "Error creating stream", status);
pjmedia_transport_udp_close(transport);
return status;
}
return PJ_SUCCESS;
}
/*
* usage()
*/
static void usage()
{
puts(desc);
}
/*
* main()
*/
int main(int argc, char *argv[])
{
pj_caching_pool cp;
pjmedia_endpt *med_endpt;
pj_pool_t *pool;
pjmedia_port *rec_file_port = NULL, *play_file_port = NULL;
pjmedia_master_port *master_port = NULL;
pjmedia_snd_port *snd_port = NULL;
pjmedia_stream *stream = NULL;
pjmedia_port *stream_port;
char tmp[10];
pj_status_t status;
/* Default values */
const pjmedia_codec_info *codec_info;
pjmedia_dir dir = PJMEDIA_DIR_DECODING;
pj_sockaddr_in remote_addr;
pj_uint16_t local_port = 4000;
char *codec_id = NULL;
char *rec_file = NULL;
char *play_file = NULL;
enum {
OPT_CODEC = 'c',
OPT_LOCAL_PORT = 'p',
OPT_REMOTE = 'r',
OPT_PLAY_FILE = 'w',
OPT_RECORD_FILE = 'R',
OPT_SEND_RECV = 'b',
OPT_SEND_ONLY = 's',
OPT_RECV_ONLY = 'i',
OPT_HELP = 'h',
};
struct pj_getopt_option long_options[] = {
{ "codec", 1, 0, OPT_CODEC },
{ "local-port", 1, 0, OPT_LOCAL_PORT },
{ "remote", 1, 0, OPT_REMOTE },
{ "play-file", 1, 0, OPT_PLAY_FILE },
{ "record-file", 1, 0, OPT_RECORD_FILE },
{ "send-recv", 0, 0, OPT_SEND_RECV },
{ "send-only", 0, 0, OPT_SEND_ONLY },
{ "recv-only", 0, 0, OPT_RECV_ONLY },
{ "help", 0, 0, OPT_HELP },
{ NULL, 0, 0, 0 },
};
int c;
int option_index;
pj_bzero(&remote_addr, sizeof(remote_addr));
/* init PJLIB : */
status = pj_init();
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
/* Parse arguments */
pj_optind = 0;
while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1) {
switch (c) {
case OPT_CODEC:
codec_id = pj_optarg;
break;
case OPT_LOCAL_PORT:
local_port = (pj_uint16_t) atoi(pj_optarg);
if (local_port < 1) {
printf("Error: invalid local port %s\n", pj_optarg);
return 1;
}
break;
case OPT_REMOTE:
{
pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));
status = pj_sockaddr_in_init(&remote_addr, &ip, port);
if (status != PJ_SUCCESS) {
app_perror(THIS_FILE, "Invalid remote address", status);
return 1;
}
}
break;
case OPT_PLAY_FILE:
play_file = pj_optarg;
break;
case OPT_RECORD_FILE:
rec_file = pj_optarg;
break;
case OPT_SEND_RECV:
dir = PJMEDIA_DIR_ENCODING_DECODING;
break;
case OPT_SEND_ONLY:
dir = PJMEDIA_DIR_ENCODING;
break;
case OPT_RECV_ONLY:
dir = PJMEDIA_DIR_DECODING;
break;
case OPT_HELP:
usage();
return 1;
default:
printf("Invalid options %s\n", argv[pj_optind]);
return 1;
}
}
/* Verify arguments. */
if (dir & PJMEDIA_DIR_ENCODING) {
if (remote_addr.sin_addr.s_addr == 0) {
printf("Error: remote address must be set\n");
return 1;
}
}
if (play_file != NULL && dir != PJMEDIA_DIR_ENCODING) {
printf("Direction is set to --send-only because of --play-file\n");
dir = PJMEDIA_DIR_ENCODING;
}
/* Must create a pool factory before we can allocate any memory. */
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
/*
* Initialize media endpoint.
* This will implicitly initialize PJMEDIA too.
*/
status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
/* Create memory pool for application purpose */
pool = pj_pool_create( &cp.factory, /* pool factory */
"app", /* pool name. */
4000, /* init size */
4000, /* increment size */
NULL /* callback on error */
);
/* Register all supported codecs */
status = init_codecs(med_endpt);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
/* Find which codec to use. */
if (codec_id) {
unsigned count = 1;
pj_str_t str_codec_id = pj_str(codec_id);
pjmedia_codec_mgr *codec_mgr = pjmedia_endpt_get_codec_mgr(med_endpt);
status = pjmedia_codec_mgr_find_codecs_by_id( codec_mgr,
&str_codec_id, &count,
&codec_info, NULL);
if (status != PJ_SUCCESS) {
printf("Error: unable to find codec %s\n", codec_id);
return 1;
}
} else {
/* Default to pcmu */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -