⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pjsua_app.c

📁 基于sip协议的网络电话源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    return PJ_FALSE;}/* Callback from timer when the maximum call duration has been * exceeded. */static void call_timeout_callback(pj_timer_heap_t *timer_heap,				  struct pj_timer_entry *entry){    pjsua_call_id call_id = entry->id;    pjsua_msg_data msg_data;    pjsip_generic_string_hdr warn;    pj_str_t hname = pj_str("Warning");    pj_str_t hvalue = pj_str("399 pjsua \"Call duration exceeded\"");    PJ_UNUSED_ARG(timer_heap);    if (call_id == PJSUA_INVALID_ID) {	PJ_LOG(1,(THIS_FILE, "Invalid call ID in timer callback"));	return;    }        /* Add warning header */    pjsua_msg_data_init(&msg_data);    pjsip_generic_string_hdr_init2(&warn, &hname, &hvalue);    pj_list_push_back(&msg_data.hdr_list, &warn);    /* Call duration has been exceeded; disconnect the call */    PJ_LOG(3,(THIS_FILE, "Duration (%d seconds) has been exceeded "			 "for call %d, disconnecting the call",			 app_config.duration, call_id));    entry->id = PJSUA_INVALID_ID;    pjsua_call_hangup(call_id, 200, NULL, &msg_data);}/* * Handler when invite state has changed. */static void on_call_state(pjsua_call_id call_id, pjsip_event *e){    pjsua_call_info call_info;    PJ_UNUSED_ARG(e);    pjsua_call_get_info(call_id, &call_info);    if (call_info.state == PJSIP_INV_STATE_DISCONNECTED) {	/* Cancel duration timer, if any */	if (app_config.call_data[call_id].timer.id != PJSUA_INVALID_ID) {	    struct call_data *cd = &app_config.call_data[call_id];	    pjsip_endpoint *endpt = pjsua_get_pjsip_endpt();	    cd->timer.id = PJSUA_INVALID_ID;	    pjsip_endpt_cancel_timer(endpt, &cd->timer);	}	PJ_LOG(3,(THIS_FILE, "Call %d is DISCONNECTED [reason=%d (%s)]", 		  call_id,		  call_info.last_status,		  call_info.last_status_text.ptr));	if (call_id == current_call) {	    find_next_call();	}	/* Dump media state upon disconnected */	if (1) {	    char buf[1024];	    pjsua_call_dump(call_id, PJ_TRUE, buf, 			    sizeof(buf), "  ");	    PJ_LOG(5,(THIS_FILE, 		      "Call %d disconnected, dumping media stats\n%s", 		      call_id, buf));	}    } else {	if (app_config.duration!=NO_LIMIT && 	    call_info.state == PJSIP_INV_STATE_CONFIRMED) 	{	    /* Schedule timer to hangup call after the specified duration */	    struct call_data *cd = &app_config.call_data[call_id];	    pjsip_endpoint *endpt = pjsua_get_pjsip_endpt();	    pj_time_val delay;	    cd->timer.id = call_id;	    delay.sec = app_config.duration;	    delay.msec = 0;	    pjsip_endpt_schedule_timer(endpt, &cd->timer, &delay);	}	if (call_info.state == PJSIP_INV_STATE_EARLY) {	    int code;	    pj_str_t reason;	    pjsip_msg *msg;	    /* This can only occur because of TX or RX message */	    pj_assert(e->type == PJSIP_EVENT_TSX_STATE);	    if (e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {		msg = e->body.tsx_state.src.rdata->msg_info.msg;	    } else {		msg = e->body.tsx_state.src.tdata->msg;	    }	    code = msg->line.status.code;	    reason = msg->line.status.reason;	    PJ_LOG(3,(THIS_FILE, "Call %d state changed to %s (%d %.*s)", 		      call_id, call_info.state_text.ptr,		      code, (int)reason.slen, reason.ptr));	} else {	    PJ_LOG(3,(THIS_FILE, "Call %d state changed to %s", 		      call_id,		      call_info.state_text.ptr));	}	if (current_call==PJSUA_INVALID_ID)	    current_call = call_id;    }}/** * Handler when there is incoming call. */static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,			     pjsip_rx_data *rdata){    pjsua_call_info call_info;    PJ_UNUSED_ARG(acc_id);    PJ_UNUSED_ARG(rdata);    pjsua_call_get_info(call_id, &call_info);    if (app_config.auto_answer > 0) {	pjsua_call_answer(call_id, app_config.auto_answer, NULL, NULL);    }    if (app_config.auto_answer < 200) {	PJ_LOG(3,(THIS_FILE,		  "Incoming call for account %d!\n"		  "From: %s\n"		  "To: %s\n"		  "Press a to answer or h to reject call",		  acc_id,		  call_info.remote_info.ptr,		  call_info.local_info.ptr));    }}/* * Callback on media state changed event. * The action may connect the call to sound device, to file, or * to loop the call. */static void on_call_media_state(pjsua_call_id call_id){    pjsua_call_info call_info;    pjsua_call_get_info(call_id, &call_info);    if (call_info.media_status == PJSUA_CALL_MEDIA_ACTIVE) {	pj_bool_t connect_sound = PJ_TRUE;	/* Loopback sound, if desired */	if (app_config.auto_loop) {	    pjsua_conf_connect(call_info.conf_slot, call_info.conf_slot);	    connect_sound = PJ_FALSE;	    /* Automatically record conversation, if desired */	    if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) {		pjsua_conf_connect(call_info.conf_slot, app_config.rec_port);	    }	}	/* Stream a file, if desired */	if (app_config.auto_play && app_config.wav_port != PJSUA_INVALID_ID) {	    pjsua_conf_connect(app_config.wav_port, call_info.conf_slot);	    connect_sound = PJ_FALSE;	}	/* Put call in conference with other calls, if desired */	if (app_config.auto_conf) {	    pjsua_call_id call_ids[PJSUA_MAX_CALLS];	    unsigned call_cnt=PJ_ARRAY_SIZE(call_ids);	    unsigned i;	    /* Get all calls, and establish media connection between	     * this call and other calls.	     */	    pjsua_enum_calls(call_ids, &call_cnt);	    for (i=0; i<call_cnt; ++i) {		if (call_ids[i] == call_id)		    continue;				if (!pjsua_call_has_media(call_ids[i]))		    continue;		pjsua_conf_connect(call_info.conf_slot,				   pjsua_call_get_conf_port(call_ids[i]));		pjsua_conf_connect(pjsua_call_get_conf_port(call_ids[i]),				   call_info.conf_slot);		/* Automatically record conversation, if desired */		if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) {		    pjsua_conf_connect(pjsua_call_get_conf_port(call_ids[i]), 				       app_config.rec_port);		}	    }	    /* Also connect call to local sound device */	    connect_sound = PJ_TRUE;	}	/* Otherwise connect to sound device */	if (connect_sound) {	    pjsua_conf_connect(call_info.conf_slot, 0);	    pjsua_conf_connect(0, call_info.conf_slot);	    /* Automatically record conversation, if desired */	    if (app_config.auto_rec && app_config.rec_port != PJSUA_INVALID_ID) {		pjsua_conf_connect(call_info.conf_slot, app_config.rec_port);		pjsua_conf_connect(0, app_config.rec_port);	    }	}	PJ_LOG(3,(THIS_FILE, "Media for call %d is active", call_id));    } else if (call_info.media_status == PJSUA_CALL_MEDIA_LOCAL_HOLD) {	PJ_LOG(3,(THIS_FILE, "Media for call %d is suspended (hold) by local",		  call_id));    } else if (call_info.media_status == PJSUA_CALL_MEDIA_REMOTE_HOLD) {	PJ_LOG(3,(THIS_FILE, 		  "Media for call %d is suspended (hold) by remote",		  call_id));    } else {	PJ_LOG(3,(THIS_FILE, 		  "Media for call %d is inactive",		  call_id));    }}/* * DTMF callback. */static void call_on_dtmf_callback(pjsua_call_id call_id, int dtmf){    PJ_LOG(3,(THIS_FILE, "Incoming DTMF on call %d: %c", call_id, dtmf));}/* * Handler registration status has changed. */static void on_reg_state(pjsua_acc_id acc_id){    PJ_UNUSED_ARG(acc_id);    // Log already written.}/* * Handler on buddy state changed. */static void on_buddy_state(pjsua_buddy_id buddy_id){    pjsua_buddy_info info;    pjsua_buddy_get_info(buddy_id, &info);    PJ_LOG(3,(THIS_FILE, "%.*s status is %.*s",	      (int)info.uri.slen,	      info.uri.ptr,	      (int)info.status_text.slen,	      info.status_text.ptr));}/** * Incoming IM message (i.e. MESSAGE request)! */static void on_pager(pjsua_call_id call_id, const pj_str_t *from, 		     const pj_str_t *to, const pj_str_t *contact,		     const pj_str_t *mime_type, const pj_str_t *text){    /* Note: call index may be -1 */    PJ_UNUSED_ARG(call_id);    PJ_UNUSED_ARG(to);    PJ_UNUSED_ARG(contact);    PJ_UNUSED_ARG(mime_type);    PJ_LOG(3,(THIS_FILE,"MESSAGE from %.*s: %.*s (%.*s)",	      (int)from->slen, from->ptr,	      (int)text->slen, text->ptr,	      (int)mime_type->slen, mime_type->ptr));}/** * Received typing indication */static void on_typing(pjsua_call_id call_id, const pj_str_t *from,		      const pj_str_t *to, const pj_str_t *contact,		      pj_bool_t is_typing){    PJ_UNUSED_ARG(call_id);    PJ_UNUSED_ARG(to);    PJ_UNUSED_ARG(contact);    PJ_LOG(3,(THIS_FILE, "IM indication: %.*s %s",	      (int)from->slen, from->ptr,	      (is_typing?"is typing..":"has stopped typing")));}/** * Call transfer request status. */static void on_call_transfer_status(pjsua_call_id call_id,				    int status_code,				    const pj_str_t *status_text,				    pj_bool_t final,				    pj_bool_t *p_cont){    PJ_LOG(3,(THIS_FILE, "Call %d: transfer status=%d (%.*s) %s",	      call_id, status_code,	      (int)status_text->slen, status_text->ptr,	      (final ? "[final]" : "")));    if (status_code/100 == 2) {	PJ_LOG(3,(THIS_FILE, 	          "Call %d: call transfered successfully, disconnecting call",		  call_id));	pjsua_call_hangup(call_id, PJSIP_SC_GONE, NULL, NULL);	*p_cont = PJ_FALSE;    }}/* * Notification that call is being replaced. */static void on_call_replaced(pjsua_call_id old_call_id,			     pjsua_call_id new_call_id){    pjsua_call_info old_ci, new_ci;    pjsua_call_get_info(old_call_id, &old_ci);    pjsua_call_get_info(new_call_id, &new_ci);    PJ_LOG(3,(THIS_FILE, "Call %d with %.*s is being replaced by "			 "call %d with %.*s",			 old_call_id, 			 (int)old_ci.remote_info.slen, old_ci.remote_info.ptr,			 new_call_id,			 (int)new_ci.remote_info.slen, new_ci.remote_info.ptr));}/* * Print buddy list. */static void print_buddy_list(void){    pjsua_buddy_id ids[64];    int i;    unsigned count = PJ_ARRAY_SIZE(ids);    puts("Buddy list:");    pjsua_enum_buddies(ids, &count);    if (count == 0)	puts(" -none-");    else {	for (i=0; i<(int)count; ++i) {	    pjsua_buddy_info info;	    if (pjsua_buddy_get_info(ids[i], &info) != PJ_SUCCESS)		continue;	    printf(" [%2d] <%7s>  %.*s\n", 		    ids[i]+1, info.status_text.ptr, 		    (int)info.uri.slen,		    info.uri.ptr);	}    }    puts("");}/* * Print account status. */static void print_acc_status(int acc_id){    char buf[80];    pjsua_acc_info info;    pjsua_acc_get_info(acc_id, &info);    if (!info.has_registration) {	pj_ansi_snprintf(buf, sizeof(buf), "%.*s", 			 (int)info.status_text.slen,			 info.status_text.ptr);    } else {	pj_ansi_snprintf(buf, sizeof(buf),			 "%d/%.*s (expires=%d)",			 info.status,			 (int)info.status_text.slen,			 info.status_text.ptr,			 info.expires);    }    printf(" %c[%2d] %.*s: %s\n", (acc_id==current_acc?'*':' '),	   acc_id,  (int)info.acc_uri.slen, info.acc_uri.ptr, buf);    printf("       Online status: %s\n", 	   (info.online_status ? "Online" : "Invisible"));}/* * Show a bit of help. */static void keystroke_help(void){    pjsua_acc_id acc_ids[16];    unsigned count = PJ_ARRAY_SIZE(acc_ids);    int i;    printf(">>>>\n");    pjsua_enum_accs(acc_ids, &count);    printf("Account list:\n");    for (i=0; i<(int)count; ++i)	print_acc_status(acc_ids[i]);    print_buddy_list();        //puts("Commands:");    puts("+=============================================================================+");    puts("|       Call Commands:         |   Buddy, IM & Presence:  |     Account:      |");    puts("|                              |                          |                   |");    puts("|  m  Make new call            | +b  Add new buddy       .| +a  Add new accnt |");    puts("|  M  Make multiple calls      | -b  Delete buddy         | -a  Delete accnt. |");    puts("|  a  Answer call              | !b  Modify buddy         | !a  Modify accnt. |");    puts("|  h  Hangup call  (ha=all)    |  i  Send IM              | rr  (Re-)register |");    puts("|  H  Hold call                |  s  Subscribe presence   | ru  Unregister    |");    puts("|  v  re-inVite (release hold) |  u  Unsubscribe presence |  >  Cycle next ac.|");    puts("|  ]  Select next dialog       |  t  ToGgle Online status |  <  Cycle prev ac.|");    puts("|  [  Select previous dialog   +--------------------------+-------------------+");    puts("|  x  Xfer call                |      Media Commands:     |  Status & Config: |");    puts("|  X  Xfer with Replaces       |                          |                   |");    puts("|  #  Send DTMF string         | cl  List ports           |  d  Dump status   |");    puts("| dq  Dump curr. call quality  | cc  Connect port         | dd  Dump detailed |");    puts("|                              | cd  Disconnect port      | dc  Dump config   |");    puts("|  S  Send arbitrary REQUEST   |  V  Adjust audio Volume  |  f  Save config   |");    puts("+------------------------------+--------------------------+-------------------+");    puts("|  q  QUIT                  sleep N: console sleep for N ms                   |");    puts("+=============================================================================+");    i = pjsua_call_get_count();    printf("You have %d active call%s\n", i, (i>1?"s":""));    if (current_call != PJSUA_INVALID_ID) {	pjsua_call_info ci;	if (pjsua_call_get_info(current_call, &ci)==PJ_SUCCESS)	    printf("Current call id=%d to %.*s [%.*s]\n", current_call,		   (int)ci.remote_info.slen, ci.remote_info.ptr,		   (int)ci.state_text.slen, ci.state_text.ptr);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -