Home / Guides / Tutorial

Asterisk queues.conf: periodic-announce, announce-frequency & Queue Directives

Call queues distribute incoming calls among agents efficiently. This guide covers everything from basic queue setup to advanced ring strategies and real-time monitoring.

Sign up now or see the full rate table

Tutorial · · Updated · 16 min read

Queue Basics

An Asterisk call queue holds incoming calls and distributes them to available agents (extensions) using a configurable ring strategy. Callers hear music on hold or periodic announcements while waiting. When an agent becomes available, the next call in the queue is delivered to them.

Queues are essential for:

  • Support desks handling multiple incoming calls
  • Sales teams distributing leads fairly
  • Any scenario where more calls arrive than agents can immediately answer

Configuring queues.conf

Queue configuration lives in /etc/asterisk/queues.conf. Here is a complete support queue example:

/etc/asterisk/queues.conf
[general]
persistentmembers=yes
autofill=yes
shared_lastcall=yes
log_membername_as_agent=yes
[support]
; Ring strategy
strategy=leastrecent
; Timeout for each agent ring attempt (seconds)
timeout=15
; How long to wait before trying the next agent
retry=5
; Which timeout wins when Queue() and queues.conf disagree (see Queue() syntax below)
timeoutpriority=app
; Max callers allowed in queue - 0 for unlimited
maxlen=20
; Wrap-up time after a call (seconds)
wrapuptime=10
; Music on hold class
musicclass=default
; Join announcement
joinempty=yes
leavewhenempty=no
; Announce position in queue
announce-frequency=60
announce-position=yes
announce-holdtime=yes
; Periodic announcements
periodic-announce=queue-thankyou
periodic-announce-frequency=120
; Service level target (seconds)
servicelevel=60
; Ring an in-use agent?
ringinuse=no
; Static members (always in queue)
member => PJSIP/100,0,John Smith,hint:100@default
member => PJSIP/101,0,Jane Doe,hint:101@default
member => PJSIP/102,0,Bob Wilson,hint:102@default

Ring Strategies

The ring strategy determines how calls are distributed among agents. Choose based on your team's workflow:

ringall

Rings all available agents simultaneously. First to answer gets the call. Good for small teams where speed matters.

leastrecent

Rings the agent who has been idle the longest since their last call. Distributes calls evenly over time.

fewestcalls

Rings the agent with the fewest completed calls. Balances total call count across agents.

random

Randomly selects an available agent. Simple and fair over large volumes.

rrmemory

Round-robin with memory. Remembers where it left off and continues to the next agent. Predictable and fair.

linear

Always tries agents in order (first member first). Good when you have a preferred agent or skill-based tiering.

Building this? Your PBX will need a number

Find a phone number for your trunk

Local numbers $1.50 a month, toll-free $2.00, $1.00 one-time setup. Pick one here and it carries into signup.

Enter an area code, or wait a moment for numbers near you.

More numbers, porting and E911 in the portal

Outbound US and Canada
$0.010 /min
Inbound
$0.009 /min
Local number
$1.50 /mo
Per channel
$0 no set limits

Sign up now or see the full rate table. No contracts.

Penalties, weight, autofill and the two strategies the tiles leave out

Two further strategies are valid in strategy=. wrandom is weighted random: each member's penalty is used as a weight, so a penalty-0 agent is picked more often than a penalty-2 agent but nobody is excluded. rrordered is rrmemory with the member order taken from queues.conf instead of Asterisk's internal order, which is what you want when "ring Alice first, then Bob" has to be predictable.

Penalties are the second field on a member line and work with every strategy except wrandom. Asterisk only rings members with the lowest penalty that is currently available; higher-penalty members are backup agents who ring when nobody with a lower penalty is available:

/etc/asterisk/queues.conf - tiered agents
[support]
strategy=rrordered
timeout=20
retry=2
; penalty 0 = front line, 1 = second line, 2 = managers
member => PJSIP/100,0,Alice,hint:100@default
member => PJSIP/101,0,Bob,hint:101@default
member => PJSIP/110,1,Carol,hint:110@default
member => PJSIP/120,2,Dave,hint:120@default
; include higher-penalty members when fewer than 2 lower-penalty members are available
penaltymemberslimit=2
; escalate automatically the longer the caller waits (rule defined in queuerules.conf)
defaultrule=escalate
/etc/asterisk/queuerules.conf
[escalate]
; after 60 s waiting, also ring penalty 1; after 180 s, also ring penalty 2
penaltychange => 60,1
penaltychange => 180,2

