Skip to content

Commit c6d3fe0

Browse files
committed
Fix draft-18 subgroup object framing
1 parent ec8bacd commit c6d3fe0

3 files changed

Lines changed: 43 additions & 8 deletions

File tree

include/openmoq/publisher/transport/moqt_control_messages.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,11 @@ std::vector<std::uint8_t> encode_subgroup_header(DraftVersion draft,
149149
std::uint64_t subgroup_id,
150150
bool end_of_group);
151151

152-
// Object fields to append to an already-open subgroup stream. Per spec
153-
// §10.4.2 the first object on the stream carries its absolute Object ID
154-
// (pass std::nullopt for previous_object_id); subsequent objects encode
155-
// Object ID Delta = object_id - previous_object_id - 1.
152+
// Object fields to append to an already-open subgroup stream. The first object
153+
// on the stream carries its absolute Object ID (pass std::nullopt for
154+
// previous_object_id); subsequent objects encode Object ID Delta =
155+
// object_id - previous_object_id - 1. Draft-18 only emits Object Status when
156+
// the payload length is zero.
156157
std::vector<std::uint8_t> encode_subgroup_object(DraftVersion draft,
157158
std::optional<std::uint64_t> previous_object_id,
158159
std::uint64_t object_id,

src/transport/moqt_control_messages.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,12 +1137,11 @@ std::vector<std::uint8_t> encode_subgroup_object(DraftVersion draft,
11371137
previous_object_id.has_value() ? (object_id - *previous_object_id - 1) : object_id;
11381138
std::vector<std::uint8_t> bytes;
11391139
append_varint(bytes, object_id_delta);
1140-
if (draft == DraftVersion::kDraft18) {
1141-
// draft-18 subgroup object encoding includes Object Status. For normal
1142-
// payload-carrying objects this is OBJECT_STATUS_NORMAL (0).
1140+
append_varint(bytes, payload.size());
1141+
if (draft == DraftVersion::kDraft18 && payload.empty()) {
1142+
// draft-18 only carries Object Status after a zero payload length.
11431143
append_varint(bytes, 0);
11441144
}
1145-
append_varint(bytes, payload.size());
11461145
bytes.insert(bytes.end(), payload.begin(), payload.end());
11471146
return bytes;
11481147
}

tests/moqt_control_messages_test.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "openmoq/publisher/transport/moqt_control_messages.h"
22

33
#include <cstdint>
4+
#include <cstddef>
5+
#include <optional>
46
#include <iostream>
57
#include <span>
68
#include <string>
@@ -20,6 +22,7 @@ using openmoq::publisher::transport::decode_server_setup_message;
2022
using openmoq::publisher::transport::decode_varint;
2123
using openmoq::publisher::transport::encode_request_ok_message;
2224
using openmoq::publisher::transport::encode_setup_message;
25+
using openmoq::publisher::transport::encode_subgroup_object;
2326

2427
bool expect(bool condition, const std::string& message) {
2528
if (!condition) {
@@ -152,5 +155,37 @@ int main() {
152155
ok &= expect(message.request_id == 7, "expected draft-16 request_ok request_id to remain parsed");
153156
}
154157

158+
{
159+
const std::vector<std::uint8_t> payload = {0xaa, 0xbb, 0xcc};
160+
const std::vector<std::uint8_t> bytes =
161+
encode_subgroup_object(DraftVersion::kDraft18, std::nullopt, 0, payload);
162+
std::size_t offset = 0;
163+
std::uint64_t object_id_delta = 99;
164+
std::uint64_t payload_length = 99;
165+
ok &= expect(decode_varint(bytes, offset, object_id_delta) && object_id_delta == 0,
166+
"expected draft-18 first subgroup object id delta");
167+
ok &= expect(decode_varint(bytes, offset, payload_length) && payload_length == payload.size(),
168+
"expected draft-18 payload length immediately after object id delta");
169+
ok &= expect(offset + payload_length == bytes.size(), "expected draft-18 payload object to omit status");
170+
ok &= expect(std::vector<std::uint8_t>(bytes.begin() + static_cast<std::ptrdiff_t>(offset), bytes.end()) == payload,
171+
"expected draft-18 payload bytes after length");
172+
}
173+
174+
{
175+
const std::vector<std::uint8_t> bytes =
176+
encode_subgroup_object(DraftVersion::kDraft18, std::nullopt, 0, {});
177+
std::size_t offset = 0;
178+
std::uint64_t object_id_delta = 99;
179+
std::uint64_t payload_length = 99;
180+
std::uint64_t object_status = 99;
181+
ok &= expect(decode_varint(bytes, offset, object_id_delta) && object_id_delta == 0,
182+
"expected draft-18 empty object id delta");
183+
ok &= expect(decode_varint(bytes, offset, payload_length) && payload_length == 0,
184+
"expected draft-18 empty object payload length");
185+
ok &= expect(decode_varint(bytes, offset, object_status) && object_status == 0,
186+
"expected draft-18 empty object status after zero length");
187+
ok &= expect(offset == bytes.size(), "expected draft-18 empty object to contain no payload");
188+
}
189+
155190
return ok ? 0 : 1;
156191
}

0 commit comments

Comments
 (0)