#include #include #include #include #include #include #include #include struct IOMux *mux; #define errx(x, ...) do { fprintf(stderr, x, __VA_ARGS__); exit(1); } while(0) struct RTPSender { FILE *file; char remote_ip[48]; uint16_t remote_port; struct UCTimer timer; uint32_t ts; struct timespec last_ts; RtpSession *rtp_sess; RtpProfile *rtp_profile; int accum_diff; uint8_t frame[160]; }; //returns microsec int diffts(const struct timespec *a, struct timespec *b) { struct timespec diff; diff.tv_sec = b->tv_sec - a->tv_sec; diff.tv_nsec = b->tv_nsec - a->tv_nsec; if (diff.tv_nsec < 0) { diff.tv_sec--; diff.tv_nsec += 1000000000; } return (int) (diff.tv_sec * 1000 + (diff.tv_nsec + 500)/1000); } void timer_cb(struct UCTimers *timers, struct UCTimer *timer) { struct RTPSender *s = CONTAINER_OF(timer, struct RTPSender, timer); int rc; ssize_t r; struct timespec ts; int diff; int adjust; clock_gettime(CLOCK_MONOTONIC, &ts); rc = rtp_session_send_with_ts(s->rtp_sess,s->frame, sizeof s->frame, s->ts); if(rc < sizeof s->frame) { printf("Error, short send of %d bytes\n", rc); } s->ts += 160; r = fread(s->frame,1, sizeof s->frame, s->file); if (r <= 0) { rtp_session_bye(s->rtp_sess, "Finished"); return; } diff = diffts(&s->last_ts, &ts); diff -= 20000; s->accum_diff += diff; if (s->accum_diff > 500) adjust = -1000; else if (s->accum_diff < -500) adjust = 1000; else adjust = s->accum_diff; if (s->accum_diff >= 20000 || s->accum_diff <= -20000) { s->ts += 160; printf("Skew ! accum_diff %d\n", s->accum_diff); s->accum_diff -= 20000; } uc_timers_add(iomux_get_timers(mux), &s->timer, 0, 20 * 1000 + adjust); s->last_ts = ts; } void init_sender(FILE* file, const char *remote_ip, uint16_t remote_port) { struct RTPSender *s = calloc(1, sizeof *s); RtpSession *rtp_sess = rtp_session_new(RTP_SESSION_SENDONLY); RtpProfile *rtp_prof = rtp_profile_new("pcmu8000"); rtp_profile_set_payload(rtp_prof, 0, &payload_type_pcmu8000); rtp_session_set_profile(rtp_sess, rtp_prof); //rtp_session_set_local_addr("192.168.1.55", 0); rtp_session_set_remote_addr(rtp_sess, remote_ip, remote_port); rtp_session_set_blocking_mode(rtp_sess, FALSE); s->file = file; strcpy(s->remote_ip, remote_ip); s->remote_port = remote_port; s->rtp_sess = rtp_sess; s->rtp_profile = rtp_prof; s->timer.callback = timer_cb; clock_gettime(CLOCK_MONOTONIC, &s->last_ts); uc_timers_add(iomux_get_timers(mux), &s->timer, 0, 20000); } int main(int argc, char *argv[]) { mux = iomux_create(IOMUX_TYPE_DEFAULT); FILE *file; if(argc != 4) { puts("Specify a file name, remote IP and remote port"); return 1; } if(strcmp(argv[1], "-") == 0) { file = stdin; } else { file = fopen(argv[1], "rb"); if(file == NULL) { perror("Cannot open file"); return 1; } } ortp_init(); ortp_set_log_level_mask(ORTP_DEBUG| ORTP_MESSAGE| ORTP_WARNING| ORTP_ERROR|ORTP_FATAL); init_sender(file ,argv[2], atoi(argv[3])); iomux_run(mux); fclose(file); ortp_exit(); return 0; } //compile: // gcc -Wall -g -O `pkg-config --cflags --libs ortp` ortp-send-simple.c