Create new send API

This API is used to send small messages. The message may consist of
several smaller buffers or it may just be one buffer containing all the
data.

The total size of buffers must not exceed the MAX_PAYLOAD limit
This commit is contained in:
Aaro Altonen 2019-07-18 11:57:32 +03:00
parent 9484444699
commit 6b89c779d7
4 changed files with 79 additions and 88 deletions

View File

@ -16,7 +16,7 @@
#include "writer.hh" #include "writer.hh"
// TODO implement frame splitting if data_len > MTU // TODO implement frame splitting if data_len > MTU
rtp_error_t kvz_rtp::generic::push_generic_frame(connection *conn, uint8_t *data, size_t data_len, uint32_t timestamp) rtp_error_t kvz_rtp::generic::push_generic_frame(kvz_rtp::connection *conn, uint8_t *data, size_t data_len, uint32_t timestamp)
{ {
if (data_len > MAX_PAYLOAD) { if (data_len > MAX_PAYLOAD) {
LOG_WARN("packet is larger (%zu bytes) than MAX_PAYLOAD (%u bytes)", data_len, MAX_PAYLOAD); LOG_WARN("packet is larger (%zu bytes) than MAX_PAYLOAD (%u bytes)", data_len, MAX_PAYLOAD);
@ -25,7 +25,7 @@ rtp_error_t kvz_rtp::generic::push_generic_frame(connection *conn, uint8_t *data
uint8_t header[kvz_rtp::frame::HEADER_SIZE_RTP]; uint8_t header[kvz_rtp::frame::HEADER_SIZE_RTP];
conn->fill_rtp_header(header, timestamp); conn->fill_rtp_header(header, timestamp);
return kvz_rtp::sender::write_frame(conn, header, sizeof(header), data, data_len); return kvz_rtp::send::send_frame(conn, header, sizeof(header), data, data_len);
} }
kvz_rtp::frame::rtp_frame *kvz_rtp::generic::process_generic_frame( kvz_rtp::frame::rtp_frame *kvz_rtp::generic::process_generic_frame(

View File

@ -9,6 +9,9 @@
/* Validity of arguments is checked by kvz_rtp::sender. We just need to relay them there */ /* Validity of arguments is checked by kvz_rtp::sender. We just need to relay them there */
rtp_error_t kvz_rtp::opus::push_opus_frame(connection *conn, uint8_t *data, uint32_t data_len, uint32_t timestamp) rtp_error_t kvz_rtp::opus::push_opus_frame(connection *conn, uint8_t *data, uint32_t data_len, uint32_t timestamp)
{ {
return kvz_rtp::generic::push_generic_frame(conn, data, data_len, timestamp);
#if 0
rtp_error_t ret; rtp_error_t ret;
if ((ret = kvz_rtp::sender::write_rtp_header(conn, timestamp)) != RTP_OK) { if ((ret = kvz_rtp::sender::write_rtp_header(conn, timestamp)) != RTP_OK) {
@ -18,7 +21,6 @@ rtp_error_t kvz_rtp::opus::push_opus_frame(connection *conn, uint8_t *data, uint
return kvz_rtp::sender::write_payload(conn, data, data_len); return kvz_rtp::sender::write_payload(conn, data, data_len);
#if 0
uint8_t buffer[MAX_PACKET] = { 0 }; uint8_t buffer[MAX_PACKET] = { 0 };
RTPOpus::OpusConfig *config = (RTPOpus::OpusConfig *)conn->getConfig(); RTPOpus::OpusConfig *config = (RTPOpus::OpusConfig *)conn->getConfig();

View File

@ -16,76 +16,49 @@
#include "util.hh" #include "util.hh"
#include "writer.hh" #include "writer.hh"
rtp_error_t kvz_rtp::sender::write_payload(kvz_rtp::connection *conn, uint8_t *payload, size_t payload_len) rtp_error_t kvz_rtp::send::send_frame(
kvz_rtp::connection *conn,
uint8_t *frame, size_t frame_len
)
{ {
if (!conn) if (!conn || !frame || frame_len == 0)
return RTP_INVALID_VALUE; return RTP_INVALID_VALUE;
conn->inc_sent_bytes(payload_len); if (frame_len >= MAX_PAYLOAD) {
LOG_WARN("Frame length (%lu) is larger than MAX_PAYLOAD (%u)", frame_len, MAX_PAYLOAD);
}
conn->inc_sent_bytes(frame_len);
conn->inc_sent_pkts(); conn->inc_sent_pkts();
conn->inc_rtp_sequence(); conn->inc_rtp_sequence();
return conn->get_socket().sendto(payload, payload_len, 0, NULL); return conn->get_socket().sendto(frame, frame_len, 0, NULL);
} }
rtp_error_t kvz_rtp::sender::write_generic_header(kvz_rtp::connection *conn, uint8_t *header, size_t header_len) rtp_error_t kvz_rtp::send::send_frame(
{
if (!conn)
return RTP_INVALID_VALUE;
#ifdef __linux__
return conn->get_socket().sendto(header, header_len, MSG_MORE, NULL);
#else
return conn->get_socket().sendto(header, header_len, MSG_PARTIAL, NULL);
#endif
}
rtp_error_t kvz_rtp::sender::write_rtp_header(kvz_rtp::connection *conn, uint32_t timestamp)
{
if (!conn)
return RTP_INVALID_VALUE;
uint8_t header[kvz_rtp::frame::HEADER_SIZE_RTP] = { 0 };
conn->fill_rtp_header(header, timestamp);
return kvz_rtp::sender::write_generic_header(conn, header, kvz_rtp::frame::HEADER_SIZE_RTP);
}
rtp_error_t kvz_rtp::sender::write_generic_frame(kvz_rtp::connection *conn, kvz_rtp::frame::rtp_frame *frame)
{
if (!frame)
return RTP_INVALID_VALUE;
rtp_error_t ret;
if ((ret = kvz_rtp::sender::write_payload(conn, frame->data, frame->total_len)) != RTP_OK) {
LOG_ERROR("Failed to send payload! Size %zu, Type %d", frame->total_len, frame->type);
return ret;
}
return RTP_OK;
}
rtp_error_t kvz_rtp::sender::write_frame(
kvz_rtp::connection *conn, kvz_rtp::connection *conn,
uint8_t *header, size_t header_len, uint8_t *header, size_t header_len,
uint8_t *payload, size_t payload_len uint8_t *payload, size_t payload_len
) )
{ {
if (!conn || !header || !payload || header_len == 0 || payload_len == 0) if (!conn || !header || header_len == 0 || !payload || payload_len == 0)
return RTP_INVALID_VALUE; return RTP_INVALID_VALUE;
rtp_error_t ret; std::vector<std::pair<size_t, uint8_t *>> buffers;
if ((ret = kvz_rtp::sender::write_generic_header(conn, header, header_len)) != RTP_OK) { buffers.push_back(std::make_pair(header_len, header));
LOG_ERROR("Failed to write generic header, length: %zu", header_len); buffers.push_back(std::make_pair(payload_len, payload));
return ret;
}
if ((ret = kvz_rtp::sender::write_payload(conn, payload, payload_len)) != RTP_OK) { return conn->get_socket().sendto(buffers, 0);
LOG_ERROR("Failed to write payload, length: %zu", payload_len); }
return ret;
} rtp_error_t kvz_rtp::send::send_frame(
kvz_rtp::connection *conn,
return ret; std::vector<std::pair<size_t, uint8_t *>>& buffers
)
{
if (!conn)
return RTP_INVALID_VALUE;
return conn->get_socket().sendto(buffers, 0);
} }

View File

@ -7,43 +7,59 @@
namespace kvz_rtp { namespace kvz_rtp {
class connection; class connection;
namespace sender { namespace send {
/* Send RTP Frame to remote
*
* This functions assumes "frame_len" is smaller than MAX_PAYLOAD
* No measures are taken (apart from print a warning) if it's larger
* TODO: should it split the frame?
*
* send_frame() assumes that "frame" starts with a valid RTP header
*
* Return RTP_OK on success
* Return RTP_INVALID_VALUE if one of the values are invalid
* Return RTP_SEND_ERROR if sending the frame failed */
rtp_error_t send_frame(
kvz_rtp::connection *conn,
uint8_t *frame, size_t frame_len
);
/* Write RTP Header to OS buffers. This should be called first when sending new RTP packet. /* Send RTP Frame to remote
* *
* Return RTP_OK on success and RTP_ERROR on error */ * This functions assumes "frame_len" + "header_len" is smaller than MAX_PAYLOAD
rtp_error_t write_rtp_header(kvz_rtp::connection *conn, uint32_t timestamp); * No measures are taken (apart from print a warning) if it's larger
* TODO: should it split the frame?
/* To minimize the amount of copying, write all headers directly to operating system's buffers
* This function uses MSG_MORE/MSG_PARTIAL to prevent the actual sending.
* *
* Return RTP_OK on success and RTP_ERROR on error */ * send_frame() assumes that "header" points to a valid RTP header
rtp_error_t write_generic_header(kvz_rtp::connection *conn, uint8_t *header, size_t header_len);
/* Write the actual data payload and send the full datagram to remote
* *
* Caller should first write the RTP and all other necessary headers by calling * Return RTP_OK on success
* write_*_header() and then finalize the send by calling writePayload() * Return RTP_INVALID_VALUE if one of the values are invalid
* * Return RTP_SEND_ERROR if sending the frame failed */
* return RTP_OK on success and RTP_ERROR on error */ rtp_error_t send_frame(
rtp_error_t write_payload(kvz_rtp::connection *conn, uint8_t *payload, size_t payload_len);
/* Write a generic frame
* This function sends the datagram immediately,
*
* Return RTP_OK on success and RTP_ERROR on error */
rtp_error_t write_generic_frame(kvz_rtp::connection *conn, kvz_rtp::frame::rtp_frame *frame);
/* If the header and payload of RTP messages are separate, the can be combined and sent
* using write_frame()
*
* This function will send the message right away.
*
* return RTP_OK on success and RTP_ERROR on error */
rtp_error_t write_frame(
kvz_rtp::connection *conn, kvz_rtp::connection *conn,
uint8_t *header, size_t header_len, uint8_t *header, size_t header_len,
uint8_t *payload, size_t payload_len uint8_t *payload, size_t payload_len
); );
/* Send RTP Frame to remote
*
* This functions assumes "frame_len" is smaller than MAX_PAYLOAD
* No measures are taken (apart from print a warning) if it's larger
* TODO: should it split the frame?
*
* send_frame() assumes that "buffers" contains at least two buffers:
* - RTP header
* - RTP payload
*
* RTP header must be the first buffer of the "buffers" vector
*
* Return RTP_OK on success
* Return RTP_INVALID_VALUE if one of the values are invalid
* Return RTP_SEND_ERROR if sending the frame failed */
rtp_error_t send_frame(
kvz_rtp::connection *conn,
std::vector<std::pair<size_t, uint8_t *>>& buffers
);
}; };
}; };