📄 rtone.c
字号:
#include "assert.h"#include "ratconf.h"#include "config_unix.h"#include "config_win32.h"#include "audio_types.h"#include "sndfile.h"#include "codec.h"#include "rtp.h"#include "util.h"#include <math.h>#include <stdlib.h>#ifndef UNUSED#define UNUSED(x) x = x#endif/* This program is a BIG KLUDGE that acts as an RTP audio source. It will: * * - encode a tone or audio file (-f) and transmit it. * - add jitter to departure times (-j <jitter_ms>). * - modulate transmission with pseudo-voice modulation (-b). *//* ------------------------------------------------------------------------- *//* Outgoing packet buffering for jitter */struct pkt { uint32_t depart_ts; uint32_t rtp_ts; uint8_t pt; int m; void *data; int32_t data_len; struct pkt *next;};static struct pkt pkt_queue;static voidpkt_queue_init() { pkt_queue.next = &pkt_queue;}static void pkt_queue_add(uint32_t rtp_ts, uint8_t pt, int marker, void *data, int32_t data_len) { struct pkt *p, **c, *sentinel; p = (struct pkt *)xmalloc(sizeof(*p)); p->rtp_ts = rtp_ts; p->pt = pt; p->m = marker; p->data = data; p->data_len = data_len; sentinel = &pkt_queue; c = &sentinel->next; while (*c != sentinel && (*c)->rtp_ts < rtp_ts) { c = &((*c)->next); } p->next = *c; *c = p;}static voidpkt_queue_send(struct rtp *session, uint32_t now) { struct pkt *sentinel, **c, *n; struct timeval tv; sentinel = &pkt_queue; c = &sentinel->next; while (*c != sentinel && (*c)->rtp_ts <= now) { n = *c; *c = n->next; gettimeofday(&tv, NULL); rtp_send_data(session, n->rtp_ts, n->pt, n->m, 0, 0, n->data, n->data_len, NULL, 0, 0); xfree(n->data); xfree(n); }}/* speed is the fraction we are faster than the system clock *//* all us to spoof larger clock drifts for debugging playout *//* adjustment tweaks. */static double speed = 1.0;/* gettime returns a timeval which is relative to first call *//* and scaled by clock rate. */static void gettime(struct timeval *tv) { static struct timeval s; double sec, usec, m; gettimeofday(tv, NULL); if (s.tv_sec == 0) { s.tv_sec = tv->tv_sec; s.tv_usec = tv->tv_usec; } sec = (double)(tv->tv_sec - s.tv_sec); usec = (double)(tv->tv_usec - s.tv_usec); if (usec < 0) { usec += 1e6; sec -= 1; } sec *= speed; usec *= speed; m = fmod(sec, 1.0); sec -= m; usec += 1e6 * m; if (usec > 1e6) { m = fmod(usec,1e6); sec += (usec - m) / 1e6; usec = m; } m = fmod(sec, 1.0); sec -= m; usec += 1e6 * m; tv->tv_sec = (long)sec; tv->tv_usec = (long)usec;}static voidtv_bound (struct timeval *t) { while (t->tv_usec > 1000000) { t->tv_usec -= 1000000; t->tv_sec += 1; } while (t->tv_usec < 0) { t->tv_usec += 1000000; t->tv_sec -= 1; }}static void tv_diff(struct timeval *delta, struct timeval *a, struct timeval *b){ assert(a->tv_sec >= b->tv_sec); assert(a->tv_usec <= 1000000); assert(b->tv_usec <= 1000000); delta->tv_sec = a->tv_sec - b->tv_sec; delta->tv_usec = a->tv_usec - b->tv_usec; tv_bound(delta); assert(delta->tv_sec >= 0);}static void usage(){ fprintf(stderr, "\rtone [-c <codec>] [-f freq] [-g gain] [-l] [-s sp] [-t ttl] [-u <upp>] addr/portwhere:\t-c selects the codec used.\t-f sets the tone frequency.\t-F <filename> stream file.\t-g sets the gain (0-32767).\t-j <jitter> set jitter in ms.\t-l lists available codecs.\t-s sets the speed relative to real time (>1.0 == faster).\t-S set rtp SSRC.\t-t sets ttl.\t-u sets units per packet.\n"); exit(-1);}static void list_codecs(){ const codec_format_t *cf; codec_id_t cid; uint32_t i, n; fprintf(stderr, "Available Codecs:\n"); n = codec_get_number_of_codecs(); for(i = 0; i < n; i++) { cid = codec_get_codec_number(i); cf = codec_get_format(cid); fprintf(stderr, "\t%s\n", cf->long_name); }} static void tone_gen (sample *buffer, int samples, int tone_gain, int tone_rate, int sample_rate, int channels){ static int t = 0; int i; if (channels == 1) { for(i = 0; i < samples; i++) { double f = (double)tone_gain * sin(2 * M_PI * t * tone_rate / (double)sample_rate); buffer[i] = (sample)f; t++; } } else if (channels == 2) { for(i = 0; i < samples; i++) { double f = (double)tone_gain * sin(2 * M_PI * t * tone_rate / (double)sample_rate); buffer[2 * i] = (sample)f; buffer[2 * i + 1] = (sample)f; t++; } }}static voidrtp_callback(struct rtp *session, rtp_event *e){ UNUSED(session); if (e->type == RX_RTP) { xfree(e->data); } return;}int main(int argc, char* argv[]){ const codec_format_t *cf; codec_id_t cid; struct timeval last, now, delta, pause, wakeup; struct s_sndfile *sf = NULL; int ac, gain = 5000, freq = 400, ttl = 8, upp = 2, i, ulen, done, file_mode = 0, bursty = 0, sleeping = 0, m = 1; int duration = -1, duration_step = 0; long int packet_us, avail_us, jitter_ms = 0; codec_state *cs; coded_unit *in; coded_unit *out; uint32_t ts, timeout, my_ssrc, set_ssrc = 0; char *u, *addr = NULL, *port = NULL, pt; struct rtp *session; ac = 1; codec_init(); cid = codec_get_by_name("pcmu-8k-mono"); pkt_queue_init(); while((ac + 1) < argc && argv[ac][0] == '-') { switch(argv[ac][1]) { case 'b': bursty = 1; break; case 'c': cid = codec_get_by_name(argv[++ac]); if (codec_id_is_valid(cid) == FALSE) { fprintf(stderr, "Codec %s is not one of:\n", argv[ac]); list_codecs(); exit(-1); } break; case 'd': duration = atoi(argv[++ac]); duration_step = 1; break; case 'f': freq = atoi(argv[++ac]); break; case 'F': if (snd_read_open(&sf, argv[++ac], NULL)) { fprintf(stderr, "Could not open %s\n", argv[ac]); } file_mode = 1; break; case 'g': gain = atoi(argv[++ac]); break; case 'j': jitter_ms = atoi(argv[++ac]); break; case 'l': list_codecs(); exit(-1); break; case 's': speed = atof(argv[++ac]); break; case 'S': my_ssrc = strtoul(argv[++ac], NULL, 10); set_ssrc = 1; break; case 't': ttl = atoi(argv[++ac]); break; case 'u': upp = atoi(argv[++ac]); break; } ac++; } if (ac != argc - 1) { usage(); } addr = strtok(argv[ac], "/"); port = strtok(NULL, "/"); if (addr == NULL || port == NULL) { usage(); } session = rtp_init(addr, atoi(port), atoi(port), ttl, 64000, rtp_callback, NULL); if (session == NULL) { fprintf(stderr, "Failed with -t %d %s/%s\n", ttl, addr, port); exit(-1); } if (set_ssrc) { rtp_set_my_ssrc(session, my_ssrc); printf("Setting my_ssrc 0x%08x\n", my_ssrc); } cf = codec_get_format(cid); pt = codec_get_payload(cid); packet_us = 1000000 * upp * cf->format.bytes_per_block / (cf->format.channels * cf->format.sample_rate * (cf->format.bits_per_sample / 8)); printf("%s port %s ttl %d\n", addr, port, ttl); printf("Codec: %s %d units per packetTone freq: %d gain: %d (%f dBov)Packets every %ld us\n", cf->long_name, upp, freq, gain, -20 * log(32767.0/(double)gain), packet_us); printf("Speed %.2f real-time.\n", speed); codec_encoder_create(cid, &cs); in = (coded_unit*)calloc(1, sizeof(coded_unit)); out = (coded_unit*)calloc(upp, sizeof(coded_unit)); in->id = codec_get_native_coding(cf->format.sample_rate, cf->format.channels); in->data = (u_char*)malloc(cf->format.bytes_per_block); in->data_len = cf->format.bytes_per_block; gettime(&last); srand48(last.tv_usec); avail_us = 0; while(duration != 0) { gettime(&now); if (bursty && drand48() < 0.005) { sleeping = 1; wakeup = now; wakeup.tv_usec += lrand48() % 10000000; wakeup.tv_sec += (wakeup.tv_usec / 1000000); wakeup.tv_usec %= 1000000; } if (sleeping) { if (now.tv_sec > wakeup.tv_sec || ((now.tv_sec == wakeup.tv_sec) && (now.tv_usec > wakeup.tv_usec))) { sleeping = 0; m = 1; } } tv_diff(&delta, &now, &last); avail_us += delta.tv_usec + 1000000 * delta.tv_sec; while(avail_us > packet_us) { ulen = 0; for(i = 0; i < upp; i++) { tone_gen((sample*)in->data, in->data_len / (sizeof(sample) * cf->format.channels), gain, freq, cf->format.sample_rate, cf->format.channels); if (sf) { snd_read_audio(&sf, (sample*)in->data, in->data_len / (sizeof(sample) * cf->format.channels)); } memset(&out[i], 0, sizeof(coded_unit)); codec_encode(cs, in, &out[i]); ulen += out[i].data_len; ts += in->data_len / (sizeof(sample) * cf->format.channels); } ulen += out[0].state_len; u = (char*)xmalloc(ulen); done = 0; for(i = 0; i < upp; i++) { if (i == 0 && out[i].state_len) { memcpy(u, out[i].state, out[i].state_len); done += out[i].state_len; block_free(out[i].state, out[i].state_len); } memcpy(u + done, out[i].data, out[i].data_len); done += out[i].data_len; block_free(out[i].data, out[i].data_len); } timeout = jitter_ms * cf->format.sample_rate / 1000; if (sleeping == 0) { pkt_queue_add(ts + timeout, pt, m, u, ulen); } timeout = (uint32_t)(timeout * drand48()); pkt_queue_send(session, ts + timeout); avail_us -= packet_us; m = 0; } pause.tv_sec = 0; pause.tv_usec = 20000; rtp_recv(session, &pause, ts); rtp_send_ctrl(session, ts, NULL); rtp_update(session); last = now; if (file_mode && sf == NULL) { break; } duration -= duration_step; } free(in); free(out); rtp_done(session); codec_encoder_destroy(&cs); codec_exit(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -