Skip to content

Commit a436779

Browse files
committed
Integrate picoquic build path and docs
1 parent bb64ca0 commit a436779

16 files changed

Lines changed: 1449 additions & 5 deletions

CMakeLists.txt

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,43 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
1010
set(CMAKE_CXX_EXTENSIONS OFF)
1111

1212
option(OPENMOQ_BUILD_TESTS "Build OpenMOQ publisher tests" ON)
13+
option(OPENMOQ_ENABLE_PICOQUIC "Enable picoquic transport integration when picoquic is available" ON)
14+
option(OPENMOQ_RUN_PICOQUIC_SMOKE_TESTS "Build and run picoquic loopback smoke tests" OFF)
15+
16+
set(OPENMOQ_PICOQUIC_SOURCE_DIR "/media/mondain/terrorbyte/workspace/github/picoquic" CACHE PATH
17+
"Path to a picoquic source checkout")
18+
19+
set(OPENMOQ_HAS_PICOQUIC OFF)
20+
21+
if(OPENMOQ_ENABLE_PICOQUIC AND EXISTS "${OPENMOQ_PICOQUIC_SOURCE_DIR}/CMakeLists.txt")
22+
set(OPENMOQ_PICOTLS_SOURCE_DIR "${OPENMOQ_PICOQUIC_SOURCE_DIR}/../picotls" CACHE PATH
23+
"Path to a picotls source checkout")
24+
25+
if(EXISTS "${OPENMOQ_PICOTLS_SOURCE_DIR}/CMakeLists.txt")
26+
set(PICOQUIC_FETCH_PTLS ON CACHE BOOL "" FORCE)
27+
set(FETCHCONTENT_SOURCE_DIR_PICOTLS "${OPENMOQ_PICOTLS_SOURCE_DIR}" CACHE PATH "" FORCE)
28+
set(picoquic_BUILD_TESTS OFF CACHE BOOL "" FORCE)
29+
set(BUILD_DEMO OFF CACHE BOOL "" FORCE)
30+
set(BUILD_HTTP OFF CACHE BOOL "" FORCE)
31+
set(BUILD_PQBENCH OFF CACHE BOOL "" FORCE)
32+
set(BUILD_LOGLIB OFF CACHE BOOL "" FORCE)
33+
set(BUILD_LOGREADER OFF CACHE BOOL "" FORCE)
34+
add_subdirectory("${OPENMOQ_PICOQUIC_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/picoquic")
35+
set(OPENMOQ_HAS_PICOQUIC ON)
36+
else()
37+
message(STATUS "picoquic checkout found, but picotls source was not found; building without picoquic integration")
38+
endif()
39+
endif()
1340

1441
add_library(openmoq_publisher_lib
1542
src/cli_options.cpp
1643
src/cmaf_segmenter.cpp
1744
src/cmsf_packager.cpp
1845
src/moq_draft.cpp
1946
src/mp4_box.cpp
47+
src/transport/moqt_session.cpp
48+
src/transport/picoquic_client.cpp
49+
src/transport/publisher_transport.cpp
2050
)
2151

