Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions cpp/moq/MIGRATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first.

## Unreleased

### `announce` takes an `AnnounceRoute`

`BroadcastProducer::announce` takes `moq::AnnounceRoute{cost, epoch}` instead of a `moq::Route`: the origin builds the hop chain, so `hops` is no longer an input.
`moq::Route` is only what announcements report. To re-announce an observed route, copy its `cost` and `epoch`.

### A broadcast reference waits for its sibling's announcement (#6254)

Resolving a rendition's `broadcast` reference, through `BroadcastConsumer::resolve` and the rendition-based subscribes and fetches, now waits for a sibling nothing announces yet instead of failing as unroutable, so a late sibling plays once it is announced.
Expand All @@ -30,7 +35,7 @@ Pass the new `moq::ContainerFormat::kCmaf` to keep publishing CMAF.
### Catalog references carry their epoch

`Video` and `Audio` gain `epoch`, the publisher instance their `broadcast` reference names, right after `broadcast`; positional initializers shift by one.
`BroadcastConsumer::resolve(reference)` becomes `resolve(reference, epoch)`; pass the rendition's `epoch` alongside its `broadcast`, or `std::nullopt` to resolve whichever instance answers.
`BroadcastConsumer::resolve(reference)` becomes `resolve(rendition)`, taking the catalog `Rendition` and reading its `broadcast` and `epoch` from it.
Comment thread
kixelated marked this conversation as resolved.
Resolving, and the rendition-based consumers, fail with `moq::Error::kMux` for a rendition whose broadcast is proven to serve another epoch.

### Timestamps stop at 2^61 - 1 microseconds (#6168)
Expand Down Expand Up @@ -105,11 +110,11 @@ To start at group `n`, pass one range starting at the absolute anchor for group
### Receive estimates come from `Session::recv_bandwidth` (#5777)

The connection stats no longer carry a receive estimate.
Hold the consumer `Session::recv_bandwidth` returns to request PROBE, read it with `peek()` or wait with `changed()`, and `cancel()` it to stop.
Hold the consumer `Session::recv_bandwidth` returns to request PROBE, read it with `rate()` or wait with `rate_changed()`, and `cancel()` it to stop.

```cpp
auto bandwidth = session->recv_bandwidth();
auto rate = bandwidth ? bandwidth->peek() : std::nullopt;
auto rate = bandwidth ? bandwidth->rate() : std::nullopt;
```

### `AnnouncedBroadcast::available()` waits for the next publisher instance (#5700)
Expand Down
2 changes: 1 addition & 1 deletion cpp/moq/include/moq/moq.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ inline bool qlog_supported() {
return moq_qlog_supported();
}

// Mints a fresh publisher epoch, ordered newest last. Announce one per run in Route::epoch,
// Mints a fresh publisher epoch, ordered newest last. Announce one per run in AnnounceRoute::epoch,
// so viewers see a restart as a new broadcast instead of a stalled one.
inline std::string mint_epoch() {
return moq_mint_epoch();
Expand Down
4 changes: 2 additions & 2 deletions cpp/obs/src/moq-output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ bool MoQOutput::Start()
LOG_ERROR("Failed to create broadcast: %s", next_broadcast.error().to_string().c_str());
return false;
}
moq::Route route;
moq::AnnounceRoute route;
route.epoch = moq::mint_epoch();
if (auto announced = (*next_broadcast)->announce(route); !announced) {
LOG_ERROR("Failed to announce broadcast: %s", announced.error().to_string().c_str());
Expand Down Expand Up @@ -502,7 +502,7 @@ bool MoQOutput::TryGetConnectionStats(ConnectionStats *out)
snapshot.estimated_send_rate_valid = raw.estimated_send_rate_bps.has_value();
snapshot.estimated_send_rate_bps =
raw.estimated_send_rate_bps ? static_cast<double>(*raw.estimated_send_rate_bps) : 0;
const auto recv_rate = receive ? receive->peek() : std::nullopt;
const auto recv_rate = receive ? receive->rate() : std::nullopt;
snapshot.estimated_recv_rate_valid = recv_rate.has_value();
snapshot.estimated_recv_rate_bps = recv_rate ? static_cast<double>(*recv_rate) : 0;
snapshot.bytes_sent_valid = raw.bytes_sent.has_value();
Expand Down
2 changes: 1 addition & 1 deletion cpp/obs/test/moq-audio-encoder-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ void CheckSubscriberDecodes(const char *preset, size_t channels)

auto origin = moq::OriginProducer::init(moq::OriginConfig{});
auto broadcast = TestOk(origin->create_broadcast("room"), "create_broadcast");
moq::Route route;
moq::AnnounceRoute route;
route.epoch = moq::mint_epoch();
TestOk(broadcast->announce(route), "announce");

Expand Down
2 changes: 1 addition & 1 deletion cpp/obs/test/moq-source-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ class Publisher {
TestOk(moq::MediaTrackProducer::audio(broadcast, moq::MediaTarget::kNamed{}, init),
"audio producer");
}
TestOk(broadcast->announce(moq::Route{}), "announce");
TestOk(broadcast->announce(moq::AnnounceRoute{}), "announce");
}

