AlexxIT/go2rtc · warning

hap: no free streams

Error message

hap: no free streams

What it means

GetFreeStream scans the HAP camera's fixed pool of streams and returns this error when every stream is already occupied by an active HomeKit session. The library does not preempt existing sessions; the caller must wait for one to be released or increase the stream count.

Solutions

  1. Ensure all streams are properly closed when sessions end (check for leaked sessions from crashed clients).
  2. Reduce concurrent viewers or serialize stream access behind a mutex/semaphore in your code.
  3. Restart the camera accessory process to clear leaked stream reservations.
  4. Increase the configured stream count for the HAP camera accessory if the device supports it.

Example fix

// before: unbounded concurrent viewers exhaust the pool
for _, viewer := range viewers { go viewer.Start(stream) }
// after: serialize with a semaphore of capacity = stream count
sem := make(chan struct{}, cameraStreamCount)
for _, viewer := range viewers {
    go func(v *Viewer) {
        sem <- struct{}{}
        defer func() { <-sem }()
        v.Start(stream)
    }(viewer)
}
Defensive patterns

Strategy: retry

Validate before calling

// cap concurrency at the number of camera streams before requesting one
const maxStreams = 2
sem := make(chan struct{}, maxStreams)
sem <- struct{}{} // blocks until a slot (stream) is available
defer func() { <-sem }()

Type guard

func hasFreeStream(count, active int) bool { return active < count }

Try / catch

stream, err := cameraStream.GetFreeStream()
if err != nil {
    if strings.Contains(err.Error(), "no free streams") {
        time.Sleep(2 * time.Second) // wait for a session to release
        stream, err = cameraStream.GetFreeStream()
    }
    if err != nil { return err }
}

Prevention

When it happens

Trigger: More concurrent HomeKit viewers than configured streams (e.g. 2 viewers on a 1-stream camera); a stale session that never released its stream; NewStream called in a loop without closing previous streams.

Common situations: Multiple HomeKit hubs/clients (iPhone + iPad + HomeHub) watching simultaneously; a crashed viewer whose session was not torn down, leaking the stream; testing scripts that open streams without closing them.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/a145d6dc96fdef52. Report an issue: GitHub.

Appendix: source

Thrown at pkg/hap/camera/stream.go:102

	}

	for _, srv := range acc.Services {
		for _, char := range srv.Characters {
			if char.Type == TypeStreamingStatus {
				var status StreamingStatus
				if err = char.ReadTLV8(&status); err != nil {
					return err
				}

				if status.Status == StreamingStatusAvailable {
					s.service = srv
					return nil
				}
			}
		}
	}

	return errors.New("hap: no free streams")
}

func (s *Stream) ExchangeEndpoints(videoSession, audioSession *srtp.Session) error {
	req := SetupEndpointsRequest{
		SessionID: s.id,
		Address: Address{
			IPVersion:    0,
			IPAddr:       videoSession.Local.Addr,
			VideoRTPPort: videoSession.Local.Port,
			AudioRTPPort: audioSession.Local.Port,
		},
		VideoCrypto: SRTPCryptoSuite{
			MasterKey:  string(videoSession.Local.MasterKey),
			MasterSalt: string(videoSession.Local.MasterSalt),
		},
		AudioCrypto: SRTPCryptoSuite{
			MasterKey:  string(audioSession.Local.MasterKey),
			MasterSalt: string(audioSession.Local.MasterSalt),

View on GitHub (pinned to c245815e75)