Skip to content

Add subscribe hints #289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Oct 23, 2023
Merged

Add subscribe hints #289

merged 23 commits into from
Oct 23, 2023

Conversation

suhasHere
Copy link
Collaborator

@suhasHere suhasHere commented Oct 17, 2023

This is a initial PR to get some basic definition of subscription hints. I would like to get us to an agreement for the basic proposal and then discuss further on error codes, edge cases and impacts/interactions with other messages (Sub Fin, RST, UPD)

Fixes #111
Fixes #245
Fixes #260

Copy link
Contributor

@huitema huitema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, that's a complicated syntax. You have optional elements, but the TLS1.3 syntax that we use limits how we can specify optional elements. For example, when you write:

StartPoint Payload {
  Mode (i),
  [GroupCount (i)]
}

the decoder has an issue. If there are bytes in the message following the encoding of encoding of "mode", do those bytes encode the GroupCount, or do they belong to the encoding of the next element in the subscribe command? Your description of "now" says that "The optional parameter GroupCount, if specified, MUST be ignored" -- but there the decoder is really in a bind.

This is a problem throughout. You allow extension points, but the syntax is not designed to "skip over" unknown extensions. To be on the safe side, I would change the syntax of the subscription hint to be:

SUBSCRIPTION HINT {
  HintType (i),
  HintLength(i),
  Payload (...)
}

If you do that, then you can have optional elements for each payload type. (I would rename "payload" to "hint parameters" or "hintValue".)

Regarding the HintType, how is this defined? Suppose that I want to define a new hint type, what do I do? Will there be an IANA registry? Will there be a range of numbers reserved for experimentation?

Copy link
Collaborator

@afrind afrind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Individual Review

Thanks for this PR, I think it's directionally right but needs a few tweaks for parseability.

@afrind
Copy link
Collaborator

afrind commented Oct 18, 2023

Can you mark this as Fixes: #245 so it shows as having a PR attached (also possibly 111 and 260)? Also recommend closing #246 as this replaces it.

@kixelated kixelated mentioned this pull request Oct 18, 2023
Copy link
Collaborator

@kixelated kixelated left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really a complicated encoding and yet not that flexible. I don't like modes that can't be generalized; we'll end up with spaghetti.

Here's my proposal: #245 (comment)

@suhasHere
Copy link
Collaborator Author

Here's my proposal: #245 (comment)

I feel #245 proposal is more ambiguous though. I agree we can make the proposed ending in this PR to make it easier to encode/decode.

I have to get higher level idea agreed upon

  1. There are subscription hints. 2 hints are defined in this PR a) StartPoint b) Interval
  2. There may be hints we might want to add in future and hence a Hint structure identifies a type and value
  3. StartPoint hint can support 4 modes. These modes are only applicable when the HintType is StartPoint
  4. Interval hint is totally separate hintType that defines ranges of groups/objects

@suhasHere
Copy link
Collaborator Author

Regarding the HintType, how is this defined? Suppose that I want to define a new hint type, what do I do? Will there be an IANA registry? Will there be a range of numbers reserved for experimentation?

Having a registry is the idea and I was thinking once we get to agreement of Hint strucutres , then we can follow with defining error codes, registries for types and cleaning up track request params

@suhasHere
Copy link
Collaborator Author

SUBSCRIPTION HINT {
HintType (i),
HintLength(i),
Payload (...)
}

Payload(b) is defined to have len and value . Here is the definition as defined in the draft today
x (b): : Indicates that x consists of a variable length integer, followed by that many bytes of binary data.

@suhasHere
Copy link
Collaborator Author

suhasHere commented Oct 18, 2023

So pushed few more commits cleaning up somethings and considering suggestion from Alan on TrackOffset and removing text on error. Thanks everyone for the review feedback

Would love to hear feedback on the whole text.

Copy link
Collaborator

@afrind afrind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Individual Review:

Thank you for the update. This looks implementable. I'd probably just have one hint with this definition rather than a list. The main open question is if we need the additional flexibility mentioned in Luke's last comment in #245:

Here's some things you can't do with the proposed encoding:

  • Start 4 groups in the past and end 2 in the future: start=relative/4 end=future/1
  • Start at group 69 and end at latest: start=absolute/69 end=relative/0
  • Start at 69 and end 4 groups in the past (might be a noop): start=absolute/69 end=relative/4
  • Keep refreshing a relative subscription while it's needed: start=relative/4 end=future/3

