147 lines
3.5 KiB
C
147 lines
3.5 KiB
C
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ortp/ortp.h>
|
|
#include <ucore/iomux.h>
|
|
#include <ucore/utils.h>
|
|
#include <ucore/string.h>
|
|
|
|
|
|
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 = UC_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
|