Manage streams

Preview
List, retrieve, stop, and re-egress existing video streams.

Use the Lattice SDK to inspect active streams, retrieve a specific stream, archive a stream when its source goes offline, and re-publish over RTSP or SRT for downstream consumers.

List active streams

Call ListIngressStreams to retrieve the current page of active streams. Archived streams are not returned. Send an empty request to fetch the first page (default: 50, max: 100), then iterate while next_page_token is non-empty.

Pagination contract

Pass the previous response’s next_page_token as page_token and keep every other request field identical. The server may reject requests that change other fields between pages.

1// This Go example uses the Lattice REST SDK (lattice-sdk-go) to list active ingress streams.
2package main
3
4import (
5 "context"
6 "fmt"
7 "net/http"
8 "os"
9
10 Lattice "github.com/anduril/lattice-sdk-go/v5"
11 "github.com/anduril/lattice-sdk-go/v5/client"
12 "github.com/anduril/lattice-sdk-go/v5/option"
13)
14
15func main() {
16 // Get environment variables
17 latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
18 clientSecret := os.Getenv("LATTICE_CLIENT_SECRET")
19 clientId := os.Getenv("LATTICE_CLIENT_ID")
20
21 // Remove sandboxesToken from the following statements if you are not developing on Sandboxes.
22 sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
23
24 // Check required environment variables
25 if latticeEndpoint == "" || clientId == "" || clientSecret == "" || sandboxesToken == "" {
26 fmt.Println("Missing required environment variables")
27 os.Exit(1)
28 }
29
30 // Initialize headers for sandbox authorization
31 headers := http.Header{}
32 headers.Add("Anduril-Sandbox-Authorization", fmt.Sprintf("Bearer %s", sandboxesToken))
33
34 // Create the client
35 LatticeClient := client.NewClient(
36 option.WithClientCredentials(clientId, clientSecret),
37 option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
38 option.WithHTTPHeader(headers),
39 )
40
41 ctx := context.Background()
42
43 // Iterate every page of active streams. Keep all request fields identical between
44 // pages other than pageToken; the server may reject a request that changes them.
45 pageToken := ""
46 for {
47 response, err := LatticeClient.Video.ListIngressStreams(ctx, &Lattice.ListIngressStreamsRequest{
48 PageToken: &pageToken,
49 })
50 if err != nil {
51 fmt.Printf("Failed to list streams: %v\n", err)
52 os.Exit(1)
53 }
54
55 for _, stream := range response.GetIngressStreams() {
56 fmt.Printf("Stream %s status %s\n", *stream.GetIngressID(), *stream.GetStatus())
57 }
58
59 if response.GetNextPageToken() == nil || *response.GetNextPageToken() == "" {
60 break
61 }
62 pageToken = *response.GetNextPageToken()
63 }
64}

Get a single stream

Call GetIngressStream with an ingress_id to retrieve a single IngressStream. The response includes the current status, ingress configuration, and associated egress stream identifiers. For a description of every field, see IngressStream object.

MPEG-TS streams are read-only over the public internet

MPEG-TS ingress is supported only at the edge, in closed networks. If you connect to Lattice over the public internet, you can’t start an MPEG-TS stream, but a stream created at the edge still appears in ListIngressStreams and can be inspected with GetIngressStream.

1// This Go example uses the Lattice REST SDK (lattice-sdk-go) to retrieve a single ingress stream.
2package main
3
4import (
5 "context"
6 "fmt"
7 "net/http"
8 "os"
9
10 Lattice "github.com/anduril/lattice-sdk-go/v5"
11 "github.com/anduril/lattice-sdk-go/v5/client"
12 "github.com/anduril/lattice-sdk-go/v5/option"
13)
14
15// Ingress ID of the stream to get. Replace before running.
16const ingressID = "<INGRESS-ID>"
17
18func main() {
19 // Get environment variables
20 latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
21 clientSecret := os.Getenv("LATTICE_CLIENT_SECRET")
22 clientId := os.Getenv("LATTICE_CLIENT_ID")
23
24 // Remove sandboxesToken from the following statements if you are not developing on Sandboxes.
25 sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
26
27 // Check required environment variables
28 if latticeEndpoint == "" || clientId == "" || clientSecret == "" || sandboxesToken == "" {
29 fmt.Println("Missing required environment variables")
30 os.Exit(1)
31 }
32
33 // Initialize headers for sandbox authorization
34 headers := http.Header{}
35 headers.Add("Anduril-Sandbox-Authorization", fmt.Sprintf("Bearer %s", sandboxesToken))
36
37 // Create the client
38 LatticeClient := client.NewClient(
39 option.WithClientCredentials(clientId, clientSecret),
40 option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
41 option.WithHTTPHeader(headers),
42 )
43
44 ctx := context.Background()
45
46 response, err := LatticeClient.Video.GetIngressStream(ctx, &Lattice.GetIngressStreamRequest{
47 IngressID: ingressID,
48 })
49 if err != nil {
50 fmt.Printf("Failed to get stream: %v\n", err)
51 os.Exit(1)
52 }
53
54 stream := response.GetIngressStream()
55 if stream == nil {
56 fmt.Printf("No ingress stream found for %s\n", ingressID)
57 os.Exit(1)
58 }
59 fmt.Printf("Ingress ID: %s\n", *stream.GetIngressID())
60 fmt.Printf("Title: %q\n", *stream.GetTitle())
61 fmt.Printf("Status: %s\n", *stream.GetStatus())
62}

