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

📄 iaxclient_lib.c

📁 ppciaxclient softphone
💻 C
📖 第 1 页 / 共 3 页
字号:
	    iax_set_networking(iaxc_sendto, iaxc_recvfrom);
	}

	nCalls = inCalls;
	/* initialize calls */
	if(nCalls <= 0) nCalls = 1; /* 0 == Default? */

	/* calloc zeroes for us */
	calls = calloc(sizeof(struct iaxc_call), nCalls);
	if(!calls)
	{
		iaxc_usermsg(IAXC_ERROR, "Fatal error: can't allocate memory");
		return -1;
	}
	iAudioType = audType;
	selected_call = 0;

	for(i=0; i<nCalls; i++) {
	    strncpy(calls[i].callerid_name,   DEFAULT_CALLERID_NAME,   IAXC_EVENT_BUFSIZ);
	    strncpy(calls[i].callerid_number, DEFAULT_CALLERID_NUMBER, IAXC_EVENT_BUFSIZ);
	}

	gettimeofday(&lastouttm,NULL);
	switch (iAudioType) {
#ifdef USE_WIN_AUDIO
		case AUDIO_INTERNAL:
			if (win_initialize_audio() != 0)
				return -1;
			break;
#endif
		default:
		case AUDIO_INTERNAL_PA:
			if (pa_initialize(&audio, 8000))
				return -1;
			break;
/*		case AUDIO_INTERNAL_FILE:
			if (file_initialize(&audio, 8000))
				return -1;
				*/
			break;
	}

	audio_format_capability = IAXC_FORMAT_ULAW | IAXC_FORMAT_ALAW | IAXC_FORMAT_GSM | IAXC_FORMAT_SPEEX;
	audio_format_preferred = IAXC_FORMAT_SPEEX;

#ifdef IAXC_VIDEO
	if(iaxc_video_initialize()) {
		fprintf(stderr, "can't initialize pv\n");
		return -1;
	}
#endif


	return 0;
}

EXPORT void iaxc_shutdown() {
	iaxc_dump_all_calls();

	get_iaxc_lock();
	audio.destroy(&audio);
	put_iaxc_lock();
	free(calls);
	calls = NULL;
	MUTEXDESTROY(&iaxc_lock);
}


EXPORT void iaxc_set_formats(int preferred, int allowed)
{
	audio_format_capability = allowed;
	audio_format_preferred = preferred;
}

EXPORT void iaxc_set_min_outgoing_framesize(int samples) {
    minimum_outgoing_framesize = samples;
}

EXPORT void iaxc_set_callerid(char *name, char *number) {
    int i;
    
    for(i=0; i<nCalls; i++) {
        strncpy(calls[i].callerid_name,   name,   IAXC_EVENT_BUFSIZ);
        strncpy(calls[i].callerid_number, number, IAXC_EVENT_BUFSIZ);
    }
}

static void iaxc_note_activity(int callNo) {
  if(callNo < 0)
      return;
  //fprintf(stderr, "Noting activity for call %d\n", callNo);
  gettimeofday(&calls[callNo].last_activity, NULL);   
}
void iaxc_refresh_registrations() {
    struct iaxc_registration *cur;
    struct timeval now;

    gettimeofday(&now,NULL);

    for(cur = registrations; cur != NULL; cur=cur->next) {
	if(iaxc_usecdiff(&now, &cur->last) > cur->refresh ) {
	    //fprintf(stderr, "refreshing registration %s:%s@%s\n", cur->user, cur->pass, cur->host);
	    if( cur->session != NULL ) {	
		    iax_destroy( cur->session );
	    }
	    cur->session = iax_session_new();
	    if(!cur->session) {
		    iaxc_usermsg(IAXC_ERROR, "Can't make new registration session");
		    return;
	    }

	    iax_register(cur->session, cur->host, cur->user, cur->pass, 120);
	    cur->last = now;
	}
    }
}

EXPORT void iaxc_process_calls(void) {

#ifdef USE_WIN_AUDIO	
    win_flush_audio_output_buffers();
    if (iAudioType == AUDIO_INTERNAL) {
	    win_prepare_audio_buffers();
    }
#endif
    get_iaxc_lock();
    iaxc_service_network();
    service_audio();
    iaxc_refresh_registrations();
    
    // XXX move to service_audio or something -- set call properly!
#ifdef IAXC_VIDEO
    iaxc_send_video(NULL);
#endif
    put_iaxc_lock();
}

THREADFUNCDECL(iaxc_processor)
{
    THREADFUNCRET(ret);
    /* Increase Priority */
    iaxc_prioboostbegin(); 

    while(1) { 
	iaxc_process_calls();
	iaxc_millisleep(5);	
	if(procThreadQuitFlag)
	  break;
    }

    iaxc_prioboostend(); 
    return ret;
}

EXPORT int iaxc_start_processing_thread()
{
      procThreadQuitFlag = 0;
      if( THREADCREATE(iaxc_processor, NULL, procThread, procThreadID) 
	    == THREADCREATE_ERROR)	
	  return -1;

      return 0;
}

