Almost done

This commit is contained in:
mannol 2015-04-26 00:31:03 +02:00
parent 1bfd93e64a
commit 144fc94d69
9 changed files with 439 additions and 342 deletions

View File

@ -33,10 +33,11 @@ static int jbuf_write(struct JitterBuffer *q, RTPMessage *m);
static RTPMessage *jbuf_read(struct JitterBuffer *q, int32_t *success);
OpusEncoder* create_audio_encoder (int32_t bitrate, int32_t sampling_rate, int32_t channel_count);
bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch,
int32_t *old_br, int32_t *old_sr, int32_t *old_ch);
bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels);
ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *cb, void *cb_data)
{
ACSession *ac = calloc(sizeof(ACSession), 1);
@ -71,10 +72,20 @@ ACSession* ac_new(ToxAV* av, uint32_t friend_id, toxav_receive_audio_frame_cb *c
if (ac->encoder == NULL)
goto DECODER_CLEANUP;
ac->test_encoder = create_audio_encoder(48000, 48000, 2);
if (ac->test_encoder == NULL) {
opus_encoder_destroy(ac->encoder);
goto DECODER_CLEANUP;
}
ac->last_encoding_bitrate = 48000;
ac->last_encoding_sampling_rate = 48000;
ac->last_encoding_channel_count = 2;
ac->last_test_encoding_bitrate = 48000;
ac->last_test_encoding_sampling_rate = 48000;
ac->last_test_encoding_channel_count = 2;
ac->last_decoding_channel_count = 2;
ac->last_decoding_sampling_rate = 48000;
ac->last_decoder_reconfiguration = 0; /* Make it possible to reconfigure straight away */
@ -141,7 +152,7 @@ void ac_do(ACSession* ac)
cs->last_packet_sampling_rate = rc;
} else {
LOGGER_WARNING("Failed to load packet values!");
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
continue;
}*/
@ -157,12 +168,12 @@ void ac_do(ACSession* ac)
*/
if (!reconfigure_audio_decoder(ac, ac->last_packet_sampling_rate, ac->last_packet_channel_count)) {
LOGGER_WARNING("Failed to reconfigure decoder!");
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
continue;
}
rc = opus_decode(ac->decoder, msg->data + 4, msg->length - 4, tmp, 5760, 0);
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
}
if (rc < 0) {
@ -183,15 +194,15 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
if (!acp || !msg)
return -1;
if ((msg->header->marker_payloadt & 0x7f) == rtp_TypeDummyAudio % 128) {
if ((msg->header->marker_payloadt & 0x7f) == (rtp_TypeAudio + 2) % 128) {
LOGGER_WARNING("Got dummy!");
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
return 0;
}
if ((msg->header->marker_payloadt & 0x7f) != rtp_TypeAudio % 128) {
LOGGER_WARNING("Invalid payload type!");
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
return -1;
}
@ -203,7 +214,7 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
if (rc == -1) {
LOGGER_WARNING("Could not queue the message!");
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
return -1;
}
@ -211,35 +222,22 @@ int ac_queue_message(void* acp, struct RTPMessage_s *msg)
}
int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels)
{
if (!ac)
return;
/* Values are checked in toxav.c */
if (ac->last_encoding_sampling_rate != sampling_rate || ac->last_encoding_channel_count != channels) {
OpusEncoder* new_encoder = create_audio_encoder(bitrate, sampling_rate, channels);
if (new_encoder == NULL)
return -1;
opus_encoder_destroy(ac->encoder);
ac->encoder = new_encoder;
} else if (ac->last_encoding_bitrate == bitrate)
return 0; /* Nothing changed */
else {
int status = opus_encoder_ctl(ac->encoder, OPUS_SET_BITRATE(bitrate));
if ( status != OPUS_OK ) {
LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status));
return -1;
}
}
ac->last_encoding_bitrate = bitrate;
ac->last_encoding_sampling_rate = sampling_rate;
ac->last_encoding_channel_count = channels;
if (!ac || !reconfigure_audio_encoder(&ac->encoder, bitrate, sampling_rate, channels,
&ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
return -1;
LOGGER_DEBUG ("Reconfigured audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels);
return 0;
}
int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels)
{
if (!ac || !reconfigure_audio_encoder(&ac->test_encoder, bitrate, sampling_rate, channels,
&ac->last_encoding_bitrate, &ac->last_encoding_sampling_rate, &ac->last_encoding_channel_count))
return -1;
LOGGER_DEBUG ("Reconfigured test audio encoder br: %d sr: %d cc:%d", bitrate, sampling_rate, channels);
return 0;
}
@ -277,7 +275,7 @@ static void jbuf_clear(struct JitterBuffer *q)
{
for (; q->bottom != q->top; ++q->bottom) {
if (q->queue[q->bottom % q->size]) {
rtp_free_msg(NULL, q->queue[q->bottom % q->size]);
rtp_free_msg(q->queue[q->bottom % q->size]);
q->queue[q->bottom % q->size] = NULL;
}
}
@ -372,6 +370,34 @@ FAILURE:
opus_encoder_destroy(rc);
return NULL;
}
bool reconfigure_audio_encoder(OpusEncoder** e, int32_t new_br, int32_t new_sr, uint8_t new_ch,
int32_t* old_br, int32_t* old_sr, int32_t* old_ch)
{
/* Values are checked in toxav.c */
if (*old_sr != new_sr || *old_ch != new_ch) {
OpusEncoder* new_encoder = create_audio_encoder(new_br, new_sr, new_ch);
if (new_encoder == NULL)
return false;
opus_encoder_destroy(*e);
*e = new_encoder;
} else if (*old_br == new_br)
return true; /* Nothing changed */
else {
int status = opus_encoder_ctl(*e, OPUS_SET_BITRATE(new_br));
if ( status != OPUS_OK ) {
LOGGER_ERROR("Error while setting encoder ctl: %s", opus_strerror(status));
return false;
}
}
*old_br = new_br;
*old_sr = new_sr;
*old_ch = new_ch;
return true;
}
bool reconfigure_audio_decoder(ACSession* ac, int32_t sampling_rate, int8_t channels)
{
if (sampling_rate != ac->last_decoding_sampling_rate || channels != ac->last_decoding_channel_count) {

View File

@ -38,6 +38,12 @@ typedef struct ACSession_s {
int32_t last_encoding_channel_count;
int32_t last_encoding_bitrate;
/* Testing encoder for dynamic bitrate streaming */
OpusEncoder *test_encoder;
int32_t last_test_encoding_sampling_rate;
int32_t last_test_encoding_channel_count;
int32_t last_test_encoding_bitrate;
/* decoding */
OpusDecoder *decoder;
int32_t last_packet_channel_count;
@ -60,4 +66,5 @@ void ac_kill(ACSession* ac);
void ac_do(ACSession* ac);
int ac_queue_message(void *acp, struct RTPMessage_s *msg);
int ac_reconfigure_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels);
int ac_reconfigure_test_encoder(ACSession* ac, int32_t bitrate, int32_t sampling_rate, uint8_t channels);
#endif /* AUDIO_H */

View File

@ -186,7 +186,7 @@ void t_toxav_receive_video_frame_cb(ToxAV *av, uint32_t friend_number,
unsigned long int i, j;
for (i = 0; i < height; ++i) {
for (j = 0; j < width; ++j) {
uint8_t *point = (void*)img_data + 3 * ((i * width) + j);
uint8_t *point = (uint8_t*) img_data + 3 * ((i * width) + j);
int yx = y[(i * ystride) + j];
int ux = u[((i / 2) * ustride) + (j / 2)];
int vx = v[((i / 2) * vstride) + (j / 2)];
@ -226,7 +226,7 @@ void t_toxav_receive_audio_frame_cb(ToxAV *av, uint32_t friend_number,
void t_accept_friend_request_cb(Tox *m, const uint8_t *public_key, const uint8_t *data, size_t length, void *userdata)
{
if (length == 7 && memcmp("gentoo", data, 7) == 0) {
assert(tox_friend_add_norequest(m, public_key, NULL) != ~0);
assert(tox_friend_add_norequest(m, public_key, NULL) != (uint32_t) ~0);
}
}
@ -262,7 +262,7 @@ void initialize_tox(Tox** bootstrap, ToxAV** AliceAV, CallControl* AliceCC, ToxA
tox_self_get_address(Alice, address);
assert(tox_friend_add(Bob, address, (uint8_t *)"gentoo", 7, NULL) != ~0);
assert(tox_friend_add(Bob, address, (uint8_t *)"gentoo", 7, NULL) != (uint32_t) ~0);
uint8_t off = 1;
@ -563,7 +563,7 @@ int main (int argc, char** argv)
} \
} \
\
iterate(bootstrap, AliceAV, BobAV); \
iterate_tox(bootstrap, AliceAV, BobAV); \
} \
printf("Success!\n");\
} while(0)

View File

@ -29,6 +29,7 @@
#include "rtp.h"
#include <stdlib.h>
#include <assert.h>
#define size_32 4
#define RTCP_REPORT_INTERVAL_MS 500
@ -37,8 +38,8 @@
#define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0)
#define ADD_FLAG_EXTENSION(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xEF;( _h->flags ) |= ( ( ( _v ) << 4 ) & 0x10 ); } while(0)
#define ADD_FLAG_CSRCC(_h, _v) do { ( _h->flags ) &= 0xF0; ( _h->flags ) |= ( ( _v ) & 0x0F ); } while(0)
#define ADD_SETTING_MARKER(_h, _v) do { if ( _v > 1 ) _v = 1; ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0)
#define ADD_SETTING_PAYLOAD(_h, _v) do { if ( _v > 127 ) _v = 127; ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0)
#define ADD_SETTING_MARKER(_h, _v) do { ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0)
#define ADD_SETTING_PAYLOAD(_h, _v) do { ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0)
#define GET_FLAG_VERSION(_h) (( _h->flags & 0xd0 ) >> 6)
#define GET_FLAG_PADDING(_h) (( _h->flags & 0x20 ) >> 5)
@ -70,17 +71,19 @@ typedef struct RTCPSession_s {
RTPHeader *parse_header_in ( const uint8_t *payload, int length );
RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length );
RTPMessage *msg_parse ( const uint8_t *data, int length );
uint8_t *parse_header_out ( const RTPHeader* header, uint8_t* payload );
uint8_t *parse_ext_header_out ( const RTPExtHeader* header, uint8_t* payload );
void build_header ( RTPSession* session, RTPHeader* header );
void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
int handle_rtp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object );
int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object );
void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) )
{
assert(mcb);
assert(cs);
assert(messenger);
RTPSession *retu = calloc(1, sizeof(RTPSession));
if ( !retu ) {
@ -107,6 +110,8 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
/* Also set payload type as prefix */
retu->prefix = payload_type;
retu->cs = cs;
retu->mcb = mcb;
/* Initialize rtcp session */
if (!(retu->rtcp_session = calloc(1, sizeof(RTCPSession)))) {
@ -120,6 +125,14 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
retu->rtcp_session->pl_stats = rb_new(4);
retu->rtcp_session->rtp_session = retu;
if (-1 == rtp_start_receiving(retu)) {
LOGGER_WARNING("Failed to start rtp receiving mode");
free(retu->rtcp_session);
free(retu->csrc);
free(retu);
return NULL;
}
return retu;
}
void rtp_kill ( RTPSession *session )
@ -156,11 +169,12 @@ void rtp_do(RTPSession *session)
RTCPReport* reports[4];
int i = 0;
for (; rb_read(session->rtcp_session->pl_stats, (void**) reports + i); i++);
for (; i < 4; i++)
rb_read(session->rtcp_session->pl_stats, (void**) reports + i);
/* Check for timed out reports (> 6 sec) */
uint64_t now = current_time_monotonic();
for (i = 0; i < 4 && now - reports[i]->timestamp < 6000; i ++);
for (i = 0; i < 4 && (now - reports[i]->timestamp) < 6000; i ++);
for (; i < 4; i ++) {
rb_write(session->rtcp_session->pl_stats, reports[i]);
reports[i] = NULL;
@ -168,18 +182,18 @@ void rtp_do(RTPSession *session)
if (!rb_empty(session->rtcp_session->pl_stats)) {
for (i = 0; reports[i] != NULL; i ++)
free(reports[i]);
return; /* As some reports are timed out, we need more... */
return; /* As some reports are timed out, we need more */
}
/* We have 4 on-time reports so we can proceed */
uint32_t quality = 100;
for (i = 0; i < 4; i++) {
uint32_t idx = reports[i]->received_packets * 100 / reports[i]->expected_packets;
quality = MIN(quality, idx);
uint32_t current = reports[i]->received_packets * 100 / reports[i]->expected_packets;
quality = MIN(quality, current);
free(reports[i]);
}
if (quality <= 70) {
if (quality <= 90) {
session->tstate = rtp_StateBad;
LOGGER_WARNING("Stream quality: BAD");
} else if (quality >= 99) {
@ -220,7 +234,7 @@ int rtp_stop_receiving(RTPSession* session)
return 0;
}
int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
int rtp_send_data ( RTPSession *session, const uint8_t *data, uint16_t length, bool dummy )
{
if ( !session ) {
LOGGER_WARNING("No session!");
@ -231,12 +245,31 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
uint8_t *it;
RTPHeader header[1];
build_header(session, header);
ADD_FLAG_VERSION ( header, session->version );
ADD_FLAG_PADDING ( header, session->padding );
ADD_FLAG_EXTENSION ( header, session->extension );
ADD_FLAG_CSRCC ( header, session->cc );
ADD_SETTING_MARKER ( header, session->marker );
if (dummy)
ADD_SETTING_PAYLOAD ( header, (session->payload_type + 2) % 128 );
else
ADD_SETTING_PAYLOAD ( header, session->payload_type );
header->sequnum = session->sequnum;
header->timestamp = current_time_monotonic();
header->ssrc = session->ssrc;
int i;
for ( i = 0; i < session->cc; i++ )
header->csrc[i] = session->csrc[i];
header->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
uint32_t parsed_len = length + header->length + 1;
assert(parsed_len + (session->ext_header ? session->ext_header->length * size_32 : 0) > MAX_RTP_SIZE );
parsed[0] = session->prefix;
it = parse_header_out ( header, parsed + 1 );
if ( session->ext_header ) {
@ -244,8 +277,7 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
it = parse_ext_header_out ( session->ext_header, it );
}
memcpy ( it, data, length );
memcpy(it, data, length);
if ( -1 == send_custom_lossy_packet(session->m, session->friend_id, parsed, parsed_len) ) {
LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
@ -256,18 +288,11 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
return 0;
}
void rtp_free_msg ( RTPSession *session, RTPMessage *msg )
void rtp_free_msg ( RTPMessage *msg )
{
if ( !session ) {
if ( msg->ext_header ) {
free ( msg->ext_header->table );
free ( msg->ext_header );
}
} else {
if ( msg->ext_header && session->ext_header != msg->ext_header ) {
free ( msg->ext_header->table );
free ( msg->ext_header );
}
if ( msg->ext_header ) {
free ( msg->ext_header->table );
free ( msg->ext_header );
}
free ( msg->header );
@ -389,50 +414,6 @@ RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length )
return retu;
}
RTPMessage *msg_parse ( const uint8_t *data, int length )
{
/* TODO: data dynamic, [0]
* TODO: dummy payload type
* TODO: parse header before allocating message
*/
RTPMessage *retu = calloc(1, sizeof (RTPMessage));
retu->header = parse_header_in ( data, length ); /* It allocates memory and all */
if ( !retu->header ) {
LOGGER_WARNING("Header failed to extract!");
free(retu);
return NULL;
}
uint16_t from_pos = retu->header->length;
retu->length = length - from_pos;
if ( GET_FLAG_EXTENSION ( retu->header ) ) {
retu->ext_header = parse_ext_header_in ( data + from_pos, length );
if ( retu->ext_header ) {
retu->length -= ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
from_pos += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
} else { /* Error */
LOGGER_WARNING("Ext Header failed to extract!");
rtp_free_msg(NULL, retu);
return NULL;
}
} else {
retu->ext_header = NULL;
}
if ( length - from_pos <= MAX_RTP_SIZE )
memcpy ( retu->data, data + from_pos, length - from_pos );
else {
LOGGER_WARNING("Invalid length!");
rtp_free_msg(NULL, retu);
return NULL;
}
return retu;
}
uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload )
{
uint8_t cc = GET_FLAG_CSRCC ( header );
@ -495,88 +476,95 @@ uint8_t *parse_ext_header_out ( const RTPExtHeader *header, uint8_t *payload )
return it + 4;
}
void build_header ( RTPSession *session, RTPHeader *header )
{
ADD_FLAG_VERSION ( header, session->version );
ADD_FLAG_PADDING ( header, session->padding );
ADD_FLAG_EXTENSION ( header, session->extension );
ADD_FLAG_CSRCC ( header, session->cc );
ADD_SETTING_MARKER ( header, session->marker );
ADD_SETTING_PAYLOAD ( header, session->payload_type );
header->sequnum = session->sequnum;
header->timestamp = current_time_monotonic(); /* milliseconds */
header->ssrc = session->ssrc;
int i;
for ( i = 0; i < session->cc; i++ )
header->csrc[i] = session->csrc[i];
header->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
}
void send_rtcp_report(RTCPSession* session, Messenger* m, uint32_t friendnumber)
{
if (session->last_expected_packets == 0)
return;
uint8_t parsed[9];
parsed[0] = session->prefix;
uint32_t received_packets = htonl(session->last_received_packets);
uint32_t expected_packets = htonl(session->last_expected_packets);
memcpy(parsed + 1, &received_packets, 4);
memcpy(parsed + 5, &expected_packets, 4);
if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed)))
LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno));
else {
LOGGER_DEBUG("Sent rtcp report: ex: %d rc: %d", session->last_expected_packets, session->last_received_packets);
session->last_received_packets = 0;
session->last_expected_packets = 0;
session->last_sent_report_ts = current_time_monotonic();
}
}
int handle_rtp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object )
{
RTPSession *session = object;
RTPMessage *msg;
if ( !session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */
if ( !session || length < 13 || length > MAX_RTP_SIZE ) {
LOGGER_WARNING("No session or invalid length of received buffer!");
return -1;
}
RTPHeader* header = parse_header_in ( data, length );
msg = msg_parse ( data + 1, length - 1 );
if ( !msg ) {
LOGGER_WARNING("Could not parse message!");
if ( !header ) {
LOGGER_WARNING("Could not parse message: Header failed to extract!");
return -1;
}
RTPExtHeader* ext_header = NULL;
uint16_t from_pos = header->length;
uint16_t msg_length = length - from_pos;
if ( GET_FLAG_EXTENSION ( header ) ) {
ext_header = parse_ext_header_in ( data + from_pos, length );
if ( ext_header ) {
msg_length -= ( 4 /* Minimum ext header len */ + ext_header->length * size_32 );
from_pos += ( 4 /* Minimum ext header len */ + ext_header->length * size_32 );
} else { /* Error */
LOGGER_WARNING("Could not parse message: Ext Header failed to extract!");
free(header);
return -1;
}
}
if (msg_length > MAX_RTP_SIZE) {
LOGGER_WARNING("Could not parse message: Invalid length!");
free(header);
free(ext_header);
return -1;
}
/* Check if message came in late */
if ( msg->header->sequnum > session->rsequnum || msg->header->timestamp > session->rtimestamp ) {
if ( header->sequnum > session->rsequnum || header->timestamp > session->rtimestamp ) {
/* Not late */
if (msg->header->sequnum > session->rsequnum)
session->rtcp_session->last_expected_packets += msg->header->sequnum - session->rsequnum;
else if (msg->header->sequnum < session->rsequnum)
session->rtcp_session->last_expected_packets += (msg->header->sequnum + 65535) - session->rsequnum;
if (header->sequnum > session->rsequnum)
session->rtcp_session->last_expected_packets += header->sequnum - session->rsequnum;
else if (header->sequnum < session->rsequnum)
session->rtcp_session->last_expected_packets += (header->sequnum + 65535) - session->rsequnum;
else /* Usual case when transmission starts */
session->rtcp_session->last_expected_packets ++;
session->rsequnum = msg->header->sequnum;
session->rtimestamp = msg->header->timestamp;
session->rsequnum = header->sequnum;
session->rtimestamp = header->timestamp;
}
session->rtcp_session->last_received_packets ++;
if (session->mcb)
return session->mcb (session->cs, msg);
else {
rtp_free_msg(session, msg);
/* Check if the message is dummy. We don't keep dummy messages */
if (GET_SETTING_PAYLOAD(header) == (session->payload_type + 2) % 128) {
LOGGER_DEBUG("Received dummy rtp message");
free(header);
free(ext_header);
return 0;
}
/* Otherwise we will store the message if we have an appropriate handler */
if (!session->mcb) {
LOGGER_DEBUG("No handler for the message of %d payload", GET_SETTING_PAYLOAD(header));
free(header);
free(ext_header);
return 0;
}
RTPMessage *msg = calloc(1, sizeof (RTPMessage) + msg_length);
if ( !msg ) {
LOGGER_WARNING("Could not parse message: Allocation failed!");
free(header);
free(ext_header);
return -1;
}
msg->header = header;
msg->ext_header = ext_header;
msg->length = msg_length;
memcpy ( msg->data, data + from_pos, msg_length );
return session->mcb (session->cs, msg);
}
int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object )
{
@ -605,4 +593,28 @@ int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* dat
LOGGER_DEBUG("Got rtcp report: ex: %d rc: %d", report->expected_packets, report->received_packets);
return 0;
}
void send_rtcp_report(RTCPSession* session, Messenger* m, uint32_t friendnumber)
{
if (session->last_expected_packets == 0)
return;
uint8_t parsed[9];
parsed[0] = session->prefix;
uint32_t received_packets = htonl(session->last_received_packets);
uint32_t expected_packets = htonl(session->last_expected_packets);
memcpy(parsed + 1, &received_packets, 4);
memcpy(parsed + 5, &expected_packets, 4);
if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed)))
LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno));
else {
LOGGER_DEBUG("Sent rtcp report: ex: %d rc: %d", session->last_expected_packets, session->last_received_packets);
session->last_received_packets = 0;
session->last_expected_packets = 0;
session->last_sent_report_ts = current_time_monotonic();
}
}