If these are important then we can shuffle the encoding a bit.


### RelativeStartPoint Hint {#relative}

The `RelativeStartPoint` subscription hint identifies a starting point relative to publisher's view of the ongoing state of the track for delivering objects. A publisher's current state of the track is defined by the most recent group and object sequence received (or active in the cache), if available, at the time of request.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe SUBSCRIBE OK should tell you the absolute value of the publisher's start point. The first object I receive may not be the start.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder there is any way a subscriber can know this info. Whatever publisher says in the OBJECT message is considered to be the start for all relative requests. isn't it ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thought was that the first object received might not be the first object sent by the publisher (due to out of order delivery, congestion, etc), hence it might be good for the publisher to indicate to the subscriber what they are going to get.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the thing is , when you send subscribe , there might not be any publisher started publishing .. so info in OK is not sufficient ..
May be we need a bit in the object header, that if set means its the first object in the track

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the thing is , when you send subscribe , there might not be any publisher started publishing .. so info in OK is not sufficient ..

This makes sense too. Optional flag in SUBSCRIBE OK? I could live with punting this feature also for now.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, let's open an new issue to add a flag to the OBJECT and also have some info on OK message

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TO DISCUSS LIVE

Copy link
Contributor

@huitema huitema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is progressing. Apart from the comments below, I would take a hard look at the extension points. Do we need them, or can we just say that "a future version of this spec may define more hint types"?

This would be in line with only having extensions by version number, negotiated during the connection.

Copy link
Contributor

@huitema huitema left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one minor comment. I think this is pretty much ready.

