c语言实现UDP-server将freeswitch媒体流传输到其他服务02

上一节,我们重点讲解了开发此服务架构和功能,已经freeswitch自定义application对应的方法。这一节,我们将重点介绍freeswitch自定义旁路输出media bug后,如何定义UDP服务,如何进行项目服务绑定。

我们先来看看C语言实现UDPserver

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(void){
    int socket_desc;
    struct sockaddr_in server_addr, client_addr;
    char server_message[2000], client_message[2000];
    int client_struct_length = sizeof(client_addr);
    
    // Clean buffers:
    memset(server_message, '\0', sizeof(server_message));
    memset(client_message, '\0', sizeof(client_message));
    
    // Create UDP socket:
    socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    
    if(socket_desc < 0){
        printf("Error while creating socket\n");
        return -1;
    }
    printf("Socket created successfully\n");
    
    // Set port and IP:
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(2000);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
    // Bind to the set port and IP:
    if(bind(socket_desc, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){
        printf("Couldn't bind to the port\n");
        return -1;
    }
    printf("Done with binding\n");
    
    printf("Listening for incoming messages...\n\n");
    
    // Receive client's message:
    if (recvfrom(socket_desc, client_message, sizeof(client_message), 0,
         (struct sockaddr*)&client_addr, &client_struct_length) < 0){
        printf("Couldn't receive\n");
        return -1;
    }
    printf("Received message from IP: %s and port: %i\n",
           inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
    
    printf("Msg from client: %s\n", client_message);
    
    // Respond to client:
    strcpy(server_message, client_message);
    
    if (sendto(socket_desc, server_message, strlen(server_message), 0,
         (struct sockaddr*)&client_addr, client_struct_length) < 0){
        printf("Can't send\n");
        return -1;
    }
    
    // Close the socket:
    close(socket_desc);
    
    return 0;
}

用c实现一个UDPclient

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int main(void){
    int socket_desc;
    struct sockaddr_in server_addr;
    char server_message[2000], client_message[2000];
    int server_struct_length = sizeof(server_addr);
    
    // Clean buffers:
    memset(server_message, '\0', sizeof(server_message));
    memset(client_message, '\0', sizeof(client_message));
    
    // Create socket:
    socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    
    if(socket_desc < 0){
        printf("Error while creating socket\n");
        return -1;
    }
    printf("Socket created successfully\n");
    
    // Set port and IP:
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(2000);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    
    // Get input from the user:
    printf("Enter message: ");
    gets(client_message);
    
    // Send the message to server:
    if(sendto(socket_desc, client_message, strlen(client_message), 0,
         (struct sockaddr*)&server_addr, server_struct_length) < 0){
        printf("Unable to send message\n");
        return -1;
    }
    
    // Receive the server's response:
    if(recvfrom(socket_desc, server_message, sizeof(server_message), 0,
         (struct sockaddr*)&server_addr, &server_struct_length) < 0){
        printf("Error while receiving server's msg\n");
        return -1;
    }
    
    printf("Server's response: %s\n", server_message);
    
    // Close the socket:
    close(socket_desc);
    
    return 0;
}

使用gcc 编译后,即可执行查看

稍微讲解一下:

int socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

创建socket,返回一个文件描述符

然后初始化server

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(2000);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

然后将socket 描述符和 server addr进行绑定

bind(socket_desc, (struct sockaddr*)&server_addr, sizeof(server_addr);

C语言实现UDPserver 是如此简单。

那我们需要当前Server启动时候的配置信息,比如server 的端口,绑定地址等。 因此需要我们在freeswitch 此app load时候,将这些信息进行初始化

CUSTOM event type

#define YOURAPP_EVENT_UDP "robot::udp"

定义你配置文件地址

#define app_config "/usr/local/freeswitch/conf/your_app.conf"

SWITCH_MODULE_LOAD_FUNCTION(mod_app_load)
{
	switch_application_interface_t *app_interface;

	
     /* connect my internal structure to the blank pointer passed to me */
	*module_interface = switch_loadable_module_create_module_interface(pool, modname);

	SWITCH_ADD_APP(app_interface, "your_app", "your_app", "ai your_app", your_start_function, "[name]", SAF_NONE);
	/* indicate that the module should continue to be loaded */
	return SWITCH_STATUS_SUCCESS;
}
 

定义配置文件读取方法

int get_config__yxp_string(const char*set,const char*cmd,const char*def,char*res,int para_len,const char*filename)
{
	
} 

接下来就是最关键的 SWITCH_STANDARD_APP

SWITCH_STANDARD_APP(robot_start_function)
{
	switch_media_bug_t *bug;
	switch_status_t status;
	switch_channel_t *channel;
	your_session_info_t *robot_info;  // 自定义一个结构体

	
       // 定义 
	status = switch_core_media_bug_add(session, "yourmod", NULL, your_app_callback, robot_info, 0, SMBF_READ_REPLACE, &bug);

	
}

接下来就是 your_app_callback 收到media bug回调后,将数据使用UDP server 传输出去

static switch_bool_t yourcode_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
	your_session_info_t *robot_info;

	switch_frame_t *frame;

	robot_info = (your_session_info_t *) user_data;
	if (robot_info == NULL) {
		return SWITCH_FALSE;
	}

	switch (type) {

	case SWITCH_ABC_TYPE_INIT:
		break;

	case SWITCH_ABC_TYPE_READ_REPLACE:
		if(robot_info->uuid[0]==0) break;
		frame = switch_core_media_bug_get_read_replace_frame(bug);
		process_your_code();
		break;
	
	case SWITCH_ABC_TYPE_CLOSE:
		process_yourcode_close();
		break;
	default:
		break;
	}

	return SWITCH_TRUE;
}

处理frame数据

static switch_bool_t process_data(your_session_info_t *rh, switch_frame_t *frame,switch_media_bug_t*bug)
{

		UDPSend();

		return 	SWITCH_TRUE;
}

这样基本的流程完成了,我们需要完成当服务close,等释放内存、关闭socket等操作。

由此从freeswitch的媒体流,我们进行了转移到我们所熟悉的开发语言上,进行二次高级开发。

接下来就是我们之前讲过的使用freeswitch进行ESL连接,曾经我们处理event record的操作类似,不过我们这里需要使用ESL进行command。

当时候netty处理的流被ASR实时语音转写,再将结果实时送至 智能问答引擎(或者简单规则),我们将问答引擎返回的结果,使用ESL进行command处理。

既然是智能视频IVR,我们可以预先定义好多个视频+路由规则。当用户的话语触发了问答引擎的结果,一一对应至视频的路由。 由此视频IVR从传统按键,转化为通过识别声音而进行智能转发。

下面的我将继续,实现netty接收UDP数据后,如何进行实时语音识别,如何和问答引擎(或智能引擎进行对接),如何提升反应速度等。 (周末结束,繁忙的工作又开始是,加油!!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值