View File

@ -39,7 +39,7 @@
} while(0)
#define MAX_SEQU_NUM 65535
#define MAX_RTP_SIZE 65535
#define MAX_RTP_SIZE 1500
/**
* Payload type identifier. Also used as rtp callback prefix. (Not dummies)
@ -47,8 +47,6 @@
enum {
rtp_TypeAudio = 192,
rtp_TypeVideo,
rtp_TypeDummyAudio,
rtp_TypeDummyVideo,
};
typedef enum {
@ -85,8 +83,8 @@ typedef struct RTPMessage_s {
RTPHeader *header;
RTPExtHeader *ext_header;
uint8_t data[MAX_RTP_SIZE];
uint32_t length;
uint8_t data[];
} RTPMessage;
/**
@ -128,7 +126,7 @@ typedef struct {
/**
* Must be called before calling any other rtp function.
*/
RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num );
RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) );
/**
* Terminate the session.
@ -141,7 +139,7 @@ void rtp_kill ( RTPSession* session );
void rtp_do(RTPSession *session);
/**
* By default rtp is not in receiving state
* By default rtp is in receiving state
*/
int rtp_start_receiving (RTPSession *session);
@ -153,12 +151,12 @@ int rtp_stop_receiving (RTPSession *session);
/**
* Sends msg to RTPSession::dest
*/
int rtp_send_msg ( RTPSession* session, const uint8_t* data, uint16_t length );
int rtp_send_data ( RTPSession* session, const uint8_t* data, uint16_t length, bool dummy );
/**
* Dealloc msg.
*/
void rtp_free_msg ( RTPSession *session, RTPMessage *msg );
void rtp_free_msg ( RTPMessage *msg );
#endif /* RTP_H */

