AirPlay.V2.Session (AirPlay v0.4.0)

Copy Markdown View Source

Persistent AirPlay 2 session for a single receiver.

Unlike AirPlay.V2.Player.play_file/3 (which pairs, sets up, runs PTP, streams one file, and tears everything down), a Session keeps the connection and clock warm across tracks:

  • connect/2 performs the one-time handshake (transient pair, SETUP session + stream, RECORD, BMCA-yield PTP) and returns the session process pid.
  • play/3 streams a file: FLUSH (continuing the RTP timeline, not resetting to zero) then ALAC RTP send. When the file ends the session notifies its owner with {AirPlay.V2.Session, :ended, play_gen} and goes idle — the connection stays up.
  • while idle, the session keeps sending RTSP FEEDBACK so the receiver does not tear the stream down between tracks.
  • close/1 issues the teardown and closes all sockets.

This is what lets an album or audiobook change tracks without paying the ~5s pair + SETUP + PTP cold-start on every track.

Owner notifications (sent to the :owner pid, defaulting to the caller of connect/2):

  • {AirPlay.V2.Session, :ended, play_gen} — current track finished cleanly
  • {AirPlay.V2.Session, :error, play_gen, reason} — a track failed to start (e.g. the decoder could not be prepared); the session stays connected and idle

Summary

Functions

Tear down the session and close all sockets.

Open a persistent session to an AirPlay 2 receiver.

Play (or skip to) a file on an open session. Continues the RTP timeline.

Set the receiver volume (0.0..1.0).

Stop the current track but keep the connection warm.

Functions

close(pid)

@spec close(pid()) :: :ok

Tear down the session and close all sockets.

connect(host, opts \\ [])

@spec connect(
  String.t(),
  keyword()
) :: {:ok, pid()} | {:error, term()}

Open a persistent session to an AirPlay 2 receiver.

Options:

  • :port - RTSP port, defaults to 7000
  • :owner - pid to receive :ended / :error notifications, defaults to the calling process
  • :render_delay_ms - added to PT=87 sync timestamps, defaults to 0
  • :ptp_settle_ms - PTP settle delay after BMCA, defaults to 500
  • :connect_timeout_ms - give up on the handshake after this long, default 20_000

play(pid, path, opts \\ [])

@spec play(pid(), String.t(), keyword()) :: :ok

Play (or skip to) a file on an open session. Continues the RTP timeline.

set_volume(pid, volume)

@spec set_volume(pid(), number()) :: :ok

Set the receiver volume (0.0..1.0).

stop(pid)

@spec stop(pid()) :: :ok

Stop the current track but keep the connection warm.