~Publisher() { (void)broadcast->close(); }
Expand Down
13 changes: 9 additions & 4 deletions dart/moq/MIGRATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first.

## Unreleased

### `announce` takes an `AnnounceRoute`

`BroadcastProducer.announce(route:)` takes `AnnounceRoute(cost:, epoch:)` instead of a `MoqRoute`: the origin builds the hop chain, so `hops` is no longer an input.
`MoqRoute` is only what announcements report. To re-announce an observed route, copy its `cost` and `epoch`.

### Cancelling a stream cancels its pending read

`await subscription.cancel()` on announcements, authorization grants, and server requests now waits for the pending native operation to release, even when no event arrives.
Expand Down Expand Up @@ -43,7 +48,7 @@ Pass the new `ContainerFormat.cmaf` to keep publishing CMAF.
### Catalog references carry their epoch

`Video` and `Audio` renditions gain `epoch`, the publisher instance their `broadcast` reference names.
`BroadcastConsumer.resolve(reference:)` requires `epoch:` too; pass the rendition's `epoch` alongside its `broadcast`, or `null` to resolve whichever instance answers.
`BroadcastConsumer.resolve(reference:)` becomes `resolve(rendition:)`, taking the catalog `Rendition` and reading its `broadcast` and `epoch` from it.
Resolving, and the rendition-based consumers, throw for a rendition whose broadcast is proven to serve another epoch.

### Timestamps stop at 2^61 - 1 microseconds (#6168)
Expand Down Expand Up @@ -89,7 +94,7 @@ A subscription now reads only the groups its own `ranges` cover.
`TrackDemand.isUsed()`, `used()`, and `unused()` are gone.
`wanted()` returns null while nobody subscribes, otherwise the group subscribers want next, and `wantedChanged()` waits for it to change (the first call returns at once).
Loop on `wantedChanged()` until it returns non-null where you awaited `used()`, and null where you awaited `unused()`.
`TrackInfo` gains `refresh`. `GroupDemand` is unchanged.
`TrackInfo` gains `refresh`.

### `CongestionControl` gained `none` (#5926)

Expand All @@ -109,8 +114,8 @@ To start at group `n`, pass one range starting at the absolute anchor for group
### Receive estimates come from `Session.recvBandwidth` (#5777)

The connection stats no longer carry a receive estimate.
Hold the consumer `Session.recvBandwidth` returns to request PROBE, read it with `peek()` or wait with `changed()`, and `cancel()` it to stop.
Replace `stats().estimatedRecvRateBps` with `recvBandwidth()?.peek()`.
Hold the consumer `Session.recvBandwidth` returns to request PROBE, read it with `rate()` or wait with `rateChanged()`, and `cancel()` it to stop.
Replace `stats().estimatedRecvRateBps` with `recvBandwidth()?.rate()`.

### `AnnouncedBroadcast.available()` waits for the next publisher instance (#5700)