The same thing can be done per call by setting QUEUE_MAX_PENALTY and QUEUE_MIN_PENALTY on the channel before Queue(), which is how a VIP caller identified by DID or caller ID can be sent straight to the senior tier.

Two [general] and per-queue options change how those members are used:

  • autofill=yes delivers several waiting calls to several available agents at the same time. With autofill=no (the pre-1.4 behaviour) the queue hands out one call at a time and the second caller waits until the first has been bridged, even if ten agents are idle.
  • weight= matters when an agent belongs to more than one queue. If sales has weight=10 and support has weight=0, a shared agent is offered the sales call first whenever both queues have callers waiting.
  • ringinuse=no skips members whose device state is In Use. Keep it off for ringall queues unless you really want agents on a call to hear a second ring.

Agent Management

Agents can be added to queues statically (in queues.conf) or dynamically (via the dialplan or AMI). Dynamic membership is more flexible for shift-based operations:

extensions.conf - Dynamic agent login/logout
[agents]
; Login to support queue - dial *500
exten => *500,1,NoOp(Agent login to support queue)
 same => n,AddQueueMember(support,PJSIP/${CALLERID(num)})
 same => n,Playback(agent-loginok)
 same => n,Hangup()
; Logout from support queue - dial *501
exten => *501,1,NoOp(Agent logout from support queue)
 same => n,RemoveQueueMember(support,PJSIP/${CALLERID(num)})
 same => n,Playback(agent-loggedoff)
 same => n,Hangup()
; Pause/unpause (toggle) - dial *502
exten => *502,1,NoOp(Toggle agent pause)
 same => n,Set(QSTATUS=${QUEUE_MEMBER(support,paused,PJSIP/${CALLERID(num)})})
 same => n,GotoIf($["${QSTATUS}"="1"]?unpause)
 same => n,PauseQueueMember(support,PJSIP/${CALLERID(num)},,Break)
 same => n,Playback(beep)
 same => n,Hangup()
 same => n(unpause),UnpauseQueueMember(support,PJSIP/${CALLERID(num)})
 same => n,Playback(beep&beep)
 same => n,Hangup()

Queue Announcements

Keep callers informed while they wait with these announcement options:

  • announce-frequency: How often (seconds) to announce the caller's position and estimated hold time. Set to 0 to disable.
  • announce-position: Tell callers their position in queue ("You are caller number 3").
  • announce-holdtime: Announce estimated hold time based on recent call data. Only announces if the estimate is meaningful.
  • periodic-announce: Play a custom recording periodically (e.g., "Thank you for holding, your call is important to us").
  • periodic-announce-frequency: How often (seconds) to play periodic announcements.

Dialplan Integration

Connect incoming calls to your queue through the dialplan. Handle queue exits gracefully:

extensions.conf - Queue with failover
[from-ipcomms]
; Route inbound DID to support queue
exten => 2125551000,1,NoOp(Inbound to support)
 same => n,Answer()
 same => n,Playback(welcome-message)
 same => n,Queue(support,t,,,300)
 ; If caller times out after 300 seconds (5 min)
 same => n,VoiceMail(support@default,u)
 same => n,Hangup()
; Alternative: IVR then queue
exten => 2125551001,1,NoOp(Main IVR)
 same => n,Answer()
 same => n,Background(main-ivr-greeting)
 same => n,WaitExten(5)
exten => 1,1,Queue(sales,t,,,180)
 same => n,VoiceMail(sales@default,u)
 same => n,Hangup()
exten => 2,1,Queue(support,t,,,300)
 same => n,VoiceMail(support@default,u)
 same => n,Hangup()

The Queue() application options include:

  • t - Allow the called agent to transfer the call
  • T - Allow the caller to transfer
  • n - No retry on timeout (exit queue if no agent answers)
  • H - Allow the caller to hang up by pressing *
  • The 5th parameter (300) - Maximum wait time in seconds

Queue() application syntax, options and timeouts