View File

@ -36,6 +36,14 @@
#define MAX_ENCODE_TIME_US ((1000 / 24) * 1000)
typedef struct ToxAvBitrateAdapter_s {
bool active;
uint32_t cycle_sent;
uint32_t cycle_ratio;
uint32_t cycle_repeat;
uint64_t start_time;
uint32_t bit_rate;
} ToxAvBitrateAdapter;
typedef struct ToxAVCall_s {
ToxAV* av;
@ -55,7 +63,10 @@ typedef struct ToxAVCall_s {
uint32_t audio_bit_rate; /* Sending audio bitrate */
uint32_t video_bit_rate; /* Sending video bitrate */
/** Required for monitoring */
ToxAvBitrateAdapter aba;
ToxAvBitrateAdapter vba;
/** Required for monitoring changes in states */
uint8_t previous_self_capabilities;
/** Quality control */
@ -82,8 +93,6 @@ struct toxAV {
PAIR(toxav_call_state_cb *, void *) scb; /* Call state callback */
PAIR(toxav_receive_audio_frame_cb *, void *) acb; /* Audio frame receive callback */
PAIR(toxav_receive_video_frame_cb *, void *) vcb; /* Video frame receive callback */
PAIR(toxav_video_frame_request_cb *, void *) rvcb; /* Video request callback */
PAIR(toxav_audio_frame_request_cb *, void *) racb; /* Audio request callback */
/** Decode time measures */
int32_t dmssc; /** Measure count */
@ -103,14 +112,15 @@ int callback_capabilites(void* toxav_inst, MSICall* call);
bool audio_bitrate_invalid(uint32_t bitrate);
bool video_bitrate_invalid(uint32_t bitrate);
void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state);
void qc_do(ToxAVCall* call);
ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error);
ToxAVCall* call_get(ToxAV* av, uint32_t friend_number);
void qc_do(ToxAVCall* call);
void call_remove(ToxAVCall* call);
bool call_prepare_transmission(ToxAVCall* call);
void call_kill_transmission(ToxAVCall* call);
void ba_set(ToxAvBitrateAdapter* ba, uint32_t bit_rate);
bool ba_shoud_send_dummy(ToxAvBitrateAdapter* ba);
void ba_update_sent_regular(ToxAvBitrateAdapter* ba);
ToxAV* toxav_new(Tox* tox, TOXAV_ERR_NEW* error)
{
@ -300,7 +310,7 @@ void toxav_callback_call(ToxAV* av, toxav_call_cb* function, void* user_data)
av->ccb.first = function;
av->ccb.second = user_data;
pthread_mutex_unlock(av->mutex);
}
}/** Required for monitoring */
bool toxav_answer(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, uint32_t video_bit_rate, TOXAV_ERR_ANSWER* error)
{
@ -505,7 +515,7 @@ END:
return rc == TOXAV_ERR_CALL_CONTROL_OK;
}
bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE* error)
bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE* error)
{
TOXAV_ERR_BIT_RATE rc = TOXAV_ERR_BIT_RATE_OK;
ToxAVCall* call;
@ -528,9 +538,17 @@ bool toxav_set_audio_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t audio_
goto END;
}
/* Decoding mutex is locked because of quality control */
if (call->audio_bit_rate == audio_bit_rate && call->aba.active && call->aba.bit_rate == audio_bit_rate) {
pthread_mutex_unlock(av->mutex);
goto END;
}
pthread_mutex_lock(call->mutex);
call->audio_bit_rate = audio_bit_rate;
if (force) {
call->audio_bit_rate = audio_bit_rate;
} else
ba_set(&call->aba, audio_bit_rate);
pthread_mutex_unlock(call->mutex);
pthread_mutex_unlock(av->mutex);
@ -541,7 +559,7 @@ END:
return rc == TOXAV_ERR_BIT_RATE_OK;
}
bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE* error)
bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_bit_rate, bool force, TOXAV_ERR_BIT_RATE* error)
{
TOXAV_ERR_BIT_RATE rc = TOXAV_ERR_BIT_RATE_OK;
ToxAVCall* call;
@ -564,9 +582,17 @@ bool toxav_set_video_bit_rate(ToxAV* av, uint32_t friend_number, uint32_t video_
goto END;
}
/* Decoding mutex is locked because of quality control */
if (call->video_bit_rate == video_bit_rate && call->vba.active && call->vba.bit_rate == video_bit_rate) {
pthread_mutex_unlock(av->mutex);
goto END;
}
pthread_mutex_lock(call->mutex);
call->video_bit_rate = video_bit_rate;
if (force) {
call->video_bit_rate = video_bit_rate;
} else {
ba_set(&call->vba, video_bit_rate);
}
pthread_mutex_unlock(call->mutex);
pthread_mutex_unlock(av->mutex);
@ -577,14 +603,6 @@ END:
return rc == TOXAV_ERR_BIT_RATE_OK;
}
void toxav_callback_video_frame_request(ToxAV* av, toxav_video_frame_request_cb* function, void* user_data)
{
pthread_mutex_lock(av->mutex);
av->rvcb.first = function;
av->rvcb.second = user_data;
pthread_mutex_unlock(av->mutex);
}
bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, uint16_t height, const uint8_t* y, const uint8_t* u, const uint8_t* v, TOXAV_ERR_SEND_FRAME* error)
{
TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;
@ -630,7 +648,7 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u
memcpy(img.planes[VPX_PLANE_U], u, (width/2) * (height/2));
memcpy(img.planes[VPX_PLANE_V], v, (width/2) * (height/2));
int vrc = vpx_codec_encode(call->video.second->v_encoder, &img,
int vrc = vpx_codec_encode(call->video.second->encoder, &img,
call->video.second->frame_counter, 1, 0, MAX_ENCODE_TIME_US);
vpx_img_free(&img);
@ -650,7 +668,7 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u
vc_init_video_splitter_cycle(call->video.second);
while ( (pkt = vpx_codec_get_cx_data(call->video.second->v_encoder, &iter)) ) {
while ( (pkt = vpx_codec_get_cx_data(call->video.second->encoder, &iter)) ) {
if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
int parts = vc_update_video_splitter_cycle(call->video.second, pkt->data.frame.buf,
pkt->data.frame.sz);
@ -665,7 +683,7 @@ bool toxav_send_video_frame(ToxAV* av, uint32_t friend_number, uint16_t width, u
for (i = 0; i < parts; i++) {
iter = vc_iterate_split_video_frame(call->video.second, &part_size);
if (rtp_send_msg(call->video.first, iter, part_size) < 0) {
if (rtp_send_data(call->video.first, iter, part_size, false) < 0) {
pthread_mutex_unlock(call->mutex_video);
LOGGER_WARNING("Could not send video frame: %s\n", strerror(errno));
goto END;
@ -684,14 +702,6 @@ END:
return rc == TOXAV_ERR_SEND_FRAME_OK;
}
void toxav_callback_audio_frame_request(ToxAV* av, toxav_audio_frame_request_cb* function, void* user_data)
{
pthread_mutex_lock(av->mutex);
av->racb.first = function;
av->racb.second = user_data;
pthread_mutex_unlock(av->mutex);
}
bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pcm, size_t sample_count, uint8_t channels, uint32_t sampling_rate, TOXAV_ERR_SEND_FRAME* error)
{
TOXAV_ERR_SEND_FRAME rc = TOXAV_ERR_SEND_FRAME_OK;
@ -746,13 +756,41 @@ bool toxav_send_audio_frame(ToxAV* av, uint32_t friend_number, const int16_t* pc
goto END;
}
// LOGGER_DEBUG("Sending encoded audio frame size: %d; channels: %d; srate: %d", vrc, channels,
// ntohl(sampling_rate));
if (rtp_send_msg(call->audio.first, dest, vrc + sizeof(sampling_rate)) != 0) {
if (rtp_send_data(call->audio.first, dest, vrc + sizeof(sampling_rate), false) != 0) {
LOGGER_WARNING("Failed to send audio packet");
rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;
}
/* For bitrate measurement; send dummy packet */
if (ba_shoud_send_dummy(&call->aba)) {
sampling_rate = ntohl(sampling_rate);
if (ac_reconfigure_test_encoder(call->audio.second, call->audio_bit_rate * 1000, sampling_rate, channels) != 0) {
/* FIXME should the bitrate changing fail here? */
pthread_mutex_unlock(call->mutex_audio);
rc = TOXAV_ERR_SEND_FRAME_INVALID;
goto END;
}
sampling_rate = htonl(sampling_rate);
memcpy(dest, &sampling_rate, sizeof(sampling_rate));
vrc = opus_encode(call->audio.second->test_encoder, pcm, sample_count,
dest + sizeof(sampling_rate), sizeof(dest) - sizeof(sampling_rate));
if (vrc < 0) {
LOGGER_WARNING("Failed to encode frame %s", opus_strerror(vrc));
pthread_mutex_unlock(call->mutex_audio);
rc = TOXAV_ERR_SEND_FRAME_INVALID;
goto END;
}
if (rtp_send_data(call->audio.first, dest, vrc + sizeof(sampling_rate), true) != 0) {
LOGGER_WARNING("Failed to send audio packet");
rc = TOXAV_ERR_SEND_FRAME_RTP_FAILED;
}
}
ba_update_sent_regular(&call->aba);
}
pthread_mutex_unlock(call->mutex_audio);
@ -894,6 +932,57 @@ void invoke_call_state(ToxAV* av, uint32_t friend_number, uint32_t state)
av->scb.first(av, friend_number, state, av->scb.second);
}
void qc_do(ToxAVCall* call)
{
/*
switch(call->audio.first->tstate) {
case rtp_StateBad:
LOGGER_DEBUG("Suggesting lower bitrate for audio...");
call->time_audio_good = 0;
call->last_bad_audio_bit_rate = call->audio_bit_rate;
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_DECREASE_AUDIO_BITRATE);
break;
case rtp_StateGood:
if (call->time_audio_good == 0)
call->time_audio_good = current_time_monotonic();
else if (current_time_monotonic() - call->time_audio_good >= 30000 &&
64 > call->audio_bit_rate)
if (call->last_bad_audio_bit_rate > call->audio_bit_rate) {
if (current_time_monotonic() - call->time_audio_good >= 45000)
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
call->last_bad_audio_bit_rate = 0;
} else
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
break;
case rtp_StateNormal:
call->time_audio_good = 0;
break;
}*/
/*
switch(call->video.first->tstate) {
case rtp_StateBad:
LOGGER_DEBUG("Suggesting lower bitrate for video...");
call->time_video_good = 0;
call->last_bad_video_bit_rate = call->video_bit_rate;
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_DECREASE_VIDEO_BITRATE);
break;
case rtp_StateGood:
if (call->time_video_good == 0)
call->time_video_good = current_time_monotonic();
else if (current_time_monotonic() - call->time_video_good >= 30000)
if (call->last_bad_video_bit_rate > call->video_bit_rate) {
if (current_time_monotonic() - call->time_video_good >= 45000)
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
call->last_bad_video_bit_rate = 0;
} else
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
break;
case rtp_StateNormal:
call->time_video_good = 0;
break;
}*/
}
ToxAVCall* call_new(ToxAV* av, uint32_t friend_number, TOXAV_ERR_CALL* error)
{
/* Assumes mutex locked */
@ -984,57 +1073,6 @@ ToxAVCall* call_get(ToxAV* av, uint32_t friend_number)
return av->calls[friend_number];
}
void qc_do(ToxAVCall* call)
{
/*
switch(call->audio.first->tstate) {
case rtp_StateBad:
LOGGER_DEBUG("Suggesting lower bitrate for audio...");
call->time_audio_good = 0;
call->last_bad_audio_bit_rate = call->audio_bit_rate;
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_DECREASE_AUDIO_BITRATE);
break;
case rtp_StateGood:
if (call->time_audio_good == 0)
call->time_audio_good = current_time_monotonic();
else if (current_time_monotonic() - call->time_audio_good >= 30000 &&
64 > call->audio_bit_rate)
if (call->last_bad_audio_bit_rate > call->audio_bit_rate) {
if (current_time_monotonic() - call->time_audio_good >= 45000)
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
call->last_bad_audio_bit_rate = 0;
} else
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE);
break;
case rtp_StateNormal:
call->time_audio_good = 0;
break;
}*/
/*
switch(call->video.first->tstate) {
case rtp_StateBad:
LOGGER_DEBUG("Suggesting lower bitrate for video...");
call->time_video_good = 0;
call->last_bad_video_bit_rate = call->video_bit_rate;
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_DECREASE_VIDEO_BITRATE);
break;
case rtp_StateGood:
if (call->time_video_good == 0)
call->time_video_good = current_time_monotonic();
else if (current_time_monotonic() - call->time_video_good >= 30000)
if (call->last_bad_video_bit_rate > call->video_bit_rate) {
if (current_time_monotonic() - call->time_video_good >= 45000)
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
call->last_bad_video_bit_rate = 0;
} else
invoke_call_state(call->av, call->friend_id, TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE);
break;
case rtp_StateNormal:
call->time_video_good = 0;
break;
}*/
}
void call_remove(ToxAVCall* call)
{
if (call == NULL)
@ -1098,41 +1136,24 @@ bool call_prepare_transmission(ToxAVCall* call)
goto VIDEO_SENDING_MUTEX_CLEANUP;
}
{ /* Prepare audio */
call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_id);
call->audio.second = ac_new(av, call->friend_id, av->acb.first, av->acb.second);
call->audio.first = rtp_new(rtp_TypeAudio, av->m, call->friend_id, call->audio.second, ac_queue_message);
if ( !call->audio.first || !call->audio.second ) {
LOGGER_ERROR("Error while starting audio!\n");
goto FAILURE;
}
call->audio.first->cs = call->audio.second;
call->audio.first->mcb = ac_queue_message;
if (rtp_start_receiving(call->audio.first) != 0) {
LOGGER_WARNING("Failed to enable audio receiving!");
goto FAILURE;
}
}
{ /* Prepare video */
call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_id);
call->video.second = vc_new(av, call->friend_id, av->vcb.first, av->vcb.second, call->msi_call->peer_vfpsz);
call->video.first = rtp_new(rtp_TypeVideo, av->m, call->friend_id, call->video.second, vc_queue_message);
if ( !call->video.first || !call->video.second ) {
LOGGER_ERROR("Error while starting video!\n");
goto FAILURE;
}
call->video.first->cs = call->video.second;
call->video.first->mcb = vc_queue_message;
if (rtp_start_receiving(call->video.first) != 0) {
LOGGER_WARNING("Failed to enable video receiving!");
goto FAILURE;
}
}
call->active = 1;
@ -1183,3 +1204,38 @@ void call_kill_transmission(ToxAVCall* call)
pthread_mutex_destroy(call->mutex_video);
pthread_mutex_destroy(call->mutex);
}
void ba_set(ToxAvBitrateAdapter* ba, uint32_t bit_rate)
{
ba->bit_rate = bit_rate;
ba->start_time = current_time_monotonic();
ba->cycle_sent = 0;
ba->cycle_repeat = 3;
ba->cycle_ratio = 4;
ba->active = true;
}
bool ba_shoud_send_dummy(ToxAvBitrateAdapter* ba)
{
if (!ba->active || ba->cycle_ratio == 0)
return false;
if (ba->cycle_sent % ba->cycle_ratio == 0)
return true;
}
void ba_update_sent_regular(ToxAvBitrateAdapter* ba)
{
if (!ba->active || ba->cycle_ratio == 0) {
ba->active = false;
return;
}
if (ba->cycle_sent % ba->cycle_ratio == 0) {
ba->cycle_sent = 0;
if (--ba->cycle_repeat == 0)
--ba->cycle_ratio;
} else
++ba->cycle_sent;
}

View File

@ -216,22 +216,6 @@ typedef enum TOXAV_CALL_STATE {
* transitions can occur for the call.
*/
TOXAV_CALL_STATE_END = 16,
/**
* AV core suggests you to lower bitrate for audio.
*/
TOXAV_CALL_STATE_DECREASE_AUDIO_BITRATE = 32,
/**
* AV core suggests you to lower bitrate for video.
*/
TOXAV_CALL_STATE_DECREASE_VIDEO_BITRATE = 64,
/**
* AV core suggests you to increase bitrate for audio.
*/
TOXAV_CALL_STATE_INCREASE_AUDIO_BITRATE = 128,
/**
* AV core suggests you to increase bitrate for video.
*/
TOXAV_CALL_STATE_INCREASE_VIDEO_BITRATE = 256,
/**
* Set by the AV core if an error occurred on the remote end.
*/
@ -348,6 +332,24 @@ typedef enum TOXAV_ERR_BIT_RATE {
*/
TOXAV_ERR_BIT_RATE_FRIEND_NOT_IN_CALL
} TOXAV_ERR_BIT_RATE;
/**
* The function type for the `audio_bitrate_control` callback.
*
* @param friend_number The friend number of the friend for which to set the
* audio bit rate.
* @param good Is the stream good enough to keep the said bitrate. Upon failed
* non forceful bit rate setup this will be set to false and 'bit_rate'
* will be set to the bit rate that failed, otherwise 'good' will be set to
* true with 'bit_rate' set to new bit rate. If the stream becomes bad,
* the 'good' wil be set to false with 'bit_rate' set to the current bit rate.
* This callback will never be called when the stream is good.
* @param bit_rate The bit rate in Kb/sec.
*/
typedef void toxav_audio_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data);
/**
* Set the callback for the `audio_bitrate_control` event. Pass NULL to unset.
*/
void toxav_callback_audio_bitrate_control(ToxAV *av, toxav_audio_bitrate_control_cb *function, void *user_data);
/**
* Set the audio bit rate to be used in subsequent audio frames.
*
@ -358,7 +360,25 @@ typedef enum TOXAV_ERR_BIT_RATE {
*
* @see toxav_call for the valid bit rates.
*/
bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, TOXAV_ERR_BIT_RATE *error);
bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error);
/**
* The function type for the `video_bitrate_control` callback.
*
* @param friend_number The friend number of the friend for which to set the
* video bit rate.
* @param good Is the stream good enough to keep the said bitrate. Upon failed
* non forceful bit rate setup this will be set to false and 'bit_rate'
* will be set to the bit rate that failed, otherwise 'good' will be set to
* true with 'bit_rate' set to new bit rate. If the stream becomes bad,
* the 'good' wil be set to false with 'bit_rate' set to the current bit rate.
* This callback will never be called when the stream is good.
* @param bit_rate The bit rate in Kb/sec.
*/
typedef void toxav_video_bitrate_control_cb(ToxAV *av, uint32_t friend_number, bool good, uint32_t bit_rate, void *user_data);
/**
* Set the callback for the `video_bitrate_control` event. Pass NULL to unset.
*/
void toxav_callback_video_bitrate_control(ToxAV *av, toxav_video_bitrate_control_cb *function, void *user_data);
/**
* Set the video bit rate to be used in subsequent video frames.
*
@ -369,7 +389,7 @@ bool toxav_set_audio_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t audio_
*
* @see toxav_call for the valid bit rates.
*/
bool toxav_set_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, TOXAV_ERR_BIT_RATE *error);
bool toxav_set_video_bit_rate(ToxAV *av, uint32_t friend_number, uint32_t video_bit_rate, bool force, TOXAV_ERR_BIT_RATE *error);
/*******************************************************************************
*
* :: A/V sending
@ -408,17 +428,6 @@ typedef enum TOXAV_ERR_SEND_FRAME {
*/
TOXAV_ERR_SEND_FRAME_RTP_FAILED
} TOXAV_ERR_SEND_FRAME;
/**
* The function type for the `video_frame_request` callback.
*
* @param friend_number The friend number of the friend for which the next video
* frame should be sent.
*/
typedef void toxav_video_frame_request_cb(ToxAV *av, uint32_t friend_number, void *user_data);
/**
* Set the callback for the `video_frame_request` event. Pass NULL to unset.
*/
void toxav_callback_video_frame_request(ToxAV *av, toxav_video_frame_request_cb *function, void *user_data);
/**
* Send a video frame to a friend.
*
@ -440,17 +449,6 @@ bool toxav_send_video_frame(ToxAV *av, uint32_t friend_number,
uint16_t width, uint16_t height,
uint8_t const *y, uint8_t const *u, uint8_t const *v,
TOXAV_ERR_SEND_FRAME *error);
/**
* The function type for the `audio_frame_request` callback.
*
* @param friend_number The friend number of the friend for which the next audio
* frame should be sent.
*/
typedef void toxav_audio_frame_request_cb(ToxAV *av, uint32_t friend_number, void *user_data);
/**
* Set the callback for the `audio_frame_request` event. Pass NULL to unset.
*/
void toxav_callback_audio_frame_request(ToxAV *av, toxav_audio_frame_request_cb *function, void *user_data);
/**
* Send an audio frame to a friend.
*

View File

@ -65,15 +65,15 @@ VCSession* vc_new(ToxAV* av, uint32_t friend_id, toxav_receive_video_frame_cb* c
if ( !(vc->vbuf_raw = rb_new(VIDEO_DECODE_BUFFER_SIZE)) )
goto BASE_CLEANUP;
int rc = vpx_codec_dec_init_ver(vc->v_decoder, VIDEO_CODEC_DECODER_INTERFACE,
int rc = vpx_codec_dec_init_ver(vc->decoder, VIDEO_CODEC_DECODER_INTERFACE,
NULL, 0, VPX_DECODER_ABI_VERSION);
if ( rc != VPX_CODEC_OK) {
LOGGER_ERROR("Init video_decoder failed: %s", vpx_codec_err_to_string(rc));
goto BASE_CLEANUP;
}
if (!create_video_encoder(vc->v_encoder, 500000)) {
vpx_codec_destroy(vc->v_decoder);
if (!create_video_encoder(vc->encoder, 500000)) {
vpx_codec_destroy(vc->decoder);
goto BASE_CLEANUP;
}
@ -99,8 +99,8 @@ void vc_kill(VCSession* vc)
if (!vc)
return;
vpx_codec_destroy(vc->v_encoder);
vpx_codec_destroy(vc->v_decoder);
vpx_codec_destroy(vc->encoder);
vpx_codec_destroy(vc->decoder);
rb_free(vc->vbuf_raw);
free(vc->split_video_frame);
free(vc->frame_buf);
@ -122,17 +122,17 @@ void vc_do(VCSession* vc)
if (rb_read(vc->vbuf_raw, (void**)&p)) {
pthread_mutex_unlock(vc->queue_mutex);
rc = vpx_codec_decode(vc->v_decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
rc = vpx_codec_decode(vc->decoder, p->data, p->size, NULL, MAX_DECODE_TIME_US);
free(p);
if (rc != VPX_CODEC_OK) {
LOGGER_ERROR("Error decoding video: %s", vpx_codec_err_to_string(rc));
} else {
vpx_codec_iter_t iter = NULL;
vpx_image_t *dest = vpx_codec_get_frame(vc->v_decoder, &iter);
vpx_image_t *dest = vpx_codec_get_frame(vc->decoder, &iter);
/* Play decoded images */
for (; dest; dest = vpx_codec_get_frame(vc->v_decoder, &iter)) {
for (; dest; dest = vpx_codec_get_frame(vc->decoder, &iter)) {
if (vc->vcb.first)
vc->vcb.first(vc->av, vc->friend_id, dest->d_w, dest->d_h,
(const uint8_t*)dest->planes[0], (const uint8_t*)dest->planes[1], (const uint8_t*)dest->planes[2],
@ -157,7 +157,7 @@ void vc_init_video_splitter_cycle(VCSession* vc)
int vc_update_video_splitter_cycle(VCSession* vc, const uint8_t* payload, uint16_t length)
{
if (!vc)
return;
return 0;
vc->processing_video_frame = payload;
vc->processing_video_frame_size = length;
@ -198,15 +198,15 @@ int vc_queue_message(void* vcp, struct RTPMessage_s *msg)
if (!vcp || !msg)
return -1;
if ((msg->header->marker_payloadt & 0x7f) == rtp_TypeDummyVideo % 128) {
if ((msg->header->marker_payloadt & 0x7f) == (rtp_TypeVideo + 2) % 128) {
LOGGER_WARNING("Got dummy!");
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
return 0;
}
if ((msg->header->marker_payloadt & 0x7f) != rtp_TypeVideo % 128) {
LOGGER_WARNING("Invalid payload type!");
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
return -1;
}
@ -280,15 +280,15 @@ int vc_queue_message(void* vcp, struct RTPMessage_s *msg)
vc->frame_size = framebuf_new_length;
end:
rtp_free_msg(NULL, msg);
rtp_free_msg(msg);
return 0;
}
int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint16_t height)
{
if (!vc)
return;
return -1;
vpx_codec_enc_cfg_t cfg = *vc->v_encoder[0].config.enc;
vpx_codec_enc_cfg_t cfg = *vc->encoder[0].config.enc;
if (cfg.rc_target_bitrate == bitrate && cfg.g_w == width && cfg.g_h == height)
return 0; /* Nothing changed */
@ -296,7 +296,7 @@ int vc_reconfigure_encoder(VCSession* vc, int32_t bitrate, uint16_t width, uint1
cfg.g_w = width;
cfg.g_h = height;
int rc = vpx_codec_enc_config_set(vc->v_encoder, &cfg);
int rc = vpx_codec_enc_config_set(vc->encoder, &cfg);
if ( rc != VPX_CODEC_OK) {
LOGGER_ERROR("Failed to set encoder control setting: %s", vpx_codec_err_to_string(rc));
return -1;

View File

@ -41,11 +41,11 @@ struct RTPMessage_s;
typedef struct VCSession_s {
/* encoding */
vpx_codec_ctx_t v_encoder[1];
vpx_codec_ctx_t encoder[1];
uint32_t frame_counter;
/* decoding */
vpx_codec_ctx_t v_decoder[1];
vpx_codec_ctx_t decoder[1];
void *vbuf_raw; /* Un-decoded data */
/* Data handling */