···20202121**Record Properties:**
22222323-| Name | Type | Req'd | Description | Constraints |
2424-| ------------- | -------- | ----- | -------------------------------------------------------------------------- | ------------------ |
2525-| `streamer` | `string` | ✅ | DID of the streamer whose livestream is being published | Format: `did` |
2626-| `server` | `string` | ✅ | did of the server that's currently rebroadcasting the livestream | Format: `did` |
2727-| `broadcaster` | `string` | ❌ | did of the broadcaster that operates the server syndicating the livestream | Format: `did` |
2828-| `updatedAt` | `string` | ✅ | Periodically updated timestamp when this origin last saw a livestream | Format: `datetime` |
2929-| `irohTicket` | `string` | ❌ | Iroh ticket that can be used to access the livestream from the server | Max Length: 2048 |
2323+| Name | Type | Req'd | Description | Constraints |
2424+| -------------- | -------- | ----- | -------------------------------------------------------------------------- | ------------------ |
2525+| `streamer` | `string` | ✅ | DID of the streamer whose livestream is being published | Format: `did` |
2626+| `server` | `string` | ✅ | did of the server that's currently rebroadcasting the livestream | Format: `did` |
2727+| `broadcaster` | `string` | ❌ | did of the broadcaster that operates the server syndicating the livestream | Format: `did` |
2828+| `updatedAt` | `string` | ✅ | Periodically updated timestamp when this origin last saw a livestream | Format: `datetime` |
2929+| `irohTicket` | `string` | ❌ | Iroh ticket that can be used to access the livestream from the server | Max Length: 2048 |
3030+| `websocketURL` | `string` | ❌ | URL of the websocket endpoint for the livestream | Format: `uri` |
30313132---
3233···6970 "type": "string",
7071 "maxLength": 2048,
7172 "description": "Iroh ticket that can be used to access the livestream from the server"
7373+ },
7474+ "websocketURL": {
7575+ "type": "string",
7676+ "format": "uri",
7777+ "description": "URL of the websocket endpoint for the livestream"
7278 }
7379 }
7480 }
···652652 ]
653653 }
654654 },
655655+ "/xrpc/place.stream.live.subscribeSegments": {
656656+ "get": {
657657+ "summary": "Subscribe to a stream's new segments as they come in!",
658658+ "operationId": "place.stream.live.subscribeSegments",
659659+ "tags": ["place.stream.live"],
660660+ "x-websocket": true,
661661+ "responses": {},
662662+ "parameters": [
663663+ {
664664+ "name": "streamer",
665665+ "in": "query",
666666+ "required": true,
667667+ "description": "The DID of the streamer to subscribe to",
668668+ "schema": {
669669+ "type": "string",
670670+ "description": "The DID of the streamer to subscribe to"
671671+ }
672672+ }
673673+ ],
674674+ "x-websocket-message": {
675675+ "schema": {
676676+ "oneOf": [
677677+ {
678678+ "$ref": "#/components/schemas/place.stream.live.subscribeSegments_segment"
679679+ }
680680+ ]
681681+ }
682682+ }
683683+ }
684684+ },
655685 "/xrpc/place.stream.graph.getFollowingUser": {
656686 "get": {
657687 "summary": "Get whether or not user A is following user B.",
···20972127 "record": {}
20982128 },
20992129 "required": ["cid", "record"]
21302130+ },
21312131+ "place.stream.live.subscribeSegments_segment": {
21322132+ "type": "string",
21332133+ "format": "byte",
21342134+ "description": "MP4 file of a user's signed livestream segment"
21002135 },
21012136 "com.atproto.repo.strongRef": {
21022137 "type": "object",
+5
lexicons/place/stream/broadcast/origin.json
···3434 "type": "string",
3535 "maxLength": 2048,
3636 "description": "Iroh ticket that can be used to access the livestream from the server"
3737+ },
3838+ "websocketURL": {
3939+ "type": "string",
4040+ "format": "uri",
4141+ "description": "URL of the websocket endpoint for the livestream"
3742 }
3843 }
3944 }
+31
lexicons/place/stream/live/subscribeSegments.json
···11+{
22+ "lexicon": 1,
33+ "id": "place.stream.live.subscribeSegments",
44+ "defs": {
55+ "main": {
66+ "type": "subscription",
77+ "description": "Subscribe to a stream's new segments as they come in!",
88+ "parameters": {
99+ "type": "params",
1010+ "required": ["streamer"],
1111+ "properties": {
1212+ "streamer": {
1313+ "type": "string",
1414+ "description": "The DID of the streamer to subscribe to"
1515+ }
1616+ }
1717+ },
1818+ "message": {
1919+ "schema": {
2020+ "type": "union",
2121+ "refs": ["#segment"]
2222+ }
2323+ },
2424+ "errors": []
2525+ },
2626+ "segment": {
2727+ "type": "bytes",
2828+ "description": "MP4 file of a user's signed livestream segment"
2929+ }
3030+ }
3131+}
···2424 Streamer string `json:"streamer" cborgen:"streamer"`
2525 // updatedAt: Periodically updated timestamp when this origin last saw a livestream
2626 UpdatedAt string `json:"updatedAt" cborgen:"updatedAt"`
2727+ // websocketURL: URL of the websocket endpoint for the livestream
2828+ WebsocketURL *string `json:"websocketURL,omitempty" cborgen:"websocketURL,omitempty"`
2729}
+59-2
pkg/streamplace/cbor_gen.go
···34553455 }
3456345634573457 cw := cbg.NewCborWriter(w)
34583458- fieldCount := 6
34583458+ fieldCount := 7
3459345934603460 if t.Broadcaster == nil {
34613461 fieldCount--
34623462 }
3463346334643464 if t.IrohTicket == nil {
34653465+ fieldCount--
34663466+ }
34673467+34683468+ if t.WebsocketURL == nil {
34653469 fieldCount--
34663470 }
34673471···36203624 }
36213625 }
36223626 }
36273627+36283628+ // t.WebsocketURL (string) (string)
36293629+ if t.WebsocketURL != nil {
36303630+36313631+ if len("websocketURL") > 1000000 {
36323632+ return xerrors.Errorf("Value in field \"websocketURL\" was too long")
36333633+ }
36343634+36353635+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("websocketURL"))); err != nil {
36363636+ return err
36373637+ }
36383638+ if _, err := cw.WriteString(string("websocketURL")); err != nil {
36393639+ return err
36403640+ }
36413641+36423642+ if t.WebsocketURL == nil {
36433643+ if _, err := cw.Write(cbg.CborNull); err != nil {
36443644+ return err
36453645+ }
36463646+ } else {
36473647+ if len(*t.WebsocketURL) > 1000000 {
36483648+ return xerrors.Errorf("Value in field t.WebsocketURL was too long")
36493649+ }
36503650+36513651+ if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(*t.WebsocketURL))); err != nil {
36523652+ return err
36533653+ }
36543654+ if _, err := cw.WriteString(string(*t.WebsocketURL)); err != nil {
36553655+ return err
36563656+ }
36573657+ }
36583658+ }
36233659 return nil
36243660}
36253661···3648368436493685 n := extra
3650368636513651- nameBuf := make([]byte, 11)
36873687+ nameBuf := make([]byte, 12)
36523688 for i := uint64(0); i < n; i++ {
36533689 nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 1000000)
36543690 if err != nil {
···37483784 }
3749378537503786 t.Broadcaster = (*string)(&sval)
37873787+ }
37883788+ }
37893789+ // t.WebsocketURL (string) (string)
37903790+ case "websocketURL":
37913791+37923792+ {
37933793+ b, err := cr.ReadByte()
37943794+ if err != nil {
37953795+ return err
37963796+ }
37973797+ if b != cbg.CborNull[0] {
37983798+ if err := cr.UnreadByte(); err != nil {
37993799+ return err
38003800+ }
38013801+38023802+ sval, err := cbg.ReadStringWithMax(cr, 1000000)
38033803+ if err != nil {
38043804+ return err
38053805+ }
38063806+38073807+ t.WebsocketURL = (*string)(&sval)
37513808 }
37523809 }
37533810
+5
pkg/streamplace/livesubscribeSegments.go
···11+// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT.
22+33+package streamplace
44+55+// schema: place.stream.live.subscribeSegments