/* mediastreamer2 library - modular sound and video processing and streaming Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.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. */ #ifdef HAVE_CONFIG_H #include "mediastreamer-config.h" #endif #include #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msequalizer.h" #include "mediastreamer2/msvolume.h" #ifdef VIDEO_ENABLED #include "mediastreamer2/msv4l.h" #endif #include #include #include #ifndef WIN32 #include #else #include #endif #include #include #include #ifdef __APPLE__ #include #endif #ifdef ANDROID #include #include #endif static int cond=1; #ifdef VIDEO_ENABLED static VideoStream *video=NULL; #endif static const char * capture_card=NULL; static const char * playback_card=NULL; static const char * camera=NULL; static const char *infile=NULL,*outfile=NULL; static float ng_threshold=-1; static bool_t use_ng=FALSE; static bool_t two_windows=FALSE; static bool_t el=FALSE; static float el_speed=-1; static float el_thres=-1; static float el_force=-1; static int el_sustain=-1; static float el_transmit_thres=-1; static float ng_floorgain=-1; static bool_t use_rc=FALSE; static const char * zrtp_id=NULL; static const char * zrtp_secrets=NULL; static PayloadType *custom_pt=NULL; static int video_window_id = -1; static int preview_window_id = -1; /* starting values echo canceller */ static int ec_len_ms=0, ec_delay_ms=0, ec_framesize=0; static void run_media_streams(int localport, const char *remote_ip, int remoteport, int payload, const char *fmtp, int jitter, int bitrate, MSVideoSize vs, bool_t ec, bool_t agc, bool_t eq, int device_rotation); static void stop_handler(int signum) { cond--; if (cond<0) { ms_error("Brutal exit (%)\n", cond); exit(-1); } } static bool_t parse_addr(const char *addr, char *ip, int len, int *port) { const char *semicolon=NULL; int iplen; int slen; const char *p; *port=0; semicolon=strchr(addr,':'); for (p=addr+strlen(addr)-1;p>addr;p--){ if (*p==':') { semicolon=p; break; } } if (semicolon==NULL) return FALSE; iplen=semicolon-addr; slen=MIN(iplen,len-1); strncpy(ip,addr,slen); ip[slen]='\0'; *port=atoi(semicolon+1); return TRUE; } static void display_items(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len){ char str[256]; int len=MIN(sizeof(str)-1,content_len); strncpy(str,content,len); str[len]='\0'; switch(t){ case RTCP_SDES_CNAME: ms_message("Found CNAME=%s",str); break; case RTCP_SDES_TOOL: ms_message("Found TOOL=%s",str); break; case RTCP_SDES_NOTE: ms_message("Found NOTE=%s",str); break; default: ms_message("Unhandled SDES item (%s)",str); } } static void parse_rtcp(mblk_t *m){ do{ if (rtcp_is_RR(m)){ ms_message("Receiving RTCP RR"); }else if (rtcp_is_SR(m)){ ms_message("Receiving RTCP SR"); }else if (rtcp_is_SDES(m)){ ms_message("Receiving RTCP SDES"); rtcp_sdes_parse(m,display_items,NULL); }else { ms_message("Receiving unhandled RTCP message"); } }while(rtcp_next_packet(m)); } static void parse_events(RtpSession *session, OrtpEvQueue *q){ OrtpEvent *ev; while((ev=ortp_ev_queue_get(q))!=NULL){ OrtpEventData *d=ortp_event_get_data(ev); switch(ortp_event_get_type(ev)){ case ORTP_EVENT_RTCP_PACKET_RECEIVED: parse_rtcp(d->packet); break; default: break; } ortp_event_destroy(ev); } } static void create_custom_payload_type(const char *type, const char *subtype, const char *rate, int number){ PayloadType *pt=payload_type_new(); if (strcasecmp(type,"audio")==0){ pt->type=PAYLOAD_AUDIO_PACKETIZED; }else if (strcasecmp(type,"video")==0){ pt->type=PAYLOAD_VIDEO; }else{ fprintf(stderr,"Unsupported payload type should be audio or video, not %s\n",type); exit(-1); } pt->mime_type=ms_strdup(subtype); pt->clock_rate=atoi(rate); custom_pt=pt; } static void parse_custom_payload(const char *name){ char type[64]={0}; char subtype[64]={0}; char clockrate[64]={0}; char *separator; if (strlen(name)>=sizeof(clockrate)-1){ fprintf(stderr,"Cannot parse %s: too long.\n",name); exit(-1); } separator=strchr(name,'/'); if (separator){ char *separator2; strncpy(type,name,separator-name); separator2=strchr(separator+1,'/'); if (separator2){ strncpy(subtype,separator+1,separator2-separator-1); strcpy(clockrate,separator2+1); fprintf(stdout,"Found custom payload type=%s, mime=%s, clockrate=%s\n",type,subtype,clockrate); create_custom_payload_type(type,subtype,clockrate,114); return; } } fprintf(stderr,"Error parsing payload name %s.\n",name); exit(-1); } static bool_t parse_window_ids(const char *ids, int* video_id, int* preview_id) { char* copy = strdup(ids); char *semicolon=strchr(copy,':'); if (semicolon==NULL) { free(copy); return FALSE; } *semicolon = '\0'; *video_id=atoi(copy); *preview_id=atoi(semicolon+1); free(copy); return TRUE; } const char *usage="mediastream --local --remote \n" "--payload \n" "[ --fmtp ]\n" "[ --jitter ]\n" "[ --width ]\n" "[ --height ]\n" "[ --bitrate ]\n" "[ --ec (enable echo canceller) ]\n" "[ --ec-tail ]\n" "[ --ec-delay ]\n" "[ --ec-framesize ]\n" "[ --agc (enable automatic gain control) ]\n" "[ --ng (enable noise gate)] \n" "[ --ng-threshold <(float) [0-1]> (noise gate threshold) ]\n" "[ --ng-floorgain <(float) [0-1]> (gain applied to the signal when its energy is below the threshold.) ]\n" "[ --capture-card ]\n" "[ --playback-card ]\n" "[ --infile specify a wav file to be used for input, instead of soundcard ]\n" "[ --outfile specify a wav file to write audio into, instead of soundcard ]\n" "[ --camera ]\n" "[ --el (enable echo limiter) ]\n" "[ --el-speed <(float) [0-1]> (gain changes are smoothed with a coefficent) ]\n" "[ --el-thres <(float) [0-1]> (Threshold above which the system becomes active) ]\n" "[ --el-force <(float) [0-1]> (The proportional coefficient controlling the mic attenuation) ]\n" "[ --el-sustain <(int)> (Time in milliseconds for which the attenuation is kept unchanged after) ]\n" "[ --el-transmit-thres <(float) [0-1]> (TO BE DOCUMENTED) ]\n" "[ --rc (enable adaptive rate control) ]\n" "[ --zrtp (enable zrtp) ]\n" "[ --verbose (most verbose messages) ]\n" "[ --video-windows-id