diff --git a/src/audio/audio.cpp b/src/audio/audio.cpp index 5b4b4d9e5..e5a16faf0 100644 --- a/src/audio/audio.cpp +++ b/src/audio/audio.cpp @@ -201,7 +201,7 @@ struct state_audio * audio_cfg_init(struct module *parent, const char *addrs, in char *audio_channel_map, const char *audio_scale, bool echo_cancellation, bool use_ipv6, const char *mcast_if, const char *audio_codec_cfg, - bool isStd, long packet_rate) + bool isStd, long packet_rate, int audio_delay) { struct state_audio *s = NULL; char *tmp, *unused = NULL; @@ -316,7 +316,7 @@ struct state_audio * audio_cfg_init(struct module *parent, const char *addrs, in s->captured = new audio_frame2; tmp = strdup(addrs); - s->audio_participants = pdb_init(); + s->audio_participants = pdb_init(audio_delay); addr = strtok_r(tmp, ",", &unused); s->audio_network_parameters.addr = strdup(addr); diff --git a/src/audio/audio.h b/src/audio/audio.h index ecb2e14e1..436cd593c 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -154,7 +154,7 @@ struct state_audio * audio_cfg_init(struct module *parent, const char *addrs, in char *jack_cfg, const char *fec_cfg, const char *encryption, char *audio_channel_map, const char *audio_scale, bool echo_cancellation, bool use_ipv6, const char *mcast_iface, const char *audio_codec_cfg, - bool isStd, long packet_rate); + bool isStd, long packet_rate, int audio_delay); void audio_finish(void); void audio_done(struct state_audio *s); void audio_join(struct state_audio *s); diff --git a/src/main.cpp b/src/main.cpp index 6124654c5..2d16c4c08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -124,6 +124,7 @@ #define OPT_LDGM_DEVICE (('L' << 8) | 'D') #define OPT_WINDOW_TITLE (('W' << 8) | 'T') #define OPT_CAPABILITIES (('C' << 8) | 'C') +#define OPT_AUDIO_DELAY (('A' << 8) | 'D') #define MAX_CAPTURE_COUNT 17 @@ -268,6 +269,9 @@ static void usage(void) printf("\n"); printf("\t--encryption \tKey material for encryption\n"); printf("\n"); + printf("\t--audio-delay \tAmount of time audio should be delayed to video\n"); + printf("\t \t(in non-negative miliseconds)\n"); + printf("\n"); printf("\taddress(es) \tdestination address\n"); printf("\n"); printf("\t \tIf comma-separated list of addresses\n"); @@ -447,6 +451,7 @@ int main(int argc, char *argv[]) int bitrate = RATE_AUTO; int rxtx_mode = 0; + int audio_delay = 0; #ifdef USE_MTRACE mtrace(); @@ -501,6 +506,7 @@ int main(int argc, char *argv[]) {"ldgm-device", required_argument, 0, OPT_LDGM_DEVICE}, {"window-title", required_argument, 0, OPT_WINDOW_TITLE}, {"capabilities", no_argument, 0, OPT_CAPABILITIES}, + {"audio-delay", required_argument, 0, OPT_AUDIO_DELAY}, {0, 0, 0, 0} }; int option_index = 0; @@ -784,6 +790,13 @@ int main(int argc, char *argv[]) print_capabilities(CAPABILITY_CAPTURE | CAPABILITY_COMPRESS); return EXIT_SUCCESS; break; + case OPT_AUDIO_DELAY: + audio_delay = atoi(optarg); + if (audio_delay < 0) { + fprintf(stderr, "Audio delay should be non-negative!\n"); + return EXIT_FAIL_USAGE; + } + break; case '?': default: usage(); @@ -872,7 +885,7 @@ int main(int argc, char *argv[]) jack_cfg, requested_audio_fec, requested_encryption, audio_channel_map, audio_scale, echo_cancellation, ipv6, requested_mcast_if, - audio_codec, isStd, packet_rate); + audio_codec, isStd, packet_rate, audio_delay); if(!uv->audio) { exit_uv(EXIT_FAIL_AUDIO); goto cleanup; diff --git a/src/pdb.c b/src/pdb.c index eb8f29d95..6022447a4 100644 --- a/src/pdb.c +++ b/src/pdb.c @@ -85,6 +85,7 @@ struct pdb { pdb_node_t *root; uint32_t magic; int count; + int delay_ms; }; /*****************************************************************************/ @@ -240,13 +241,14 @@ static pdb_node_t *pdb_delete_node(struct pdb *tree, pdb_node_t * z) /*****************************************************************************/ -struct pdb *pdb_init(void) +struct pdb *pdb_init(int delay_ms) { struct pdb *db = malloc(sizeof(struct pdb)); if (db != NULL) { db->magic = PDB_MAGIC; db->count = 0; db->root = NULL; + db->delay_ms = delay_ms; } return db; } @@ -266,7 +268,7 @@ void pdb_destroy(struct pdb **db_p) *db_p = NULL; } -static struct pdb_e *pdb_create_item(uint32_t ssrc) +static struct pdb_e *pdb_create_item(uint32_t ssrc, int delay_ms) { struct pdb_e *p = malloc(sizeof(struct pdb_e)); if (p != NULL) { @@ -282,7 +284,7 @@ static struct pdb_e *pdb_create_item(uint32_t ssrc) p->decoder_state = NULL; p->decoder_state_deleter = NULL; p->pt = 255; - p->playout_buffer = pbuf_init(); + p->playout_buffer = pbuf_init(delay_ms); p->tfrc_state = tfrc_init(p->creation_time); } return p; @@ -303,7 +305,7 @@ int pdb_add(struct pdb *db, uint32_t ssrc) return 1; } - i = pdb_create_item(ssrc); + i = pdb_create_item(ssrc, db->delay_ms); if (i == NULL) { debug_msg("Unable to create database entry - ssrc %x\n", ssrc); return 2; diff --git a/src/pdb.h b/src/pdb.h index 771ffd920..217117bcf 100644 --- a/src/pdb.h +++ b/src/pdb.h @@ -86,7 +86,11 @@ struct pdb_e { struct pdb; /* The participant database */ -struct pdb *pdb_init(void); +/** + * @param delay_ms delay to be added to playback. Main reason is to give user a possibility to + * sync audio and video. + */ +struct pdb *pdb_init(int delay_ms); void pdb_destroy(struct pdb **db); int pdb_add(struct pdb *db, uint32_t ssrc); struct pdb_e *pdb_get(struct pdb *db, uint32_t ssrc); diff --git a/src/rtp/pbuf.c b/src/rtp/pbuf.c index 004e4d868..45e71e9d3 100644 --- a/src/rtp/pbuf.c +++ b/src/rtp/pbuf.c @@ -155,7 +155,7 @@ static void pbuf_validate(struct pbuf *playout_buf) #endif } -struct pbuf *pbuf_init(void) +struct pbuf *pbuf_init(int delay_ms) { struct pbuf *playout_buf = NULL; @@ -166,7 +166,7 @@ struct pbuf *pbuf_init(void) /* Playout delay... should really be adaptive, based on the */ /* jitter, but we use a (conservative) fixed 32ms delay for */ /* now (2 video frames at 60fps). */ - playout_buf->playout_delay = 0.032; + playout_buf->playout_delay = 0.032 + delay_ms / 1000.0; } else { debug_msg("Failed to allocate memory for playout buffer\n"); } diff --git a/src/rtp/pbuf.h b/src/rtp/pbuf.h index ca101b258..ed620019d 100644 --- a/src/rtp/pbuf.h +++ b/src/rtp/pbuf.h @@ -109,7 +109,7 @@ typedef int decode_frame_t(struct coded_data *cdata, void *decode_data); /* * External interface: */ -struct pbuf *pbuf_init(void); +struct pbuf *pbuf_init(int delay_ms); void pbuf_insert(struct pbuf *playout_buf, rtp_packet *r); int pbuf_is_empty(struct pbuf *playout_buf); int pbuf_decode(struct pbuf *playout_buf, struct timeval curr_time, diff --git a/src/video_capture/rtsp.c b/src/video_capture/rtsp.c index eccc4d229..4f54f6383 100644 --- a/src/video_capture/rtsp.c +++ b/src/video_capture/rtsp.c @@ -471,7 +471,7 @@ vidcap_rtsp_init(const struct vidcap_params *params) { s->vrtsp_state->device = (struct rtp *) malloc( (s->vrtsp_state->required_connections) * sizeof(struct rtp *)); - s->vrtsp_state->participants = pdb_init(); + s->vrtsp_state->participants = pdb_init(0); s->vrtsp_state->new_frame = FALSE; diff --git a/src/video_rxtx/rtp.cpp b/src/video_rxtx/rtp.cpp index bd9b7ac0e..6b11422dc 100644 --- a/src/video_rxtx/rtp.cpp +++ b/src/video_rxtx/rtp.cpp @@ -129,7 +129,7 @@ rtp_video_rxtx::rtp_video_rxtx(map const ¶ms) : throw ug_runtime_error(oss.str(), EXIT_FAIL_USAGE); } - m_participants = pdb_init(); + m_participants = pdb_init(0); m_requested_receiver = (const char *) params.at("receiver").ptr; m_recv_port_number = params.at("rx_port").i; m_send_port_number = params.at("tx_port").i;