mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Almost done
This commit is contained in:
parent
1bfd93e64a
commit
144fc94d69
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
|
@ -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)
|
||||
|
|
276
toxav/rtp.c
276
toxav/rtp.c
|
@ -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();
|
||||
}
|
||||
}
|
14
toxav/rtp.h
14
toxav/rtp.h
|
@ -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 */
|
||||
|
|
268
toxav/toxav.c
268
toxav/toxav.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue
Block a user