> ## Documentation Index
> Fetch the complete documentation index at: https://gomoqt.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Relay

## Relay a Track

By relaying media data from a source track to one or more destination tracks by servers, contents are delivered to a wider audience or users.
To forward media data, a server subscribes to a source track as a subscriber to upstream and handles one or more downstream subscriptions as a publisher.

<Accordion title="Overview">
  ```go theme={null}
      var src *moqt.TrackReader
      var dests []*moqt.TrackWriter

      for {
          gr, err := src.AcceptGroup(context.Background())
          if err != nil {
              break
          }

          go func(gr *moqt.GroupReader) {
              seq := gr.GroupSequence()

              writers := make([]*moqt.GroupWriter, 0, len(dests))
              for _, dest := range dests {
                  gw, err := dest.OpenGroupAt(context.Background(), seq)
                  if err != nil {
                      // One failing destination must not stop the fan-out
                      // to the others.
                      continue
                  }

                  writers = append(writers, gw)
              }

              frame := moqt.NewFrame(0)
              for {
                  err := gr.ReadFrame(frame)
                  if err != nil {
                      if errors.Is(err, io.EOF) {
                          for _, gw := range writers {
                              gw.Close()
                          }
                      } else {
                          // Handle error
                          for _, gw := range writers {
                              gw.CancelWrite(moqt.InternalGroupErrorCode)
                          }
                      }
                      break
                  }

                  // Keep only the destinations that accepted the frame, so a
                  // dead one is dropped instead of retried on every frame.
                  live := writers[:0]
                  for _, gw := range writers {
                      if err := gw.WriteFrame(frame); err != nil {
                          gw.CancelWrite(moqt.InternalGroupErrorCode)
                          continue
                      }
                      live = append(live, gw)
                  }
                  writers = live
              }
          }(gr)
      }
  ```
</Accordion>

<Tip>
  **Tip: The First Subscription**

  Making the first subscription before downstream clients have subscribed can reduce latency, but may increase resource usage. This trade-off should be considered when designing your relay logic.
  When the track is a high-frequency track (e.g., video), it is recommended to make the first subscription after downstream clients subscribe to avoid unnecessary resource consumption.
</Tip>

## Relay Broadcasts

`TrackMux` acts as a hub for relaying broadcasts.

<Note>
  **Note: Relay Implementation**

  `gomoqt` does not provide built-in implementation for relaying broadcasts and tracks because there are many scenarios on relaying and many different implementations. The relay implementation is left to the user.
</Note>

## Hop ID and Loop Avoidance

Relay nodes MUST use a unique non-zero hop ID to enable loop avoidance. When creating a `TrackMux` for a relay, use `moqt.NewHopID()` to generate a unique identifier:

```go theme={null}
    mux := moqt.NewTrackMux(moqt.NewHopID())
    fmt.Printf("Relay HopID: %d\n", mux.HopID())
```

When the mux accepts an announce interest (`AcceptAnnounce`), it automatically sends an `ExcludeHop` with the mux's hop ID to prevent announcement loops. Each `Announcement` carries a list of hop IDs it has traversed, accessible via `Announcement.HopIDs`.

```go theme={null}
    ann, err := ar.ReceiveAnnouncement(ctx)
    if err != nil {
        // Handle error
    }
    fmt.Printf("Announcement traversed hops: %v\n", ann.HopIDs())
```

For edge nodes (origin publishers or pure subscribers), pass `0` as the hop ID:

```go theme={null}
    mux := moqt.NewTrackMux(0) // Edge node, no hop tracking
```

## Caching

To enhance UX, consider implementing caching strategies for frequently accessed data or long-lived objects. This can help reduce latency and improve overall performance. Some common caching techniques include:

1. **In-Memory Caching**: Store frequently accessed data in memory (RAM) for quick retrieval.
2. **Distributed Caching**: Use a distributed cache system to share cached data across multiple instances.
3. **Cache Invalidation**: Implement strategies to invalidate stale cache entries to ensure data consistency.

By leveraging caching, you can significantly improve the responsiveness of your application and provide a smoother user experience.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.