esl全称Event Socket Library,通过它可以与freeswitch进行交互,执行app和api以及接收事件,esl 支持多种语言java、c\c++、golang,php等等。
esl开发支持inbound和outbound模式。
outbound模式,是FS在单个channel中创建并连接到外部tcp server服务,随着会话的结束而断开socket连接。适合控制单个会话的呼叫和语音控制;而Inbound的连接由客户端主动向FS发起连接,更适合接收所有的事件,进行自动呼叫服务。
开发注意事项:
1、outbound模式中为了避免接收不到挂机信号,可以设置linger超时时间来延时FS挂断socket连接。
2、接收事件采用队列模型把原始事件对象先入列,然后开线程处理线程中的事件对象,以避免丢掉事件。
outbound例子:
#include
#include
#include
typedef struct{
esl_handle_t *handle;
int running;
}esl_callback_t;
static void *event_thread(esl_thread_t *me, void *obj)
{
int done = 0;
time_t exp = 0;
esl_status_t status;
esl_callback_t *callback = (esl_callback_t *)obj;
esl_handle_t *handle = callback->handle;
while((status = esl_recv_timed(handle, 1000)) != ESL_FAIL) {
if (done) {
if (time(NULL) >= exp) {
esl_log(ESL_LOG_INFO, "10 seconds timeout.\n");
callback->running = 0;
break;
}
} else if (status == ESL_SUCCESS) {
const char *type = esl_event_get_header(handle->last_event, "content-type");
if (type && !strcasecmp(type, "text/disconnect-notice")) {
const char *dispo = esl_event_get_header(handle->last_event, "content-disposition");
esl_log(ESL_LOG_INFO, "Got a disconnection notice dispostion: [%s]\n", dispo ? dispo : "");
if (dispo && !strcmp(dispo, "linger")) {
done = 1;
esl_log(ESL_LOG_INFO, "Waiting 10 seconds for any remaining events.\n");
exp = time(NULL) + 10;
}
}
}
}
}
static void mycallback(esl_socket_t server_sock, esl_socket_t client_sock, struct sockaddr_in *addr, void *user_data)
{
esl_handle_t handle = {{0}};
esl_callback_t callback = {0};
esl_attach_handle(&handle, client_sock, addr);
handle.event_lock = 1;
esl_log(ESL_LOG_INFO, "Connected! %d\n", handle.sock);
esl_filter(&handle, "unique-id", esl_event_get_header(handle.info_event, "caller-unique-id"));
esl_events(&handle, ESL_EVENT_TYPE_PLAIN, "CHANNEL_ANSWER CHANNEL_HANGUP CHANNEL_HANGUP_COMPLETE DTMF");
esl_send_recv(&handle, "linger");
callback.handle = &handle;
callback.running = 1;
esl_thread_create_detached(event_thread, &callback);
esl_execute(&handle, "answer", NULL, NULL);
esl_execute(&handle, "playback", "/home/test.wav", NULL);
esl_execute(&handle, "sleep", "1000", NULL);
esl_execute(&handle, "hangup", NULL, NULL);
while(handle.connected && callback.running){
usleep(10000);
}
esl_log(ESL_LOG_INFO, "Disconnected! %d\n", handle.sock);
esl_disconnect(&handle);
}
int main(void)
{
esl_global_set_default_logger(7);
esl_listen_threaded("localhost", 8040, mycallback, NULL, 100000);
return 0;
}
inbound例子:
#include
#include
#include
int main(void)
{
esl_handle_t handle = {{0}};
esl_connect(&handle, "localhost", 8021, NULL, "ClueCon");
esl_send_recv(&handle, "api status\n\n");
if (handle.last_sr_event && handle.last_sr_event->body) {
printf("%s\n", handle.last_sr_event->body);
} else {
// this is unlikely to happen with api or bgapi (which is hardcoded above) but prefix but may be true for other commands
printf("%s\n", handle.last_sr_reply);
}
esl_disconnect(&handle);
return 0;
}
欢迎加入Freeswitch QQ群640880657一起研究讨论。