Stop an ingress stream

Stopping a stream archives it. The IngressStream record remains retrievable with GetIngressStream, but its status transitions to STREAM_STATUS_ARCHIVED and ListIngressStreams no longer returns the record.

Archive, not delete

DeleteIngressStream does not delete the underlying record. To remove the stale media reference from the camera entity, follow up with an OverrideEntity call as shown in the example below. The example reads the entity, filters out the stale MediaItem, and writes the surviving items back. A field_path of media replaces the entire Media component while leaving every other entity component untouched.

1// This Go example uses the Lattice REST SDK (lattice-sdk-go) to stop (archive) an ingress stream
2// and remove its stale media reference from the associated camera entity.
3package main
4
5import (
6 "context"
7 "fmt"
8 "net/http"
9 "os"
10 "time"
11
12 Lattice "github.com/anduril/lattice-sdk-go/v5"
13 "github.com/anduril/lattice-sdk-go/v5/client"
14 "github.com/anduril/lattice-sdk-go/v5/option"
15)
16
17const (
18 // Ingress ID of the stream to stop. Replace before running.
19 ingressID = "<INGRESS-ID>"
20 // Entity the video is attached to. Set to "" to only stop the stream without
21 // editing any entity's media list.
22 entityID = "<ENTITY-ID>"
23)
24
25func main() {
26 // Get environment variables
27 latticeEndpoint := os.Getenv("LATTICE_ENDPOINT")
28 clientSecret := os.Getenv("LATTICE_CLIENT_SECRET")
29 clientId := os.Getenv("LATTICE_CLIENT_ID")
30
31 // Remove sandboxesToken from the following statements if you are not developing on Sandboxes.
32 sandboxesToken := os.Getenv("SANDBOXES_TOKEN")
33
34 // Check required environment variables
35 if latticeEndpoint == "" || clientId == "" || clientSecret == "" || sandboxesToken == "" {
36 fmt.Println("Missing required environment variables")
37 os.Exit(1)
38 }
39
40 // Initialize headers for sandbox authorization
41 headers := http.Header{}
42 headers.Add("Anduril-Sandbox-Authorization", fmt.Sprintf("Bearer %s", sandboxesToken))
43
44 // Create the client
45 LatticeClient := client.NewClient(
46 option.WithClientCredentials(clientId, clientSecret),
47 option.WithBaseURL(fmt.Sprintf("https://%s", latticeEndpoint)),
48 option.WithHTTPHeader(headers),
49 )
50
51 ctx := context.Background()
52
53 fmt.Printf("Stopping ingress stream with ID: %s\n", ingressID)
54 _, err := LatticeClient.Video.DeleteIngressStream(ctx, &Lattice.DeleteIngressStreamRequest{
55 IngressID: ingressID,
56 })
57 if err != nil {
58 fmt.Printf("Failed to stop ingress stream: %v\n", err)
59 os.Exit(1)
60 }
61
62 // With no entity to update, stopping the stream is all there is to do.
63 if entityID == "" {
64 return
65 }
66
67 // Read the entity, filter the stale MediaItem out, and write the surviving items back.
68 entity, err := LatticeClient.Entities.GetEntity(ctx, &Lattice.GetEntityRequest{
69 EntityID: entityID,
70 })
71 if err != nil {
72 fmt.Printf("Failed to fetch entity %s: %v\n", entityID, err)
73 os.Exit(1)
74 }
75
76 var current []*Lattice.MediaItem
77 if entity.GetMedia() != nil {
78 current = entity.GetMedia().GetMedia()
79 }
80 remaining := make([]*Lattice.MediaItem, 0, len(current))
81 for _, item := range current {
82 if item.GetItemIdentifier() == nil || *item.GetItemIdentifier() != ingressID {
83 remaining = append(remaining, item)
84 }
85 }
86
87 if len(remaining) == len(current) {
88 fmt.Printf("Video %s was not in entity %s media list; nothing to remove\n", ingressID, entityID)
89 return
90 }
91
92 // A field_path of media replaces the entire Media component with the surviving items.
93 _, err = LatticeClient.Entities.OverrideEntity(ctx, &Lattice.EntityOverride{
94 EntityID: entityID,
95 FieldPath: "media",
96 Entity: &Lattice.Entity{
97 EntityID: Lattice.String(entityID),
98 Media: &Lattice.Media{
99 Media: remaining,
100 },
101 },
102 Provenance: &Lattice.Provenance{
103 IntegrationName: Lattice.String("lattice-video-integration"),
104 DataType: Lattice.String("video-association"),
105 SourceUpdateTime: Lattice.Time(time.Now().UTC()),
106 },
107 })
108 if err != nil {
109 fmt.Printf("Failed to override entity media: %v\n", err)
110 os.Exit(1)
111 }
112 fmt.Printf("Removed video %s from entity %s\n", ingressID, entityID)
113}

What’s next

  • Overview: Review the API surface and stream lifecycle.
  • Stream a video: Publish an asset and start an ingress stream.