EXPORT int iaxc_stop_processing_thread()
{
    if(procThreadQuitFlag >= 0)
    {
	procThreadQuitFlag = 1;
	THREADJOIN(procThread);
    }
    procThreadQuitFlag = -1;
    return 0;
}


static int service_audio()
{
	// we do this here to avoid looking at calls[-1]
	if(selected_call < 0) {
	    static int i=0;
	    if(i++ % 50 == 0) iaxc_do_levels_callback(-99,-99);

	    // make sure audio is stopped
	    audio.stop(&audio);
	    return 0;
	}	

	/* send audio only if incoming call answered, or outgoing call
	 * selected. */
	if( (calls[selected_call].state & IAXC_CALL_STATE_OUTGOING) 
	    || (calls[selected_call].state & IAXC_CALL_STATE_COMPLETE)) 
	{
	    short buf[1024];

	    // make sure audio is running
	    if(audio.start(&audio))
	    {
	    	iaxc_usermsg(IAXC_ERROR, "Can't start audio");
	    }

	    for(;;) {
		int toRead;
		int cmin;

	        /* find mimumum frame size */
	        toRead = minimum_outgoing_framesize; 

		/* use codec minimum if higher */
		if(calls[selected_call].encoder)
		   cmin = calls[selected_call].encoder->minimum_frame_size; 
		else
		   cmin = 1;

		if(cmin > toRead)
		    toRead = cmin;
	   
		/* round up to next multiple */
		if(toRead % cmin)
		  toRead += cmin - (toRead % cmin);

		if(toRead > sizeof(buf)/sizeof(short))
		{
		    fprintf(stderr, "internal error: toRead > sizeof(buf)\n");
		    exit(1);
		}

		if(audio.input(&audio,buf,&toRead))
		{
		    iaxc_usermsg(IAXC_ERROR, "ERROR reading audio\n");
		    break;
		}
		if(!toRead) break;  /* frame not available */
		/* currently, pa will always give us 0 or what we asked
		 * for samples */

		send_encoded_audio(&calls[selected_call], buf, 
		      calls[selected_call].format, toRead);
	    }

	} else {
	    static int i=0;
	    if(i++ % 50 == 0) iaxc_do_levels_callback(-99,-99);

	    // make sure audio is stopped
	    audio.stop(&audio);
	}
	return 0;
}

/* handle IAX text events */
static void handle_text_event(struct iax_event *e, int callNo) {
    iaxc_event ev;

   if(callNo < 0)
       return;
    ev.type=IAXC_EVENT_TEXT;
    ev.ev.text.type=IAXC_TEXT_TYPE_IAX;
    ev.ev.text.callNo = callNo;

    strncpy(ev.ev.text.message, (char *) e->data, IAXC_EVENT_BUFSIZ);
    iaxc_post_event(ev);
}

/* handle IAX URL events */
void handle_url_event( struct iax_event *e, int callNo ) {
	iaxc_event ev;

	if(callNo < 0) return;

	ev.ev.url.callNo = callNo;
	ev.type = IAXC_EVENT_URL;
	strcpy( ev.ev.url.url, "" );

	switch( e->subclass ) {
		case AST_HTML_URL:
			ev.ev.url.type = IAXC_URL_URL;
			if( e->datalen ) {
				if( e->datalen > IAXC_EVENT_BUFSIZ ) {
					fprintf( stderr, "ERROR: URL too long %d > %d\n", 
							e->datalen, IAXC_EVENT_BUFSIZ );
				} else {
					strncpy( ev.ev.url.url, (char *) e->data, e->datalen );
				}
			}
			/* fprintf( stderr, "URL:%s\n", ev.ev.url.url ); */
			break;
		case AST_HTML_LINKURL:
			ev.ev.url.type = IAXC_URL_LINKURL;
			/* fprintf( stderr, "LINKURL event\n" ); */
			break;
		case AST_HTML_LDCOMPLETE:
			ev.ev.url.type = IAXC_URL_LDCOMPLETE;
			/* fprintf( stderr, "LDCOMPLETE event\n" ); */
			break;
		case AST_HTML_UNLINK:
			ev.ev.url.type = IAXC_URL_UNLINK;
			/* fprintf( stderr, "UNLINK event\n" ); */
			break;
		case AST_HTML_LINKREJECT:
			ev.ev.url.type = IAXC_URL_LINKREJECT;
			/* fprintf( stderr, "LINKREJECT event\n" ); */
			break;
		default:
			fprintf( stderr, "Unknown URL event %d\n", e->subclass );
			break;
	}
    iaxc_post_event( ev );
}

/* DANGER: bad things can happen if iaxc_netstat != iax_netstat.. */
EXPORT int iaxc_get_netstats(int call, int *rtt, struct iaxc_netstat *local, struct iaxc_netstat *remote) {
    return iax_get_netstats(calls[call].session, rtt, (struct iax_netstat *)local, (struct iax_netstat *)remote);
}

