diff --git a/Makefile b/Makefile index f61e331..b9ffe92 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,11 @@ PJSIP_DIR=pjproject-2.11.1 PKG_CONFIG_PATH=pjsip.install/lib/pkgconfig +ifndef NO_PULSE + DM_LDFLAGS += -l pulse -l pulse-simple + DM_CFLAGS += -DHAS_PULSE +endif + all: d-modem slmodemd $(PKG_CONFIG_PATH)/libpjproject.pc: @@ -9,13 +14,16 @@ $(PKG_CONFIG_PATH)/libpjproject.pc: $(MAKE) -C $(PJSIP_DIR) install d-modem: d-modem.c $(PKG_CONFIG_PATH)/libpjproject.pc + $(CC) $(DM_CFLAGS) -o $@ $< `PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --static --cflags --libs libpjproject` $(DM_LDFLAGS) + +d-modem.nopulse: d-modem.c $(PKG_CONFIG_PATH)/libpjproject.pc $(CC) -o $@ $< `PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --static --cflags --libs libpjproject` slmodemd: $(MAKE) -C slmodemd clean: - rm -f d-modem.o d-modem + rm -f d-modem.o d-modem d-modem.nopulse $(MAKE) -C slmodemd clean realclean: clean diff --git a/d-modem.c b/d-modem.c index 79bc028..fa9df83 100644 --- a/d-modem.c +++ b/d-modem.c @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include #include @@ -24,14 +25,35 @@ #include // test #include +#include + +#include + +#define PCM_FILE "dmodem.%s.s16le.9600hz.pcm" +#undef PCM_FILE +//#define HAS_PULSE + +#ifdef HAS_PULSE +pa_simple *pa_s1 = NULL; +pa_simple *pa_s2 = NULL; +const pa_sample_spec pa_ss = { + .format = PA_SAMPLE_S16LE, + .rate = 9600, + .channels = 1 +}; +#endif +#ifdef PCM_FILE +int wave_recv = -1; +int wave_transmit = -1; +#endif #define SIGNATURE PJMEDIA_SIG_CLASS_PORT_AUD('D','M') #define DMODEM_DIAL_MODE 0 -#define DMODEM_ANSWER_MODE 2 -#define DMODEM_RING_DETECT_MODE 3 +#define DMODEM_ANSWER_MODE 1 uint8_t mode = DMODEM_DIAL_MODE; uint8_t ringing = 0; +uint8_t answered = 0; pjsua_call_id incoming; struct dmodem { @@ -44,20 +66,85 @@ static struct dmodem port; static bool destroying = false; static pj_pool_t *pool; +void stop_pa(); static void error_exit(const char *title, pj_status_t status) { pjsua_perror(__FILE__, title, status); if (!destroying) { destroying = true; pjsua_destroy(); + stop_pa(); + if (answered) + execl("/bin/sh", "/bin/sh", "-cx", "kill -INT $PPID", NULL); exit(1); } } +void start_pa() { +#ifdef PCM_FILE + char _wavbuf[50]; + sprintf(_wavbuf, PCM_FILE, "recv"); + wave_recv = open(_wavbuf, O_WRONLY | O_CREAT, 00644); + sprintf(_wavbuf, PCM_FILE, "transmit"); + wave_recv = open(_wavbuf, O_WRONLY | O_CREAT, 00644); + if (wave_recv <= 0 || wave_transmit <= 0) + error_exit("open wave files", 1); +#endif +#ifdef HAS_PULSE + pa_s1 = pa_simple_new(NULL, // Use the default server. + "dmodem", // Our application's name. + PA_STREAM_PLAYBACK, + NULL, // Use the default device. + "recv", // Description of our stream. + &pa_ss, // Our sample format. + NULL, // Use default channel map + NULL, // Use default buffering attributes. + NULL // Ignore error code. + ); + pa_s2 = pa_simple_new(NULL, // Use the default server. + "dmodem", // Our application's name. + PA_STREAM_PLAYBACK, + NULL, // Use the default device. + "transmit", // Description of our stream. + &pa_ss, // Our sample format. + NULL, // Use default channel map + NULL, // Use default buffering attributes. + NULL // Ignore error code. + ); + if (!pa_s1 || !pa_s2) + error_exit("pulseaudio", 1); +#endif +} + +void stop_pa() { +#ifdef HAS_PULSE + if(pa_s1) + pa_simple_free(pa_s1); + if(pa_s2) + pa_simple_free(pa_s2); + pa_s1 = 0; + pa_s1 = 0; +#endif +#ifdef PCM_FILE + if (wave_recv >= 0) + close(wave_recv); + if (wave_transmit >= 0) + close(wave_transmit); + wave_recv = -1; + wave_transmit = -1; +#endif +} + static pj_status_t dmodem_put_frame(pjmedia_port *this_port, pjmedia_frame *frame) { struct dmodem *sm = (struct dmodem *)this_port; int len; if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO) { +#ifdef HAS_PULSE + pa_simple_write(pa_s1, frame->buf, frame->size, NULL); +#endif +#ifdef PCM_FILE + write(wave_recv, frame->buf, frame->size); +#endif if ((len=write(sm->sock, frame->buf, frame->size)) != frame->size) { error_exit("error writing frame",0); } @@ -78,12 +165,20 @@ static pj_status_t dmodem_get_frame(pjmedia_port *this_port, pjmedia_frame *fram frame->timestamp.u64 = sm->timestamp.u64; frame->type = PJMEDIA_FRAME_TYPE_AUDIO; sm->timestamp.u64 += PJMEDIA_PIA_SPF(&this_port->info); +#ifdef HAS_PULSE + pa_simple_write(pa_s2, frame->buf, frame->size, NULL); +#endif +#ifdef PCM_FILE + write(wave_transmit, frame->buf, frame->size); +#endif return PJ_SUCCESS; } static pj_status_t dmodem_on_destroy(pjmedia_port *this_port) { printf("destroy\n"); + if (answered) + execl("/bin/sh", "/bin/sh", "-cx", "kill -INT $PPID", NULL); exit(-1); } @@ -99,15 +194,15 @@ static void on_call_state(pjsua_call_id call_id, pjsip_event *e) { ci.state_text.ptr)); if (ci.state == PJSIP_INV_STATE_DISCONNECTED) { - if(mode != DMODEM_RING_DETECT_MODE) { - close(port.sock); - if (!destroying) { - destroying = true; - pjsua_destroy(); - exit(0); - } + close(port.sock); + if (!destroying) { + destroying = true; + pjsua_destroy(); + stop_pa(); + if (answered) + execl("/bin/sh", "/bin/sh", "-cx", "kill -INT $PPID", NULL); + exit(0); } - ringing = 0; } } @@ -117,6 +212,11 @@ static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_r char* tmp = malloc(pj_strlen(&ci.remote_contact)+1); strcpy(tmp, ci.remote_contact.ptr); tmp[pj_strlen(&ci.remote_contact)] = '\0'; + if (answered) { + printf("Incoming call rejected from: %s\n", tmp); + pjsua_call_hangup(call_id, 0u, NULL, NULL); + return; + } printf("Incoming call from: %s\n", tmp); free(tmp); incoming = call_id; @@ -144,26 +244,41 @@ static void on_call_media_state(pjsua_call_id call_id) { } } - int main(int argc, char *argv[]) { pjsua_acc_id acc_id; pj_status_t status; if (argc != 3) { return -1; } - ringing = 0; - if(!strncmp(argv[1], "++", 2)) { + if(!strncmp(argv[1], "rr", 2)) { mode = DMODEM_ANSWER_MODE; - } else if(!strncmp(argv[1], "rr", 2)) { - mode = DMODEM_RING_DETECT_MODE; } signal(SIGPIPE,SIG_IGN); char *dialstr = argv[1]; - char *sip_user = "dialupuser"; - char *sip_domain = "192.168.1.2"; - char *sip_pass = "pppasswdModem1"; - printf("sip data: user: %s, passwd: %s, server: %s\nMODE: %d\n", sip_user, sip_pass, sip_domain, mode); + int has_sip_user = 1; + char *sip_user = getenv("SIP_LOGIN"); + if (!sip_user) { + has_sip_user = 0; + printf("[!] SIP_LOGIN is empty, no registration will be attempted\n"); + char sip_user_buf[40]; + strcpy(sip_user_buf, "placeholder:placeholder@placeholder"); + sip_user = sip_user_buf; + } + if (!sip_user) { + return -1; + } + char *sip_domain = strchr(sip_user,'@'); + if (!sip_domain) { + return -1; + } + *sip_domain++ = '\0'; + char *sip_pass = strchr(sip_user,':'); + if (!sip_pass) { + return -1; + } + *sip_pass++ = '\0'; + status = pjsua_create(); if (status != PJ_SUCCESS) error_exit("Error in pjsua_create()", status); @@ -177,7 +292,7 @@ int main(int argc, char *argv[]) { cfg.cb.on_call_media_state = &on_call_media_state; cfg.cb.on_call_state = &on_call_state; - if(mode == DMODEM_RING_DETECT_MODE) { + if(mode == DMODEM_ANSWER_MODE) { cfg.cb.on_incoming_call = &on_incoming_call; } @@ -189,7 +304,10 @@ int main(int argc, char *argv[]) { med_cfg.ec_tail_len = 0; med_cfg.jb_max = 2000; // med_cfg.jb_init = 200; - med_cfg.audio_frame_ptime = 5; +/* // med_cfg.jb_init = 200 */ +// med_cfg.jb_init = 0; +/* med_cfg.audio_frame_ptime = 5; */ + med_cfg.audio_frame_ptime = 10; status = pjsua_init(&cfg, &log_cfg, &med_cfg); if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status); @@ -205,7 +323,7 @@ int main(int argc, char *argv[]) { for (int i=0; itpdata[transport_id].has_bound_addr = PJ_TRUE; + if (getenv("PJSIP_IPV6")) + pjsua_get_var()->acc[acc_id].cfg.ipv6_media_use = PJSUA_IPV6_ENABLED; + start_pa(); if(mode == DMODEM_DIAL_MODE) { - snprintf(buf,sizeof(buf),"sip:%s@%s",dialstr,sip_domain); + if (has_sip_user) + snprintf(buf,sizeof(buf),"sip:%s@%s",dialstr,sip_domain); + else + snprintf(buf,sizeof(buf),"sip:%s",dialstr); printf("calling %s\n",buf); pj_str_t uri = pj_str(buf); pjsua_call_id callid; status = pjsua_call_make_call(acc_id, &uri, 0, NULL, NULL, &callid); if (status != PJ_SUCCESS) error_exit("Error making call", status); } - if(mode == DMODEM_ANSWER_MODE) { - pjsua_call_id id; - char* cid = strrchr(argv[1], '+'); - id = atoi(cid); - status = pjsua_call_answer(id, 200, NULL, NULL); - if (status != PJ_SUCCESS) error_exit("Error answering call", status); - } - struct timespec ts = {100, 0}; - if(mode == DMODEM_RING_DETECT_MODE) - ts.tv_sec = 1; - time_t now = time(NULL); + + struct timespec ts = {0, 1}; while(1) { - if(mode == DMODEM_RING_DETECT_MODE) { + if(mode == DMODEM_ANSWER_MODE) { if(ringing) { - char cid[11]; - snprintf(cid, 10, "%d", incoming); - write(atoi(argv[2]), cid, strlen(cid)); + status = pjsua_call_answer(incoming, 200, NULL, NULL); + if (status != PJ_SUCCESS) error_exit("Error answering call", status); + ringing = 0; + answered = 1; } } nanosleep(&ts,NULL); diff --git a/slmodemd/modem.c b/slmodemd/modem.c index 3a4c711..ab052d2 100644 --- a/slmodemd/modem.c +++ b/slmodemd/modem.c @@ -70,6 +70,7 @@ #define MODEM_DBG(fmt,arg...) dprintf("%s: " fmt , m->name , ##arg) #define MODEM_ERR(fmt,arg...) eprintf("%s: " fmt , m->name , ##arg) +short _MODEM_DO_ANSWER = 0; /* external symbols */ extern int process_at_command(struct modem *m, char *buf); extern void *dp_runtime_create(struct modem *m); @@ -1567,6 +1568,7 @@ int modem_recv_from_tty(struct modem *m, char *buf, int n) int modem_answer(struct modem *m) { + _MODEM_DO_ANSWER = 1; MODEM_DBG("modem answer...\n"); if ( m->dp ) { MODEM_ERR("dp %d is already exists.\n", m->dp->id); @@ -1613,6 +1615,7 @@ static int modem_dial_start(struct modem *m) int modem_dial(struct modem *m) { + _MODEM_DO_ANSWER = 0; int ret; MODEM_DBG("modem dial: %s...\n", m->dial_string); m->dp_requested = 0; diff --git a/slmodemd/modem.h b/slmodemd/modem.h index 3550d83..62b2e02 100644 --- a/slmodemd/modem.h +++ b/slmodemd/modem.h @@ -456,5 +456,7 @@ extern void modem_update_config(struct modem *m, struct modem_config *cfg); #define MODEM_DP(m) ((m)->sregs[SREG_DP]) #define MODEM_AUTOMODE(m) ((m)->sregs[SREG_AUTOMODE]) +extern short _MODEM_DO_ANSWER; + #endif /* __MODEM_H__ */ diff --git a/slmodemd/modem_cmdline.c b/slmodemd/modem_cmdline.c index ec20a91..52efcb9 100644 --- a/slmodemd/modem_cmdline.c +++ b/slmodemd/modem_cmdline.c @@ -68,10 +68,10 @@ extern unsigned int modem_debug_logging; /* config parameters */ const char *modem_dev_name = NULL; -const char *modem_default_dev_name = "/dev/slamr0"; +const char *modem_default_dev_name = "/tmp/ttySL0"; const char *modem_alsa_dev_name = "modem:1"; const char *modem_exec = NULL; -unsigned int need_realtime = 1; +unsigned int need_realtime = 0; #ifdef MODEM_CONFIG_RING_DETECTOR unsigned int ring_detector = 0; #endif @@ -125,7 +125,7 @@ static struct opt { {'s',"shortbuffer","use short buffer (4 periods length)"}, {'d',"debug","debug level (developers only, for ./sl...)",OPTIONAL,INTEGER,"0"}, {'l',"log","logging mode",OPTIONAL,INTEGER,"5"}, - {'e',"exec","path to external application that transmits audio over the socket (required)",MANDATORY,STRING,""}, + {'e',"exec","path to external application that transmits audio over the socket (required)",MANDATORY,STRING,"./d-modem"}, {} }; diff --git a/slmodemd/modem_main.c b/slmodemd/modem_main.c index 0a20e61..6b20166 100644 --- a/slmodemd/modem_main.c +++ b/slmodemd/modem_main.c @@ -87,7 +87,7 @@ #define DBG(fmt,args...) dprintf("main: " fmt, ##args) -#define SLMODEMD_USER "nobody" +//#define SLMODEMD_USER "nobody" #define LOCKED_MEM_MIN_KB (8UL * 1024) #define LOCKED_MEM_MIN (LOCKED_MEM_MIN_KB * 1024) @@ -635,10 +635,12 @@ static int socket_start (struct modem *m) char str[16]; snprintf(str,sizeof(str),"%d",sockets[0]); close(sockets[1]); - if(m->hook == MODEM_HOOK_SNOOPING) { + if(_MODEM_DO_ANSWER) { + DBG("MODEM_ANSW execl arg: %s, %s, %s\n",modem_exec,"rr",str); ret = execl(modem_exec,modem_exec,"rr",str,NULL); } else { + DBG("MODEM_DIAL execl arg: %s, %s, %s\n",modem_exec,m->dial_string,str); ret = execl(modem_exec,modem_exec,m->dial_string,str,NULL); } if (ret == -1) { @@ -820,6 +822,7 @@ int create_pty(struct modem *m) modem_update_termios(m,&termios); + modem_group = NULL; if(modem_group && *modem_group) { struct group *grp = getgrnam(modem_group); if(!grp) { @@ -1074,7 +1077,7 @@ int modem_main(const char *dev_name) struct modem *m; int pty; int ret = 0; - struct passwd *pwd; +// struct passwd *pwd; modem_debug_init(basename(dev_name)); @@ -1089,7 +1092,7 @@ int modem_main(const char *dev_name) prop_dp_init(); modem_timer_init(); - sprintf(link_name,"/dev/ttySL%d", device.num); + sprintf(link_name, "%s", modem_dev_name); m = modem_create(modem_driver,basename(dev_name)); m->name = basename(dev_name); @@ -1105,8 +1108,8 @@ int modem_main(const char *dev_name) INFO("modem `%s' created. TTY is `%s'\n", m->name, m->pty_name); - sprintf(path_name,"/var/lib/slmodem/data.%s",basename(dev_name)); - datafile_load_info(path_name,&m->dsp_info); +// sprintf(path_name,"/var/lib/slmodem/data.%s",basename(dev_name)); +// datafile_load_info(path_name,&m->dsp_info); if (need_realtime) { struct sched_param prm; @@ -1199,7 +1202,7 @@ int main(int argc, char *argv[]) extern void modem_cmdline(int argc, char *argv[]); int ret; modem_cmdline(argc,argv); - if(!modem_dev_name) modem_dev_name = "/dev/slamr0"; + if(!modem_dev_name) modem_dev_name = "/tmp/ttySL0"; device_setup = socket_device_setup; device_release = mdm_device_release;