blob: 92c19cf2ad90c723927c4cc2b1807a3356d44417 [file] [log] [blame]
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/stat.h>
//#include "mbtk_log.h"
//#include "mbtk_utils.h"
// #include "audio_if_api.h"
//#include "mbtk_audio2.h"
#define RTP_UDP_SER_PORT_DEFAULT 53248
#define RTP_UDP_CLI_PORT_DEFAULT 55555
#define BUFF_SIZE 4096
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
#define FORMAT_PCM 1
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef UNUSED
#define UNUSED(a) (void)(a)
#endif
typedef unsigned int uint32; /* Unsigned 32 bit value */
struct riff_wave_header {
unsigned int riff_id;
unsigned int riff_sz;
unsigned int wave_id;
};
struct chunk_header {
unsigned int id;
unsigned int sz;
};
struct chunk_fmt {
unsigned short audio_format;
unsigned short num_channels;
unsigned int sample_rate;
unsigned int byte_rate;
unsigned short block_align;
unsigned short bits_per_sample;
};
struct wav_header {
unsigned int riff_id;
unsigned int riff_sz;
unsigned int riff_fmt;
unsigned int fmt_id;
unsigned int fmt_sz;
unsigned short audio_format;
unsigned short num_channels;
unsigned int sample_rate;
unsigned int byte_rate;
unsigned short block_align;
unsigned short bits_per_sample;
unsigned int data_id;
unsigned int data_sz;
};
#define PCM_WB_BUF_SIZE 640
#define PCM_NARROW_BUF_SIZE 320
static int record_fd = -1;
static int send_fd = -1;
static bool running = FALSE;
static void voip_playback_run(void *arg)
{
int rc, len, fd, frames = 0;
int pack_size = 320;
//char buf[MBTK_PCM_WB_BUF_SIZE];
char buf[BUFF_SIZE];
char *path = "/data/voip_playback.wav";
struct stat st;
struct riff_wave_header riff_wave_header;
struct chunk_header chunk_header;
struct chunk_fmt chunk_fmt = {0};
unsigned int more_chunks = 1;
uint32 header[4];
if(send_fd < 0) {
printf("Client socket not open.");
return;
}
/* Check and open source file */
if (access(path, F_OK) || stat(path, &st)) {
printf("%s: error reading from file %s\n", __FUNCTION__, path);
return;
}
if (!st.st_size) {
printf("%s: empty file %s\n", __FUNCTION__, path);
return;
}
fd = open(path, O_RDONLY);
if (fd < 0) {
printf("%s: error opening file %s\n", __FUNCTION__, path);
return;
}
lseek(fd, sizeof(struct wav_header), SEEK_SET);
uint32 sequence = 1;
uint32 timestamp = 0;
while (running) {
/* Playback loop */
memset(buf, 0x00, sizeof(buf));
len = read(fd, buf + 16, pack_size);
if (len == -1) {
printf("%s: error reading from file\n", __FUNCTION__);
break;
}
if (len == 0) {
/* reached EOF */
printf("%s: nothing to read\n", __FUNCTION__);
break;
}
header[0] = htonl(((uint32_t) 2 << 30) | ((uint32_t) 1 << 24) | ((uint32_t) 0x60 << 16) | ((uint32_t) sequence));
header[1] = htonl(timestamp);
header[2] = htonl(0xFFFF0000);
header[3] = htonl(0xFFFF0000);
memcpy(buf, &header, sizeof(header));
if((rc = sendto(send_fd, buf, len + 16, 0, NULL, 0)) < len + 16) {
printf("Send data fail: %d/%d\n", rc, len);
break;
} else {
printf("SEND : %d / %d\n", rc, len);
}
sequence++;
timestamp += len / 2;
++frames;
//printf("%s: No.%d frame playback[len - %d]\n", __FUNCTION__, ++frames, len);
usleep(21000);
}
printf("playback_thread exit.\n");
}
static void sig_handler(int sig)
{
running = FALSE;
printf("Success exit by signal...\n");
sleep(1);
exit(0);
}
static int rtp_udp_ser_open(const char *local_addr, int local_port)
{
// No set local addr.
UNUSED(local_addr);
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0){
printf("socket() fail.[%d]\n", errno);
return -1;
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(local_port);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(fd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) < 0) {
printf("bind() failed: %d\n", errno);
goto result_fail_with_close;
}
return fd;
result_fail_with_close:
close(fd);
fd = -1;
printf("mbtk_sock_open() end:fail\n");
return -1;
}
static int rtp_udp_cli_open(const char *remote_addr, int remote_port)
{
struct sockaddr_in dst_sa4, src_sa4;
if (inet_pton(AF_INET, "0.0.0.0", &src_sa4.sin_addr) > 0) {
src_sa4.sin_family = AF_INET;
src_sa4.sin_port = htons(0);
memset(&src_sa4.sin_zero, 0, sizeof(src_sa4.sin_zero));
} else {
printf("Set src addr fail.\n");
return -1;
}
if (inet_pton(AF_INET, remote_addr, &dst_sa4.sin_addr) > 0) {
dst_sa4.sin_family = AF_INET;
dst_sa4.sin_port = htons(remote_port);
memset(&dst_sa4.sin_zero, 0, sizeof(dst_sa4.sin_zero));
} else {
printf("Set dst addr fail.\n");
return -1;
}
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0){
printf("socket() fail.[%d]\n", errno);
return -1;
}
if (bind(fd, (struct sockaddr*) &src_sa4, sizeof(src_sa4)) < 0) {
printf("bind() failed: %d\n", errno);
goto result_fail_with_close;
}
if (connect(fd, (struct sockaddr*) &dst_sa4, sizeof(dst_sa4)) < 0) {
printf("connect() failed: %d\n", errno);
goto result_fail_with_close;
}
#if 0
if(socket_noblock(fd)) {
goto result_fail_with_close;
}
#endif
return fd;
result_fail_with_close:
close(fd);
fd = -1;
printf("mbtk_sock_open() end:fail\n");
return -1;
}
int main(int argc, char *argv[])
{
if(argc != 2) {
printf("mbtk_rtp_udp_cli <IP>\n");
return -1;
}
// mbtk_log_init("radio", "RTP_TEST");
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);
int ser_fd = rtp_udp_ser_open(NULL, RTP_UDP_SER_PORT_DEFAULT);
if(ser_fd < 0) {
printf("rtp_udp_ser_open() fail.\n");
return -1;
}
send_fd = rtp_udp_cli_open(argv[1], RTP_UDP_CLI_PORT_DEFAULT);
if(send_fd < 0) {
printf("rtp_udp_cli_open() fail.\n");
// return -1;
}
struct wav_header header;
int rc = 0;
char *path = "/data/voip_record.wav";
header.riff_id = ID_RIFF;
header.riff_sz = 0;
header.riff_fmt = ID_WAVE;
header.fmt_id = ID_FMT;
header.fmt_sz = 16;
header.audio_format = 1; //FORMAT_PCM;
header.num_channels = 1; //Modem ONLY support mono recording
header.sample_rate = 8000;
header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
header.byte_rate = (header.bits_per_sample / 8) * header.num_channels * header.sample_rate;
header.block_align = header.num_channels * (header.bits_per_sample / 8);
header.data_id = ID_DATA;
record_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (record_fd < 0) {
printf("%s: error opening file %s!\n", __FUNCTION__, path);
return -1;
}
lseek(record_fd, 0, SEEK_SET);
write(record_fd, &header, sizeof(struct wav_header));
//leave enough room for header
lseek(record_fd, sizeof(struct wav_header), SEEK_SET);
char buff[2048];
int len_recv;
int len_send;
running = TRUE;
bool is_first = TRUE;
while(running) {
len_recv = recvfrom(ser_fd, buff, sizeof(buff), 0, NULL, NULL);
if(len_recv < 0) {
printf("recvfrom() ret is %d,errno - %d\n", len_recv, errno);
continue;
} else if(len_recv == 0) {
printf("ret is 0\n");
} else if(len_recv > 16){
printf("RECV:len - %d\n", len_recv);
write(record_fd, buff + 16, len_recv - 16);
if(is_first) {
pthread_t playabck_thread/*, record_thread*/;
rc = pthread_create(&playabck_thread, NULL, (void *)&voip_playback_run, NULL);
if (rc < 0) {
printf("error creating thread_start!");
break;
}
is_first = FALSE;
}
#if 0
if(cli_fd < 0) {
cli_fd = rtp_udp_cli_open(argv[1], RTP_UDP_CLI_PORT_DEFAULT);
if(cli_fd < 0) {
printf("rtp_udp_cli_open() fail.\n");
// return -1;
} else {
printf("rtp_udp_cli_open() success.\n");
}
}
if(cli_fd > 0) {
len_send = sendto(cli_fd, buff, len_recv, 0, NULL, 0);
printf("SEND : %d / %d\n", len_send, len_recv);
}
#endif
} else {
printf("RTP Header error.\n");
}
}
close(record_fd);
close(ser_fd);
return 0;
}