The full signature is Queue(queuename[,options[,URL[,announceoverride[,timeout[,AGI[,gosub[,rule[,position]]]]]]]]). On Asterisk 18 and 20 there is an extra, deprecated macro argument between AGI and gosub; it was removed with the Macro application in Asterisk 21, so count your commas when you copy examples between versions. rule names a section of queuerules.conf for this call only, and position lets you insert a caller ahead of others (1 = front of the queue).

OptionEffect
b(context^exten^priority)Run a Gosub on the agent's channel before bridging (screen pop, set a variable the agent's phone displays)
B(context^exten^priority)Run a Gosub on the caller's channel before bridging
CMark unanswered ring attempts as "answered elsewhere" so ringall does not leave a missed-call entry on every other agent's phone
cContinue in the dialplan when the agent hangs up instead of ending the call
dData-quality call (minimum delay), for modems and fax
F([context^exten^priority])When the caller hangs up, send the agent's channel to this location (after-call work, wrap-up codes)
h / HAgent / caller may hang up by pressing *
iIgnore call-forward requests from members (a forwarded desk phone no longer steals queue calls)
IIgnore connected-line and redirecting updates on this attempt
k / KAgent / caller may park the call with the features.conf parking sequence
nNo retries: after one failed ring attempt leave the queue and continue in the dialplan
rPlay ringing instead of music on hold; periodic announcements still play
RMusic on hold while waiting, ringing only once an agent's phone is actually ringing
t / TAgent / caller may transfer the call (DTMF transfer from features.conf)
w / WAgent / caller may start recording with Monitor
x / XAgent / caller may start recording with MixMonitor

Three timers that are easy to confuse

  • timeout in queues.conf (default 15): seconds one member's phone rings in a single attempt.
  • retry in queues.conf (default 5): seconds to wait after a failed attempt before ringing the next member. timeoutrestart=yes restarts the member timer when the attempt ends in BUSY or CONGESTION, so a transient busy does not consume the whole attempt.
  • Queue() timeout (fifth argument): total seconds the caller may wait. When it expires Queue() returns with QUEUESTATUS=TIMEOUT and the dialplan continues on the next priority. Leaving it empty means the caller waits until an agent answers or the caller hangs up.

timeoutpriority=app (the default) means that when the caller's timeout would expire during a ring attempt, the attempt is cut short and the caller leaves on time. timeoutpriority=conf lets the current member finish ringing first, which is kinder to the agent but can keep the caller up to timeout seconds longer than promised.

Handling how the caller left

QUEUESTATUS is set whenever Queue() returns, so one queue can overflow into another or into voicemail without a second DID:

extensions.conf - routing on QUEUESTATUS
exten => 2125551000,1,NoOp(Inbound to support)
 same => n,Answer()
 same => n,Queue(support,tC,,,300)
 same => n,NoOp(Left support queue: ${QUEUESTATUS})
 same => n,GotoIf($["${QUEUESTATUS}"="FULL"]?overflow)
 same => n,GotoIf($["${QUEUESTATUS}"="JOINEMPTY"]?closed)
 same => n,GotoIf($["${QUEUESTATUS}"="LEAVEEMPTY"]?closed)
 same => n,VoiceMail(support@default,u)
 same => n,Hangup()
 same => n(overflow),Queue(overflow,tC,,,180)
 same => n,VoiceMail(support@default,u)
 same => n,Hangup()
 same => n(closed),Playback(custom/no-agents-logged-in)
 same => n,VoiceMail(support@default,u)
 same => n,Hangup()

The possible values are TIMEOUT, FULL (maxlen reached), JOINEMPTY (no usable members when the caller arrived), LEAVEEMPTY (the last usable member left while the caller waited), JOINUNAVAIL, LEAVEUNAVAIL and CONTINUE (option c). Which member states count as "empty" is set per queue with joinempty= and leavewhenempty=; current versions take a comma-separated list of states (paused, penalty, inuse, ringing, unavailable, invalid, unknown, wrapup) and still accept the old yes, no, strict and loose keywords. If every agent is logged out, joinempty=paused,invalid,unavailable,unknown sends the caller straight to the closed branch instead of 300 seconds of hold music. The IVR and auto attendant guide shows the menu that normally sits in front of this.

Queue Monitoring and Stats

Monitor queue performance in real-time from the Asterisk CLI:

