> Fetch clean Markdown by appending `.md` to any page URL under https://signalwire.com/docs or requesting it with the HTTP header `Accept: text/markdown`. The root index at https://signalwire.com/docs/llms.txt lists the available documentation indexes. # play > Play audio content on a call. [playaction]: /docs/server-sdks/reference/typescript/relay/actions [calling-call-play]: /docs/server-sdks/reference/typescript/relay/call#events [call-events]: /docs/server-sdks/reference/typescript/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** > > This method corresponds to the SWML [`play`][play] verb. See the > [SWML play reference][swml-play-reference] for the full specification. ## **Parameters** **`media`** `Record[]` — required Array of media items to play. Each item is an object 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 --- **`volume`** `number | undefined` Volume adjustment in dB, from `-40.0` to `40.0`. --- **`direction`** `string | undefined` Audio direction. Valid values: * `"listen"` -- play to the caller only * `"speak"` -- play to the remote party only * `"both"` -- play to both sides --- **`loop`** `number | undefined` Number of times to repeat the media. `0` loops indefinitely. --- **`controlId`** `string | undefined` Custom control ID for this operation. Auto-generated if not provided. --- **`onCompleted`** `(event: RelayEvent) => void | Promise` Callback invoked when playback reaches a terminal state. Can be a regular function or async function. --- ## **Returns** `Promise<`[`PlayAction`][playaction]`>` -- An action handle with `stop()`, `pause()`, `resume()`, `volume()`, and `wait()` methods. ## **Examples** ### Text-to-Speech ```typescript {11} import { RelayClient } from '@signalwire/sdk'; const client = new RelayClient({ project: process.env.SIGNALWIRE_PROJECT_ID!, token: process.env.SIGNALWIRE_API_TOKEN!, contexts: ['default'] }); client.onCall(async (call) => { await call.answer(); const action = await call.play([{ type: 'tts', text: 'Welcome to SignalWire!' }]); await action.wait(); }); await client.run(); ``` ### Audio File with Loop ```typescript {12} import { RelayClient } from '@signalwire/sdk'; const client = new RelayClient({ project: process.env.SIGNALWIRE_PROJECT_ID!, token: process.env.SIGNALWIRE_API_TOKEN!, contexts: ['default'] }); client.onCall(async (call) => { await call.answer(); // Play hold music on loop const action = await call.play( [{ type: 'audio', url: 'https://example.com/hold-music.mp3' }], { loop: 0, direction: 'listen' } ); // Later, stop the music await action.stop(); }); await client.run(); ``` ### Multiple Media Items ```typescript {11} import { RelayClient } from '@signalwire/sdk'; const client = new RelayClient({ project: process.env.SIGNALWIRE_PROJECT_ID!, token: process.env.SIGNALWIRE_API_TOKEN!, contexts: ['default'] }); client.onCall(async (call) => { await call.answer(); const 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(); }); await client.run(); ``` > Play audio content on a call.