FreeCalypso > hg > sipout-test-utils
view test-voice/rtp_tx.c @ 17:830af7de3403
sipout-test-voice: disallow empty files for play command
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 13 May 2024 22:31:24 -0800 |
parents | 71f01a834820 |
children |
line wrap: on
line source
/* * In this module we implement outgoing RTP stream generation. */ #include <sys/types.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <unistd.h> #include "../include/tmgw_const.h" #include "../include/rtp_defs.h" #include "../libutil/osmo_bits.h" extern struct sockaddr_in rtp_local_addr, rtp_remote_addr; extern int rtp_udp_fd, rtcp_udp_fd, pcma_selected; extern struct timeval cur_event_time; static const uint8_t dmw_alaw[8] = {0x34, 0x21, 0x21, 0x34, 0xB4, 0xA1, 0xA1, 0xB4}; static const uint8_t dmw_ulaw[8] = {0x1E, 0x0B, 0x0B, 0x1E, 0x9E, 0x8B, 0x8B, 0x9E}; static uint32_t rtp_ssrc; static uint32_t rtp_out_ts; static uint16_t rtp_out_seq; static uint8_t pcm_fill_octet; static int dmw_active; static uint8_t *play_buffer; static unsigned play_buf_nframes, play_buf_ptr; static int play_loop; static uint16_t tfo_fill_buf[9], tfo_req_buf[7]; static uint16_t *is_out_ptr; static unsigned is_out_count; static int tfo_stop_req; void assign_rtpout_ssrc() { rtp_ssrc = cur_event_time.tv_sec ^ cur_event_time.tv_usec ^ getpid(); } void init_pcm_fill_octet() { if (pcma_selected) pcm_fill_octet = 0xD5; else pcm_fill_octet = 0xFF; } void prepare_tfo_fill() { tfo_fill_buf[0] = 0x15A; tfo_fill_buf[1] = 0x1A9; tfo_fill_buf[2] = 0x129; tfo_fill_buf[3] = 0x15A; tfo_fill_buf[4] = 0x1A9; tfo_fill_buf[5] = 0x129; tfo_fill_buf[6] = 0x15A; tfo_fill_buf[7] = 0x1A9; tfo_fill_buf[8] = 0x129; } static void insert_is_msg(payload, word) uint8_t *payload; uint16_t word; { ubit_t is_bits[10]; uint8_t *bytep; unsigned n; uint16_to_bits(word, is_bits, 10); for (n = 0; n < 10; n++) { bytep = payload + n * 16; *bytep &= 0xFE; *bytep |= is_bits[n]; } } static void fill_with_dmw(buf) uint8_t *buf; { const uint8_t *src; unsigned n; if (pcma_selected) src = dmw_alaw; else src = dmw_ulaw; for (n = 0; n < 20; n++) { memcpy(buf, src, 8); buf += 8; } } static void fill_with_play(outbuf) uint8_t *outbuf; { memcpy(outbuf, play_buffer + play_buf_ptr * 160, 160); play_buf_ptr++; if (play_buf_ptr < play_buf_nframes) return; if (play_loop) play_buf_ptr = 0; else { free(play_buffer); play_buffer = 0; printf("file play finished\n"); } } void generate_rtp_packet() { struct rtp_packet pkt; socklen_t addrlen; pkt.v_p_x_cc = 0x80; pkt.m_pt = pcma_selected ? PSTN_CODEC_PCMA : PSTN_CODEC_PCMU; pkt.seq = htons(rtp_out_seq++); pkt.tstamp = htonl(rtp_out_ts); rtp_out_ts += 160; pkt.ssrc = rtp_ssrc; if (play_buffer) fill_with_play(pkt.payload); else if (dmw_active) fill_with_dmw(pkt.payload); else memset(pkt.payload, pcm_fill_octet, RTP_MAX_PAYLOAD); if (is_out_count) { insert_is_msg(pkt.payload, *is_out_ptr++); is_out_count--; if (!is_out_count && !tfo_stop_req) { is_out_ptr = tfo_req_buf; is_out_count = 7; } } addrlen = sizeof(struct sockaddr_in); sendto(rtp_udp_fd, &pkt, RTP_PACKET_SIZE_PSTN, 0, (struct sockaddr *) &rtp_remote_addr, addrlen); } void set_pcm_fill_octet(oct) unsigned oct; { pcm_fill_octet = oct; } void send_tfo_req(sig, codec) unsigned sig, codec; { tfo_req_buf[0] = 0x15A; tfo_req_buf[1] = 0x1A9; tfo_req_buf[2] = 0x05D; tfo_req_buf[3] = 0x14E; tfo_req_buf[4] = 0x14B; encode_tfo_ext_words(sig, codec, 0, tfo_req_buf + 5); is_out_ptr = tfo_fill_buf; is_out_count = 9; tfo_stop_req = 0; } void stop_tfo_out() { tfo_stop_req = 1; } void cmd_dmw_on() { dmw_active = 1; } void cmd_dmw_off() { dmw_active = 0; } void play_file_cmdop(filename, loop) char *filename; { int fd; struct stat st; if (play_buffer) { fprintf(stderr, "error: file play already in progress\n"); return; } fd = open(filename, O_RDONLY); if (fd < 0) { perror(filename); return; } fstat(fd, &st); if (!S_ISREG(st.st_mode)) { close(fd); fprintf(stderr, "error: %s is not a regular file\n", filename); return; } if (!st.st_size) { close(fd); fprintf(stderr, "error: %s is an empty file\n", filename); return; } if (st.st_size % 160) { close(fd); fprintf(stderr, "error: size of %s is not a multiple of 160 bytes\n", filename); return; } play_buffer = malloc(st.st_size); if (!play_buffer) { close(fd); fprintf(stderr, "unable to malloc buffer for %s\n", filename); return; } read(fd, play_buffer, st.st_size); close(fd); play_buf_nframes = st.st_size / 160; play_buf_ptr = 0; play_loop = loop; } void play_file_offset(filename, offset) char *filename; unsigned offset; { int fd; struct stat st; unsigned pre_offset; if (play_buffer) { fprintf(stderr, "error: file play already in progress\n"); return; } fd = open(filename, O_RDONLY); if (fd < 0) { perror(filename); return; } fstat(fd, &st); if (!S_ISREG(st.st_mode)) { close(fd); fprintf(stderr, "error: %s is not a regular file\n", filename); return; } if (!st.st_size) { close(fd); fprintf(stderr, "error: %s is an empty file\n", filename); return; } if (st.st_size % 160) { close(fd); fprintf(stderr, "error: size of %s is not a multiple of 160 bytes\n", filename); return; } play_buffer = malloc(st.st_size + 160); if (!play_buffer) { close(fd); fprintf(stderr, "unable to malloc buffer for %s\n", filename); return; } pre_offset = 160 - offset; memset(play_buffer, pcm_fill_octet, pre_offset); read(fd, play_buffer + pre_offset, st.st_size); close(fd); memset(play_buffer + pre_offset + st.st_size, pcm_fill_octet, offset); play_buf_nframes = st.st_size / 160 + 1; play_buf_ptr = 0; play_loop = 0; } void play_file_stop() { if (!play_buffer) return; free(play_buffer); play_buffer = 0; }