Skip to content

Commit 81c6e61

Browse files
authored
Implement S/G IO for non-batched sends and eliminate more data copies (#2867)
1 parent b93756a commit 81c6e61

File tree

5 files changed

+78
-65
lines changed

5 files changed

+78
-65
lines changed

src/platform/common.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,10 @@ namespace platf {
620620
send_batch(batched_send_info_t &send_info);
621621

622622
struct send_info_t {
623-
const char *buffer;
624-
size_t size;
623+
const char *header;
624+
size_t header_size;
625+
const char *payload;
626+
size_t payload_size;
625627

626628
std::uintptr_t native_socket;
627629
boost::asio::ip::address &target_address;

src/platform/linux/misc.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -606,12 +606,19 @@ namespace platf {
606606
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
607607
}
608608

609-
struct iovec iov = {};
610-
iov.iov_base = (void *) send_info.buffer;
611-
iov.iov_len = send_info.size;
612-
613-
msg.msg_iov = &iov;
614-
msg.msg_iovlen = 1;
609+
struct iovec iovs[2] = {};
610+
int iovlen = 0;
611+
if (send_info.header) {
612+
iovs[iovlen].iov_base = (void *) send_info.header;
613+
iovs[iovlen].iov_len = send_info.header_size;
614+
iovlen++;
615+
}
616+
iovs[iovlen].iov_base = (void *) send_info.payload;
617+
iovs[iovlen].iov_len = send_info.payload_size;
618+
iovlen++;
619+
620+
msg.msg_iov = iovs;
621+
msg.msg_iovlen = iovlen;
615622

616623
msg.msg_controllen = cmbuflen;
617624

src/platform/macos/misc.mm

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,12 +363,19 @@
363363
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
364364
}
365365

366-
struct iovec iov = {};
367-
iov.iov_base = (void *) send_info.buffer;
368-
iov.iov_len = send_info.size;
366+
struct iovec iovs[2] = {};
367+
int iovlen = 0;
368+
if (send_info.header) {
369+
iovs[iovlen].iov_base = (void *) send_info.header;
370+
iovs[iovlen].iov_len = send_info.header_size;
371+
iovlen++;
372+
}
373+
iovs[iovlen].iov_base = (void *) send_info.payload;
374+
iovs[iovlen].iov_len = send_info.payload_size;
375+
iovlen++;
369376

370-
msg.msg_iov = &iov;
371-
msg.msg_iovlen = 1;
377+
msg.msg_iov = iovs;
378+
msg.msg_iovlen = iovlen;
372379

373380
msg.msg_controllen = cmbuflen;
374381

src/platform/windows/misc.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1535,12 +1535,19 @@ namespace platf {
15351535
msg.namelen = sizeof(taddr_v4);
15361536
}
15371537

1538-
WSABUF buf;
1539-
buf.buf = (char *) send_info.buffer;
1540-
buf.len = send_info.size;
1541-
1542-
msg.lpBuffers = &buf;
1543-
msg.dwBufferCount = 1;
1538+
WSABUF bufs[2];
1539+
DWORD bufcount = 0;
1540+
if (send_info.header) {
1541+
bufs[bufcount].buf = (char *) send_info.header;
1542+
bufs[bufcount].len = send_info.header_size;
1543+
bufcount++;
1544+
}
1545+
bufs[bufcount].buf = (char *) send_info.payload;
1546+
bufs[bufcount].len = send_info.payload_size;
1547+
bufcount++;
1548+
1549+
msg.lpBuffers = bufs;
1550+
msg.dwBufferCount = bufcount;
15441551
msg.dwFlags = 0;
15451552

15461553
char cmbuf[std::max(WSA_CMSG_SPACE(sizeof(IN6_PKTINFO)), WSA_CMSG_SPACE(sizeof(IN_PKTINFO)))] = {};

src/stream.cpp

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -136,12 +136,7 @@ namespace stream {
136136
std::uint8_t tag[16];
137137
};
138138

139-
struct audio_packet_raw_t {
140-
uint8_t *
141-
payload() {
142-
return (uint8_t *) (this + 1);
143-
}
144-
139+
struct audio_packet_t {
145140
RTP_PACKET rtp;
146141
};
147142

@@ -219,12 +214,7 @@ namespace stream {
219214
// encrypted control_header_v2 and payload data follow
220215
} *control_encrypted_p;
221216

222-
struct audio_fec_packet_raw_t {
223-
uint8_t *
224-
payload() {
225-
return (uint8_t *) (this + 1);
226-
}
227-
217+
struct audio_fec_packet_t {
228218
RTP_PACKET rtp;
229219
AUDIO_FEC_HEADER fecHeader;
230220
};
@@ -238,8 +228,6 @@ namespace stream {
238228
constexpr std::size_t MAX_AUDIO_PACKET_SIZE = 1400;
239229

240230
using video_packet_t = util::c_ptr<video_packet_raw_t>;
241-
using audio_packet_t = util::c_ptr<audio_packet_raw_t>;
242-
using audio_fec_packet_t = util::c_ptr<audio_fec_packet_raw_t>;
243231
using audio_aes_t = std::array<char, round_to_pkcs7_padded(MAX_AUDIO_PACKET_SIZE)>;
244232

245233
using av_session_id_t = std::variant<asio::ip::address, std::string>; // IP address or SS-Ping-Payload from RTSP handshake
@@ -249,14 +237,14 @@ namespace stream {
249237
// return bytes written on success
250238
// return -1 on error
251239
static inline int
252-
encode_audio(bool encrypted, const audio::buffer_t &plaintext, audio_packet_t &destination, crypto::aes_t &iv, crypto::cipher::cbc_t &cbc) {
240+
encode_audio(bool encrypted, const audio::buffer_t &plaintext, uint8_t *destination, crypto::aes_t &iv, crypto::cipher::cbc_t &cbc) {
253241
// If encryption isn't enabled
254242
if (!encrypted) {
255-
std::copy(std::begin(plaintext), std::end(plaintext), destination->payload());
243+
std::copy(std::begin(plaintext), std::end(plaintext), destination);
256244
return plaintext.size();
257245
}
258246

259-
return cbc.encrypt(std::string_view { (char *) std::begin(plaintext), plaintext.size() }, destination->payload(), &iv);
247+
return cbc.encrypt(std::string_view { (char *) std::begin(plaintext), plaintext.size() }, destination, &iv);
260248
}
261249

262250
static inline void
@@ -755,6 +743,7 @@ namespace stream {
755743
std::vector<uint8_t>
756744
replace(const std::string_view &original, const std::string_view &old, const std::string_view &_new) {
757745
std::vector<uint8_t> replaced;
746+
replaced.reserve(original.size() + _new.size() - old.size());
758747

759748
auto begin = std::begin(original);
760749
auto end = std::end(original);
@@ -1531,6 +1520,8 @@ namespace stream {
15311520
BOOST_LOG(verbose) << "Falling back to unbatched send"sv;
15321521
for (auto y = 0; y < current_batch_size; y++) {
15331522
auto send_info = platf::send_info_t {
1523+
nullptr,
1524+
0,
15341525
shards.prefix(next_shard_to_send + y),
15351526
shards.prefixsize + shards.blocksize,
15361527
(uintptr_t) sock.native_handle(),
@@ -1584,9 +1575,7 @@ namespace stream {
15841575
auto shutdown_event = mail::man->event<bool>(mail::broadcast_shutdown);
15851576
auto packets = mail::man->queue<audio::packet_t>(mail::audio_packets);
15861577

1587-
constexpr auto max_block_size = crypto::cipher::round_to_pkcs7_padded(2048);
1588-
1589-
audio_packet_t audio_packet { (audio_packet_raw_t *) malloc(sizeof(audio_packet_raw_t) + max_block_size) };
1578+
audio_packet_t audio_packet;
15901579
fec::rs_t rs { reed_solomon_new(RTPA_DATA_SHARDS, RTPA_FEC_SHARDS) };
15911580
crypto::aes_t iv(16);
15921581

@@ -1598,9 +1587,9 @@ namespace stream {
15981587
const unsigned char parity[] = { 0x77, 0x40, 0x38, 0x0e, 0xc7, 0xa7, 0x0d, 0x6c };
15991588
memcpy(rs.get()->p, parity, sizeof(parity));
16001589

1601-
audio_packet->rtp.header = 0x80;
1602-
audio_packet->rtp.packetType = 97;
1603-
audio_packet->rtp.ssrc = 0;
1590+
audio_packet.rtp.header = 0x80;
1591+
audio_packet.rtp.packetType = 97;
1592+
audio_packet.rtp.ssrc = 0;
16041593

16051594
// Audio traffic is sent on this thread
16061595
platf::adjust_thread_priority(platf::thread_priority_e::high);
@@ -1618,26 +1607,28 @@ namespace stream {
16181607

16191608
*(std::uint32_t *) iv.data() = util::endian::big<std::uint32_t>(session->audio.avRiKeyId + sequenceNumber);
16201609

1621-
auto bytes = encode_audio(session->config.encryptionFlagsEnabled & SS_ENC_AUDIO, packet_data, audio_packet, iv, session->audio.cipher);
1610+
auto &shards_p = session->audio.shards_p;
1611+
1612+
auto bytes = encode_audio(session->config.encryptionFlagsEnabled & SS_ENC_AUDIO, packet_data,
1613+
shards_p[sequenceNumber % RTPA_DATA_SHARDS], iv, session->audio.cipher);
16221614
if (bytes < 0) {
16231615
BOOST_LOG(error) << "Couldn't encode audio packet"sv;
16241616
break;
16251617
}
16261618

1627-
audio_packet->rtp.sequenceNumber = util::endian::big(sequenceNumber);
1628-
audio_packet->rtp.timestamp = util::endian::big(timestamp);
1619+
audio_packet.rtp.sequenceNumber = util::endian::big(sequenceNumber);
1620+
audio_packet.rtp.timestamp = util::endian::big(timestamp);
16291621

16301622
session->audio.sequenceNumber++;
16311623
session->audio.timestamp += session->config.audio.packetDuration;
16321624

1633-
auto &shards_p = session->audio.shards_p;
1634-
1635-
std::copy_n(audio_packet->payload(), bytes, shards_p[sequenceNumber % RTPA_DATA_SHARDS]);
16361625
auto peer_address = session->audio.peer.address();
16371626
try {
16381627
auto send_info = platf::send_info_t {
1639-
(const char *) audio_packet.get(),
1640-
sizeof(audio_packet_raw_t) + bytes,
1628+
(const char *) &audio_packet,
1629+
sizeof(audio_packet),
1630+
(const char *) shards_p[sequenceNumber % RTPA_DATA_SHARDS],
1631+
(size_t) bytes,
16411632
(uintptr_t) sock.native_handle(),
16421633
peer_address,
16431634
session->audio.peer.port(),
@@ -1649,22 +1640,23 @@ namespace stream {
16491640
auto &fec_packet = session->audio.fec_packet;
16501641
// initialize the FEC header at the beginning of the FEC block
16511642
if (sequenceNumber % RTPA_DATA_SHARDS == 0) {
1652-
fec_packet->fecHeader.baseSequenceNumber = util::endian::big(sequenceNumber);
1653-
fec_packet->fecHeader.baseTimestamp = util::endian::big(timestamp);
1643+
fec_packet.fecHeader.baseSequenceNumber = util::endian::big(sequenceNumber);
1644+
fec_packet.fecHeader.baseTimestamp = util::endian::big(timestamp);
16541645
}
16551646

16561647
// generate parity shards at the end of the FEC block
16571648
if ((sequenceNumber + 1) % RTPA_DATA_SHARDS == 0) {
16581649
reed_solomon_encode(rs.get(), shards_p.begin(), RTPA_TOTAL_SHARDS, bytes);
16591650

16601651
for (auto x = 0; x < RTPA_FEC_SHARDS; ++x) {
1661-
fec_packet->rtp.sequenceNumber = util::endian::big<std::uint16_t>(sequenceNumber + x + 1);
1662-
fec_packet->fecHeader.fecShardIndex = x;
1663-
memcpy(fec_packet->payload(), shards_p[RTPA_DATA_SHARDS + x], bytes);
1652+
fec_packet.rtp.sequenceNumber = util::endian::big<std::uint16_t>(sequenceNumber + x + 1);
1653+
fec_packet.fecHeader.fecShardIndex = x;
16641654

16651655
auto send_info = platf::send_info_t {
1666-
(const char *) fec_packet.get(),
1667-
sizeof(audio_fec_packet_raw_t) + bytes,
1656+
(const char *) &fec_packet,
1657+
sizeof(fec_packet),
1658+
(const char *) shards_p[RTPA_DATA_SHARDS + x],
1659+
(size_t) bytes,
16681660
(uintptr_t) sock.native_handle(),
16691661
peer_address,
16701662
session->audio.peer.port(),
@@ -2030,15 +2022,13 @@ namespace stream {
20302022
session->audio.shards = std::move(shards);
20312023
session->audio.shards_p = std::move(shards_p);
20322024

2033-
session->audio.fec_packet.reset((audio_fec_packet_raw_t *) malloc(sizeof(audio_fec_packet_raw_t) + max_block_size));
2034-
2035-
session->audio.fec_packet->rtp.header = 0x80;
2036-
session->audio.fec_packet->rtp.packetType = 127;
2037-
session->audio.fec_packet->rtp.timestamp = 0;
2038-
session->audio.fec_packet->rtp.ssrc = 0;
2025+
session->audio.fec_packet.rtp.header = 0x80;
2026+
session->audio.fec_packet.rtp.packetType = 127;
2027+
session->audio.fec_packet.rtp.timestamp = 0;
2028+
session->audio.fec_packet.rtp.ssrc = 0;
20392029

2040-
session->audio.fec_packet->fecHeader.payloadType = 97;
2041-
session->audio.fec_packet->fecHeader.ssrc = 0;
2030+
session->audio.fec_packet.fecHeader.payloadType = 97;
2031+
session->audio.fec_packet.fecHeader.ssrc = 0;
20422032

20432033
session->audio.cipher = crypto::cipher::cbc_t {
20442034
launch_session.gcm_key, true

0 commit comments

Comments
 (0)