mirror of
https://github.com/irungentoo/toxcore.git
synced 2024-03-22 13:30:51 +08:00
Started adding public API
This commit is contained in:
parent
b30b98aa0b
commit
292708c336
|
@ -37,9 +37,8 @@
|
|||
#include <opus/opus.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "toxmsi.h"
|
||||
#include "toxrtp.h"
|
||||
#include "toxmedia.h"
|
||||
#include "rtp.h"
|
||||
#include "media.h"
|
||||
|
||||
struct jitter_buffer {
|
||||
RTPMessage **queue;
|
||||
|
@ -79,8 +78,6 @@ struct jitter_buffer *create_queue(int capacity)
|
|||
/* returns 1 if 'a' has a higher sequence number than 'b' */
|
||||
uint8_t sequence_number_older(uint16_t sn_a, uint16_t sn_b, uint32_t ts_a, uint32_t ts_b)
|
||||
{
|
||||
/* should be stable enough */
|
||||
|
||||
/* TODO: There is already this kind of function in toxrtp.c.
|
||||
* Maybe merge?
|
||||
*/
|
||||
|
@ -141,7 +138,6 @@ int empty_queue(struct jitter_buffer *q)
|
|||
{
|
||||
while (q->size > 0) {
|
||||
q->size--;
|
||||
/* FIXME: */
|
||||
rtp_free_msg(NULL, q->queue[q->front]);
|
||||
q->front++;
|
||||
|
||||
|
@ -207,64 +203,56 @@ int queue(struct jitter_buffer *q, RTPMessage *pk)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int init_receive_audio(codec_state *cs)
|
||||
{
|
||||
int rc;
|
||||
cs->audio_decoder = opus_decoder_create(48000, 1, &rc );
|
||||
|
||||
if ( rc != OPUS_OK ){
|
||||
printf("Error while starting audio decoder!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = opus_decoder_init(cs->audio_decoder, 48000, 1);
|
||||
|
||||
if ( rc != OPUS_OK ){
|
||||
printf("Error while starting audio decoder!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
printf("Init audio decoder successful\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int init_receive_video(codec_state *cs)
|
||||
int init_video_decoder(CodecState *cs)
|
||||
{
|
||||
cs->video_decoder = avcodec_find_decoder(VIDEO_CODEC);
|
||||
|
||||
|
||||
if (!cs->video_decoder) {
|
||||
printf("Init video_decoder failed\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Init video_decoder failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
cs->video_decoder_ctx = avcodec_alloc_context3(cs->video_decoder);
|
||||
|
||||
|
||||
if (!cs->video_decoder_ctx) {
|
||||
printf("Init video_decoder_ctx failed\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Init video_decoder_ctx failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (avcodec_open2(cs->video_decoder_ctx, cs->video_decoder, NULL) < 0) {
|
||||
printf("Opening video decoder failed\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Opening video decoder failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Init video decoder successful\n");
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_send_video(codec_state *cs)
|
||||
int init_audio_decoder(CodecState *cs, uint32_t audio_channels)
|
||||
{
|
||||
cs->video_input_format = av_find_input_format(VIDEO_DRIVER);
|
||||
int rc;
|
||||
cs->audio_decoder = opus_decoder_create(cs->audio_sample_rate, audio_channels, &rc );
|
||||
|
||||
if ( rc != OPUS_OK ){
|
||||
fprintf(stderr, "Error while starting audio decoder!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (avformat_open_input(&cs->video_format_ctx, DEFAULT_WEBCAM, cs->video_input_format, NULL) != 0) {
|
||||
printf("opening video_input_format failed\n");
|
||||
return 0;
|
||||
|
||||
int init_video_encoder(CodecState *cs, const char* webcam, const char* video_driver, uint32_t video_bitrate)
|
||||
{
|
||||
cs->video_input_format = av_find_input_format(video_driver);
|
||||
|
||||
if (avformat_open_input(&cs->video_format_ctx, webcam, cs->video_input_format, NULL) != 0) {
|
||||
fprintf(stderr, "Opening video_input_format failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
avformat_find_stream_info(cs->video_format_ctx, NULL);
|
||||
av_dump_format(cs->video_format_ctx, 0, DEFAULT_WEBCAM, 0);
|
||||
av_dump_format(cs->video_format_ctx, 0, webcam, 0);
|
||||
|
||||
int i;
|
||||
|
||||
|
@ -279,42 +267,42 @@ int init_send_video(codec_state *cs)
|
|||
cs->webcam_decoder = avcodec_find_decoder(cs->webcam_decoder_ctx->codec_id);
|
||||
|
||||
if (cs->webcam_decoder == NULL) {
|
||||
printf("Unsupported codec\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Unsupported codec!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cs->webcam_decoder_ctx == NULL) {
|
||||
printf("init webcam_decoder_ctx failed\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Init webcam_decoder_ctx failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (avcodec_open2(cs->webcam_decoder_ctx, cs->webcam_decoder, NULL) < 0) {
|
||||
printf("opening webcam decoder failed\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Opening webcam decoder failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC);
|
||||
|
||||
if (!cs->video_encoder) {
|
||||
printf("init video_encoder failed\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Init video_encoder failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder);
|
||||
|
||||
if (!cs->video_encoder_ctx) {
|
||||
printf("init video_encoder_ctx failed\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Init video_encoder_ctx failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cs->video_encoder_ctx->bit_rate = VIDEO_BITRATE;
|
||||
cs->video_encoder_ctx->bit_rate = video_bitrate;
|
||||
cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate;
|
||||
av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0);
|
||||
av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0);
|
||||
|
||||
cs->video_encoder_ctx->thread_count = 4;
|
||||
cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95;
|
||||
cs->video_encoder_ctx->rc_buffer_size = VIDEO_BITRATE * 6;
|
||||
cs->video_encoder_ctx->rc_buffer_size = video_bitrate * 6;
|
||||
cs->video_encoder_ctx->profile = 3;
|
||||
cs->video_encoder_ctx->qmax = 54;
|
||||
cs->video_encoder_ctx->qmin = 4;
|
||||
|
@ -326,66 +314,84 @@ int init_send_video(codec_state *cs)
|
|||
cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height;
|
||||
|
||||
if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) {
|
||||
printf("opening video encoder failed\n");
|
||||
return 0;
|
||||
fprintf(stderr, "Opening video encoder failed!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("init video encoder successful\n");
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_send_audio(codec_state *cs)
|
||||
int init_audio_encoder(CodecState *cs)
|
||||
{
|
||||
cs->support_send_audio = 0;
|
||||
|
||||
int err = OPUS_OK;
|
||||
cs->audio_bitrate = AUDIO_BITRATE;
|
||||
cs->audio_encoder = opus_encoder_create(AUDIO_SAMPLE_RATE, 1, OPUS_APPLICATION_VOIP, &err);
|
||||
cs->audio_encoder = opus_encoder_create(cs->audio_sample_rate, 1, OPUS_APPLICATION_VOIP, &err);
|
||||
|
||||
err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_BITRATE(cs->audio_bitrate));
|
||||
err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_COMPLEXITY(10));
|
||||
err = opus_encoder_ctl(cs->audio_encoder, OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
|
||||
|
||||
/* NOTE: What do we do with this? */
|
||||
int nfo;
|
||||
err = opus_encoder_ctl(cs->audio_encoder, OPUS_GET_LOOKAHEAD(&nfo));
|
||||
/* printf("Encoder lookahead delay : %d\n", nfo); */
|
||||
printf("init audio encoder successful\n");
|
||||
|
||||
return 1;
|
||||
|
||||
return err == OPUS_OK ? 0 : -1;
|
||||
}
|
||||
|
||||
int init_encoder(codec_state *cs)
|
||||
|
||||
CodecState* codec_init_session ( uint32_t audio_bitrate,
|
||||
uint16_t audio_frame_duration,
|
||||
uint32_t audio_sample_rate,
|
||||
uint32_t audio_channels,
|
||||
uint32_t video_bitrate,
|
||||
const char* webcam,
|
||||
const char* webcam_driver )
|
||||
{
|
||||
CodecState* _retu = av_calloc(sizeof(CodecState), 1);
|
||||
assert(_retu);
|
||||
|
||||
|
||||
avdevice_register_all();
|
||||
avcodec_register_all();
|
||||
avdevice_register_all();
|
||||
av_register_all();
|
||||
|
||||
pthread_mutex_init(&cs->ctrl_mutex, NULL);
|
||||
|
||||
cs->support_send_video = init_send_video(cs);
|
||||
cs->support_send_audio = init_send_audio(cs);
|
||||
|
||||
cs->send_audio = 1;
|
||||
cs->send_video = 1;
|
||||
|
||||
return 1;
|
||||
|
||||
|
||||
_retu->audio_bitrate = audio_bitrate;
|
||||
_retu->audio_sample_rate = audio_sample_rate;
|
||||
|
||||
pthread_mutex_init(&_retu->ctrl_mutex, NULL);
|
||||
|
||||
|
||||
/* Encoders */
|
||||
if ( 0 == init_video_encoder(_retu, webcam, webcam_driver, video_bitrate) )
|
||||
printf("Video encoder initialized!\n");
|
||||
|
||||
if ( 0 == init_audio_encoder(_retu) )
|
||||
printf("Audio encoder initialized!\n");
|
||||
|
||||
|
||||
/* Decoders */
|
||||
if ( 0 == init_video_decoder(_retu) )
|
||||
printf("Video decoder initialized!\n");
|
||||
|
||||
if ( 0 == init_audio_decoder(_retu, audio_channels) )
|
||||
printf("Audio decoder initialized!\n");
|
||||
|
||||
|
||||
return _retu;
|
||||
}
|
||||
|
||||
int init_decoder(codec_state *cs)
|
||||
void codec_terminate_session ( CodecState* cs )
|
||||
{
|
||||
avdevice_register_all();
|
||||
avcodec_register_all();
|
||||
avdevice_register_all();
|
||||
av_register_all();
|
||||
|
||||
cs->receive_video = 0;
|
||||
cs->receive_audio = 0;
|
||||
|
||||
cs->support_receive_video = init_receive_video(cs);
|
||||
cs->support_receive_audio = init_receive_audio(cs);
|
||||
|
||||
cs->receive_audio = 1;
|
||||
cs->receive_video = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
if ( cs->audio_encoder ) {
|
||||
opus_encoder_destroy(cs->audio_encoder);
|
||||
printf("Terminated encoder!\n");
|
||||
}
|
||||
|
||||
if ( cs->audio_decoder ) {
|
||||
opus_decoder_destroy(cs->audio_decoder);
|
||||
printf("Terminated decoder!\n");
|
||||
}
|
||||
|
||||
/* TODO: Terminate video */
|
||||
|
||||
}
|
|
@ -27,8 +27,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "toxrtp.h"
|
||||
#include "toxmsi.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
/* Video encoding/decoding */
|
||||
|
@ -75,16 +73,7 @@
|
|||
#define DEFAULT_WEBCAM "0"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint8_t send_audio;
|
||||
uint8_t receive_audio;
|
||||
uint8_t send_video;
|
||||
uint8_t receive_video;
|
||||
|
||||
uint8_t support_send_audio;
|
||||
uint8_t support_send_video;
|
||||
uint8_t support_receive_audio;
|
||||
uint8_t support_receive_video;
|
||||
typedef struct _CodecState{
|
||||
|
||||
/* video encoding */
|
||||
AVInputFormat *video_input_format;
|
||||
|
@ -102,19 +91,19 @@ typedef struct {
|
|||
/* audio encoding */
|
||||
OpusEncoder *audio_encoder;
|
||||
int audio_bitrate;
|
||||
int audio_sample_rate;
|
||||
|
||||
/* audio decoding */
|
||||
OpusDecoder *audio_decoder;
|
||||
|
||||
uint8_t req_video_refresh;
|
||||
|
||||
pthread_mutex_t ctrl_mutex;
|
||||
|
||||
|
||||
uint32_t frame_rate;
|
||||
|
||||
} codec_state;
|
||||
} CodecState;
|
||||
|
||||
typedef struct _RTPMessage RTPMessage;
|
||||
|
||||
struct jitter_buffer *create_queue(int capacity);
|
||||
int empty_queue(struct jitter_buffer *q);
|
||||
|
@ -123,8 +112,14 @@ int queue(struct jitter_buffer *q, RTPMessage *pk);
|
|||
RTPMessage *dequeue(struct jitter_buffer *q, int *success);
|
||||
|
||||
|
||||
int init_encoder(codec_state *cs);
|
||||
int init_decoder(codec_state *cs);
|
||||
CodecState* codec_init_session( uint32_t audio_bitrate,
|
||||
uint16_t audio_frame_duration,
|
||||
uint32_t audio_sample_rate,
|
||||
uint32_t audio_channels,
|
||||
uint32_t video_bitrate,
|
||||
const char* webcam,
|
||||
const char* webcam_driver );
|
||||
|
||||
void codec_terminate_session(CodecState* cs);
|
||||
|
||||
#endif
|
44
toxav/toxmsi.c → toxav/msi.c
Executable file → Normal file
44
toxav/toxmsi.c → toxav/msi.c
Executable file → Normal file
|
@ -29,7 +29,7 @@
|
|||
|
||||
#define _BSD_SOURCE
|
||||
|
||||
#include "toxmsi.h"
|
||||
#include "msi.h"
|
||||
#include "../toxcore/util.h"
|
||||
#include "../toxcore/network.h"
|
||||
#include "../toxcore/event.h"
|
||||
|
@ -335,8 +335,6 @@ MSIMessage* msi_new_message ( uint8_t type, const uint8_t* type_id ) {
|
|||
MSIMessage* _retu = calloc ( sizeof ( MSIMessage ), 1 );
|
||||
assert ( _retu );
|
||||
|
||||
memset ( _retu, 0, sizeof ( MSIMessage ) );
|
||||
|
||||
if ( type == TYPE_REQUEST ) {
|
||||
ALLOCATE_HEADER ( _retu->request, type_id, strlen ( (const char*)type_id ) )
|
||||
|
||||
|
@ -641,7 +639,7 @@ int handle_error ( MSISession* session, MSICallError errid, uint32_t to ) {
|
|||
session->last_error_id = errid;
|
||||
session->last_error_str = stringify_error ( errid );
|
||||
|
||||
event.rise ( callbacks[MSI_OnError], session );
|
||||
event.rise ( callbacks[MSI_OnError], session->agent_handler );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -692,12 +690,12 @@ void* handle_timeout ( void* arg )
|
|||
/* Cancel all? */
|
||||
uint16_t _it = 0;
|
||||
for ( ; _it < _peer_count; _it++ )
|
||||
msi_cancel ( arg, _peers[_it] );
|
||||
msi_cancel ( arg, _peers[_it], (const uint8_t*)"Timeout" );
|
||||
|
||||
}
|
||||
|
||||
( *callbacks[MSI_OnTimeout] ) ( arg );
|
||||
( *callbacks[MSI_OnEnding ] ) ( arg );
|
||||
( *callbacks[MSI_OnTimeout] ) ( _session->agent_handler );
|
||||
( *callbacks[MSI_OnEnding ] ) ( _session->agent_handler );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -829,7 +827,7 @@ int handle_recv_invite ( MSISession* session, MSIMessage* msg ) {
|
|||
send_message ( session, _msg_ringing, msg->friend_id );
|
||||
free_message ( _msg_ringing );
|
||||
|
||||
event.rise ( callbacks[MSI_OnInvite], session );
|
||||
event.rise ( callbacks[MSI_OnInvite], session->agent_handler );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -852,7 +850,7 @@ int handle_recv_start ( MSISession* session, MSIMessage* msg ) {
|
|||
|
||||
flush_peer_type ( session, msg, 0 );
|
||||
|
||||
event.rise ( callbacks[MSI_OnStart], session );
|
||||
event.rise ( callbacks[MSI_OnStart], session->agent_handler );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -868,7 +866,7 @@ int handle_recv_reject ( MSISession* session, MSIMessage* msg ) {
|
|||
free_message ( _msg_end );
|
||||
|
||||
event.timer_release ( session->call->request_timer_id );
|
||||
event.rise ( callbacks[MSI_OnReject], session );
|
||||
event.rise ( callbacks[MSI_OnReject], session->agent_handler );
|
||||
session->call->request_timer_id = event.timer_alloc ( handle_timeout, session, m_deftout );
|
||||
|
||||
return 1;
|
||||
|
@ -882,7 +880,7 @@ int handle_recv_cancel ( MSISession* session, MSIMessage* msg ) {
|
|||
|
||||
terminate_call ( session );
|
||||
|
||||
event.rise ( callbacks[MSI_OnCancel], session );
|
||||
event.rise ( callbacks[MSI_OnCancel], session->agent_handler );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -899,7 +897,7 @@ int handle_recv_end ( MSISession* session, MSIMessage* msg ) {
|
|||
|
||||
terminate_call ( session );
|
||||
|
||||
event.rise ( callbacks[MSI_OnEnd], session );
|
||||
event.rise ( callbacks[MSI_OnEnd], session->agent_handler );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -912,7 +910,7 @@ int handle_recv_ringing ( MSISession* session, MSIMessage* msg ) {
|
|||
return 0;
|
||||
|
||||
session->call->ringing_timer_id = event.timer_alloc ( handle_timeout, session, session->call->ringing_tout_ms );
|
||||
event.rise ( callbacks[MSI_OnRinging], session );
|
||||
event.rise ( callbacks[MSI_OnRinging], session->agent_handler );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -950,7 +948,7 @@ int handle_recv_starting ( MSISession* session, MSIMessage* msg ) {
|
|||
|
||||
flush_peer_type ( session, msg, 0 );
|
||||
|
||||
event.rise ( callbacks[MSI_OnStarting], session );
|
||||
event.rise ( callbacks[MSI_OnStarting], session->agent_handler );
|
||||
event.timer_release ( session->call->ringing_timer_id );
|
||||
|
||||
return 1;
|
||||
|
@ -964,7 +962,7 @@ int handle_recv_ending ( MSISession* session, MSIMessage* msg ) {
|
|||
|
||||
terminate_call ( session );
|
||||
|
||||
event.rise ( callbacks[MSI_OnEnding], session );
|
||||
event.rise ( callbacks[MSI_OnEnding], session->agent_handler );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -980,7 +978,7 @@ int handle_recv_error ( MSISession* session, MSIMessage* msg ) {
|
|||
|
||||
terminate_call ( session );
|
||||
|
||||
event.rise ( callbacks[MSI_OnEnding], session );
|
||||
event.rise ( callbacks[MSI_OnEnding], session->agent_handler );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1138,14 +1136,13 @@ void msi_register_callback ( MSICallback callback, MSICallbackID id )
|
|||
* @return MSISession* The created session.
|
||||
* @retval NULL Error occured.
|
||||
*/
|
||||
MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent ) {
|
||||
MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name ) {
|
||||
assert ( messenger );
|
||||
assert ( user_agent );
|
||||
|
||||
MSISession* _retu = calloc ( sizeof ( MSISession ), 1 );
|
||||
assert ( _retu );
|
||||
|
||||
_retu->user_agent = user_agent;
|
||||
_retu->ua_name = ua_name;
|
||||
_retu->messenger_handle = messenger;
|
||||
_retu->agent_handler = NULL;
|
||||
|
||||
|
@ -1300,14 +1297,17 @@ int msi_answer ( MSISession* session, MSICallType call_type ) {
|
|||
* @brief Cancel request.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @param friend_id The friend.
|
||||
* @param reason Set optional reason header. Pass NULL if none.
|
||||
* @return int
|
||||
*/
|
||||
int msi_cancel ( MSISession* session, int friend_id ) {
|
||||
int msi_cancel ( MSISession* session, uint32_t peer, const uint8_t* reason ) {
|
||||
assert ( session );
|
||||
|
||||
MSIMessage* _msg_cancel = msi_new_message ( TYPE_REQUEST, stringify_request ( cancel ) );
|
||||
send_message ( session, _msg_cancel, friend_id );
|
||||
|
||||
if ( reason ) msi_msg_set_reason(_msg_cancel, reason, strlen((const char*)reason));
|
||||
|
||||
send_message ( session, _msg_cancel, peer );
|
||||
free_message ( _msg_cancel );
|
||||
|
||||
terminate_call ( session );
|
9
toxav/toxmsi.h → toxav/msi.h
Executable file → Normal file
9
toxav/toxmsi.h → toxav/msi.h
Executable file → Normal file
|
@ -103,7 +103,7 @@ typedef struct _MSISession {
|
|||
int last_error_id; /* Determine the last error */
|
||||
const uint8_t* last_error_str;
|
||||
|
||||
const uint8_t* user_agent;
|
||||
const uint8_t* ua_name;
|
||||
|
||||
void* agent_handler; /* Pointer to an object that is handling msi */
|
||||
Tox* messenger_handle;
|
||||
|
@ -156,7 +156,7 @@ void msi_register_callback(MSICallback callback, MSICallbackID id);
|
|||
* @return MSISession* The created session.
|
||||
* @retval NULL Error occured.
|
||||
*/
|
||||
MSISession* msi_init_session ( Tox* messenger, const uint8_t* user_agent );
|
||||
MSISession* msi_init_session ( Tox* messenger, const uint8_t* ua_name );
|
||||
|
||||
|
||||
/**
|
||||
|
@ -205,10 +205,11 @@ int msi_answer ( MSISession* session, MSICallType call_type );
|
|||
* @brief Cancel request.
|
||||
*
|
||||
* @param session Control session.
|
||||
* @param friend_id The friend.
|
||||
* @param peer To which peer.
|
||||
* @param reason Set optional reason header. Pass NULL if none.
|
||||
* @return int
|
||||
*/
|
||||
int msi_cancel ( MSISession* session, int friend_id );
|
||||
int msi_cancel ( MSISession* session, uint32_t peer, const uint8_t* reason );
|
||||
|
||||
|
||||
/**
|
467
toxav/phone.c
467
toxav/phone.c
|
@ -51,9 +51,8 @@
|
|||
#include <pthread.h>
|
||||
#include <opus/opus.h>
|
||||
|
||||
#include "toxmsi.h"
|
||||
#include "toxrtp.h"
|
||||
#include "toxmedia.h"
|
||||
#include "media.h"
|
||||
#include "toxav.h"
|
||||
#include "../toxcore/event.h"
|
||||
#include "../toxcore/tox.h"
|
||||
|
||||
|
@ -75,13 +74,9 @@ typedef struct av_friend_s {
|
|||
} av_friend_t;
|
||||
|
||||
typedef struct av_session_s {
|
||||
MSISession* _msi;
|
||||
RTPSession* _rtp_audio;
|
||||
RTPSession* _rtp_video;
|
||||
|
||||
/* Encoding/decoding/capturing/playing */
|
||||
ToxAv* av;
|
||||
|
||||
codec_state* cs;
|
||||
VideoPicture video_picture;
|
||||
struct ALCdevice *audio_capture_device;
|
||||
|
||||
|
@ -91,8 +86,9 @@ typedef struct av_session_s {
|
|||
/* context for converting webcam image format to something the video encoder can use */
|
||||
struct SwsContext *sws_ctx;
|
||||
|
||||
/**/
|
||||
|
||||
/* Thread running control */
|
||||
int running_decaud, running_encaud,
|
||||
running_decvid, running_encvid;
|
||||
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
|
@ -243,7 +239,7 @@ static void fraddr_to_str(uint8_t *id_bin, char *id_str)
|
|||
|
||||
int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame)
|
||||
{
|
||||
codec_state* cs = _phone->cs;
|
||||
CodecState* cs = get_cs_temp(_phone->av);
|
||||
AVPicture pict;
|
||||
SDL_LockYUVOverlay(_phone->video_picture.bmp);
|
||||
|
||||
|
@ -268,71 +264,15 @@ int display_received_frame(av_session_t* _phone, AVFrame *r_video_frame)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int video_encoder_refresh(codec_state *cs, int bps)
|
||||
{
|
||||
if (cs->video_encoder_ctx)
|
||||
avcodec_close(cs->video_encoder_ctx);
|
||||
|
||||
cs->video_encoder = avcodec_find_encoder(VIDEO_CODEC);
|
||||
|
||||
if (!cs->video_encoder) {
|
||||
printf("init video_encoder failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cs->video_encoder_ctx = avcodec_alloc_context3(cs->video_encoder);
|
||||
|
||||
if (!cs->video_encoder_ctx) {
|
||||
printf("init video_encoder_ctx failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cs->video_encoder_ctx->bit_rate = bps;
|
||||
cs->video_encoder_ctx->rc_min_rate = cs->video_encoder_ctx->rc_max_rate = cs->video_encoder_ctx->bit_rate;
|
||||
av_opt_set_double(cs->video_encoder_ctx->priv_data, "max-intra-rate", 90, 0);
|
||||
av_opt_set(cs->video_encoder_ctx->priv_data, "quality", "realtime", 0);
|
||||
|
||||
cs->video_encoder_ctx->thread_count = 4;
|
||||
cs->video_encoder_ctx->rc_buffer_aggressivity = 0.95;
|
||||
cs->video_encoder_ctx->rc_buffer_size = bps * 6;
|
||||
cs->video_encoder_ctx->profile = 0;
|
||||
cs->video_encoder_ctx->qmax = 54;
|
||||
cs->video_encoder_ctx->qmin = 4;
|
||||
AVRational myrational = {1, 25};
|
||||
cs->video_encoder_ctx->time_base = myrational;
|
||||
cs->video_encoder_ctx->gop_size = 99999;
|
||||
cs->video_encoder_ctx->pix_fmt = PIX_FMT_YUV420P;
|
||||
cs->video_encoder_ctx->width = cs->webcam_decoder_ctx->width;
|
||||
cs->video_encoder_ctx->height = cs->webcam_decoder_ctx->height;
|
||||
|
||||
if (avcodec_open2(cs->video_encoder_ctx, cs->video_encoder, NULL) < 0) {
|
||||
printf("opening video encoder failed\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int video_decoder_refresh(av_session_t* _phone, int width, int height)
|
||||
{
|
||||
printf("need to refresh\n");
|
||||
screen = SDL_SetVideoMode(width, height, 0, 0);
|
||||
|
||||
if (_phone->video_picture.bmp)
|
||||
SDL_FreeYUVOverlay(_phone->video_picture.bmp);
|
||||
|
||||
_phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen);
|
||||
_phone->sws_SDL_r_ctx = sws_getContext(width, height, _phone->cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P,
|
||||
SWS_BILINEAR, NULL, NULL, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *encode_video_thread(void *arg)
|
||||
{
|
||||
INFO("Started encode video thread!");
|
||||
|
||||
av_session_t* _phone = arg;
|
||||
|
||||
codec_state *cs = _phone->cs;
|
||||
_phone->running_encvid = 1;
|
||||
|
||||
CodecState *cs = get_cs_temp(_phone->av);
|
||||
AVPacket pkt1, *packet = &pkt1;
|
||||
int p = 0;
|
||||
int got_packet;
|
||||
|
@ -354,7 +294,7 @@ void *encode_video_thread(void *arg)
|
|||
cs->webcam_decoder_ctx->pix_fmt, cs->webcam_decoder_ctx->width, cs->webcam_decoder_ctx->height, PIX_FMT_YUV420P,
|
||||
SWS_BILINEAR, NULL, NULL, NULL);
|
||||
|
||||
while (cs->send_video) {
|
||||
while (_phone->running_encvid) {
|
||||
|
||||
if (av_read_frame(cs->video_format_ctx, packet) < 0) {
|
||||
printf("error reading frame\n");
|
||||
|
@ -400,9 +340,7 @@ void *encode_video_thread(void *arg)
|
|||
|
||||
if (!enc_video_packet.data) fprintf(stderr, "video packet data is NULL\n");
|
||||
|
||||
if ( 0 > rtp_send_msg ( _phone->_rtp_video, _phone->_messenger, enc_video_packet.data, enc_video_packet.size) ) {
|
||||
printf("Failed sending message\n");
|
||||
}
|
||||
toxav_send_rtp_payload(_phone->av, TypeVideo, enc_video_packet.data, enc_video_packet.size);
|
||||
|
||||
av_free_packet(&enc_video_packet);
|
||||
}
|
||||
|
@ -420,6 +358,9 @@ void *encode_video_thread(void *arg)
|
|||
avcodec_close(cs->webcam_decoder_ctx);
|
||||
avcodec_close(cs->video_encoder_ctx);
|
||||
pthread_mutex_unlock(&cs->ctrl_mutex);
|
||||
|
||||
_phone->running_encvid = -1;
|
||||
|
||||
pthread_exit ( NULL );
|
||||
}
|
||||
|
||||
|
@ -427,8 +368,8 @@ void *encode_audio_thread(void *arg)
|
|||
{
|
||||
INFO("Started encode audio thread!");
|
||||
av_session_t* _phone = arg;
|
||||
_phone->running_encaud = 1;
|
||||
|
||||
codec_state *cs = _phone->cs;
|
||||
unsigned char encoded_data[4096];
|
||||
int encoded_size = 0;
|
||||
int16_t frame[4096];
|
||||
|
@ -436,39 +377,46 @@ void *encode_audio_thread(void *arg)
|
|||
ALint sample = 0;
|
||||
alcCaptureStart((ALCdevice*)_phone->audio_capture_device);
|
||||
|
||||
while (cs->send_audio) {
|
||||
while (_phone->running_encaud) {
|
||||
alcGetIntegerv((ALCdevice*)_phone->audio_capture_device, ALC_CAPTURE_SAMPLES, (ALCsizei)sizeof(ALint), &sample);
|
||||
|
||||
if (sample >= frame_size) {
|
||||
alcCaptureSamples((ALCdevice*)_phone->audio_capture_device, frame, frame_size);
|
||||
encoded_size = opus_encode(cs->audio_encoder, frame, frame_size, encoded_data, MAX_RTP_SIZE);
|
||||
|
||||
encoded_size = toxav_encode_audio(_phone->av, frame, frame_size, encoded_data);
|
||||
|
||||
if (encoded_size <= 0) {
|
||||
printf("Could not encode audio packet\n");
|
||||
} else {
|
||||
rtp_send_msg ( _phone->_rtp_audio, _phone->_messenger, encoded_data, encoded_size );
|
||||
if ( -1 == toxav_send_rtp_payload(_phone->av, TypeAudio, encoded_data, encoded_size) )
|
||||
assert(0);
|
||||
}
|
||||
} else {
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
/* clean up codecs */
|
||||
pthread_mutex_lock(&cs->ctrl_mutex);
|
||||
/* clean up codecs *
|
||||
pthread_mutex_lock(&cs->ctrl_mutex);*/
|
||||
alcCaptureStop((ALCdevice*)_phone->audio_capture_device);
|
||||
alcCaptureCloseDevice((ALCdevice*)_phone->audio_capture_device);
|
||||
pthread_mutex_unlock(&cs->ctrl_mutex);
|
||||
pthread_exit ( NULL );
|
||||
/*pthread_mutex_unlock(&cs->ctrl_mutex);*/
|
||||
_phone->running_encaud = -1;
|
||||
pthread_exit ( NULL );
|
||||
}
|
||||
|
||||
void *decode_video_thread(void *arg)
|
||||
{
|
||||
INFO("Started decode video thread!");
|
||||
av_session_t* _phone = arg;
|
||||
_phone->running_decvid = 1;
|
||||
|
||||
codec_state *cs = _phone->cs;
|
||||
CodecState *cs = get_cs_temp(_phone->av);
|
||||
cs->video_stream = 0;
|
||||
RTPMessage *r_msg;
|
||||
|
||||
int recved_size;
|
||||
uint8_t dest[RTP_PAYLOAD_SIZE];
|
||||
|
||||
int dec_frame_finished;
|
||||
AVFrame *r_video_frame;
|
||||
r_video_frame = avcodec_alloc_frame();
|
||||
|
@ -477,20 +425,34 @@ void *decode_video_thread(void *arg)
|
|||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
while (cs->receive_video) {
|
||||
r_msg = rtp_recv_msg ( _phone->_rtp_video );
|
||||
while (_phone->running_decvid) {
|
||||
|
||||
if (r_msg) {
|
||||
memcpy(dec_video_packet.data, r_msg->data, r_msg->length);
|
||||
dec_video_packet.size = r_msg->length;
|
||||
recved_size = toxav_recv_rtp_payload(_phone->av, TypeVideo, 1, dest);
|
||||
|
||||
if (recved_size) {
|
||||
memcpy(dec_video_packet.data, dest, recved_size);
|
||||
dec_video_packet.size = recved_size;
|
||||
|
||||
avcodec_decode_video2(cs->video_decoder_ctx, r_video_frame, &dec_frame_finished, &dec_video_packet);
|
||||
|
||||
if (dec_frame_finished) {
|
||||
|
||||
/* Check if size has changed */
|
||||
if (cs->video_decoder_ctx->width != width || cs->video_decoder_ctx->height != height) {
|
||||
|
||||
width = cs->video_decoder_ctx->width;
|
||||
height = cs->video_decoder_ctx->height;
|
||||
|
||||
printf("w: %d h: %d \n", width, height);
|
||||
video_decoder_refresh(_phone, width, height);
|
||||
|
||||
screen = SDL_SetVideoMode(width, height, 0, 0);
|
||||
|
||||
if (_phone->video_picture.bmp)
|
||||
SDL_FreeYUVOverlay(_phone->video_picture.bmp);
|
||||
|
||||
_phone->video_picture.bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, screen);
|
||||
_phone->sws_SDL_r_ctx = sws_getContext(width, height, cs->video_decoder_ctx->pix_fmt, width, height, PIX_FMT_YUV420P,
|
||||
SWS_BILINEAR, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
display_received_frame(_phone, r_video_frame);
|
||||
|
@ -498,18 +460,20 @@ void *decode_video_thread(void *arg)
|
|||
/* TODO: request the sender to create a new i-frame immediatly */
|
||||
printf("Bad video packet\n");
|
||||
}
|
||||
|
||||
rtp_free_msg(NULL, r_msg);
|
||||
}
|
||||
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
/* clean up codecs */
|
||||
pthread_mutex_lock(&cs->ctrl_mutex);
|
||||
av_free(r_video_frame);
|
||||
|
||||
pthread_mutex_lock(&cs->ctrl_mutex);
|
||||
avcodec_close(cs->video_decoder_ctx);
|
||||
pthread_mutex_unlock(&cs->ctrl_mutex);
|
||||
|
||||
_phone->running_decvid = -1;
|
||||
|
||||
pthread_exit ( NULL );
|
||||
}
|
||||
|
||||
|
@ -517,9 +481,10 @@ void *decode_audio_thread(void *arg)
|
|||
{
|
||||
INFO("Started decode audio thread!");
|
||||
av_session_t* _phone = arg;
|
||||
|
||||
codec_state *cs = _phone->cs;
|
||||
RTPMessage *r_msg;
|
||||
_phone->running_decaud = 1;
|
||||
|
||||
int recved_size;
|
||||
uint8_t dest [RTP_PAYLOAD_SIZE];
|
||||
|
||||
int frame_size = AUDIO_FRAME_SIZE;
|
||||
int data_size;
|
||||
|
@ -538,7 +503,7 @@ void *decode_audio_thread(void *arg)
|
|||
alSourcei(source, AL_LOOPING, AL_FALSE);
|
||||
|
||||
ALuint buffer;
|
||||
ALint val;
|
||||
ALint ready;
|
||||
|
||||
uint16_t zeros[frame_size];
|
||||
memset(zeros, 0, frame_size);
|
||||
|
@ -557,83 +522,58 @@ void *decode_audio_thread(void *arg)
|
|||
goto ending;
|
||||
}
|
||||
|
||||
struct jitter_buffer *j_buf = NULL;
|
||||
int dec_frame_len = 0;
|
||||
|
||||
j_buf = create_queue(20);
|
||||
|
||||
int success = 0;
|
||||
|
||||
int dec_frame_len = 0;
|
||||
|
||||
|
||||
while (cs->receive_audio) {
|
||||
while (_phone->running_decaud) {
|
||||
|
||||
r_msg = rtp_recv_msg ( _phone->_rtp_audio );
|
||||
alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
|
||||
|
||||
if (r_msg) {
|
||||
/* push the packet into the queue */
|
||||
queue(j_buf, r_msg);
|
||||
recved_size = toxav_recv_rtp_payload(_phone->av, TypeAudio, ready, dest);
|
||||
|
||||
if ( recved_size == ErrorAudioPacketLost ) {
|
||||
printf("Lost packet\n");
|
||||
dec_frame_len = toxav_decode_audio(_phone->av, NULL, 0, frame_size, PCM);
|
||||
|
||||
} else if ( recved_size ) {
|
||||
dec_frame_len = toxav_decode_audio(_phone->av, dest, recved_size, frame_size, PCM);
|
||||
}
|
||||
|
||||
success = 0;
|
||||
alGetSourcei(source, AL_BUFFERS_PROCESSED, &val);
|
||||
|
||||
/* grab a packet from the queue */
|
||||
if (val > 0) {
|
||||
r_msg = dequeue(j_buf, &success);
|
||||
}
|
||||
|
||||
if (success > 0) {
|
||||
/* good packet */
|
||||
if (success == 1) {
|
||||
dec_frame_len = opus_decode(cs->audio_decoder, r_msg->data, r_msg->length, PCM, frame_size, 0);
|
||||
rtp_free_msg(NULL, r_msg);
|
||||
/* Play the packet */
|
||||
if (dec_frame_len) {
|
||||
alGetSourcei(source, AL_BUFFERS_PROCESSED, &ready);
|
||||
|
||||
if (ready <= 0)
|
||||
continue;
|
||||
|
||||
alSourceUnqueueBuffers(source, 1, &buffer);
|
||||
data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1);
|
||||
alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000);
|
||||
int error = alGetError();
|
||||
|
||||
if (error != AL_NO_ERROR) {
|
||||
fprintf(stderr, "Error setting buffer %d\n", error);
|
||||
break;
|
||||
}
|
||||
|
||||
/* lost packet */
|
||||
else if (success == 2) {
|
||||
printf("Lost packet\n");
|
||||
dec_frame_len = opus_decode(cs->audio_decoder, NULL, 0, PCM, frame_size, 1);
|
||||
alSourceQueueBuffers(source, 1, &buffer);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
fprintf(stderr, "Error: could not buffer audio\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (dec_frame_len) {
|
||||
alGetSourcei(source, AL_BUFFERS_PROCESSED, &val);
|
||||
|
||||
if (val <= 0)
|
||||
continue;
|
||||
|
||||
alSourceUnqueueBuffers(source, 1, &buffer);
|
||||
data_size = av_samples_get_buffer_size(NULL, 1, dec_frame_len, AV_SAMPLE_FMT_S16, 1);
|
||||
alBufferData(buffer, AL_FORMAT_MONO16, PCM, data_size, 48000);
|
||||
int error = alGetError();
|
||||
|
||||
if (error != AL_NO_ERROR) {
|
||||
fprintf(stderr, "Error setting buffer %d\n", error);
|
||||
break;
|
||||
}
|
||||
|
||||
alSourceQueueBuffers(source, 1, &buffer);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR) {
|
||||
fprintf(stderr, "Error: could not buffer audio\n");
|
||||
break;
|
||||
}
|
||||
|
||||
alGetSourcei(source, AL_SOURCE_STATE, &val);
|
||||
|
||||
if (val != AL_PLAYING)
|
||||
alSourcePlay(source);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
alGetSourcei(source, AL_SOURCE_STATE, &ready);
|
||||
|
||||
if (ready != AL_PLAYING) alSourcePlay(source);
|
||||
}
|
||||
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
|
||||
ending:
|
||||
/* clean up codecs */
|
||||
/* clean up codecs * /
|
||||
pthread_mutex_lock(&cs->ctrl_mutex);
|
||||
|
||||
alDeleteSources(1, &source);
|
||||
|
@ -642,7 +582,10 @@ ending:
|
|||
alcDestroyContext(ctx);
|
||||
alcCloseDevice(dev);
|
||||
|
||||
pthread_mutex_unlock(&cs->ctrl_mutex);
|
||||
pthread_mutex_unlock(&cs->ctrl_mutex); */
|
||||
|
||||
_phone->running_decaud = -1;
|
||||
|
||||
pthread_exit ( NULL );
|
||||
}
|
||||
|
||||
|
@ -650,61 +593,42 @@ ending:
|
|||
|
||||
|
||||
|
||||
int phone_startmedia_loop ( av_session_t* _phone )
|
||||
int phone_startmedia_loop ( ToxAv* arg )
|
||||
{
|
||||
if ( !_phone ){
|
||||
if ( !arg ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
_phone->_rtp_audio = rtp_init_session (
|
||||
type_audio,
|
||||
_phone->_messenger,
|
||||
_phone->_msi->call->peers[0],
|
||||
_phone->_msi->call->key_peer,
|
||||
_phone->_msi->call->key_local,
|
||||
_phone->_msi->call->nonce_peer,
|
||||
_phone->_msi->call->nonce_local
|
||||
);
|
||||
|
||||
_phone->_rtp_video = rtp_init_session (
|
||||
type_video,
|
||||
_phone->_messenger,
|
||||
_phone->_msi->call->peers[0],
|
||||
_phone->_msi->call->key_peer,
|
||||
_phone->_msi->call->key_local,
|
||||
_phone->_msi->call->nonce_peer,
|
||||
_phone->_msi->call->nonce_local
|
||||
);
|
||||
|
||||
init_encoder(_phone->cs);
|
||||
init_decoder(_phone->cs);
|
||||
|
||||
|
||||
toxav_prepare_transmission(arg);
|
||||
|
||||
/*
|
||||
* Rise all threads
|
||||
*/
|
||||
|
||||
/* Only checks for last peer */
|
||||
if ( _phone->_msi->call->type_peer[0] == type_video && 0 > event.rise(encode_video_thread, _phone) )
|
||||
if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
|
||||
0 > event.rise(encode_video_thread, toxav_get_agent_handler(arg)) )
|
||||
{
|
||||
INFO("Error while starting encode_video_thread()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Always send audio */
|
||||
if ( 0 > event.rise(encode_audio_thread, _phone) )
|
||||
if ( 0 > event.rise(encode_audio_thread, toxav_get_agent_handler(arg)) )
|
||||
{
|
||||
INFO("Error while starting encode_audio_thread()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Only checks for last peer */
|
||||
if ( _phone->_msi->call->type_peer[0] == type_video && 0 > event.rise(decode_video_thread, _phone) )
|
||||
if ( toxav_get_peer_transmission_type(arg, 0) == TypeVideo &&
|
||||
0 > event.rise(decode_video_thread, toxav_get_agent_handler(arg)) )
|
||||
{
|
||||
INFO("Error while starting decode_video_thread()");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( 0 > event.rise(decode_audio_thread, _phone) )
|
||||
if ( 0 > event.rise(decode_audio_thread, toxav_get_agent_handler(arg)) )
|
||||
{
|
||||
INFO("Error while starting decode_audio_thread()");
|
||||
return -1;
|
||||
|
@ -734,13 +658,13 @@ int phone_startmedia_loop ( av_session_t* _phone )
|
|||
|
||||
void* callback_recv_invite ( void* _arg )
|
||||
{
|
||||
MSISession* _msi = _arg;
|
||||
|
||||
switch ( _msi->call->type_peer[_msi->call->peer_count - 1] ){
|
||||
case type_audio:
|
||||
assert(_arg);
|
||||
|
||||
switch ( toxav_get_peer_transmission_type(_arg, 0) ){
|
||||
case TypeAudio:
|
||||
INFO( "Incoming audio call!");
|
||||
break;
|
||||
case type_video:
|
||||
case TypeVideo:
|
||||
INFO( "Incoming video call!");
|
||||
break;
|
||||
}
|
||||
|
@ -754,8 +678,7 @@ void* callback_recv_ringing ( void* _arg )
|
|||
}
|
||||
void* callback_recv_starting ( void* _arg )
|
||||
{
|
||||
MSISession* _session = _arg;
|
||||
if ( 0 != phone_startmedia_loop(_session->agent_handler) ){
|
||||
if ( 0 != phone_startmedia_loop(_arg) ){
|
||||
INFO("Starting call failed!");
|
||||
} else {
|
||||
INFO ("Call started! ( press h to hangup )");
|
||||
|
@ -764,15 +687,21 @@ void* callback_recv_starting ( void* _arg )
|
|||
}
|
||||
void* callback_recv_ending ( void* _arg )
|
||||
{
|
||||
av_session_t* _phone = ((MSISession*)_arg)->agent_handler;
|
||||
av_session_t* _phone = toxav_get_agent_handler(_arg);
|
||||
|
||||
_phone->cs->send_audio = 0;
|
||||
_phone->cs->send_video = 0;
|
||||
_phone->cs->receive_audio = 0;
|
||||
_phone->cs->receive_video = 0;
|
||||
_phone->running_encaud = 0;
|
||||
_phone->running_decaud = 0;
|
||||
_phone->running_encvid = 0;
|
||||
_phone->running_decvid = 0;
|
||||
|
||||
/* Wait until all threads are done */
|
||||
usleep(10000000);
|
||||
|
||||
while ( _phone->running_encaud != -1 ||
|
||||
_phone->running_decaud != -1 ||
|
||||
_phone->running_encvid != -1 ||
|
||||
_phone->running_decvid != -1 )
|
||||
|
||||
usleep(10000000);
|
||||
|
||||
INFO ( "Call ended!" );
|
||||
pthread_exit(NULL);
|
||||
|
@ -780,16 +709,15 @@ void* callback_recv_ending ( void* _arg )
|
|||
|
||||
void* callback_recv_error ( void* _arg )
|
||||
{
|
||||
MSISession* _session = _arg;
|
||||
/*MSISession* _session = _arg;
|
||||
|
||||
INFO( "Error: %s", _session->last_error_str );
|
||||
INFO( "Error: %s", _session->last_error_str ); */
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void* callback_call_started ( void* _arg )
|
||||
{
|
||||
MSISession* _session = _arg;
|
||||
if ( 0 != phone_startmedia_loop(_session->agent_handler) ){
|
||||
if ( 0 != phone_startmedia_loop(_arg) ){
|
||||
INFO("Starting call failed!");
|
||||
} else {
|
||||
INFO ("Call started! ( press h to hangup )");
|
||||
|
@ -809,16 +737,23 @@ void* callback_call_rejected ( void* _arg )
|
|||
}
|
||||
void* callback_call_ended ( void* _arg )
|
||||
{
|
||||
av_session_t* _phone = ((MSISession*)_arg)->agent_handler;
|
||||
av_session_t* _phone = toxav_get_agent_handler(_arg);
|
||||
|
||||
_phone->cs->send_audio = 0;
|
||||
_phone->cs->send_video = 0;
|
||||
_phone->cs->receive_audio = 0;
|
||||
_phone->cs->receive_video = 0;
|
||||
_phone->running_encaud = 0;
|
||||
_phone->running_decaud = 0;
|
||||
_phone->running_encvid = 0;
|
||||
_phone->running_decvid = 0;
|
||||
|
||||
/* Wait until all threads are done */
|
||||
usleep(10000000);
|
||||
|
||||
while ( _phone->running_encaud != -1 ||
|
||||
_phone->running_decaud != -1 ||
|
||||
_phone->running_encvid != -1 ||
|
||||
_phone->running_decvid != -1 )
|
||||
|
||||
usleep(10000000);
|
||||
|
||||
toxav_kill_transmission(_phone->av);
|
||||
INFO ( "Call ended!" );
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
@ -844,9 +779,7 @@ av_session_t* av_init_session()
|
|||
}
|
||||
|
||||
_retu->_friends = NULL;
|
||||
|
||||
_retu->_rtp_audio = NULL;
|
||||
_retu->_rtp_video = NULL;
|
||||
_retu->av = toxav_new(_retu->_messenger, _retu, _USERAGENT);
|
||||
|
||||
|
||||
const ALchar *_device_list = alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
|
||||
|
@ -878,9 +811,7 @@ av_session_t* av_init_session()
|
|||
else {
|
||||
INFO("Selected: %d ( %s )", selection, device_names[selection]);
|
||||
}
|
||||
|
||||
_retu->cs = av_calloc(sizeof(codec_state), 1);
|
||||
|
||||
|
||||
_retu->audio_capture_device =
|
||||
(struct ALCdevice*)alcCaptureOpenDevice(
|
||||
device_names[selection], AUDIO_SAMPLE_RATE, AL_FORMAT_MONO16, AUDIO_FRAME_SIZE * 4);
|
||||
|
@ -890,36 +821,29 @@ av_session_t* av_init_session()
|
|||
printf("Could not start capture device! %d\n", alcGetError((ALCdevice*)_retu->audio_capture_device));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t _byte_address[TOX_FRIEND_ADDRESS_SIZE];
|
||||
tox_get_address(_retu->_messenger, _byte_address );
|
||||
fraddr_to_str( _byte_address, _retu->_my_public_id );
|
||||
|
||||
|
||||
/* Initialize msi */
|
||||
_retu->_msi = msi_init_session ( _retu->_messenger, (const uint8_t*)_USERAGENT );
|
||||
|
||||
if ( !_retu->_msi ) {
|
||||
fprintf ( stderr, "msi_init_session() failed\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_retu->_msi->agent_handler = _retu;
|
||||
|
||||
/* ------------------ */
|
||||
msi_register_callback(callback_call_started, MSI_OnStart);
|
||||
msi_register_callback(callback_call_canceled, MSI_OnCancel);
|
||||
msi_register_callback(callback_call_rejected, MSI_OnReject);
|
||||
msi_register_callback(callback_call_ended, MSI_OnEnd);
|
||||
msi_register_callback(callback_recv_invite, MSI_OnInvite);
|
||||
|
||||
msi_register_callback(callback_recv_ringing, MSI_OnRinging);
|
||||
msi_register_callback(callback_recv_starting, MSI_OnStarting);
|
||||
msi_register_callback(callback_recv_ending, MSI_OnEnding);
|
||||
|
||||
msi_register_callback(callback_recv_error, MSI_OnError);
|
||||
msi_register_callback(callback_requ_timeout, MSI_OnTimeout);
|
||||
|
||||
toxav_register_callstate_callback(callback_call_started, OnStart);
|
||||
toxav_register_callstate_callback(callback_call_canceled, OnCancel);
|
||||
toxav_register_callstate_callback(callback_call_rejected, OnReject);
|
||||
toxav_register_callstate_callback(callback_call_ended, OnEnd);
|
||||
toxav_register_callstate_callback(callback_recv_invite, OnInvite);
|
||||
|
||||
toxav_register_callstate_callback(callback_recv_ringing, OnRinging);
|
||||
toxav_register_callstate_callback(callback_recv_starting, OnStarting);
|
||||
toxav_register_callstate_callback(callback_recv_ending, OnEnding);
|
||||
|
||||
toxav_register_callstate_callback(callback_recv_error, OnError);
|
||||
toxav_register_callstate_callback(callback_requ_timeout, OnTimeout);
|
||||
|
||||
/* ------------------ */
|
||||
|
||||
return _retu;
|
||||
|
@ -927,17 +851,18 @@ av_session_t* av_init_session()
|
|||
|
||||
int av_terminate_session(av_session_t* _phone)
|
||||
{
|
||||
if ( _phone->_msi->call ){
|
||||
msi_hangup(_phone->_msi); /* Hangup the phone first */
|
||||
}
|
||||
toxav_hangup(_phone->av);
|
||||
|
||||
free(_phone->_friends);
|
||||
msi_terminate_session(_phone->_msi);
|
||||
pthread_mutex_destroy ( &_phone->_mutex );
|
||||
|
||||
Tox* _p = _phone->_messenger;
|
||||
_phone->_messenger = NULL; usleep(100000); /* Wait for tox_pool to end */
|
||||
_phone->_messenger = NULL; usleep(100000); /* Wait for tox_poll to end */
|
||||
|
||||
tox_kill(_p);
|
||||
toxav_kill(_phone->av);
|
||||
|
||||
free(_phone);
|
||||
|
||||
printf("\r[i] Quit!\n");
|
||||
return 0;
|
||||
|
@ -1047,22 +972,17 @@ void do_phone ( av_session_t* _phone )
|
|||
} break;
|
||||
case 'c':
|
||||
{
|
||||
if ( _phone->_msi->call ){
|
||||
INFO("Already in a call");
|
||||
break;
|
||||
}
|
||||
|
||||
MSICallType _ctype;
|
||||
ToxAvCallType _ctype;
|
||||
|
||||
if ( _len < 5 ){
|
||||
INFO("Invalid input; usage: c a/v [friend]");
|
||||
break;
|
||||
}
|
||||
else if ( _line[2] == 'a' || _line[2] != 'v' ){ /* default and audio */
|
||||
_ctype = type_audio;
|
||||
_ctype = TypeAudio;
|
||||
}
|
||||
else { /* video */
|
||||
_ctype = type_video;
|
||||
_ctype = TypeVideo;
|
||||
}
|
||||
|
||||
char* _end;
|
||||
|
@ -1073,45 +993,41 @@ void do_phone ( av_session_t* _phone )
|
|||
break;
|
||||
}
|
||||
|
||||
/* Set timeout */
|
||||
msi_invite ( _phone->_msi, _ctype, 10 * 1000, _friend );
|
||||
INFO("Calling friend: %d!", _friend);
|
||||
if ( toxav_call(_phone->av, _friend, _ctype, 30) == ErrorAlreadyInCall ){
|
||||
INFO("Already in a call");
|
||||
break;
|
||||
}
|
||||
else INFO("Calling friend: %d!", _friend);
|
||||
|
||||
} break;
|
||||
case 'h':
|
||||
{
|
||||
if ( !_phone->_msi->call ){
|
||||
if ( toxav_hangup(_phone->av) == ErrorNoCall ) {
|
||||
INFO("No call!");
|
||||
break;
|
||||
}
|
||||
|
||||
msi_hangup(_phone->_msi);
|
||||
|
||||
INFO("Hung up...");
|
||||
else INFO("Hung up...");
|
||||
|
||||
} break;
|
||||
case 'a':
|
||||
{
|
||||
|
||||
if ( _phone->_msi->call && _phone->_msi->call->state != call_starting ) {
|
||||
break;
|
||||
}
|
||||
|
||||
ToxAvError rc;
|
||||
|
||||
if ( _len > 1 && _line[2] == 'v' )
|
||||
msi_answer(_phone->_msi, type_video);
|
||||
rc = toxav_answer(_phone->av, TypeVideo);
|
||||
else
|
||||
msi_answer(_phone->_msi, type_audio);
|
||||
rc = toxav_answer(_phone->av, TypeAudio);
|
||||
|
||||
if ( rc == ErrorInvalidState ) {
|
||||
INFO("No call to answer!");
|
||||
}
|
||||
|
||||
} break;
|
||||
case 'r':
|
||||
{
|
||||
if ( _phone->_msi->call && _phone->_msi->call->state != call_starting ){
|
||||
break;
|
||||
}
|
||||
|
||||
msi_reject(_phone->_msi, NULL);
|
||||
|
||||
INFO("Call Rejected...");
|
||||
if ( toxav_reject(_phone->av, "User action") == ErrorInvalidState )
|
||||
INFO("No state to cancel!");
|
||||
else INFO("Call Rejected...");
|
||||
|
||||
} break;
|
||||
case 'q':
|
||||
|
@ -1124,7 +1040,6 @@ void do_phone ( av_session_t* _phone )
|
|||
}
|
||||
default:
|
||||
{
|
||||
INFO("Invalid command!");
|
||||
} break;
|
||||
|
||||
}
|
||||
|
|
3
toxav/toxrtp.c → toxav/rtp.c
Executable file → Normal file
3
toxav/toxrtp.c → toxav/rtp.c
Executable file → Normal file
|
@ -26,7 +26,7 @@
|
|||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxrtp.h"
|
||||
#include "rtp.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -245,6 +245,7 @@ RTPHeader* extract_header ( const uint8_t* payload, int length )
|
|||
* Now it my happen that this is out of order but
|
||||
* it cuts down chances of parsing some invalid value
|
||||
*/
|
||||
|
||||
if ( GET_FLAG_VERSION(_retu) != RTP_VERSION ){
|
||||
/* Deallocate */
|
||||
free(_retu);
|
0
toxav/toxrtp.h → toxav/rtp.h
Executable file → Normal file
0
toxav/toxrtp.h → toxav/rtp.h
Executable file → Normal file
352
toxav/toxav.c
Normal file
352
toxav/toxav.c
Normal file
|
@ -0,0 +1,352 @@
|
|||
/** toxav.c
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Report bugs/suggestions at either #tox-dev @ freenode.net:6667 or
|
||||
* my email: eniz_vukovic@hotmail.com
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include "toxav.h"
|
||||
#include "../toxcore/tox.h"
|
||||
#include "rtp.h"
|
||||
#include "msi.h"
|
||||
#include "media.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define inline__ inline __attribute__((always_inline))
|
||||
|
||||
static const uint8_t audio_index = 0, video_index = 1;
|
||||
|
||||
|
||||
typedef enum {
|
||||
ts_closing,
|
||||
ts_running,
|
||||
ts_closed
|
||||
|
||||
} ThreadState;
|
||||
|
||||
typedef struct _ToxAv
|
||||
{
|
||||
Tox* messenger;
|
||||
|
||||
MSISession* msi_session; /** Main msi session */
|
||||
|
||||
RTPSession* rtp_sessions[2]; /* Audio is first and video is second */
|
||||
|
||||
/* TODO: Add media session */
|
||||
struct jitter_buffer* j_buf;
|
||||
CodecState* cs;
|
||||
/* TODO: Add media session threads */
|
||||
|
||||
|
||||
void* agent_handler;
|
||||
} ToxAv;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
* PUBLIC API FUNCTIONS IMPLEMENTATIONS
|
||||
*
|
||||
*
|
||||
*
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************
|
||||
********************************************************************************************************************/
|
||||
|
||||
|
||||
|
||||
ToxAv* toxav_new( Tox* messenger, void* useragent, const char* ua_name )
|
||||
{
|
||||
ToxAv* av = calloc ( sizeof(ToxAv), 1);
|
||||
|
||||
av->msi_session = msi_init_session(messenger, (const unsigned char*) ua_name );
|
||||
av->msi_session->agent_handler = av;
|
||||
|
||||
av->rtp_sessions[0] = av->rtp_sessions [1] = NULL;
|
||||
|
||||
av->messenger = messenger;
|
||||
|
||||
/* NOTE: This should be user defined or? */
|
||||
av->j_buf = create_queue(20);
|
||||
|
||||
av->cs = codec_init_session(AUDIO_BITRATE, AUDIO_FRAME_DURATION, AUDIO_SAMPLE_RATE, 1, VIDEO_BITRATE, DEFAULT_WEBCAM, VIDEO_DRIVER);
|
||||
|
||||
av->agent_handler = useragent;
|
||||
|
||||
return av;
|
||||
}
|
||||
|
||||
void toxav_kill ( ToxAv* av )
|
||||
{
|
||||
msi_terminate_session(av->msi_session);
|
||||
|
||||
if ( av->rtp_sessions[audio_index] ) {
|
||||
rtp_terminate_session(av->rtp_sessions[audio_index], av->msi_session->messenger_handle);
|
||||
}
|
||||
|
||||
if ( av->rtp_sessions[video_index] ) {
|
||||
rtp_terminate_session(av->rtp_sessions[video_index], av->msi_session->messenger_handle);
|
||||
}
|
||||
|
||||
codec_terminate_session(av->cs);
|
||||
|
||||
free(av);
|
||||
}
|
||||
|
||||
void toxav_register_callstate_callback ( ToxAVCallback callback, ToxAvCallbackID id )
|
||||
{
|
||||
msi_register_callback((MSICallback)callback, (MSICallbackID) id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int toxav_call (ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds )
|
||||
{
|
||||
if ( av->msi_session->call ) {
|
||||
return ErrorAlreadyInCall;
|
||||
}
|
||||
|
||||
return msi_invite(av->msi_session, call_type, ringing_seconds * 1000, user);
|
||||
}
|
||||
|
||||
int toxav_hangup ( ToxAv* av )
|
||||
{
|
||||
if ( !av->msi_session->call ) {
|
||||
return ErrorNoCall;
|
||||
}
|
||||
|
||||
if ( av->msi_session->call->state != call_active ) {
|
||||
return ErrorInvalidState;
|
||||
}
|
||||
|
||||
return msi_hangup(av->msi_session);
|
||||
}
|
||||
|
||||
int toxav_answer ( ToxAv* av, ToxAvCallType call_type )
|
||||
{
|
||||
if ( !av->msi_session->call ) {
|
||||
return ErrorNoCall;
|
||||
}
|
||||
|
||||
if ( av->msi_session->call->state != call_starting ) {
|
||||
return ErrorInvalidState;
|
||||
}
|
||||
|
||||
return msi_answer(av->msi_session, call_type);
|
||||
}
|
||||
|
||||
int toxav_reject ( ToxAv* av, const char* reason )
|
||||
{
|
||||
if ( !av->msi_session->call ) {
|
||||
return ErrorNoCall;
|
||||
}
|
||||
|
||||
if ( av->msi_session->call->state != call_starting ) {
|
||||
return ErrorInvalidState;
|
||||
}
|
||||
|
||||
return msi_reject(av->msi_session, (const uint8_t*) reason);
|
||||
}
|
||||
|
||||
int toxav_cancel ( ToxAv* av, const char* reason )
|
||||
{
|
||||
if ( !av->msi_session->call ) {
|
||||
return ErrorNoCall;
|
||||
}
|
||||
|
||||
return msi_cancel(av->msi_session, 0, (const uint8_t*)reason);
|
||||
}
|
||||
|
||||
/* You can stop the call at any state */
|
||||
int toxav_stop_call ( ToxAv* av )
|
||||
{
|
||||
if ( !av->msi_session->call ) {
|
||||
return ErrorNoCall;
|
||||
}
|
||||
|
||||
return msi_stopcall(av->msi_session);
|
||||
}
|
||||
|
||||
|
||||
int toxav_prepare_transmission ( ToxAv* av )
|
||||
{
|
||||
assert(av->msi_session);
|
||||
if ( !av->msi_session || !av->msi_session->call ) {
|
||||
return ErrorNoCall;
|
||||
}
|
||||
|
||||
av->rtp_sessions[audio_index] = rtp_init_session(
|
||||
type_audio,
|
||||
av->messenger,
|
||||
av->msi_session->call->peers[0],
|
||||
av->msi_session->call->key_peer,
|
||||
av->msi_session->call->key_local,
|
||||
av->msi_session->call->nonce_peer,
|
||||
av->msi_session->call->nonce_local
|
||||
);
|
||||
|
||||
|
||||
if ( !av->rtp_sessions[audio_index] ) {
|
||||
fprintf(stderr, "Error while starting audio RTP session!\n");
|
||||
return ErrorStartingAudioRtp;
|
||||
}
|
||||
|
||||
av->rtp_sessions[video_index] = rtp_init_session (
|
||||
type_video,
|
||||
av->messenger,
|
||||
av->msi_session->call->peers[0],
|
||||
av->msi_session->call->key_peer,
|
||||
av->msi_session->call->key_local,
|
||||
av->msi_session->call->nonce_peer,
|
||||
av->msi_session->call->nonce_local
|
||||
);
|
||||
|
||||
|
||||
if ( !av->rtp_sessions[video_index] ) {
|
||||
fprintf(stderr, "Error while starting video RTP session!\n");
|
||||
return ErrorStartingVideoRtp;
|
||||
}
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
|
||||
int toxav_kill_transmission ( ToxAv* av )
|
||||
{
|
||||
/* Both sessions should be active at any time */
|
||||
if ( !av->rtp_sessions[0] || !av->rtp_sessions[0] )
|
||||
return ErrorNoTransmission;
|
||||
|
||||
|
||||
if ( -1 == rtp_terminate_session(av->rtp_sessions[audio_index], av->messenger) ) {
|
||||
fprintf(stderr, "Error while terminating audio RTP session!\n");
|
||||
return ErrorTerminatingAudioRtp;
|
||||
}
|
||||
|
||||
if ( -1 == rtp_terminate_session(av->rtp_sessions[video_index], av->messenger) ) {
|
||||
fprintf(stderr, "Error while terminating video RTP session!\n");
|
||||
return ErrorTerminatingVideoRtp;
|
||||
}
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
|
||||
inline__ int toxav_send_rtp_payload ( ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length )
|
||||
{
|
||||
if ( av->rtp_sessions[type - TypeAudio] )
|
||||
return rtp_send_msg ( av->rtp_sessions[type - TypeAudio], av->msi_session->messenger_handle, payload, length );
|
||||
else return -1;
|
||||
}
|
||||
|
||||
inline__ int toxav_recv_rtp_payload ( ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest )
|
||||
{
|
||||
if ( !dest ) return ErrorInternal;
|
||||
|
||||
if ( !av->rtp_sessions[type - TypeAudio] ) return ErrorNoRtpSession;
|
||||
|
||||
RTPMessage* message;
|
||||
|
||||
if ( type == TypeAudio ) {
|
||||
|
||||
message = rtp_recv_msg(av->rtp_sessions[audio_index]);
|
||||
|
||||
if (message) {
|
||||
/* push the packet into the queue */
|
||||
queue(av->j_buf, message);
|
||||
}
|
||||
|
||||
if (ready) {
|
||||
int success = 0;
|
||||
message = dequeue(av->j_buf, &success);
|
||||
|
||||
if ( success == 2) return ErrorAudioPacketLost;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
else {
|
||||
message = rtp_recv_msg(av->rtp_sessions[video_index]);
|
||||
}
|
||||
|
||||
if ( message ) {
|
||||
memcpy(dest, message->data, message->length);
|
||||
|
||||
int length = message->length;
|
||||
|
||||
rtp_free_msg(NULL, message);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline__ int toxav_decode_audio ( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest )
|
||||
{
|
||||
if ( !dest ) return ErrorInternal;
|
||||
|
||||
return opus_decode(av->cs->audio_decoder, payload, length, dest, frame_size, payload ? 0 : 1);
|
||||
}
|
||||
|
||||
inline__ int toxav_encode_audio ( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest )
|
||||
{
|
||||
if ( !dest )
|
||||
return ErrorInternal;
|
||||
|
||||
return opus_encode(av->cs->audio_encoder, frame, frame_size, dest, RTP_PAYLOAD_SIZE);
|
||||
}
|
||||
|
||||
int toxav_get_peer_transmission_type ( ToxAv* av, int peer )
|
||||
{
|
||||
assert(av->msi_session);
|
||||
if ( peer < 0 || !av->msi_session->call || av->msi_session->call->peer_count <= peer )
|
||||
return ErrorInternal;
|
||||
|
||||
return av->msi_session->call->type_peer[peer];
|
||||
}
|
||||
|
||||
void* toxav_get_agent_handler ( ToxAv* av )
|
||||
{
|
||||
return av->agent_handler;
|
||||
}
|
||||
|
||||
|
||||
/* Only temporary */
|
||||
void* get_cs_temp(ToxAv* av)
|
||||
{
|
||||
return av->cs;
|
||||
}
|
129
toxav/toxav.h
Normal file
129
toxav/toxav.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/** toxav.h
|
||||
*
|
||||
* Copyright (C) 2013 Tox project All Rights Reserved.
|
||||
*
|
||||
* This file is part of Tox.
|
||||
*
|
||||
* Tox is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tox is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* Report bugs/suggestions to me ( mannol ) at either #tox-dev @ freenode.net:6667 or
|
||||
* my email: eniz_vukovic@hotmail.com
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __TOXAV
|
||||
#define __TOXAV
|
||||
#include <inttypes.h>
|
||||
|
||||
typedef void* ( *ToxAVCallback ) ( void* arg );
|
||||
typedef struct _ToxAv ToxAv;
|
||||
|
||||
#ifndef __TOX_DEFINED__
|
||||
#define __TOX_DEFINED__
|
||||
typedef struct Tox Tox;
|
||||
#endif
|
||||
|
||||
#define RTP_PAYLOAD_SIZE 10400
|
||||
|
||||
/**
|
||||
* @brief Callbacks ids that handle the call states
|
||||
*/
|
||||
typedef enum {
|
||||
/* Requests */
|
||||
OnInvite,
|
||||
OnStart,
|
||||
OnCancel,
|
||||
OnReject,
|
||||
OnEnd,
|
||||
|
||||
/* Responses */
|
||||
OnRinging,
|
||||
OnStarting,
|
||||
OnEnding,
|
||||
|
||||
/* Protocol */
|
||||
OnError,
|
||||
OnTimeout
|
||||
|
||||
} ToxAvCallbackID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Call type identifier.
|
||||
*/
|
||||
typedef enum {
|
||||
TypeAudio = 70,
|
||||
TypeVideo
|
||||
} ToxAvCallType;
|
||||
|
||||
|
||||
typedef enum {
|
||||
ErrorNone = 0,
|
||||
ErrorInternal = -1, /* Internal error */
|
||||
ErrorAlreadyInCall = -2, /* Already has an active call */
|
||||
ErrorNoCall = -3, /* Trying to perform call action while not in a call */
|
||||
ErrorInvalidState = -4, /* Trying to perform call action while in invalid state*/
|
||||
ErrorNoRtpSession = -5, /* Trying to perform rtp action on invalid session */
|
||||
ErrorAudioPacketLost = -6, /* Indicating packet loss */
|
||||
ErrorStartingAudioRtp = -7, /* Error in toxav_prepare_transmission() */
|
||||
ErrorStartingVideoRtp = -8 , /* Error in toxav_prepare_transmission() */
|
||||
ErrorNoTransmission = -9, /* Returned in toxav_kill_transmission() */
|
||||
ErrorTerminatingAudioRtp = -10, /* Returned in toxav_kill_transmission() */
|
||||
ErrorTerminatingVideoRtp = -11, /* Returned in toxav_kill_transmission() */
|
||||
|
||||
} ToxAvError;
|
||||
|
||||
|
||||
ToxAv* toxav_new(Tox* messenger, void* useragent, const char* ua_name);
|
||||
void toxav_kill(ToxAv* av);
|
||||
|
||||
void toxav_register_callstate_callback (ToxAVCallback callback, ToxAvCallbackID id);
|
||||
|
||||
|
||||
int toxav_call(ToxAv* av, int user, ToxAvCallType call_type, int ringing_seconds);
|
||||
int toxav_hangup(ToxAv* av);
|
||||
int toxav_answer(ToxAv* av, ToxAvCallType call_type );
|
||||
int toxav_reject(ToxAv* av, const char* reason);
|
||||
int toxav_cancel(ToxAv* av, const char* reason);
|
||||
int toxav_stop_call(ToxAv* av);
|
||||
|
||||
int toxav_prepare_transmission(ToxAv* av);
|
||||
int toxav_kill_transmission(ToxAv* av);
|
||||
|
||||
|
||||
int toxav_send_rtp_payload(ToxAv* av, ToxAvCallType type, const uint8_t* payload, uint16_t length);
|
||||
|
||||
/* Return length of received packet. Returns 0 if nothing recved. Dest has to have
|
||||
* MAX_RTP_PAYLOAD_SIZE space available. Returns -1 if packet is not ready (ready < 1) for deque.
|
||||
* For video packets set 'ready' at _any_ value.
|
||||
*/
|
||||
int toxav_recv_rtp_payload(ToxAv* av, ToxAvCallType type, int ready, uint8_t* dest);
|
||||
|
||||
|
||||
|
||||
|
||||
int toxav_decode_audio( ToxAv* av, const uint8_t* payload, uint16_t length, int frame_size, short int* dest );
|
||||
|
||||
/* Please make sure 'dest' has enough storage for RTP_PAYLOAD_SIZE length of data */
|
||||
int toxav_encode_audio( ToxAv* av, const short int* frame, int frame_size, uint8_t* dest );
|
||||
|
||||
|
||||
|
||||
int toxav_get_peer_transmission_type ( ToxAv* av, int peer );
|
||||
void* toxav_get_agent_handler ( ToxAv* av );
|
||||
|
||||
/* Use this to get handle of CodecState from ToxAv struct */
|
||||
void* get_cs_temp( ToxAv* av );
|
||||
#endif /* __TOXAV */
|
Loading…
Reference in New Issue
Block a user