Expand Down
2 changes: 1 addition & 1 deletion dart/moq/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ final server = await Server.listen(
),
);
final broadcast = server.createBroadcast('live');
broadcast.announce(route: MoqRoute()); // unannounced broadcasts are invisible
broadcast.announce(route: AnnounceRoute()); // unannounced broadcasts are invisible
await for (final request in server.requests()) {
final session = await request.accept();
print(session.connects());
Expand Down
6 changes: 3 additions & 3 deletions dart/moq/lib/src/aliases.dart
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ typedef AnnounceConfig = MoqAnnounceConfig;
/// A pending wait for a route to cover a specific path.
typedef AnnouncedBroadcast = MoqAnnouncedBroadcast;

/// How a broadcast advertises its exact path: its static production cost and publisher epoch.
typedef AnnounceRoute = MoqAnnounceRoute;

/// A route over a prefix: its origin-relative path, wildcard captures, and route metadata.
typedef Announce = MoqAnnounce;

Expand Down Expand Up @@ -106,9 +109,6 @@ typedef TrackConsumer = MoqTrackConsumer;
/// A request to produce one uncached group for a fetch consumer.
typedef GroupRequest = MoqGroupRequest;

/// A watch-only handle to whether any caller still wants a requested group; holding it keeps nothing open.
typedef GroupDemand = MoqGroupDemand;

/// The write side of a single group: append frames to it.
typedef GroupProducer = MoqGroupProducer;

Expand Down
2 changes: 1 addition & 1 deletion dart/moq/lib/src/epoch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:moq_ffi/moq_ffi.dart';

/// Mint a fresh publisher epoch from the wall clock and secure randomness,
/// ordered newest last. Mint one per publisher run and announce it in
/// `MoqRoute.epoch`, so viewers see a restart as a new broadcast instead of a
/// `AnnounceRoute.epoch`, so viewers see a restart as a new broadcast instead of a
/// stalled one.
String mintEpoch() => moqMintEpoch();

Expand Down
14 changes: 7 additions & 7 deletions dart/moq/test/moq_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ void main() {
name: 'events',
info: TrackInfo(timescale: 1000000),
);
broadcast.announce(route: MoqRoute());
broadcast.announce(route: AnnounceRoute());
final announced =
(await announcement.timeout(timeout) as AnnounceEventStart).announce;
expect(announced.prefix, 'live');
Expand Down Expand Up @@ -309,7 +309,7 @@ void main() {
);
final broadcast = server.createBroadcast('live');
final track = broadcast.publishTrack(name: 'events', info: null);
broadcast.announce(route: MoqRoute());
broadcast.announce(route: AnnounceRoute());
final announced =
(await announcement.timeout(timeout) as AnnounceEventStart).announce;
expect(announced.prefix, 'live');
Expand Down Expand Up @@ -445,7 +445,7 @@ void main() {
throwsA(anything),
);

broadcast.announce(route: MoqRoute());
broadcast.announce(route: AnnounceRoute());
final announced = consumer.announced(config: MoqAnnounceConfig());
final first = await nextRoute(announced);
expect(first, isA<AnnounceEventStart>());
Expand All @@ -460,7 +460,7 @@ void main() {
throwsA(anything),
);

broadcast.announce(route: MoqRoute());
broadcast.announce(route: AnnounceRoute());
expect(await nextRoute(announced), isA<AnnounceEventStart>());
await consumer.requestBroadcast(path: 'live').timeout(timeout);
announced.cancel();
Expand All @@ -477,12 +477,12 @@ void main() {
epochTime('018bcfe5-6800-7000-8000-000000000000'),
DateTime.utc(2023, 11, 14, 22, 13, 20),
);
broadcast.announce(route: MoqRoute(epoch: first));
broadcast.announce(route: AnnounceRoute(epoch: first));
final start = await nextRoute(announced) as AnnounceEventStart;
expect(start.announce.route.epoch, first);

final second = mintEpoch();
broadcast.announce(route: MoqRoute(epoch: second));
broadcast.announce(route: AnnounceRoute(epoch: second));
final restart = await nextRoute(announced) as AnnounceEventRestart;
expect(restart.announce.route.epoch, second);

Expand All @@ -497,7 +497,7 @@ void main() {
config: MoqAnnounceConfig(prefix: 'room', filter: '*/chat'),
);
final broadcast = origin.createBroadcast(path: 'room/alice/chat');
broadcast.announce(route: MoqRoute());
broadcast.announce(route: AnnounceRoute());

final update = await nextRoute(announced) as AnnounceEventStart;
expect(update.announce.prefix, 'room/alice/chat');
Expand Down
7 changes: 6 additions & 1 deletion dart/moq_ffi/MIGRATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ How to update your code for each breaking change, newest first.

## Unreleased

### `announce` takes a `MoqAnnounceRoute`

`MoqBroadcastProducer.announce` takes `MoqAnnounceRoute` (`cost`, `epoch`) instead of a `MoqRoute`: the origin builds the hop chain, so `hops` is no longer an input.
`MoqRoute` is only what announcements report, and the `InvalidRoute` error is gone.

### Native futures support operation cancellation

Generated async calls return `UniffiRustFuture<T>`, which implements `Future<T>` and adds `Future<void> cancel()`.
Expand Down Expand Up @@ -38,7 +43,7 @@ Regenerate the bindings for the changed `request_broadcast` checksum.
### Catalog references carry their epoch

`MoqVideo` and `MoqAudio` gain `epoch`, the publisher instance their `broadcast` reference names.
`MoqBroadcastConsumer.resolve(reference:)` requires `epoch:` too; pass the rendition's `epoch` alongside, or `null` to resolve whichever instance answers.
`MoqBroadcastConsumer.resolve(reference:)` becomes `resolve(rendition:)`, taking the catalog `MoqRendition` and reading its `broadcast` and `epoch` from it.
Resolving, and the rendition-based consumers, fail a rendition whose broadcast is proven to serve another epoch with `MuxMoqException`.

### Finished tracks stay until the broadcast ends (#6157)
Expand Down
Loading
Loading