{: #moq-transport-track-offset format title="MOQT TrackOffset"}

`ObjectSequence` set to 0x0 implies until the end of the group identified in `GroupSequence`.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think that ObjectSequence set to 0x0 implies until the end from the beginning of the group identified in GroupSequence.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+100

How are you supposed to request the first object from a group otherwise? What is even the use-case of requesting the max object from an old group?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DISCUSS LIVE

@@ -797,6 +797,8 @@ The format of SUBSCRIBE REQUEST is as follows:
SUBSCRIBE REQUEST Message {
Full Track Name Length (i),
Full Track Name (...),
Number of Hints (i),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain what does it mean to have multiple hints? Like, semantically, if I supply both a relative and an absolute offset, what should happen?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was thinking if we define a new hint type that is not related to start point in future, allowing it to be useful. OTOH i wonder if we can make a request that if there exists both relative and absolute start point, have absolute take preference always ?

I don't know why would one define, but we need to define what happens when one does so

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't want multiple hints. It's not clear how overlapping hints are supposed to interact, which makes it implementation specific.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DISCUSS LIVE

GroupCount(i)
}
~~~
{: #moq-transport-relative-start-next-hint format title="MOQT RelativeStartNext Hint"}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the relationship between Current, RelativeStartPrevious with count 0, and RelativeStartNext with count 0? Are they identical? Is count 0 disallowed by the protocol?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my thinking is count of 0 for RelativeStartPrevious gives the current group. Do you see if there is any issues with that ? We can have GroupCount > 0 always too ..

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just confusing and you need to clarify at least. This is a classic off-by-one bug waiting to happen. It also might make caching more difficult because there's 3 different ways to request the latest group.

IMO
RelativeStartPrevious is relative to current
RelativeStartNext is relative to current+1
Current is removed in favor of RelativeStartPrevious count=0

Copy link
Collaborator Author

@suhasHere suhasHere Oct 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see it causes implementation confusion or off-by-one bug. The semantics are clear and yes, more text can be added, if needed.

5 4 3 2 1 CURRENT (0) 1 2 3 4 5

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DISCUSS LIVE


### AbsoluteStart Hint

The `AbsoluteStart` subscription hint allows subscribers to specify an absolute point in the track to start delivering objects, as indicated by the `TrackOffset` hint attribute.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can TrackOffset be in the future? If so, please document the expected behavior.

Copy link
Collaborator Author

@suhasHere suhasHere Oct 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, it can be .. What aspects were you thinking we should document ? Happy to add

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe - 1) state that it is intended that subscribers can ask for a future offset (similar to RelativeStartNext with a positive number), and then specify if the publisher needs to wait for those objects to be available to issue SUBSCRIBE OK, or it issues a SUBSCRIBE OK immediately? What if those objects never materialize?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DISCUSS LIVE

Copy link
Collaborator

@afrind afrind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Individual Review

On successful subscription, the publisher SHOULD start delivering
objects from the group sequence and object sequence as defined in the
`Track Request Parameters`.

OPEN QUESTION: Should we disallow multiple hints ?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference is for only a single hint. The current hint set can be mixed in non-sensical ways.

~~~
SUBSCRIPTION HINT {
HintType (i),
HintValueLength (i),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As currently defined, the length is not needed because the length of all hint types is known.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you only need the length if you want to support unknown HintTypes. However, I think it should just be a protocol violation if you use an unknown type, so you don't need the length.

~~~
{: #moq-transport-absolute-interval-hint format title="MOQT AbsoluteInterval Hint"}

The end track offset of the range is exclusive.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that's:

[0, 0], to [2, 0] = all of groups 0 and 1
[0, 0], to [2, 1] = all of groups 0 and 1, and group 2, object 0,

etc?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, seems right. The problem is that if you want inclusive, you have to write:

[0, 0], to [1, 7563] = all of groups 0 and 1

But you can only do that if you know in advance that group 1 has exactly 7563 objects -- and that's no obvious.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's true .. as a mental model, it helps me build nice breakpoints between end of one range and start of new range in a easier way ..


### AbsoluteStart Hint

The `AbsoluteStart` subscription hint allows subscribers to specify an absolute point in the track to start delivering objects, as indicated by the `TrackOffset` hint attribute.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe - 1) state that it is intended that subscribers can ask for a future offset (similar to RelativeStartNext with a positive number), and then specify if the publisher needs to wait for those objects to be available to issue SUBSCRIBE OK, or it issues a SUBSCRIBE OK immediately? What if those objects never materialize?

Copy link
Collaborator

@kixelated kixelated left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to +1 Alan's comment but I think it got buried in changes. We will eventually need the selected start/end group/object echoed in SUBSCRIBE_OK. Otherwise I don't think you can actually use these relative hints; there's a bunch of edge cases and races.

@@ -797,6 +797,8 @@ The format of SUBSCRIBE REQUEST is as follows:
SUBSCRIBE REQUEST Message {
Full Track Name Length (i),
Full Track Name (...),
Number of Hints (i),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really don't want multiple hints. It's not clear how overlapping hints are supposed to interact, which makes it implementation specific.

~~~
SUBSCRIPTION HINT {
HintType (i),
HintValueLength (i),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you only need the length if you want to support unknown HintTypes. However, I think it should just be a protocol violation if you use an unknown type, so you don't need the length.


### Now Hint

`Now` subscription hint specifies the start point for object delivery from the most recent object of the current group. Now hint type defines no further hint attributes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this include the most recent object? If so, the latest object could have been generated hours ago, so "now" is a little misleading.

I would rename:

old new
Current CurrentGroup
Now CurrentObject

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to like Now better than CurrentObject since it feels more suited when used with subscribe. CurrentObject makes me wonder if it is more befitting to Fetch/Get semantics (#111 )


### RelativeStartPrevious Hint

`RelativeStartPrevious` subscription hint specifies the start point for object delivery from an earlier group relative to the current group. The `GroupCount` hint attribute specifies the number of groups to go back from the current group to determine the start point.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would RelativeStartPrevious GroupCount = 0 be identical to Current?

Can you clarify if this is the case, and give an example?


### RelativeStartNext Hint

`RelativeStartNext` subscription hint specifies the start point for object delivery to a future group relative to the current group. The `GroupCount` hint attribute specifies the number of groups to wait on before delivering the objects.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would RelativeStartNext GroupCount = 0 be identical to Current?

Can you clarify if this is the case, and give an example?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing text does say the count needs to be happen from the current group as anchor. That seems pretty clear though.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DISCUSS LIVE

GroupCount(i)
}
~~~
{: #moq-transport-relative-start-next-hint format title="MOQT RelativeStartNext Hint"}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just confusing and you need to clarify at least. This is a classic off-by-one bug waiting to happen. It also might make caching more difficult because there's 3 different ways to request the latest group.

IMO
RelativeStartPrevious is relative to current
RelativeStartNext is relative to current+1
Current is removed in favor of RelativeStartPrevious count=0

{: #moq-transport-track-offset format title="MOQT TrackOffset"}

`ObjectSequence` set to 0x0 implies until the end of the group identified in `GroupSequence`.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+100

How are you supposed to request the first object from a group otherwise? What is even the use-case of requesting the max object from an old group?

Copy link
Collaborator

@afrind afrind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to summarize what we need to discuss live:

  1. Do the use cases mentioned by Luke in 245 need to be covered now?
  2. One hint or multiple hints?
  3. Is RelativeStart(Next/Prev), Group=0 the same as Current?
    3a. If so, should those be disallowed?
  4. How should a publisher respond to a hint in the future?
  5. Does TrackOffset ObjectSequence=0 mean "from the beginning" or "til the end" of the group?

Anything else?

If a publisher cannot satisfy the requested start or end for the subscription it
MAY send a SUBSCRIBE_ERROR with code TBD.

PROPOSAL 3: More explicit
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thing i like about this proposal is having just 2 dimensions to define the combinations of things. This also seems pretty flexible.

I feel we don't need signed value but rather a direction indicator instead to compute the resultign object/group - Increasing/Decreasing Delta

Having thought about it a bit more , I seem to agree with @fluffy on Relay update cycles and thus supporting flexibility is a good way to move.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One clarification needed in the text is ,

One should compute target group index first and then compute the object index.
If the start_group mode is relative, then either use +ve or -ve delta from the current group to compute the target group
if the start_group mode is absolute, then target group is the group in the request

Same thing is one for target object index.

if

@fluffy
Copy link
Collaborator

fluffy commented Oct 22, 2023

So @kixelated proposal in the thread above that is similar to mine just seems better than what I proposed. It covers all the cases, it is easy to describe and validate work and does not have a bunch of uses cases.

I would put in a very weak argument for instead of taking the bottom two bits to encode the (absolute, relative, future, none ) , instead just put that into it's own VarInt. I would not argue very much for that because this is all going to get put in 5 lines of code I will never look at again and it's does not turn up on the wire in something that has to be small. Probably the worst part of is is someone looking at network dump might be confused but that just means the wireshark dissector needs to know about how to the >>2 works. I'd be totally fine with proposal as is.

Some strong points I see for this:

  1. we could merge it by Monday
  2. It covers all the uses case we can imagine now plus has a high chance of covering the future cases we can not imagine now
  3. It is simple to understand, think about, and test

Copy link
Collaborator

@afrind afrind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per Luke's proposal:

It would be encoded as:

SUBSCRIBE {
...
start_group_hint: (i)
start_object_hint: (i)
end_group_hint (i)
end_object_hint (i)
...
}

I think I would also use a separate varint for the mode for each param rather that the LSBs. Keep in mind that taking 2 bits from a varint means only 0-15 can be encoded in a single byte, and we shouldn't be trying to squeeze bytes out of this control message.

Hint {
  Mode (i),
  [Value (i)]
}
Modes = None, Relative, Next, Absolute
Value is not present when Mode is None

SUBSCRIBE {
  ...
  start_group_hint: Hint
  start_object_hint: Hint
  end_group_hint: Hint
  end_object_hint: Hint
  ...
}

Start Group and Start Object cannot be None. End Group and Object must either both be None (Closed Range), or Neither (Open Subscribe).

Also bikeshed on whether this is a Hint or a Parameter (not to be confused with Track Request Parameter). Hint implies that it's ok if the publisher ignores it.

|--------------|-------|----------|--------------------|
| START_OBJECT_MODE | 0x3 | No | Relative |
|--------------|-------|----------|--------------------|
| START_OBJECT_DELTA | 0x4 | No | 0 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go back 100 groups from the current group, then start at the 100th from the beginning of the group

I think that would be

START_GROUP_MODE=relative
START_GROUP=-100
START_OBJECT_MODE=*absolute*
START_OBJECT=100

But later I started thinking about a text chat client where each "chat room" was a track, and each thread was a group, and each message was in an object.

This implies a track with multiple active groups. I guess the current draft doesn't prohibit that, but I'm not sure we're thought through the implications completely.

I guess I can see "give me the N previous objects from Now (current group)", but struggling to see why I would want N previous objects from the largest one you have in some previous group. That said, the simplicity of the Luke's proposal is alluring, even if it allows you do request some bizarre things.

@kixelated
Copy link
Collaborator

kixelated commented Oct 22, 2023

I think I would also use a separate varint for the mode for each param rather that the LSBs. Keep in mind that taking 2 bits from a varint means only 0-15 can be encoded in a single byte, and we shouldn't be trying to squeeze bytes out of this control message.

A 0-16 range would work for the majority of relative/future hints, so it would definitely save that byte. But I'm fine keeping it verbose for now; the important part is the reusable Hint encoding.

Start Group and Start Object cannot be None. End Group and Object must either both be None (Closed Range), or Neither (Open Subscribe).

start_group=none would be useful for checking track existence without receiving OBJECTs. But let's rule it out for now because it would mean a subscription that will never match objects, which would need some extra text.

start_group=N, start_object=none would be same as start_group=N+1, start_object=0 but that's not obvious. We can also rule it out.

end_group=N, end_object=none is required to specify the FIN of a group. ex. end at the last object of group 69.

end_group=none, end_object=N is invalid though.

Also bikeshed on whether this is a Hint or a Parameter (not to be confused with Track Request Parameter). Hint implies that it's ok if the publisher ignores it.

I think it's a hint right now, since the publisher can choose to drop objects/groups on a whim. Even if you ask to start at group 3, you might never get it for congestion control reasons.

But the bigger issue is that a subscriber doesn't know the upstream's expiration time. A publisher may only cache the last 3 groups, so a subscriber can't just ask for the the last 8 groups and expect to receive them all. Throwing an error in that situation seems futile.

But I think the publisher should signal the (absolute) start/end range in SUBSCRIBE_OK, which may be a subset of the requested range. Then it would be a start/end range request, resulting in a start/end range response.

@fluffy
Copy link
Collaborator

fluffy commented Oct 22, 2023

I like the direction that Alan has take Lukes stuff.

To bikeshed the Hint. I think "Location" would be a better name than "Hint". I think this is not really a hint but more a filter that relay will not send me objects on this subscription before the Start location or after the end Location. So if you want my bikeshedy 0.000002 cents, I would define

Location {
GroupMode (i),
GroupValue (i),
ObjectMode (i),
ObjectValue (i)
}
ObjectModes = None, Absolute, Past, Future
GroupModes = None, Absolute, Past, Future

The the subscribe would have a Start and End Location.

Location become a clean way to specify a specific a specific object in a track and may turn out to be useful in other parts of the spec.

@fluffy
Copy link
Collaborator

fluffy commented Oct 22, 2023

< rant >
I'd like to take a moment to reflect that the notation we are using for is both shitty and bad.

Take
Hint {
Mode (i),
[Value (i)]
}
Modes = None, Relative, Next, Absolute

By shitty, I mean super non intuitive. What does (i) mean? Is [X] optional or an array? But no, that would be ... Can I have more than one X? If I had Mode(2) followed by [Value(i)], would it be bit packed or would the Mode be padded out to a byte? And what type is Mode. Or if Mode is a type what is then encoding of all that crap. Most schema languages are fairly intuitive to read and guess what they might mean. This is not.

Then there is the bad. Say I want to define a type called Mode then have two fields in a record called ObjectMode and GroupMode both of type Mode. What do I do?

Location {
GroupMode (i),
ObjectMode (i)
}
ObjectModes = None, Absolute, Past, Future
GroupModes = None, Absolute, Past, Future

This can not possibly be the right way to do it. I mean now that Mode is not reusable and repeats itself.

If only we had a well defined language for expressing this. Oh wait we do https://datatracker.ietf.org/doc/html/rfc5234

Copy link
Collaborator

@ianswett ianswett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Option 3 looks good, but I'm unsure why we might want different modes for the group and object. I guess it depends upon how you define how the group modes affects the object?

--- back

# Pseudo-code for Interpreting Subscribe Track Request Parameters

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to removing it before merging, but I'm glad it helped people understand.

@kixelated
Copy link
Collaborator

kixelated commented Oct 22, 2023

Option 3 looks good, but I'm unsure why we might want different modes for the group and object. I guess it depends upon how you define how the group modes affects the object?

I went ahead and enumerated the permutations

group object useful notes
absolute absolute yes range request
absolute relative audio* tail of group
absolute future no
absolute none yes full group
relative absolute yes head of live group
relative relative audio* tail of live group
relative future audio* next audio sample(s)
relative none yes full group
future absolute yes head of future group
future relative no
future future no
future none yes future group(s)
none none yes tail of track
none * no

The ones labeled with audio* are only when you have partially independent samples. For example, each audio GROUP is 2s long and each audio OBJECT is 21ms.

SUBSCRIBE audio start_group=relative/0 start_object=relative/5

This would get you the last 105ms of audio (target initial buffer) most of the time. However, you could get unlucky and a new group could have started with less than that available, but it doesn't really matter if the target buffer is small because the player will just wait.

Personally, I want to remove this use-case. If objects can be independent, then they should be separate groups IMO. So each audio frame would be a group of size 21ms. You could then combine the group/object mode since object boundaries can either be absolute or none.

@afrind
Copy link
Collaborator

afrind commented Oct 23, 2023

I pushed a new commit with PROPOSAL 4, which we have been discussing, pulling the "best of" text and examples from the other proposals. I deleted the PROPOSAL 1 sample code and didn't add code for 4.

There's one DISCUSS, whether we should allow Start/EndObject to be None and have defaults, or require them to be specified.

🤞

@kixelated kixelated mentioned this pull request Oct 23, 2023
* StartObject: The Location of the requested object. StartObject's Mode MUST NOT
be None.

DISCUSS: StartObject and EndObject could be optional, with a default of
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like being explicit since the defaults aren't obvious. If the goal is to save bytes, there's other options.


* EndObject: The last Object requested in the subscription, exclusive.
EndObject's Mode MUST be None if EndGroup's Mode is None. EndObject's Mode MUST
NOT be None if EndGroup's Mode is NOT None.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EndObject's Mode MUST NOT be None if EndGroup's Mode is NOT None.

I don't think this is true. end_object=none means you want the entire group.

For example, this would request the subscription end once all objects in group 69 have been transmitted:

end_group=absolute/69
end_object=none

In my head and likely in many implementations, none means infinity. end_object=infinity means there's no end object.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would agree.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get the same behavior with:

end_group=absolute/70
end_object=0

My preference is for always explicit, no defaults, and try to avoid having more than one way to say the same thing.

### Examples

~~~
1. Now
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is technically Now+1 because the object doesn't exist yet. But yeah I understand it's meant to align with the other proposals.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can split this to two examples:

1. Latest (give me the most recent object on this group)

Start Group: Mode=RelativePrevious, Value=0
Start Object: Mode=RelateivePrevious, Value=0
End Group: Mode=None
End Object: Mode=None

StartGroup=Largest Group
StartObject=Largest Object

2. Now (I just joined.  I don't care about the past, but give me everything new)

Start Group: Mode=RelativePrevious, Value=0
Start Object: Mode=RelateiveNext, Value=0
End Group: Mode=None
End Object: Mode=None

StartGroup=Largest Group
StartObject=Largest Object + 1

Copy link
Collaborator

@ianswett ianswett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 looks good, though I think there are a lot of cases RelativeNext and RelativePrevious don't make much sense for StartGroup and EndGroup.

Absolute/0, or we can require the subscriber to be explicit.

* EndGroup: The last Group requested in the subscription, inclusive. EndGroup's
Mode MAY be None if it is an open-ended subscription.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SHOULD be None for an open-ended subscription?

Or just "is None for an open-ended subscription."

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, either it better than MAY probably.


* EndObject: The last Object requested in the subscription, exclusive.
EndObject's Mode MUST be None if EndGroup's Mode is None. EndObject's Mode MUST
NOT be None if EndGroup's Mode is NOT None.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would agree.

* StartGroup: The Location of the requested group. StartGroup's Mode MUST NOT be
None.

* StartObject: The Location of the requested object. StartObject's Mode MUST NOT
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think None means you want the whole group, but I guess that's identical to absolute/0 and I'm ok with being explicit.

If I specify a StartGroup of absolute or RelativePrevious/1, then the entire group is available. What does RelativePrevious or RelativeNext for StartObject in those cases?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think None means you want the whole group, but I guess that's identical to absolute/0 and I'm ok with being explicit.

Proposal 1 had default values everywhere to reduce edge cases but I decided explicit everywhere is better.

If I specify a StartGroup of absolute or RelativePrevious/1, then the entire group is available. What does RelativePrevious or RelativeNext for StartObject in those cases?

Relative is just relative to the largest sequence (number). If the entire group is known, RelativePrevious is how you specify the tail, and RelativeNext is equivalent to the next group, object 0, I guess?

A relay may have groups N and N+1 but group N might not be fully available yet? Cullen also raised a use case of multiple open groups, which the protocol does not prohibit.

Copy link
Collaborator

@fluffy fluffy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge it :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Subscription requests and buffers Subscription Hints Objects can be individually cached and served (A way to GET one or more objects)
7 participants