***

title: play
slug: /reference/python/relay/call/play
description: Play audio content on a call.
max-toc-depth: 3
---------------------

For a complete index of all SignalWire documentation pages, fetch https://signalwire.com/docs/llms.txt

[playaction]: /docs/server-sdks/reference/python/relay/actions

[calling-call-play]: /docs/server-sdks/reference/python/relay/call#events

[call-events]: /docs/server-sdks/reference/python/relay/call#events

[play]: /docs/swml/reference/play

[swml-play-reference]: /docs/swml/reference/play

Play audio content on the call. Supports TTS (text-to-speech), audio file URLs,
silence, and ringtone. Returns a [`PlayAction`][playaction]
that you can use to pause, resume, stop, adjust volume, or wait for completion.

<Info>
  This method emits [`calling.call.play`][calling-call-play] events. See [Call Events][call-events] for payload details.
</Info>

<Info>
  This method corresponds to the SWML [`play`][play] verb. See the
  [SWML play reference][swml-play-reference] for the full specification.
</Info>

## **Parameters**

<ParamField path="media" type="list[dict]" required={true} toc={true}>
  List of media items to play. Each item is a dict with a `type` key and
  type-specific fields:

  * `{"type": "tts", "text": "Hello", "language": "en-US", "gender": "female"}` -- text-to-speech
  * `{"type": "audio", "url": "https://example.com/audio.mp3"}` -- audio file URL
  * `{"type": "silence", "duration": 2}` -- silence for a duration in seconds
  * `{"type": "ringtone", "name": "us"}` -- play a standard ringtone
</ParamField>

<ParamField path="volume" type="Optional[float]" toc={true}>
  Volume adjustment in dB, from `-40.0` to `40.0`.
</ParamField>

<ParamField path="direction" type="Optional[str]" toc={true}>
  Audio direction. Valid values:

  * `"listen"` -- play to the caller only
  * `"speak"` -- play to the remote party only
  * `"both"` -- play to both sides
</ParamField>

<ParamField path="loop" type="Optional[int]" toc={true}>
  Number of times to repeat the media. `0` loops indefinitely.
</ParamField>

<ParamField path="control_id" type="Optional[str]" toc={true}>
  Custom control ID for this operation. Auto-generated if not provided.
</ParamField>

<ParamField path="on_completed" type="Optional[Callable[[RelayEvent], Any]]" toc={true}>
  Callback invoked when playback reaches a terminal state. Can be a regular
  function or async coroutine.
</ParamField>

## **Returns**

[`PlayAction`][playaction] -- An action handle with
`stop()`, `pause()`, `resume()`, `volume()`, and `wait()` methods.

## **Examples**

### Text-to-Speech

```python {13}
from signalwire.relay import RelayClient

client = RelayClient(
    project="your-project-id",
    token="your-api-token",
    host="your-space.signalwire.com",
    contexts=["default"],
)

@client.on_call
async def handle_call(call):
    await call.answer()
    action = await call.play([{"type": "tts", "text": "Welcome to SignalWire!"}])
    await action.wait()

client.run()
```

### Audio File with Loop

```python {14}
from signalwire.relay import RelayClient

client = RelayClient(
    project="your-project-id",
    token="your-api-token",
    host="your-space.signalwire.com",
    contexts=["default"],
)

@client.on_call
async def handle_call(call):
    await call.answer()
    # Play hold music on loop
    action = await call.play(
        [{"type": "audio", "url": "https://example.com/hold-music.mp3"}],
        loop=0,
        direction="listen",
    )
    # Later, stop the music
    await action.stop()

client.run()
```

### Multiple Media Items

```python {13}
from signalwire.relay import RelayClient

client = RelayClient(
    project="your-project-id",
    token="your-api-token",
    host="your-space.signalwire.com",
    contexts=["default"],
)

@client.on_call
async def handle_call(call):
    await call.answer()
    action = await call.play([
        {"type": "tts", "text": "Please hold while we connect you."},
        {"type": "silence", "duration": 1},
        {"type": "audio", "url": "https://example.com/hold-music.mp3"},
    ])
    await action.wait()

client.run()
```