Asterisk CLI - Queue commands
; Show all queues with stats
queue show
; Show specific queue
queue show support
; Show queue summary (compact view)
queue stats
; Real-time queue log
queue set log on
; Output example:
; support has 2 calls (max 20) in 'leastrecent' strategy
;   (service level: 60s)
;   Members:
;     PJSIP/100 (John Smith) (ringinuse disabled) (Not in use) has taken 15 calls
;     PJSIP/101 (Jane Doe) (ringinuse disabled) (In use) has taken 12 calls
;   Callers:
;     1. PJSIP/trunk-00000023 (wait: 0:45, prio: 0)

For historical reporting, Asterisk writes queue events to /var/log/asterisk/queue_log. Key events include ENTERQUEUE, CONNECT, ABANDON, COMPLETECALLER, and COMPLETEAGENT. Third-party tools like QueueMetrics can parse these logs into detailed reports.

queue reload, module reload app_queue and when a restart is needed

Nothing in queues.conf needs a restart. Edit the file, then pick the narrowest reload:

CommandWhat it re-readsEffect on live calls
queue reload allqueues.conf parameters, static members and queuerules.conf, every queueNone. Waiting callers stay in place; dynamic members are kept
queue reload all supportThe same, one queue onlyNone
queue reload parameters / members / rulesOnly that part of the configurationNone
module reload app_queue.soEquivalent to queue reload allNone
core reloadEvery module's configuration, queues includedNone, but heavier; avoid during peak hours on busy systems
queue reset stats [queue]Nothing; zeroes the calls-taken, hold-time and service-level countersNone
core restart gracefullyRestarts Asterisk once the last call endsOnly needed if app_queue was never loaded or you changed the realtime mapping in extconfig.conf

A queue you delete from queues.conf is marked for removal on reload and disappears once its last caller has left. Static members removed from the file are dropped on reload; members that were added with AddQueueMember(), AMI or the CLI survive every reload and, with persistentmembers=yes, every restart as well, because they are stored in the AstDB.

CLI commands for day-to-day agent management

Asterisk CLI - members without touching queues.conf
queue add member PJSIP/103 to support penalty 1 as "Sam Lee" state_interface hint:103@default
queue remove member PJSIP/103 from support
queue pause member PJSIP/103 queue support reason Lunch
queue unpause member PJSIP/103 queue support
queue set penalty 2 on PJSIP/103 in support
queue set ringinuse no on PJSIP/103 in support
queue show support
queue show rules
database show Queue    ; persistent dynamic members live here

Everything above is also available through AMI (QueueAdd, QueueRemove, QueuePause, QueueStatus, QueueSummary), which is what wallboards and agent desktops use. Dialplan feature codes like the *500 login example earlier wrap the same functions for agents without a desktop client.

Member status: In use, Not in use, Unavailable and Invalid

The state shown in queue show is the device state of the member's interface, or of its state_interface if one is set. The queue uses it to decide whom to ring, so a wrong state means missed calls or phantom rings.

StateMeaningRung by the queue?
Not in useRegistered and idleYes
In use / Busy / On HoldOn a callOnly when ringinuse=yes
Ringing / Ring+InusePhone is ringing (possibly from another queue)No
UnavailableInterface exists but is unreachable: PJSIP endpoint with no registered contact, phone switched off, qualify failingNo
InvalidDial string cannot be resolved: typo, channel driver not loaded, Local channel pointing at a missing extensionNo
UnknownNo device state information, typically a Local channel without state_interfaceYes, always, which is the usual cause of agents ringing while they are already on a call
(paused)Member paused with a reasonNo

For PJSIP endpoints the state comes from the registered contact and OPTIONS qualify, so pjsip show contacts and core show hints tell you why a member is Unavailable. The PJSIP configuration guide covers qualify_frequency and max_contacts, the two settings behind most Unavailable states. For members that dial through a Local channel, give the queue the real phone to watch:

/etc/asterisk/queues.conf - Local channel member with a state interface
; member => interface,penalty,membername,state_interface
member => Local/201@from-queue/n,0,Alice,PJSIP/201

From the dialplan or AGI, the QUEUE_MEMBER() function reads the same information: ${QUEUE_MEMBER(support,logged)} counts logged-in members, free counts those not in use, ready those available and not paused, and QUEUE_MEMBER(support,paused,PJSIP/201) or penalty read one member. ${QUEUE_WAITING_COUNT(support)} is the number of callers on hold, useful for an "all agents are busy, leave a message or hold" prompt before Queue().