/* handle IAX text events */
static void generate_netstat_event(int callNo) {
    iaxc_event ev;

    if(callNo < 0)
       return;

    ev.type=IAXC_EVENT_NETSTAT;
    ev.ev.netstats.callNo = callNo;

    /* only post the event if the session is valid, etc */
    if(!iaxc_get_netstats(callNo, &ev.ev.netstats.rtt, &ev.ev.netstats.local, &ev.ev.netstats.remote))
	iaxc_post_event(ev);
}

static void handle_audio_event(struct iax_event *e, int callNo) {
	int total_consumed = 0;
	int cur;
	short fr[1024];
	int samples;
	int bufsize = sizeof(fr)/sizeof(short);
	struct iaxc_call *call;
       int mainbuf_delta;

        if(callNo < 0)
            return;

	call = &calls[callNo];

	if(callNo != selected_call) {
	    /* drop audio for unselected call? */
	    return;
	}

	samples = bufsize;

	do {
               mainbuf_delta = bufsize - samples;
               cur = decode_audio(call, fr,
		    e->data+total_consumed,e->datalen-total_consumed,
		    call->format, &samples);

		if(cur < 0) {
		    iaxc_usermsg(IAXC_STATUS, "Bad or incomplete voice packet.  Unable to decode. dropping");
		    return;
		}

		total_consumed += cur;
		if(iaxc_audio_output_mode != 0) 
		    continue;
               audio.output(&audio,fr,bufsize - samples - mainbuf_delta);
	} while(total_consumed < e->datalen);
}


void iaxc_handle_network_event(struct iax_event *e, int callNo)
{

        if(callNo < 0)
            return;

	iaxc_note_activity(callNo);

	switch(e->etype) {
		case IAX_EVENT_HANGUP:
			iaxc_usermsg(IAXC_STATUS, "Call disconnected by remote");
			// XXX does the session go away now?
			iaxc_clear_call(callNo);
			
			break;


		case IAX_EVENT_REJECT:
			strncpy(calls[callNo].remote,e->ies.cause,sizeof(calls[callNo].remote));
			iaxc_usermsg(IAXC_STATUS, "Call rejected by remote");
			iaxc_clear_call(callNo);
			break;
		case IAX_EVENT_ACCEPT:
			calls[callNo].format = e->ies.format;
	  //fprintf(stderr, "outgoing call remote accepted, format=%d\n", e->ies.format);
			iaxc_usermsg(IAXC_STATUS,"Call %d accepted", callNo);
//			issue_prompt(f);
			break;
		case IAX_EVENT_ANSWER:
			calls[callNo].state &= ~IAXC_CALL_STATE_RINGING;	
			calls[callNo].state |= IAXC_CALL_STATE_COMPLETE;	
			iaxc_do_state_callback(callNo);
			iaxc_usermsg(IAXC_STATUS,"Call %d answered", callNo);
			//iaxc_answer_call(callNo);
			// notify the user?
 			break;
		case IAX_EVENT_CONGESTION:
			calls[callNo].state &= ~IAXC_CALL_STATE_RINGING;
			calls[callNo].state |= IAXC_CALL_STATE_CONGESTION;
            iaxc_do_state_callback(callNo);
			break;
        case IAX_EVENT_BUSY:
			calls[callNo].state &= ~IAXC_CALL_STATE_RINGING;	
            calls[callNo].state |= IAXC_CALL_STATE_BUSY;
            iaxc_do_state_callback(callNo);
            break;
		case IAX_EVENT_VOICE:
			handle_audio_event(e, callNo); 
			break;
		case IAX_EVENT_TEXT:
			handle_text_event(e, callNo);
			break;
		case IAX_EVENT_RINGA:
			calls[callNo].state |= IAXC_CALL_STATE_RINGING;	
			iaxc_do_state_callback(callNo);
			iaxc_usermsg(IAXC_STATUS,"Call %d ringing", callNo);
			break;
		case IAX_EVENT_PONG:  /* we got a pong */
			//fprintf(stderr, "**********GOT A PONG!\n");
			generate_netstat_event(callNo);
			break;
		case IAX_EVENT_URL:
			handle_url_event(e, callNo);
			break;
		case IAX_EVENT_CNG:
			/* ignore? */
			break;
		case IAX_EVENT_TIMEOUT:
			iax_hangup(e->session, "Call timed out");
			iaxc_usermsg(IAXC_STATUS, "Call %d timed out.", callNo);
			iaxc_clear_call(callNo);
			break;
		case IAX_EVENT_TRANSFER:
			calls[callNo].state |= IAXC_CALL_STATE_TRANSFER;	
			iaxc_do_state_callback(callNo);
			iaxc_usermsg(IAXC_STATUS,"Call %d transfer released", callNo);
			break;
		default:
			iaxc_usermsg(IAXC_STATUS, "Unknown event: %d for call %d", e->etype, callNo);
			break;
	}
}

EXPORT int iaxc_unregister( int id )
{
	int count=0;

⌨️ 快捷键说明

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