📄 iaxclient_lib.c
字号:
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 + -