queue_log: fields, events and computing service level

/var/log/asterisk/queue_log is the source of every queue report. Each line is pipe-separated: epoch|uniqueid|queue|agent|event|param1|param2|param3. The unique ID is the caller's channel unique ID, or NONE, MANAGER and REALTIME for member and system events.

EventParametersMeaning
ENTERQUEUEurl | caller IDCaller joined the queue
CONNECTholdtime | bridged channel unique ID | ringtimeAgent answered; holdtime is the caller's wait in seconds
COMPLETECALLERholdtime | calltime | original positionCall ended, caller hung up first
COMPLETEAGENTholdtime | calltime | original positionCall ended, agent hung up first
ABANDONposition | original position | waittimeCaller hung up while waiting
EXITWITHTIMEOUTposition | original position | waittimeQueue() timeout expired
EXITEMPTYposition | original position | waittimeCaller left because no members were usable (leavewhenempty)
EXITWITHKEYkey | position | original position | waittimeCaller pressed a key defined in context= to leave
RINGNOANSWERringtime (ms)Member rang and did not answer
TRANSFERextension | context | holdtime | calltime | original positionAgent transferred the caller
ADDMEMBER / REMOVEMEMBER / PAUSE / UNPAUSEreason (for PAUSE)Agent events; PAUSEALL and UNPAUSEALL cover every queue the member is in
CONFIGRELOAD / QUEUESTART-Reload and startup markers, handy for explaining gaps in reports

Two one-liners give the numbers most managers ask for. Service level is the share of answered calls whose hold time was within the servicelevel target; abandon rate is abandoned calls over calls offered:

shell - service level and abandon rate for the support queue
grep '|support|' /var/log/asterisk/queue_log | awk -F'|' '$5=="CONNECT"{n++; if($6<=60)ok++} END{printf "%d answered, %.1f%% within 60 s\n", n, 100*ok/n}'
grep '|support|' /var/log/asterisk/queue_log | awk -F'|' '$5=="ENTERQUEUE"{e++} $5=="ABANDON"{a++} END{printf "%d offered, abandon rate %.1f%%\n", e, 100*a/e}'

For anything beyond that, write the log to a database instead of a flat file: map queue_log => odbc,asterisk in extconfig.conf (with res_config_odbc and a queue_log table), and keep queue_log_to_file=yes in the [general] section of queues.conf if you also want the text file. QueueMetrics, Asternic and most wallboards read exactly these events, so the agent names you set with log_membername_as_agent=yes are what will appear in their reports. The call center SIP trunking guide explains which of these numbers carriers and auditors will ask about.

Recording queue calls

Record at the queue rather than per extension so every answered call is captured regardless of which agent took it. Two options in the queue's section turn it on, and a channel variable set before Queue() controls the file name:

