| #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; |
| } |
| |
| |