diff --git a/src/audio/audio.h b/src/audio/audio.h index 42ea9d90c..f2001ed21 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -95,6 +95,7 @@ typedef struct char *data; /* data should be at least 4B aligned */ int data_len; /* size of useful data in buffer */ audio_codec_t codec; + double duration; } audio_channel; struct module; @@ -120,17 +121,18 @@ public: audio_codec_t get_codec(); const char *get_data(int channel); size_t get_data_len(int channel); + double get_duration(); int get_channel_count(); int get_sample_count(); int get_sample_rate(); bool has_same_prop_as(audio_frame2 const &frame); + void set_duration(double duration); private: int bps; /* bytes per sample */ int sample_rate; std::vector, size_t> > channels; /* data should be at least 4B aligned */ audio_codec_t codec; - int sample_count; ///< number of samples stored in this buffer - ///< assuming that all channels has same count... + double duration; }; #endif diff --git a/src/audio/codec.cpp b/src/audio/codec.cpp index c7b5193c0..099031ea0 100644 --- a/src/audio/codec.cpp +++ b/src/audio/codec.cpp @@ -253,6 +253,7 @@ audio_frame2 *audio_codec_compress(struct audio_codec_state *s, audio_frame2 *fr } else { s->out->reset(); } + s->out->set_duration(out->duration); } else { assert(out->bps == s->out->get_bps() && out->sample_rate == s->out->get_sample_rate()); diff --git a/src/audio/codec/libavcodec.cpp b/src/audio/codec/libavcodec.cpp index 65feffd51..a1abbbe92 100644 --- a/src/audio/codec/libavcodec.cpp +++ b/src/audio/codec/libavcodec.cpp @@ -353,6 +353,7 @@ static audio_channel *libavcodec_compress(void *state, audio_channel * channel) int bps = s->output_channel.bps; int offset = 0; s->output_channel.data_len = 0; + s->output_channel.duration = 0.0; int chunk_size = s->codec_ctx->frame_size * bps; //while(offset + chunk_size <= s->tmp.data_len) { while(offset + chunk_size <= s->tmp.data_len) { @@ -370,6 +371,10 @@ static audio_channel *libavcodec_compress(void *state, audio_channel * channel) } if(got_packet) { s->output_channel.data_len += s->pkt.size; + ///@ todo + /// well, this is wrong, denominator should be actually AVStream::time_base. Where do + /// we get this?? Anyway, seems like it equals sample rate. + s->output_channel.duration += s->pkt.duration / (double) s->output_channel.sample_rate; } offset += chunk_size; if(!(s->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE)) diff --git a/src/audio/utils.cpp b/src/audio/utils.cpp index 2e9506237..beab81405 100644 --- a/src/audio/utils.cpp +++ b/src/audio/utils.cpp @@ -72,7 +72,7 @@ using namespace std; * @brief Creates empty audio_frame2 */ audio_frame2::audio_frame2() : - bps(0), sample_rate(0), codec(AC_PCM) + bps(0), sample_rate(0), codec(AC_PCM), duration(0.0) { } @@ -100,6 +100,7 @@ void audio_frame2::init(int nr_channels, audio_codec_t c, int b, int sr) bps = b; codec = c; sample_rate = sr; + duration = 0.0; } void audio_frame2::append(audio_frame2 const &src) @@ -171,6 +172,7 @@ void audio_frame2::reset() channels[i].first = unique_ptr(new char[0]); channels[i].second = 0; } + duration = 0.0; } int audio_frame2::get_bps() @@ -193,6 +195,16 @@ size_t audio_frame2::get_data_len(int channel) return channels[channel].second; } +double audio_frame2::get_duration() +{ + if (codec == AC_PCM) { + int samples = get_sample_count(); + return (double) samples / get_sample_rate(); + } else { + return duration; + } +} + int audio_frame2::get_channel_count() { return channels.size(); @@ -200,10 +212,6 @@ int audio_frame2::get_channel_count() int audio_frame2::get_sample_count() { - if (channels.size() == 0) { - throw logic_error("zero channels!"); - } - // for PCM, we can deduce samples count from length of the data if (codec == AC_PCM) { return channels[0].second / channels.size() / get_bps(); @@ -224,6 +232,11 @@ bool audio_frame2::has_same_prop_as(audio_frame2 const &frame) { channels.size() == frame.channels.size(); } +void audio_frame2::set_duration(double new_duration) +{ + duration = new_duration; +} + static double get_normalized(const char *in, int bps) { int64_t sample = 0; bool negative = false; diff --git a/src/transmit.cpp b/src/transmit.cpp index bcee120c5..5f4761ccc 100644 --- a/src/transmit.cpp +++ b/src/transmit.cpp @@ -703,8 +703,24 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer int packet_rate = tx->packet_rate; if (packet_rate == RATE_AUTO) { - /// @todo add automatic packet rate management also for audio. We currently don't - /// know actual audio buffer length (if compressed) + /** + * @todo + * Following code would actually work but seems to be useless in most of cases (eg. + * PCM 2 channels 2 Bps takes 5 std. Eth frames). On the other hand it could cause + * unexpectable problems (I'd write them here but if I'd expect them they wouldn't + * be unexpectable.) + */ +#if 0 + double time_for_frame = buffer->get_duration() / buffer->get_channel_count(); + if (time_for_frame > 0.0) { + long long req_bitrate = buffer->get_data_len(channel) * 8 / time_for_frame * tx->mult_count; + // adjust computed value to 3 + req_bitrate = req_bitrate * 3; + packet_rate = compute_packet_rate(req_bitrate, tx->mtu); + } else { + packet_rate = 0; + } +#endif packet_rate = 0; } @@ -750,12 +766,14 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer mult_index = (mult_index + 1) % tx->mult_count; } - do { - GET_STOPTIME; - GET_DELTA; - if (delta < 0) - delta += 1000000000L; - } while (packet_rate - delta > 0); + if (pos < buffer->get_data_len(channel)) { + do { + GET_STOPTIME; + GET_DELTA; + if (delta < 0) + delta += 1000000000L; + } while (packet_rate - delta > 0); + } /* when trippling, we need all streams goes to end */ if(tx->fec_scheme == FEC_MULT) { @@ -763,7 +781,7 @@ void audio_tx_send(struct tx* tx, struct rtp *rtp_session, audio_frame2 * buffer } - } while (pos < (unsigned int) buffer->get_data_len(channel)); + } while (pos < buffer->get_data_len(channel)); } tx->buffer ++;