/etc/asterisk/queues.conf - recording
[support]
monitor-type=MixMonitor
monitor-format=wav
extensions.conf - one file per call, named by time and caller
exten => 2125551000,1,Answer()
 same => n,Playback(custom/calls-may-be-recorded)
 same => n,Set(MONITOR_FILENAME=/var/spool/asterisk/monitor/support/${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${CALLERID(num)})
 same => n,Queue(support,tC,,,300)

monitor-type=MixMonitor records both legs into one file; leaving it unset uses the older Monitor application, which writes two files and mixes them afterwards. wav is safest for playback in a browser; wav49 (GSM inside a WAV container) is about eight times smaller if storage matters. Play a recording notice before the queue: consent rules differ by state and country, and the queue is the one place every caller passes through. Recordings land on the PBX, so size the disk: G.711 at wav is roughly 1 MB per minute per call.

Best Practices

  • Set ringinuse=no: Prevents delivering queue calls to agents already on a call. Without this, agents on a call will hear another ring.
  • Use wrapuptime: Give agents 10-30 seconds after each call to complete notes before the next call arrives.
  • Set a maxlen: Limit the number of callers in queue to prevent extremely long wait times. It is better to send the 21st caller to voicemail than make them wait 30 minutes.
  • Configure a timeout: Always set a max wait time in the Queue() dialplan application. Send callers to voicemail or a callback option if they wait too long.
  • Monitor service levels: Track what percentage of calls are answered within your target time (e.g., 80% within 60 seconds). This is the industry-standard metric.
  • Record queue calls: Use MixMonitor() in the queue member's context to record calls for quality assurance and training.

Asterisk Queue FAQ

How do I set up a call queue in Asterisk?
To set up a call queue in Asterisk, edit /etc/asterisk/queues.conf and define a queue context with parameters like strategy (ringall, leastrecent, round-robin), timeout, retry interval, and member agents. Then reference the queue in your dialplan using the Queue() application. Reload with 'asterisk -rx "module reload app_queue.so"'.
What is periodic-announce in queues.conf?
periodic-announce is a queues.conf parameter that plays a recorded announcement to callers waiting in the queue at regular intervals. Set periodic-announce-frequency (in seconds) to control how often it plays. Common use: 'Your call is important to us, please continue to hold.' You can specify multiple sound files separated by commas.
What ring strategies are available in Asterisk call queues?
Asterisk queues support several ring strategies: ringall (ring all available agents simultaneously), leastrecent (ring agent who has been idle longest), fewestcalls (ring agent with fewest completed calls), random (ring a random agent), rrmemory (round-robin with memory), linear (ring in order listed), and wrandom (weighted random).
How do I reload queues.conf without restarting Asterisk?
Run queue reload all from the Asterisk CLI (or asterisk -rx "queue reload all" from the shell). It re-reads queues.conf and queuerules.conf for every queue, keeps dynamically added members, and does not drop callers who are already waiting or talking. queue reload parameters, queue reload members and queue reload rules reload one part only. module reload app_queue.so does the same as queue reload all. A full core restart is only needed when app_queue was never loaded or you change the realtime configuration in extconfig.conf.
What is the difference between the Queue() timeout and timeout in queues.conf?
timeout in queues.conf is how many seconds one agent's phone rings per attempt (default 15). The fifth argument of Queue() in the dialplan is the total number of seconds the caller may wait before Queue() returns with QUEUESTATUS=TIMEOUT. retry is the pause between attempts. When the two timers would expire at the same moment, timeoutpriority=app (the default) ends the ring attempt immediately in favour of the caller's timeout, while timeoutpriority=conf lets the current ring attempt finish first.
Why does queue show list a member as Invalid or Unavailable?
Invalid means Asterisk cannot resolve the member's dial string: a typo such as PJSIP/1O1, a channel driver that is not loaded, or a Local channel with no matching extension. Unavailable means the interface exists but its device state is unreachable, usually a PJSIP endpoint with no registered contact. Both members are skipped by every strategy. Check with pjsip show contacts and core show hints, and give Local channel members a state_interface so the queue sees the real phone's state.
Where does Asterisk log queue statistics?
Every queue event is appended to /var/log/asterisk/queue_log as pipe-separated fields: epoch, caller unique ID, queue name, agent, event and up to three parameters. ENTERQUEUE, CONNECT, COMPLETECALLER, COMPLETEAGENT, ABANDON and EXITWITHTIMEOUT are enough to compute answered calls, abandon rate, average hold time and service level. queue show gives the live counters since the last reload or queue reset stats; tools such as QueueMetrics or Asternic parse queue_log into reports, and the log can also be written to a database table through extconfig.conf.
What does rrmemory mean in Asterisk?
rrmemory is round-robin with memory. Asterisk rings one member at a time, remembers which member it rang last and starts the next call with the member after that one, so calls rotate evenly instead of always starting from the first agent. rrordered behaves the same but keeps the order in which members are listed in queues.conf rather than the internal order, which makes it the better choice when you want a predictable first-ring agent.

Reliable SIP Trunking for Your Call Center

IPComms provides high-capacity SIP trunks built for call centers: $0 per channel with no set call limits, $0.009/min inbound and $0.010/min outbound, local numbers from $1.50/month and no contracts. Stop worrying about SIP trunk capacity. We have you covered. See our full Asterisk SIP trunking setup guide and the call center solutions page.

Get Started Today SIP Trunking: $0 Per Channel Call Center Solutions

Stop worrying about SIP trunk capacity. We have you covered.

SIP trunking from a US carrier since 2002: $0.009 per minute inbound, $0.010 outbound, numbers from $1.50 a month, $0 per channel, no contracts.

Sign up now or see the full rate table