📄 iaxclient_lib.c
字号:
get_iaxc_lock();
count = iaxc_remove_registration_by_id(id);
put_iaxc_lock();
return count;
}
EXPORT int iaxc_register(char *user, char *pass, char *host)
{
struct iaxc_registration *newreg;
newreg = malloc(sizeof (struct iaxc_registration));
if(!newreg) {
iaxc_usermsg(IAXC_ERROR, "Can't make new registration");
return -1;
}
get_iaxc_lock();
newreg->session = iax_session_new();
if(!newreg->session) {
iaxc_usermsg(IAXC_ERROR, "Can't make new registration session");
put_iaxc_lock();
return -1;
}
gettimeofday(&newreg->last,NULL);
newreg->refresh = 120*1000*1000; /* 120 seconds, in usecs */
strncpy(newreg->host, host, 256);
strncpy(newreg->user, user, 256);
strncpy(newreg->pass, pass, 256);
/* send out the initial registration timeout 300 seconds */
iax_register(newreg->session, host, user, pass, 300);
/* add it to the list; */
newreg->id = ++next_registration_id;
newreg->next = registrations;
registrations = newreg;
put_iaxc_lock();
return newreg->id;
}
static void codec_destroy( int callNo )
{
if( calls[callNo].encoder ) {
calls[callNo].encoder->destroy( calls[callNo].encoder );
calls[callNo].encoder = NULL;
}
if( calls[callNo].decoder ) {
calls[callNo].decoder->destroy( calls[callNo].decoder );
calls[callNo].decoder = NULL;
}
}
EXPORT void iaxc_call(char *num)
{
int callNo;
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;
}
}
// fprintf(stderr,"Trying to call");
if(callNo < 0) {
iaxc_usermsg(IAXC_STATUS, "No free call appearances");
goto iaxc_call_bail;
}
newsession = iax_session_new();
if(!newsession) {
iaxc_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);
}
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;
iax_call(calls[callNo].session, calls[callNo].callerid_number,
calls[callNo].callerid_name, num, NULL, 0,
audio_format_preferred, audio_format_capability);
// does state stuff also
iaxc_select_call(callNo);
iaxc_call_bail:
put_iaxc_lock();
}
EXPORT void iaxc_answer_call(int callNo)
{
if(callNo < 0)
return;
//fprintf(stderr, "iaxc answering call %d\n", callNo);
calls[callNo].state |= IAXC_CALL_STATE_COMPLETE;
calls[callNo].state &= ~IAXC_CALL_STATE_RINGING;
iax_answer(calls[callNo].session);
iaxc_do_state_callback(callNo);
}
EXPORT void iaxc_blind_transfer_call(int callNo, char *DestExtn)
{
iax_transfer(calls[callNo].session, DestExtn);
}
static void iaxc_dump_one_call(int callNo)
{
if(callNo < 0)
return;
if(calls[callNo].state == IAXC_CALL_STATE_FREE) return;
iax_hangup(calls[callNo].session,"Dumped Call");
iaxc_usermsg(IAXC_STATUS, "Hanging up call %d", callNo);
iaxc_clear_call(callNo);
}
EXPORT void iaxc_dump_all_calls(void)
{
int callNo;
get_iaxc_lock();
for(callNo=0; callNo<nCalls; callNo++)
iaxc_dump_one_call(callNo);
put_iaxc_lock();
}
EXPORT void iaxc_dump_call(void)
{
if(selected_call >= 0) {
get_iaxc_lock();
iaxc_dump_one_call(selected_call);
put_iaxc_lock();
}
}
EXPORT void iaxc_reject_call(void)
{
if(selected_call >= 0) {
iaxc_reject_call_number(selected_call);
}
}
EXPORT void iaxc_reject_call_number( int callNo )
{
if(callNo >= 0) {
get_iaxc_lock();
iax_reject(calls[callNo].session, "Call rejected manually.");
iaxc_clear_call(callNo);
put_iaxc_lock();
}
}
EXPORT void iaxc_send_dtmf(char digit)
{
if(selected_call >= 0) {
get_iaxc_lock();
if(calls[selected_call].state & IAXC_CALL_STATE_ACTIVE)
iax_send_dtmf(calls[selected_call].session,digit);
put_iaxc_lock();
}
}
EXPORT void iaxc_send_text(char *text)
{
if(selected_call >= 0) {
get_iaxc_lock();
if(calls[selected_call].state & IAXC_CALL_STATE_ACTIVE)
iax_send_text(calls[selected_call].session, text);
put_iaxc_lock();
}
}
EXPORT void iaxc_send_url(char *url, int link)
{
if(selected_call >= 0) {
get_iaxc_lock();
if(calls[selected_call].state & IAXC_CALL_STATE_ACTIVE)
iax_send_url(calls[selected_call].session, url, link);
put_iaxc_lock();
}
}
static int iaxc_find_call_by_session(struct iax_session *session)
{
int i;
for(i=0;i<nCalls;i++)
if (calls[i].session == session)
return i;
return -1;
}
static struct iaxc_registration *iaxc_find_registration_by_session(struct iax_session *session) {
struct iaxc_registration *reg;
for (reg = registrations; reg != NULL; reg=reg->next)
if (reg->session == session) break;
return reg;
}
static void iaxc_handle_regreply(struct iax_event *e, struct iaxc_registration *reg) {
iaxc_do_registration_callback(reg->id, e->etype, e->ies.msgcount);
// XXX I think the session is no longer valid.. at least, that's
// what miniphone does, and re-using the session doesn't seem to
// work!
iax_destroy(reg->session);
reg->session = NULL;
if (e->etype == IAX_EVENT_REGREJ) {
// we were rejected, so end the registration
iaxc_remove_registration_by_id(reg->id);
}
}
/* this is what asterisk does */
static int iaxc_choose_codec(int formats) {
int i;
static int codecs[] = {
IAXC_FORMAT_ULAW,
IAXC_FORMAT_ALAW,
IAXC_FORMAT_SLINEAR,
IAXC_FORMAT_G726,
IAXC_FORMAT_ADPCM,
IAXC_FORMAT_GSM,
IAXC_FORMAT_ILBC,
IAXC_FORMAT_SPEEX,
IAXC_FORMAT_LPC10,
IAXC_FORMAT_G729A,
IAXC_FORMAT_G723_1,
};
for(i=0;i<sizeof(codecs)/sizeof(int);i++)
if(codecs[i] & formats)
return codecs[i];
return 0;
}
static void iaxc_service_network() {
struct iax_event *e = 0;
int callNo;
struct iaxc_registration *reg;
while ( (e = iax_get_event(0))) {
// first, see if this is an event for one of our calls.
callNo = iaxc_find_call_by_session(e->session);
if(callNo >= 0) {
iaxc_handle_network_event(e, callNo);
} else if((reg = iaxc_find_registration_by_session(e->session)) != NULL) {
iaxc_handle_regreply(e,reg);
} else if((e->etype == IAX_EVENT_REGACK ) || (e->etype == IAX_EVENT_REGREJ )) {
iaxc_usermsg(IAXC_ERROR, "Unexpected registration reply");
} else if(e->etype == IAX_EVENT_REGREQ ) {
iaxc_usermsg(IAXC_ERROR, "Registration requested by someone, but we don't understand!");
} else if(e->etype == IAX_EVENT_CONNECT) {
int format = 0;
callNo = iaxc_first_free_call();
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!");
goto bail;
}
/* 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");
iaxc_usermsg(IAXC_STATUS,"Codec Negotiation Error");
goto bail;
}
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);
iaxc_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);
iax_ring_announce(calls[callNo].session);
iaxc_do_state_callback(callNo);
iaxc_usermsg(IAXC_STATUS, "Incoming call on line %d", callNo);
} else if (e->etype == IAX_EVENT_TIMEOUT) {
iaxc_usermsg(IAXC_STATUS, "Timeout for a non-existant session. Dropping", e->etype);
} else {
iaxc_usermsg(IAXC_STATUS, "Event (type %d) for a non-existant session. Dropping", e->etype);
}
bail:
iax_event_free(e);
}
}
EXPORT int iaxc_audio_devices_get(struct iaxc_audio_device **devs, int *nDevs, int *input, int *output, int *ring) {
*devs = audio.devices;
*nDevs = audio.nDevices;
audio.selected_devices(&audio,input,output,ring);
return 0;
}
EXPORT int iaxc_audio_devices_set(int input, int output, int ring) {
int ret = 0;
get_iaxc_lock();
ret = audio.select_devices(&audio, input, output, ring);
put_iaxc_lock();
return ret;
}
EXPORT double iaxc_input_level_get() {
return audio.input_level_get(&audio);
}
EXPORT double iaxc_output_level_get() {
return audio.output_level_get(&audio);
}
EXPORT int iaxc_input_level_set(double level) {
return audio.input_level_set(&audio, level);
}
EXPORT int iaxc_output_level_set(double level) {
return audio.output_level_set(&audio, level);
}
EXPORT int iaxc_play_sound(struct iaxc_sound *s, int ring) {
int ret = 0;
get_iaxc_lock();
ret = audio.play_sound(s,ring);
put_iaxc_lock();
return ret;
}
EXPORT int iaxc_stop_sound(int id) {
int ret = 0;
get_iaxc_lock();
ret = audio.stop_sound(id);
put_iaxc_lock();
return ret;
}
EXPORT int iaxc_quelch(int callNo, int MOH)
{
struct iax_session *session = calls[callNo].session;
if (!session)
return -1;
return iax_quelch_moh(session, MOH);
}
EXPORT int iaxc_unquelch(int call)
{
return iax_unquelch(calls[call].session);
}
EXPORT int iaxc_mic_boost_get( void )
{
return audio.mic_boost_get( &audio ) ;
}
EXPORT int iaxc_mic_boost_set( int enable )
{
return audio.mic_boost_set( &audio, enable ) ;
}
EXPORT char* iaxc_version(char* ver)
{
strncpy(ver, LIBVER, IAXC_EVENT_BUFSIZ);
return ver;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -