Update of /cvsroot/iaxclient/iaxclient/lib In directory sc8-pr-cvs1:/tmp/cvs-serv20862/lib Modified Files: Makefile audio_encode.c audio_encode.h audio_portaudio.c audio_portaudio.h iaxclient.h iaxclient_lib.c iaxclient_lib.h Log Message: A pretty big commit. 1) Change the overall "event" callback mechanism, to use a structure/union, with just one callback for all events. clients can accept or decline each event, in which case the library might take a "default" action for the event. (currently, the library will ignore all events except for text, which it will print to stderr/stdout). 2) Totally rework call handling, and allow the library to manage multiple calls. Call state is more or less followed through the lifetime of the call, but may not be right in all cases. 3) Implement call appearances based on all of this in wx. 4) Make testcall work with this (only one call). 5) Try to keep Faizan's "WinIAX" client up to date with the API changes, haven't tested the changes there, but they should work for one call. 6) #define out the WIN AUDIO stuff, it's pretty far behind now, and would need some work to get going. portaudio seems to handle the gory details for us very nicely. Need to do more testing with all of this, but this now allows you to make IAXClient -> IAXClient calls. Of course, allowing people to reject calls would be nice too, but I suppose you can always hang up :) Index: Makefile =================================================================== RCS file: /cvsroot/iaxclient/iaxclient/lib/Makefile,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- Makefile 9 Jun 2003 16:04:57 -0000 1.12 +++ Makefile 16 Jun 2003 23:01:29 -0000 1.13 @@ -35,7 +35,6 @@ iaxclient_lib.o OBJS_WIN32=\ - audio_win32.o \ winfuncs.o \ portaudio/pa_win_wmme/pa_win_wmme.o Index: audio_encode.c =================================================================== RCS file: /cvsroot/iaxclient/iaxclient/lib/audio_encode.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- audio_encode.c 11 Jun 2003 23:09:00 -0000 1.7 +++ audio_encode.c 16 Jun 2003 23:01:29 -0000 1.8 @@ -20,8 +20,6 @@ double ilevel, olevel; - if(!iaxc_levels_callback) return; - gettimeofday(&now,NULL); if(last.tv_sec != 0 && iaxc_usecdiff(&now,&last) < 100000) return; @@ -37,7 +35,7 @@ else olevel = 0.0; - iaxc_levels_callback(vol_to_db(ilevel), vol_to_db(olevel)); + iaxc_do_levels_callback(vol_to_db(ilevel), vol_to_db(olevel)); } static int input_postprocess(void *audio, int len, void *out) @@ -81,7 +79,7 @@ static int output_postprocess(void *audio, int len) { - int l = len; + unsigned long l = len; if(!output_compand) { char *argv[2]; @@ -97,7 +95,7 @@ return 0; } -int send_encoded_audio(struct peer *most_recent_answer, void *data, int iEncodeType) +int send_encoded_audio(struct iaxc_call *most_recent_answer, void *data, int iEncodeType) { gsm_frame fo; int silent; @@ -129,7 +127,7 @@ /* decode encoded audio; return the number of bytes decoded * negative indicates error * XXX out MUST be 160 bytes */ -int decode_audio(struct peer *p, void *out, void *data, int len, int iEncodeType) +int decode_audio(struct iaxc_call *call, void *out, void *data, int len, int iEncodeType) { int ret; int datalen; @@ -145,10 +143,10 @@ fprintf(stderr, "Weird gsm frame, not a multiple of 33.\n"); return -1; } - if (!p->gsmin) - p->gsmin = gsm_create(); + if (!call->gsmin) + call->gsmin = gsm_create(); - if(gsm_decode(p->gsmin, data, out)) + if(gsm_decode(call->gsmin, data, out)) return -1; output_postprocess(out, 160); return 33; Index: audio_encode.h =================================================================== RCS file: /cvsroot/iaxclient/iaxclient/lib/audio_encode.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- audio_encode.h 3 Jun 2003 23:03:25 -0000 1.4 +++ audio_encode.h 16 Jun 2003 23:01:29 -0000 1.5 @@ -9,8 +9,8 @@ #define ENCODE_GSM 1 -int send_encoded_audio(struct peer *most_recent_answer, void *data, int iEncodeType); -int decode_audio(struct peer *p, void *out, void *data, int len, int iEncodeType); +int send_encoded_audio(struct iaxc_call *most_recent_answer, void *data, int iEncodeType); +int decode_audio(struct iaxc_call *p, void *out, void *data, int len, int iEncodeType); int check_encoded_audio_length(struct iax_event *e, int iEncodeType); void increment_encoded_data_count(int *i, int iEncodeType); Index: audio_portaudio.c =================================================================== RCS file: /cvsroot/iaxclient/iaxclient/lib/audio_portaudio.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- audio_portaudio.c 2 Jun 2003 22:01:58 -0000 1.7 +++ audio_portaudio.c 16 Jun 2003 23:01:29 -0000 1.8 @@ -21,7 +21,55 @@ #include "iaxclient_lib.h" -PABLIO_Stream *stream; + +static PABLIO_Stream *stream; +static const PaDeviceInfo **inputDevices; +static const PaDeviceInfo **outputDevices; +static int nInputDevices; +static int nOutputDevices; + +/* scan devices and stash pointers to dev structures. + * But, these structures only remain valid while Pa is initialized, + * which, with pablio, is only while it's running! + * Also, storing these things in two separate arrays loses the actual + * PaDeviceID's associated with devices (since their index in these + * input/output arrays isn't the same as their index in the combined + * array */ +static int pa_scan_devices() { + int nDevices; + int i; + + /* we may be called multiple times */ + if(inputDevices){ + free(inputDevices); + inputDevices=NULL; + } + + if(outputDevices){ + free(outputDevices); + outputDevices=NULL; + } + + nInputDevices = nOutputDevices = 0; + + nDevices = Pa_CountDevices(); + + /* allocate in/out arrays big enough for all devices */ + inputDevices = malloc(nDevices * sizeof(PaDeviceInfo *)); + outputDevices = malloc(nDevices * sizeof(PaDeviceInfo *)); + + for(i=0;i<nDevices;i++) + { + const PaDeviceInfo *d; + d=Pa_GetDeviceInfo(i); + + if(d->maxInputChannels > 0) + inputDevices[nInputDevices++] = d; + + if(d->maxOutputChannels > 0) + outputDevices[nOutputDevices++] = d; + } +} int pa_initialize_audio() { PaError err; @@ -59,7 +107,7 @@ WriteAudioStream(stream, fr, SAMPLES_PER_FRAME * FRAMES_PER_BLOCK); } -void pa_send_audio(struct timeval *lastouttm, struct peer *most_recent_answer, int iEncodeType) { +void pa_send_audio(struct timeval *lastouttm, struct iaxc_call *most_recent_answer, int iEncodeType) { SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK]; /* send all available complete frames */ Index: audio_portaudio.h =================================================================== RCS file: /cvsroot/iaxclient/iaxclient/lib/audio_portaudio.h,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- audio_portaudio.h 16 Jun 2003 15:47:54 -0000 1.6 +++ audio_portaudio.h 16 Jun 2003 23:01:29 -0000 1.7 @@ -32,5 +32,5 @@ void handle_paerror(PaError err, char *where); void pa_read_audio_input(); void pa_play_recv_audio(void *fr, int fr_size); -void pa_send_audio(struct timeval *outtm, struct peer *most_recent_answer, int iEncodeType); +void pa_send_audio(struct timeval *outtm, struct iaxc_call *most_recent_answer, int iEncodeType); Index: iaxclient.h =================================================================== RCS file: /cvsroot/iaxclient/iaxclient/lib/iaxclient.h,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- iaxclient.h 13 Jun 2003 18:57:24 -0000 1.11 +++ iaxclient.h 16 Jun 2003 23:01:29 -0000 1.12 @@ -42,8 +42,22 @@ #define IAXC_FORMAT_H263 (1 << 19) /* H.263 Video */ -#if 0 -/* not yet implemented */ + +#define IAXC_EVENT_TEXT 1 +#define IAXC_EVENT_LEVELS 2 +#define IAXC_EVENT_STATE 3 + +#define IAXC_CALL_STATE_FREE 0 +#define IAXC_CALL_STATE_ACTIVE (1<<1) +#define IAXC_CALL_STATE_OUTGOING (1<<2) +#define IAXC_CALL_STATE_COMPLETE (1<<3) +#define IAXC_CALL_STATE_SELECTED (1<<4) + +#define IAXC_TEXT_TYPE_STATUS 1 +#define IAXC_TEXT_TYPE_NOTICE 2 +#define IAXC_TEXT_TYPE_ERROR 3 + + #define IAXC_EVENT_BUFSIZ 256 struct iaxc_ev_levels { @@ -52,28 +66,30 @@ }; struct iaxc_ev_text { + int type; char message[IAXC_EVENT_BUFSIZ]; }; -struct iaxc_ev_call { - char callerid[IAXC_EVENT_BUFSIZ]; -} +struct iaxc_ev_call_state { + int callNo; + int state; + char remote[IAXC_EVENT_BUFSIZ]; + char local[IAXC_EVENT_BUFSIZ]; +}; typedef struct iaxc_event_struct { int type; union { - struct iaxc_ev_levels levels; - struct iaxc_ev_text text; - struct iaxc_ev_call call; - } event; - struct iaxc_event_struct *next; + struct iaxc_ev_levels levels; + struct iaxc_ev_text text; + struct iaxc_ev_call_state call; + } ev; } iaxc_event; typedef int (*iaxc_event_callback_t)(iaxc_event e); -void iaxc_set_event_callback(iaxc_message_callback_t func); -#endif +void iaxc_set_event_callback(iaxc_event_callback_t func); -int iaxc_initialize(int audType); +int iaxc_initialize(int audType, int nCalls); void iaxc_shutdown(); void iaxc_set_encode_format(int fmt); void iaxc_process_calls(); @@ -81,7 +97,7 @@ int iaxc_start_processing_thread(); int iaxc_stop_processing_thread(); void iaxc_call(char *num); -void iaxc_answer_call(void); +void iaxc_answer_call(int callNo); void iaxc_dump_call(void); void iaxc_reject_call(void); void iaxc_send_dtmf(char digit); @@ -89,14 +105,7 @@ void iaxc_millisleep(long ms); void iaxc_set_silence_threshold(double thr); void iaxc_set_audio_output(int mode); - -typedef int (*iaxc_levels_callback_t)(float input, float output); -void iaxc_set_levels_callback(iaxc_levels_callback_t func); - -typedef void (*iaxc_message_callback_t)(char *); -void iaxc_set_status_callback(iaxc_message_callback_t func); -void iaxc_set_error_callback(iaxc_message_callback_t func); - +int iaxc_select_call(int callNo); #ifdef __cplusplus } Index: iaxclient_lib.c =================================================================== RCS file: /cvsroot/iaxclient/iaxclient/lib/iaxclient_lib.c,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- iaxclient_lib.c 13 Jun 2003 22:44:42 -0000 1.19 +++ iaxclient_lib.c 16 Jun 2003 23:01:29 -0000 1.20 @@ -16,15 +16,14 @@ char rcmd[RBUFSIZE]; int iaxc_audio_output_mode = 0; // Normal -static int answered_call; -static struct iax_session *newcall; -static struct peer *most_recent_answer=NULL; -static struct peer *peers; +static int selected_call; // XXX to be protected by mutex? +static struct iaxc_call* calls; +static int nCalls; // number of calls for this library session struct timeval lastouttm; -static struct peer * find_peer(struct iax_session *session); +static struct iaxc_call * find_call(struct iax_session *session); static void do_iax_event(); static THREAD procThread; @@ -33,12 +32,7 @@ /* QuitFlag: 0: Running 1: Should Quit, -1: Not Running */ static int procThreadQuitFlag = -1; - -iaxc_levels_callback_t iaxc_levels_callback = NULL; - -void iaxc_set_levels_callback(iaxc_levels_callback_t func) { - iaxc_levels_callback = func; -} +iaxc_event_callback_t iaxc_event_callback = NULL; void iaxc_set_silence_threshold(double thr) { iaxc_silence_threshold = thr; @@ -56,52 +50,140 @@ } +void iaxc_set_event_callback(iaxc_event_callback_t func) { + iaxc_event_callback = func; +} + // Messaging functions static void default_message_callback(char *message) { fprintf(stderr, "IAXCLIENT: "); fprintf(stderr, message); fprintf(stderr, "\n"); } -iaxc_message_callback_t iaxc_error_callback = default_message_callback; -iaxc_message_callback_t iaxc_status_callback = default_message_callback; -void iaxc_set_error_callback(iaxc_message_callback_t func) { - iaxc_error_callback = func; -} +// Post Events back to clients +void iaxc_post_event(iaxc_event e) { + if(iaxc_event_callback) + { + int rv; + rv = iaxc_event_callback(e); + if(rv < 0) + default_message_callback("IAXCLIENT: BIG PROBLEM, event callback returned failure!"); + // > 0 means processed + if(rv > 0) return; -void iaxc_set_status_callback(iaxc_message_callback_t func) { - iaxc_status_callback = func; + // else, fall through to "defaults" + } + + switch(e.type) + { + case IAXC_EVENT_TEXT: + default_message_callback(e.ev.text.message); + // others we just ignore too + return; + } } -#define IAXC_ERROR 1 -#define IAXC_STATUS 2 + +#define IAXC_ERROR IAXC_TEXT_TYPE_ERROR +#define IAXC_STATUS IAXC_TEXT_TYPE_STATUS +#define IAXC_NOTICE IAXC_TEXT_TYPE_NOTICE static iaxc_usermsg(int type, const char *fmt, ...) { va_list args; - char buf[256]; + iaxc_event e; + + e.type=IAXC_EVENT_TEXT; + e.ev.text.type=type; va_start(args, fmt); #ifdef WIN32 - _vsnprintf(buf, 250, fmt, args); + _vsnprintf(e.ev.text.message, IAXC_EVENT_BUFSIZ, fmt, args); #else - vsnprintf(buf, 250, fmt, args); + vsnprintf(e.ev.text.message, IAXC_EVENT_BUFSIZ, fmt, args); #endif va_end(args); - if(type == IAXC_ERROR) - iaxc_error_callback(buf); - else - iaxc_status_callback(buf); + iaxc_post_event(e); +} + + +void iaxc_do_levels_callback(float input, float output) +{ + iaxc_event e; + e.type = IAXC_EVENT_LEVELS; + e.ev.levels.input = input; + e.ev.levels.output = output; + iaxc_post_event(e); +} + +void iaxc_do_state_callback(int callNo) +{ + iaxc_event e; + e.type = IAXC_EVENT_STATE; + e.ev.call.callNo = callNo; + e.ev.call.state = calls[callNo].state; + strncpy(e.ev.call.remote, calls[callNo].remote, IAXC_EVENT_BUFSIZ); + iaxc_post_event(e); +} + +static int iaxc_next_free_call() { + int i; + for(i=0;i<nCalls;i++) + if(calls[i].session==NULL) + return i; + + return -1; +} + +static int iaxc_clear_call(int toDump) +{ + if(selected_call == toDump) iaxc_select_call(-1); + + // XXX libiax should handle cleanup, I think.. + calls[toDump].session = NULL; + calls[toDump].state = IAXC_CALL_STATE_FREE; + iaxc_do_state_callback(toDump); } +/* select a call. -1 == no call */ +/* XXX Locking?? Start/stop audio?? */ +int iaxc_select_call(int callNo) { + if(callNo < -1 || callNo >= nCalls) { + iaxc_usermsg(IAXC_ERROR, "Error: tried to select out_of_range call %d", callNo); + return -1; + } + + if(!calls[callNo].session) { + iaxc_usermsg(IAXC_ERROR, "Error: tried to select inactive call", callNo); + return -1; + } + + if(selected_call >= 0) { + calls[selected_call].state &= ~IAXC_CALL_STATE_SELECTED; + iaxc_do_state_callback(selected_call); + } + + calls[callNo].state |= IAXC_CALL_STATE_SELECTED; + + selected_call = callNo; + iaxc_do_state_callback(selected_call); +} + +/* external API accessor */ +int iaxc_selected_call() { + return selected_call; +} // Parameters: // audType - Define whether audio is handled by library or externally -int iaxc_initialize(int audType) { - /* get time of day in milliseconds, offset by tick count (see our - gettimeofday() implementation) */ +int iaxc_initialize(int audType, int inCalls) { + int i; + + /* os-specific initializations: init gettimeofday fake stuff in + * Win32, etc) */ os_init(); if ( (port = iax_init(0) < 0)) { @@ -110,16 +192,26 @@ } netfd = iax_get_fd(); + 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; - answered_call=0; - newcall=0; + selected_call = -1; + gettimeofday(&lastouttm,NULL); switch (iAudioType) { case AUDIO_INTERNAL: -#ifdef WIN32 +#ifdef USE_WIN_AUDIO if (win_initialize_audio() != 0) return -1; -#else #endif break; case AUDIO_INTERNAL_PA: @@ -133,9 +225,8 @@ void iaxc_shutdown() { switch (iAudioType) { case AUDIO_INTERNAL: -#ifdef WIN32 +#ifdef USE_WIN_AUDIO win_shutdown_audio(); -#else #endif break; case AUDIO_INTERNAL_PA: @@ -153,7 +244,7 @@ void iaxc_process_calls(void) { -#ifdef WIN32 +#ifdef USE_WIN_AUDIO win_flush_audio_output_buffers(); if (iAudioType == AUDIO_INTERNAL) { win_prepare_audio_buffers(); @@ -195,37 +286,24 @@ procThreadQuitFlag = -1; } -void start_call_processing() { - if (!answered_call) { - while(1) { - iaxc_service_network(netfd); - if (answered_call) - break; - } - } -#ifdef WIN32 - _beginthread(iaxc_process_calls, 0, NULL); -#else -#endif -} int service_audio() { /* do audio input stuff for buffers that have received data from audio in device already. Must do them in serial number order (the order in which they were originally queued). */ - if(answered_call) /* send audio only if call answered */ + if(selected_call >= 0) /* send audio only if call answered */ { switch (iAudioType) { case AUDIO_INTERNAL: iaxc_service_network(netfd); -#ifdef WIN32 - win_process_audio_buffers(&lastouttm, most_recent_answer, iEncodeType); +#ifdef USE_WIN_AUDIO + win_process_audio_buffers(&lastouttm, &calls[selected_call], iEncodeType); #endif iaxc_service_network(netfd); break; case AUDIO_INTERNAL_PA: iaxc_service_network(netfd); - pa_send_audio(&lastouttm, most_recent_answer, iEncodeType); + pa_send_audio(&lastouttm, &calls[selected_call], iEncodeType); break; default: iaxc_service_network(netfd); @@ -235,25 +313,33 @@ } } else { static int i=0; - if((i++ % 50 == 0) && iaxc_levels_callback) iaxc_levels_callback(-99,-99); + if(i++ % 50 == 0) iaxc_do_levels_callback(-99,-99); } return 0; } -void handle_audio_event(struct iax_event *e, struct peer *p) { +void handle_audio_event(struct iax_event *e, int callNo) { int total_consumed = 0; int cur; short fr[160]; + struct iaxc_call *call; + + call = &calls[callNo]; + + if(callNo != selected_call) { + /* drop audio for unselected call? */ + return; + } #ifdef IAXC_IAX2 while(total_consumed < e->datalen) { - cur = decode_audio(p, fr, + cur = decode_audio(call, fr, e->data,e->datalen-total_consumed, iEncodeType); #else while(total_consumed < e->event.voice.datalen) { - cur = decode_audio(p, fr, + cur = decode_audio(call, fr, e->event.voice.data,e->event.voice.datalen-total_consumed, iEncodeType); #endif @@ -265,7 +351,7 @@ if(iaxc_audio_output_mode != 0) continue; switch (iAudioType) { case AUDIO_INTERNAL: -#ifdef WIN32 +#ifdef USE_WIN_AUDIO win_flush_audio_output_buffers(); win_play_recv_audio(fr, sizeof(fr)); #else @@ -283,7 +369,7 @@ } } -void iaxc_handle_network_event(struct iax_event *e, struct peer *p) +void iaxc_handle_network_event(struct iax_event *e, int callNo) { // int len,n; // WHOUT *wh,*wh1; @@ -295,37 +381,34 @@ case IAX_EVENT_HANGUP: #ifndef IAXC_IAX2 /* IAX2 barfs from this. Should we do this or not? */ - iax_hangup(most_recent_answer->session, "Byeee!"); + iax_hangup(calls[callNo].session, "Byeee!"); #endif iaxc_usermsg(IAXC_STATUS, "Call disconnected by remote"); - free(most_recent_answer); - most_recent_answer = 0; - answered_call = 0; - peers = 0; - newcall = 0; + // XXX does the session go away now? + iaxc_clear_call(callNo); break; case IAX_EVENT_REJECT: - iaxc_usermsg(IAXC_STATUS, "Authentication rejected by remote"); + iaxc_usermsg(IAXC_STATUS, "Call rejected by remote"); + iaxc_clear_call(callNo); break; case IAX_EVENT_ACCEPT: - iaxc_usermsg(IAXC_STATUS,"RING RING"); + calls[callNo].state |= IAXC_CALL_STATE_COMPLETE; + iaxc_do_state_callback(callNo); + iaxc_usermsg(IAXC_STATUS,"Call %d ringing", callNo); // issue_prompt(f); break; case IAX_EVENT_ANSWER: - iaxc_answer_call(); + iaxc_answer_call(callNo); break; case IAX_EVENT_VOICE: - handle_audio_event(e, p); - break; -// default : - //fprintf(f, "Don't know how to handle that format %d\n", e->event.voice.format); + handle_audio_event(e, callNo); break; case IAX_EVENT_RINGA: break; default: - iaxc_usermsg(IAXC_STATUS, "Unknown event: %d", e->etype); + iaxc_usermsg(IAXC_STATUS, "Unknown event: %d for call %d", e->etype, callNo); break; } } @@ -333,81 +416,80 @@ void iaxc_call(char *num) { - struct peer *peer; + int callNo; + struct iax_session *newsession; - if(!newcall) - newcall = iax_session_new(); - else { - iaxc_usermsg(IAXC_STATUS, "Call already in progress"); + callNo = iaxc_next_free_call(); + if(callNo < 0) { + iaxc_usermsg(IAXC_STATUS, "No free call appearances"); return; } - if ( !(peer = malloc(sizeof(struct peer)))) { - iaxc_usermsg(IAXC_ERROR, "Warning: Unable to allocate memory!"); + newsession = iax_session_new(); + if(!newsession) { + iaxc_usermsg(IAXC_ERROR, "Can't make new session"); return; } - peer->time = time(0); - peer->session = newcall; - peer->gsmin = 0; - peer->gsmout = 0; + calls[callNo].session = newsession; - peer->next = peers; - peers = peer; + /* XXX ??? */ + calls[callNo].gsmin = 0; + calls[callNo].gsmout = 0; + + strncpy(calls[callNo].remote,num,IAXC_EVENT_BUFSIZ); + calls[callNo].state = IAXC_CALL_STATE_ACTIVE | IAXC_CALL_STATE_OUTGOING; - most_recent_answer = peer; #ifdef IAXC_IAX2 - iax_call(peer->session, "7001234567", "IAXClient User", num, NULL, 0); + iax_call(calls[callNo].session, "7001234567", "IAXClient User", num, NULL, 0); #else - iax_call(peer->session, "7001234567", num, NULL, 10); + iax_call(calls[callNo].session, "7001234567", num, NULL, 10); #endif + + // does state stuff + iaxc_select_call(callNo); } -void iaxc_answer_call(void) +void iaxc_answer_call(int callNo) { - if(most_recent_answer) - iax_answer(most_recent_answer->session); - iaxc_usermsg(IAXC_STATUS,"Connected"); - answered_call = 1; + iax_answer(calls[selected_call].session); } void iaxc_dump_call(void) { - if(most_recent_answer) + int toDump = selected_call; + if(toDump < 0) { - iax_hangup(most_recent_answer->session,""); - free(most_recent_answer); + iaxc_usermsg(IAXC_ERROR, "Error: tried to dump but no call selected"); + return; } - iaxc_usermsg(IAXC_STATUS, "Hanging up"); - answered_call = 0; - most_recent_answer = 0; - answered_call = 0; - peers = 0; - newcall = 0; + + iax_hangup(calls[selected_call].session,"Dumped Call"); + iaxc_usermsg(IAXC_STATUS, "Hanging up call %d", toDump); + iaxc_clear_call(toDump); } void iaxc_reject_call(void) { - iax_reject(most_recent_answer->session, "Call rejected manually."); - most_recent_answer = 0; + // XXX should take callNo? + iax_reject(calls[selected_call].session, "Call rejected manually."); + iaxc_clear_call(selected_call); } void iaxc_send_dtmf(char digit) { - if(most_recent_answer) - iax_send_dtmf(most_recent_answer->session,digit); + if(selected_call >= 0) + iax_send_dtmf(calls[selected_call].session,digit); } -static struct peer *find_peer(struct iax_session *session) +static int iaxc_find_call_by_session(struct iax_session *session) { - struct peer *cur = peers; - while(cur) { - if (cur->session == session) - return cur; - cur = cur->next; - } - return NULL; + int i; + for(i=0;i<nCalls;i++) + if (calls[i].session == session) + return i; + return -1; } /* handle all network requests, and a pending scheduled event, if any */ @@ -438,74 +520,66 @@ } static void do_iax_event() { - int sessions = 0; struct iax_event *e = 0; - struct peer *peer; + int callNo; while ( (e = iax_get_event(0))) { - peer = find_peer(e->session); - if(peer) { - iaxc_handle_network_event(e, peer); + callNo = iaxc_find_call_by_session(e->session); + if(callNo >= 0) { + iaxc_handle_network_event(e, callNo); iax_event_free(e); } else { if(e->etype != IAX_EVENT_CONNECT) { iaxc_usermsg(IAXC_STATUS, "Huh? This is an event for a non-existant session?"); } - sessions++; + + callNo = iaxc_next_free_call(); - if(sessions >= MAX_SESSIONS) { - iaxc_usermsg(IAXC_STATUS, "Missed a call... too many sessions open."); + if(callNo < 0) { + iaxc_usermsg(IAXC_STATUS, "Incoming Call, but no appearances"); + // XXX Reject this call!, or just ignore? + iax_reject(e->session, "Too many calls, we're busy!"); } -#ifndef IAXC_IAX2 - if(e->event.connect.callerid && e->event.connect.dnid) - iaxc_usermsg(IAXC_STATUS, "Call from '%s' for '%s'", e->event.connect.callerid, - e->event.connect.dnid); - else if(e->event.connect.dnid) { - iaxc_usermsg(IAXC_STATUS, "Call from '%s'", e->event.connect.dnid); - } else if(e->event.connect.callerid) { - iaxc_usermsg(IAXC_STATUS, "Call from '%s'", e->event.connect.callerid); - } else -#endif - iaxc_usermsg(IAXC_STATUS, "Call from"); +#ifndef IAXC_IAX2 + if(e->event.connect.dnid) + strncpy(calls[callNo].local,e->event.connect.dnid, + IAXC_EVENT_BUFSIZ); + else + strncpy(calls[callNo].local,"unknown", + IAXC_EVENT_BUFSIZ); - iaxc_usermsg(IAXC_STATUS, " (%s)", inet_ntoa(iax_get_peer_addr(e->session).sin_addr)); + if(e->event.connect.callerid) + strncpy(calls[callNo].remote, + e->event.connect.callerid, IAXC_EVENT_BUFSIZ); + else + strncpy(calls[callNo].remote, + "unknown", IAXC_EVENT_BUFSIZ); +#else + // XXX TODO +#endif + iaxc_usermsg(IAXC_STATUS, "Call from (%s)", calls[callNo].remote); - if(most_recent_answer) { - iaxc_usermsg(IAXC_STATUS, "Incoming call ignored, there's already a call waiting for answer... \ -please accept or reject first"); - iax_reject(e->session, "Too many calls, we're busy!"); - } else { - if ( !(peer = malloc(sizeof(struct peer)))) { - iaxc_usermsg(IAXC_STATUS, "Warning: Unable to allocate memory!"); - return; - } + calls[callNo].gsmin = 0; + calls[callNo].gsmout = 0; + calls[callNo].session = e->session; + calls[callNo].state = IAXC_CALL_STATE_ACTIVE; - peer->time = time(0); - peer->session = e->session; - peer->gsmin = 0; - peer->gsmout = 0; - peer->next = peers; - peers = peer; + // should we even accept? or, we accept, but + // don't necessarily answer.. + iax_accept(calls[callNo].session); + iax_ring_announce(calls[callNo].session); - iax_accept(peer->session); - iax_ring_announce(peer->session); - most_recent_answer = peer; - iaxc_usermsg(IAXC_STATUS, "Incoming call!"); - } + // should we select this call? + iaxc_select_call(callNo); + iaxc_usermsg(IAXC_STATUS, "Incoming call on line %d", callNo); iax_event_free(e); -// issue_prompt(f); } } } -int iaxc_was_call_answered() -{ - return answered_call; -} - -void iaxc_external_audio_event(struct iax_event *e, struct peer *p) +void iaxc_external_audio_event(struct iax_event *e, struct iaxc_call *call) { // To be coded in the future return; Index: iaxclient_lib.h =================================================================== RCS file: /cvsroot/iaxclient/iaxclient/lib/iaxclient_lib.h,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- iaxclient_lib.h 13 Jun 2003 18:57:24 -0000 1.15 +++ iaxclient_lib.h 16 Jun 2003 23:01:29 -0000 1.16 @@ -68,35 +68,50 @@ #include "iax-client.h" // LibIAX functions #include "gsm.h" -struct peer { - int time; - gsm gsmin; - gsm gsmout; - - struct iax_session *session; - struct peer *next; -}; long iaxc_usecdiff( struct timeval *timeA, struct timeval *timeB ); -void iaxc_handle_network_event(struct iax_event *e, struct peer *p); +void iaxc_handle_network_event(struct iax_event *e, int callNo); void iaxc_service_network(int netfd); +void iaxc_do_levels_callback(float input, float output); +#if 0 +/* Audio Driver Abstraction TODO */ +struct audio_driver_struct { + char *name; + int (*initialize)(struct audio_driver_struct *d); + +}; +typedef struct audio_driver_struct *iaxc_audio_driver; + +#endif #include "iaxclient.h" + + +struct iaxc_call { + /* to be replaced with codec-structures, with codec-private data */ + gsm gsmin; + gsm gsmout; + + /* the "state" of this call */ + int state; + char remote[IAXC_EVENT_BUFSIZ]; + char local[IAXC_EVENT_BUFSIZ]; + + struct iax_session *session; +}; + #include "audio_encode.h" #include "audio_portaudio.h" -#ifdef WIN32 +#ifdef USE_WIN_AUDIO #include "audio_win32.h" #endif - extern double iaxc_silence_threshold; extern int iaxc_audio_output_mode; -extern iaxc_levels_callback_t iaxc_levels_callback; -extern iaxc_message_callback_t iaxc_error_callback; -extern iaxc_message_callback_t iaxc_status_callback; +extern iaxc_event_callback_t iaxc_event_callback; /* external audio functions */ void iaxc_external_service_audio(); |