2252
target_include_directories(openmoq_publisher_lib
@@ -26,6 +56,11 @@ target_include_directories(openmoq_publisher_lib
2656

2757
target_compile_features(openmoq_publisher_lib PUBLIC cxx_std_20)
2858

59+
if(OPENMOQ_HAS_PICOQUIC)
60+
target_compile_definitions(openmoq_publisher_lib PRIVATE OPENMOQ_HAS_PICOQUIC=1)
61+
target_link_libraries(openmoq_publisher_lib PRIVATE picoquic-core)
62+
endif()
63+
2964
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
3065
target_compile_options(openmoq_publisher_lib PRIVATE -Wall -Wextra -Wpedantic)
3166
endif()
@@ -36,9 +71,26 @@ target_link_libraries(openmoq-publisher PRIVATE openmoq_publisher_lib)
3671
include(CTest)
3772

3873
if(OPENMOQ_BUILD_TESTS)
39-
add_executable(openmoq-publisher-tests
74+
add_executable(openmoq-publisher-packaging-tests
4075
tests/cmaf_segmenter_test.cpp
4176
)
42-
target_link_libraries(openmoq-publisher-tests PRIVATE openmoq_publisher_lib)
43-
add_test(NAME openmoq-publisher-tests COMMAND openmoq-publisher-tests)
77+
target_link_libraries(openmoq-publisher-packaging-tests PRIVATE openmoq_publisher_lib)
78+
add_test(NAME openmoq-publisher-packaging-tests COMMAND openmoq-publisher-packaging-tests)
79+
80+
add_executable(openmoq-publisher-transport-tests
81+
tests/moqt_session_test.cpp
82+
)
83+
target_link_libraries(openmoq-publisher-transport-tests PRIVATE openmoq_publisher_lib)
84+
add_test(NAME openmoq-publisher-transport-tests COMMAND openmoq-publisher-transport-tests)
85+
86+
if(OPENMOQ_HAS_PICOQUIC AND OPENMOQ_RUN_PICOQUIC_SMOKE_TESTS)
87+
add_executable(openmoq-publisher-picoquic-smoke-tests
88+
tests/picoquic_smoke_test.cpp
89+
)
90+
target_link_libraries(openmoq-publisher-picoquic-smoke-tests PRIVATE openmoq_publisher_lib)
91+
target_include_directories(openmoq-publisher-picoquic-smoke-tests PRIVATE
92+
"${OPENMOQ_PICOQUIC_SOURCE_DIR}/picoquic"
93+
)
94+
add_test(NAME openmoq-publisher-picoquic-smoke-tests COMMAND openmoq-publisher-picoquic-smoke-tests)
95+
endif()
4496
endif()

README.md

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,66 @@ This keeps the project aligned with CMAF-style publication while avoiding unnece
6060
- `src`: library and CLI implementation
6161
- `tests`: CTest-based unit coverage
6262
- `docs`: protocol notes and design references
63+
- `docs/transport-plan.md`: picoquic integration plan and implementation checklist
6364
- `.github/workflows/ci.yml`: GitHub Actions build and test workflow for Linux and macOS
6465

6566
## Build
6667

68+
### Baseline build
69+
70+
This is the default path if you only want the packaging and session-layer code:
71+
72+
```bash
73+
cmake -S . -B build -DOPENMOQ_RUN_PICOQUIC_SMOKE_TESTS=OFF
74+
cmake --build build
75+
ctest --test-dir build --output-on-failure
76+
```
77+
78+
### Build with local picoquic and picotls
79+
80+
If you have local checkouts at:
81+
82+
- `/media/mondain/terrorbyte/workspace/github/picoquic`
83+
- `/media/mondain/terrorbyte/workspace/github/picotls`
84+
85+
then the project will automatically compile against them.
86+
87+
Required picotls setup:
88+
6789
```bash
68-
cmake -S . -B build
90+
git -C /media/mondain/terrorbyte/workspace/github/picotls submodule update --init --recursive
91+
```
92+
93+
Then configure and build normally:
94+
95+
```bash
96+
cmake -S . -B build -DOPENMOQ_RUN_PICOQUIC_SMOKE_TESTS=OFF
6997
cmake --build build
7098
ctest --test-dir build --output-on-failure
7199
```
72100

101+
Useful CMake options:
102+
103+
- `-DOPENMOQ_ENABLE_PICOQUIC=ON|OFF`
104+
- `-DOPENMOQ_PICOQUIC_SOURCE_DIR=/path/to/picoquic`
105+
- `-DOPENMOQ_RUN_PICOQUIC_SMOKE_TESTS=ON|OFF`
106+
107+
### Optional picoquic smoke test
108+
109+
There is an in-repo loopback smoke test target for the picoquic transport path, but it is disabled by default:
110+
111+
```bash
112+
cmake -S . -B build -DOPENMOQ_RUN_PICOQUIC_SMOKE_TESTS=ON
113+
cmake --build build --target openmoq-publisher-picoquic-smoke-tests
114+
ctest --test-dir build --output-on-failure
115+
```
116+
117+
Current status:
118+
119+
- the smoke test compiles
120+
- the end-to-end loopback handshake currently times out
121+
- keep this option off for routine development until that runtime issue is fixed
122+
73123
## Usage
74124

75125
Inspect the publish plan for an already fragmented MP4:
@@ -90,6 +140,23 @@ Try the draft-16 compatibility profile:
90140
./build/openmoq-publisher --input sample.mp4 --draft 16 --dump-plan
91141
```
92142

143+
Transport-oriented CLI flags are also present now:
144+
145+
```bash
146+
./build/openmoq-publisher \
147+
--input sample.mp4 \
148+
--endpoint localhost:4433 \
149+
--alpn moqt \
150+
--insecure
151+
```
152+
153+
Current status:
154+
155+
- the packaging pipeline is fully usable today
156+
- the session and transport interfaces are now scaffolded in code
157+
- `--endpoint` now enters the real picoquic-backed transport path when the project is built with local picoquic and picotls support
158+
- the compile-time transport integration works, but live handshake validation is still incomplete
159+
93160
## Creating Fragmented MP4 with FFmpeg
94161

95162
The publisher’s preferred fast path is already fragmented MP4 input. You can generate that with `ffmpeg` by copying compatible AAC-LC or H.264 streams and enabling CMAF-style fragmentation flags:
@@ -128,6 +195,15 @@ GitHub Actions is configured to build and test the project on:
128195

129196
The workflow currently runs the same CMake configure, build, and CTest steps on both platforms.
130197

198+
## Picoquic status
199+
200+
The repository now includes a transport abstraction and a picoquic-backed client wrapper.
201+
202+
- if local picoquic and picotls source trees are available, CMake can compile the real picoquic transport path into this project
203+
- if those dependencies are not available, the project still builds and tests normally, and the transport layer falls back cleanly
204+
- in this workspace, picoquic and picotls compile successfully as subprojects
205+
- the remaining transport issue is runtime: the loopback smoke test handshake still times out
206+
131207
## Contributing
132208

133209
See [CONTRIBUTING.md](/media/mondain/terrorbyte/workspace/github/moqxr/CONTRIBUTING.md) for contribution expectations and development notes.

docs/transport-plan.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Picoquic Transport Plan
2+
3+
This document turns the current picoquic integration idea into an implementation checklist for `moqxr`.
4+
5+
## Goal
6+
7+
Add a native QUIC transport layer using picoquic so the existing publisher pipeline can send MOQT control and media objects over a real connection without rewriting the packaging code.
8+
9+
## Scope boundaries
10+
11+
The current repository already handles:
12+
13+
- MP4 parsing
14+
- fragmented MP4 fast-path packaging
15+
- progressive MP4 remux into synthetic fragments
16+
- draft-aware publish planning
17+
18+
The picoquic work should add:
19+
20+
- QUIC connection management
21+
- MOQT session setup and control streams
22+
- media object publication over QUIC streams
23+
- transport-level backpressure and error handling
24+
25+
The picoquic work should not initially add:
26+
27+
- HTTP/3
28+
- WebTransport
29+
- broad muxing or repackaging logic
30+
- advanced QUIC features such as migration or multipath
31+
32+
## Architecture target
33+
34+
The intended layering is:
35+
36+
1. Packaging layer
37+
Uses `ParsedMp4`, `SegmentedMp4`, and `PublishPlan`.
38+
2. Session layer
39+
Converts a `PublishPlan` into MOQT control and object publication actions.
40+
3. Transport layer
41+
Provides connection, stream, and write primitives.
42+
4. Picoquic adapter
43+
Implements the transport layer on top of picoquic callbacks and sockets.
44+
45+
This separation is important because MOQT draft churn should be isolated to the session layer, while picoquic remains a byte transport.
46+
47+
## Deliverables
48+
49+
### Phase 1: transport seam
50+
51+
- [x] Add a transport interface for connect, open stream, write, close
52+
- [x] Add a session façade that consumes `PublishPlan`
53+
- [x] Add a picoquic client stub that implements the transport interface
54+
- [x] Keep current CLI and packaging flow unchanged
55+
56+
### Phase 2: connection establishment
57+
58+
- [x] Add endpoint configuration: host, port, ALPN
59+
- [x] Add TLS configuration hooks: cert, key, CA, insecure-dev toggle
60+
- [x] Establish a client QUIC connection with picoquic
61+
- [x] Report handshake success and failures cleanly
62+
63+
### Phase 3: MOQT control plane
64+
65+
- [ ] Open a control stream after handshake
66+
- [ ] Implement setup and session negotiation
67+
- [ ] Implement namespace or publish announcement flow
68+
- [ ] Represent draft-14 and draft-16 control-plane differences behind one abstraction
69+
70+
### Phase 4: object publication
71+
72+
- [ ] Publish initialization object first
73+
- [ ] Publish media objects according to `PublishPlan`
74+
- [ ] Decide and document one stream mapping policy
75+
- [ ] Handle transport write backpressure
76+
77+
### Phase 5: observability and testing
78+
79+
- [ ] Add structured logs for handshake, stream lifecycle, and object publication
80+
- [ ] Add unit tests for session-to-transport mapping
81+
- [ ] Add loopback integration tests for transport
82+
- [ ] Add interoperability tests against an OpenMOQ-capable endpoint
83+
84+
## Proposed stream mapping
85+
86+
Initial recommendation:
87+
88+
- one bidirectional control stream per session
89+
- one unidirectional stream per published object in the first implementation
90+
91+
That policy is not necessarily optimal long-term, but it is easier to reason about and validate while the control-plane logic is still moving.
92+
93+
## Interface responsibilities
94+
95+
### `PublisherTransport`
96+
97+
Owns:
98+
99+
- connection establishment
100+
- stream creation
101+
- byte writes
102+
- close
103+
- connection state
104+
105+
Does not own:
106+
107+
- MOQT message structure
108+
- media packaging
109+
- object scheduling policy
110+
111+
### `MoqtSession`
112+
113+
Owns:
114+
115+
- setup and control-plane sequencing
116+
- draft-specific control behavior
117+
- translation from `PublishPlan` to transport actions
118+
119+
Does not own:
120+
121+
- raw QUIC callbacks
122+
- MP4 parsing
123+
- object bytes
124+
125+
### `PicoquicClient`
126+
127+
Owns:
128+
129+
- picoquic configuration and lifecycle
130+
- callback bridging
131+
- stream IDs and write execution
132+
- error translation into transport-level status objects
133+
134+
## Suggested implementation order
135+
136+
1. Land interface-only scaffolding
137+
2. Add endpoint and TLS config types
138+
3. Implement a connect-only picoquic client
139+
4. Add control stream bring-up
140+
5. Add init object publication
141+
6. Add full object publication from `PublishPlan`
142+
7. Add retry, backpressure, and metrics
143+
144+
## Current repository status
145+
146+
- The transport seam and session façade are implemented.
147+
- CLI flags for endpoint, ALPN, and TLS-related parameters are present.
148+
- The build can integrate local picoquic and picotls source checkouts directly.
149+
- The current workspace now compiles picoquic and picotls successfully.
150+
- A loopback smoke test was added for live handshake validation, but it is not enabled by default because the current handshake attempt still times out.
151+
152+
## Key risks
153+
154+
- draft-14 vs draft-16 control differences leaking into transport code
155+
- coupling picoquic callback state too tightly to publish scheduling
156+
- under-specifying how objects map to streams early on
157+
158+
## Mitigations
159+
160+
- keep draft-specific message encoding in session code
161+
- keep transport status and callbacks generic
162+
- start with a conservative one-object-per-stream policy
163+
- add integration tests before optimizing stream reuse or pacing

include/openmoq/publisher/cli_options.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
#include <string>
66

77
#include "openmoq/publisher/moq_draft.h"
8+
#include "openmoq/publisher/transport/publisher_transport.h"
89

910
namespace openmoq::publisher {
1011

1112
struct CliOptions {
1213
std::filesystem::path input_path;
1314
std::optional<std::filesystem::path> emit_dir;
15+
std::optional<transport::EndpointConfig> endpoint;
16+
transport::TlsConfig tls;
1417
DraftVersion draft_version = DraftVersion::kDraft14;
1518
bool dump_plan = false;
1619
};

include/openmoq/publisher/cmsf_packager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct PublishPlan {
3232

3333
PublishPlan build_publish_plan(const SegmentedMp4& segmented_mp4, DraftVersion version);
3434
std::string render_publish_plan(const PublishPlan& plan);
35+
PublishPlan materialize_publish_plan(const PublishPlan& plan, std::span<const std::uint8_t> bytes);
3536
void emit_plan_objects(const PublishPlan& plan,
3637
std::span<const std::uint8_t> bytes,
3738
const std::filesystem::path& output_dir);

0 commit comments

Comments
 (0)