static void iaxc_handle_connect(struct iax_event * e) { #ifdef USE_VIDEO int video_format_capability; int video_format_preferred; #endif int video_format = 0; int format = 0; int callno; callno = iaxc_first_free_call(); if ( callno < 0 ) { iaxci_usermsg(IAXC_STATUS, "%i \n Incoming Call, but no appearances", callno); // XXX Reject this call!, or just ignore? //iax_reject(e->session, "Too many calls, we're busy!"); iax_accept(e->session, audio_format_preferred & e->ies.capability); iax_busy(e->session); return; } /* negotiate codec */ /* first, try _their_ preferred format */ format = audio_format_capability & e->ies.format; if ( !format ) { /* then, try our preferred format */ format = audio_format_preferred & e->ies.capability; } if ( !format ) { /* finally, see if we have one in common */ format = audio_format_capability & e->ies.capability; /* now choose amongst these, if we got one */ if ( format ) { format = iaxc_choose_codec(format); } } if ( !format ) { iax_reject(e->session, "Could not negotiate common codec"); return; } #ifdef USE_VIDEO iaxc_video_format_get_cap(&video_format_preferred, &video_format_capability); /* first, see if they even want video */ video_format = (e->ies.format & IAXC_VIDEO_FORMAT_MASK); if ( video_format ) { /* next, try _their_ preferred format */ video_format &= video_format_capability; if ( !video_format ) { /* then, try our preferred format */ video_format = video_format_preferred & (e->ies.capability & IAXC_VIDEO_FORMAT_MASK); } if ( !video_format ) { /* finally, see if we have one in common */ video_format = video_format_capability & (e->ies.capability & IAXC_VIDEO_FORMAT_MASK); /* now choose amongst these, if we got one */ if ( video_format ) { video_format = iaxc_choose_codec(video_format); } } /* All video negotiations failed, then warn */ if ( !video_format ) { iaxci_usermsg(IAXC_NOTICE, "Notice: could not negotiate common video codec"); iaxci_usermsg(IAXC_NOTICE, "Notice: switching to audio-only call"); } } #endif /* USE_VIDEO */ calls[callno].vformat = video_format; calls[callno].format = format; if ( e->ies.called_number ) strncpy(calls[callno].local, e->ies.called_number, IAXC_EVENT_BUFSIZ); else strncpy(calls[callno].local, "unknown", IAXC_EVENT_BUFSIZ); if ( e->ies.called_context ) strncpy(calls[callno].local_context, e->ies.called_context, IAXC_EVENT_BUFSIZ); else strncpy(calls[callno].local_context, "", IAXC_EVENT_BUFSIZ); if ( e->ies.calling_number ) strncpy(calls[callno].remote, e->ies.calling_number, IAXC_EVENT_BUFSIZ); else strncpy(calls[callno].remote, "unknown", IAXC_EVENT_BUFSIZ); if ( e->ies.calling_name ) strncpy(calls[callno].remote_name, e->ies.calling_name, IAXC_EVENT_BUFSIZ); else strncpy(calls[callno].remote_name, "unknown", IAXC_EVENT_BUFSIZ); iaxc_note_activity(callno); iaxci_usermsg(IAXC_STATUS, "Call from (%s)", calls[callno].remote); codec_destroy( callno ); calls[callno].session = e->session; calls[callno].state = IAXC_CALL_STATE_ACTIVE|IAXC_CALL_STATE_RINGING; iax_accept(calls[callno].session, format | video_format); iax_ring_announce(calls[callno].session); iaxci_do_state_callback(callno); iaxci_usermsg(IAXC_STATUS, "Incoming call on line %d", callno); }
static 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_NULL: break; case IAX_EVENT_HANGUP: iaxci_usermsg(IAXC_STATUS, "Call disconnected by remote"); // XXX does the session go away now? iaxc_clear_call(callNo); break; case IAX_EVENT_REJECT: iaxci_usermsg(IAXC_STATUS, "Call rejected by remote"); iaxc_clear_call(callNo); break; case IAX_EVENT_ACCEPT: calls[callNo].format = e->ies.format & IAXC_AUDIO_FORMAT_MASK; calls[callNo].vformat = e->ies.format & IAXC_VIDEO_FORMAT_MASK; if ( !(e->ies.format & IAXC_VIDEO_FORMAT_MASK) ) { iaxci_usermsg(IAXC_NOTICE, "Failed video codec negotiation."); } iaxci_usermsg(IAXC_STATUS,"Call %d accepted", callNo); break; case IAX_EVENT_ANSWER: calls[callNo].state &= ~IAXC_CALL_STATE_RINGING; calls[callNo].state |= IAXC_CALL_STATE_COMPLETE; iaxci_do_state_callback(callNo); iaxci_usermsg(IAXC_STATUS,"Call %d answered", callNo); //iaxc_answer_call(callNo); // notify the user? break; case IAX_EVENT_BUSY: calls[callNo].state &= ~IAXC_CALL_STATE_RINGING; calls[callNo].state |= IAXC_CALL_STATE_BUSY; iaxci_do_state_callback(callNo); iaxci_usermsg(IAXC_STATUS, "Call %d busy", callNo); break; case IAX_EVENT_VOICE: handle_audio_event(e, callNo); if ( (calls[callNo].state & IAXC_CALL_STATE_OUTGOING) && (calls[callNo].state & IAXC_CALL_STATE_RINGING) ) { calls[callNo].state &= ~IAXC_CALL_STATE_RINGING; calls[callNo].state |= IAXC_CALL_STATE_COMPLETE; iaxci_do_state_callback(callNo); iaxci_usermsg(IAXC_STATUS,"Call %d progress", callNo); } break; #ifdef USE_VIDEO case IAX_EVENT_VIDEO: handle_video_event(e, callNo); break; #endif case IAX_EVENT_TEXT: handle_text_event(e, callNo); break; case IAX_EVENT_RINGA: calls[callNo].state |= IAXC_CALL_STATE_RINGING; iaxci_do_state_callback(callNo); iaxci_usermsg(IAXC_STATUS,"Call %d ringing", callNo); break; case IAX_EVENT_PONG: 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"); iaxci_usermsg(IAXC_STATUS, "Call %d timed out.", callNo); iaxc_clear_call(callNo); break; case IAX_EVENT_TRANSFER: calls[callNo].state |= IAXC_CALL_STATE_TRANSFER; iaxci_do_state_callback(callNo); iaxci_usermsg(IAXC_STATUS,"Call %d transfer released", callNo); break; case IAX_EVENT_DTMF: iaxci_do_dtmf_callback(callNo,e->subclass); iaxci_usermsg(IAXC_STATUS, "DTMF digit %c received", e->subclass); break; default: iaxci_usermsg(IAXC_STATUS, "Unknown event: %d for call %d", e->etype, callNo); break; } }
EXPORT int iaxc_call_ex(const char *num, const char* callerid_name, const char* callerid_number, int video) { int video_format_capability = 0; int video_format_preferred = 0; int callNo = -1; struct iax_session *newsession; char *ext = strstr(num, "/"); get_iaxc_lock(); // if no call is selected, get a new appearance if ( selected_call < 0 ) { callNo = iaxc_first_free_call(); } else { // use selected call if not active, otherwise, get a new appearance if ( calls[selected_call].state & IAXC_CALL_STATE_ACTIVE ) { callNo = iaxc_first_free_call(); } else { callNo = selected_call; } } if ( callNo < 0 ) { iaxci_usermsg(IAXC_STATUS, "No free call appearances"); goto iaxc_call_bail; } newsession = iax_session_new(); if ( !newsession ) { iaxci_usermsg(IAXC_ERROR, "Can't make new session"); goto iaxc_call_bail; } calls[callNo].session = newsession; codec_destroy( callNo ); if ( ext ) { strncpy(calls[callNo].remote_name, num, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].remote, ++ext, IAXC_EVENT_BUFSIZ); } else { strncpy(calls[callNo].remote_name, num, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].remote, "" , IAXC_EVENT_BUFSIZ); } if ( callerid_number != NULL ) strncpy(calls[callNo].callerid_number, callerid_number, IAXC_EVENT_BUFSIZ); if ( callerid_name != NULL ) strncpy(calls[callNo].callerid_name, callerid_name, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].local , calls[callNo].callerid_name, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].local_context, "default", IAXC_EVENT_BUFSIZ); calls[callNo].state = IAXC_CALL_STATE_ACTIVE | IAXC_CALL_STATE_OUTGOING; /* reset activity and ping "timers" */ iaxc_note_activity(callNo); calls[callNo].last_ping = calls[callNo].last_activity; #ifdef USE_VIDEO if ( video ) iaxc_video_format_get_cap(&video_format_preferred, &video_format_capability); #endif iaxci_usermsg(IAXC_NOTICE, "Originating an %s call", video_format_preferred ? "audio+video" : "audio only"); iax_call(calls[callNo].session, calls[callNo].callerid_number, calls[callNo].callerid_name, num, NULL, 0, audio_format_preferred | video_format_preferred, audio_format_capability | video_format_capability); // does state stuff also iaxc_select_call(callNo); iaxc_call_bail: put_iaxc_lock(); return callNo; }
EXPORT int iaxc_call_ex(const char *num, const char* callerid_name, const char* callerid_number, int video) { int video_format_capability = 0; int video_format_preferred = 0; int callNo = -1; struct iax_session *newsession; char *ext = strstr(num, "/"); get_iaxc_lock(); // if no call is selected, get a new appearance if ( selected_call < 0 ) { callNo = iaxc_first_free_call(); } else { // use selected call if not active, otherwise, get a new appearance if ( calls[selected_call].state & IAXC_CALL_STATE_ACTIVE ) { callNo = iaxc_first_free_call(); } else { callNo = selected_call; } } if ( callNo < 0 ) { iaxci_usermsg(IAXC_STATUS, "No free call appearances"); goto iaxc_call_bail; } newsession = iax_session_new(); if ( !newsession ) { iaxci_usermsg(IAXC_ERROR, "Can't make new session"); goto iaxc_call_bail; } calls[callNo].session = newsession; codec_destroy( callNo ); /* When the ACCEPT comes back from the other-end, these formats * are set. Whether the format is set or not determines whether * we are in the Linked state (see the iax2 rfc). * These will have already been cleared by iaxc_clear_call(), * but we reset them anyway just to be pedantic. */ calls[callNo].format = 0; calls[callNo].vformat = 0; if ( ext ) { strncpy(calls[callNo].remote_name, num, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].remote, ++ext, IAXC_EVENT_BUFSIZ); } else { strncpy(calls[callNo].remote_name, num, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].remote, "" , IAXC_EVENT_BUFSIZ); } if ( callerid_number != NULL ) strncpy(calls[callNo].callerid_number, callerid_number, IAXC_EVENT_BUFSIZ); if ( callerid_name != NULL ) strncpy(calls[callNo].callerid_name, callerid_name, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].local , calls[callNo].callerid_name, IAXC_EVENT_BUFSIZ); strncpy(calls[callNo].local_context, "default", IAXC_EVENT_BUFSIZ); calls[callNo].state = IAXC_CALL_STATE_OUTGOING; /* reset activity and ping "timers" */ iaxc_note_activity(callNo); calls[callNo].last_ping = calls[callNo].last_activity; #ifdef USE_VIDEO if ( video ) iaxc_video_format_get_cap(&video_format_preferred, &video_format_capability); #endif iaxci_usermsg(IAXC_NOTICE, "Originating an %s call", video_format_preferred ? "audio+video" : "audio only"); iax_call(calls[callNo].session, calls[callNo].callerid_number, calls[callNo].callerid_name, num, NULL, 0, audio_format_preferred | video_format_preferred, audio_format_capability | video_format_capability); // does state stuff also iaxc_select_call(callNo); iaxc_call_bail: put_iaxc_lock(); return callNo; }