# A/V API reference

## Take toxmsi/phone.c as a reference

### Initialization:

```
phone_t* initPhone(uint16_t _listen_port, uint16_t _send_port);
```

function initializes sample phone. `_listen_port` and `_send_port` are variables
only meant for local testing. You will not have to do anything regarding to that
since everything will be started within a messenger.

Phone requires one msi session and two rtp sessions (one for audio and one for
video).

```
msi_session_t* msi_init_session( void* _core_handler, const uint8_t* _user_agent );
```

initializes msi session. Params:

```
void* _core_handler - pointer to an object handling networking,
const uint8_t* _user_agent - string describing phone client version.
```

Return value: `msi_session_t*` - pointer to a newly created msi session handler.

### `msi_session_t` reference:

How to handle msi session: Controlling is done via callbacks and action
handlers. First register callbacks for every state/action received and make sure
NOT TO PLACE SOMETHING LIKE LOOPS THAT TAKES A LOT OF TIME TO EXECUTE; every
callback is being called directly from event loop. You can find examples in
phone.c.

Register callbacks:

```
void msi_register_callback_call_started ( MCALLBACK );
void msi_register_callback_call_canceled ( MCALLBACK );
void msi_register_callback_call_rejected ( MCALLBACK );
void msi_register_callback_call_ended ( MCALLBACK );

void msi_register_callback_recv_invite ( MCALLBACK );
void msi_register_callback_recv_ringing ( MCALLBACK );
void msi_register_callback_recv_starting ( MCALLBACK );
void msi_register_callback_recv_ending ( MCALLBACK );
void msi_register_callback_recv_error ( MCALLBACK );

void msi_register_callback_requ_timeout ( MCALLBACK );
```

MCALLBACK is defined as: `void (*callback) (void* _arg)` `msi_session_t*`
handler is being thrown as `_arg` so you can use that and `_agent_handler` to
get to your own phone handler directly from callback.

Actions:

```
int msi_invite ( msi_session_t* _session, call_type _call_type, uint32_t _timeoutms );
```

Sends call invite. Before calling/sending invite `msi_session_t::_friend_id` is
needed to be set or else it will not work. `_call_type` is type of the call (
Audio/Video ) and `_timeoutms` is how long will poll wait until request is
terminated.

```
int msi_hangup ( msi_session_t* _session );
```

Hangs up active call

```
int msi_answer ( msi_session_t* _session, call_type _call_type );
```

Answer incoming call. `_call_type` set's callee call type.

```
int msi_cancel ( msi_session_t* _session );
```

Cancel current request.

```
int msi_reject ( msi_session_t* _session );
```

Reject incoming call.

### Now for rtp:

You will need 2 sessions; one for audio one for video. You start them with:

```
rtp_session_t* rtp_init_session ( int _max_users, int _multi_session );
```

Params:

```
int _max_users - max users. -1 if undefined
int _multi_session - any positive number means uses multi session; -1 if not.
```

Return value:

```
rtp_session_t* - pointer to a newly created rtp session handler.
```

### How to handle rtp session:

Take a look at

```
void* phone_handle_media_transport_poll ( void* _hmtc_args_p ) in phone.c
```

on example. Basically what you do is just receive a message via:

```
struct rtp_msg_s* rtp_recv_msg ( rtp_session_t* _session );
```

and then you use payload within the `rtp_msg_s` struct. Don't forget to
deallocate it with:
`void rtp_free_msg ( rtp_session_t* _session, struct rtp_msg_s* _msg );`
Receiving should be thread safe so don't worry about that.

When you capture and encode a payload you want to send it ( obviously ).

first create a new message with:

```
struct rtp_msg_s* rtp_msg_new ( rtp_session_t* _session, const uint8_t* _data, uint32_t _length );
```

and then send it with:

```
int rtp_send_msg ( rtp_session_t* _session, struct rtp_msg_s* _msg, void* _core_handler );
```

`_core_handler` is the same network handler as in `msi_session_s` struct.

## A/V initialization:

```
int init_receive_audio(codec_state *cs);
int init_receive_video(codec_state *cs);
Initialises the A/V decoders. On failure it will print the reason and return 0. On success it will return 1.

int init_send_audio(codec_state *cs);
int init_send_video(codec_state *cs);
Initialises the A/V encoders. On failure it will print the reason and return 0. On success it will return 1.
init_send_audio will also let the user select an input device. init_send_video will determine the webcam's output codec and initialise the appropriate decoder.

int video_encoder_refresh(codec_state *cs, int bps);
Reinitialises the video encoder with a new bitrate. ffmpeg does not expose the needed VP8 feature to change the bitrate on the fly, so this serves as a workaround.
In the future, VP8 should be used directly and ffmpeg should be dropped from the dependencies.
The variable bps is the required bitrate in bits per second.
```

### A/V encoding/decoding:

```
void *encode_video_thread(void *arg);
```

Spawns the video encoding thread. The argument should hold a pointer to a
`codec_state`. This function should only be called if video encoding is
supported (when `init_send_video` returns 1). Each video frame gets encoded into
a packet, which is sent via RTP. Every 60 frames a new bidirectional interframe
is encoded.

```
void *encode_audio_thread(void *arg);
```

Spawns the audio encoding thread. The argument should hold a pointer to a
`codec_state`. This function should only be called if audio encoding is
supported (when `init_send_audio` returns 1). Audio frames are read from the
selected audio capture device during initialisation. This audio capturing can be
rerouted to a different device on the fly. Each audio frame is encoded into a
packet, and sent via RTP. All audio frames have the same amount of samples,
which is defined in `AV_codec.h`.

```
int video_decoder_refresh(codec_state *cs, int width, int height);
```

Sets the SDL window dimensions and creates a pixel buffer with the requested
size. It also creates a scaling context, which will be used to convert the input
image format to YUV420P.

```
void *decode_video_thread(void *arg);
```

Spawns a video decoding thread. The argument should hold a pointer to a
`codec_state`. The `codec_state` is assumed to contain a successfully
initialised video decoder. This function reads video packets and feeds them to
the video decoder. If the video frame's resolution has changed,
`video_decoder_refresh()` is called. Afterwards, the frame is displayed on the
SDL window.

```
void *decode_audio_thread(void *arg);
```

Spawns an audio decoding thread. The argument should hold a pointer to a
`codec_state`. The `codec_state` is assumed to contain a successfully
initialised audio decoder. All received audio packets are pushed into a jitter
buffer and are reordered. If there is a missing packet, or a packet has arrived
too late, it is treated as a lost packet and the audio decoder is informed of
the packet loss. The audio decoder will then try to reconstruct the lost packet,
based on information from previous packets. Audio is played on the default
OpenAL output device.

If you have any more qustions/bug reports/feature request contact the following
users on the irc channel #tox-dev on irc.freenode.net: For RTP and MSI: mannol
For audio and video: Martijnvdc
