> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tuple.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Local audio recording (alpha)

<View title="macOS" icon="apple">
  Tuple 2.4.0 includes the ability to record the audio for all call participants locally to disk.

  ## Starting recording

  You can start recording by clicking on the "Record audio" button in the call controls:

  <img src="https://mintcdn.com/tuple-0f82e5be/O4IiteXcXoa48ycm/images/pairing-with-tuple/local-audio-recording-alpha/record-audio-button.png?fit=max&auto=format&n=O4IiteXcXoa48ycm&q=85&s=9dfdfc9acf7b71b8c79a7d5e3883998d" alt="Call controls with the Record audio button highlighted" width="1136" height="1256" data-path="images/pairing-with-tuple/local-audio-recording-alpha/record-audio-button.png" />

  When you start recording, all other call participants will get a notification letting them know. They'll also be able to see that you're recording in the call participant list:

  <img src="https://mintcdn.com/tuple-0f82e5be/O4IiteXcXoa48ycm/images/pairing-with-tuple/local-audio-recording-alpha/recording-indicator-in-call-list.png?fit=max&auto=format&n=O4IiteXcXoa48ycm&q=85&s=462034186f285d1122285c2ffd43220a" alt="Call participant list showing that audio recording is active" width="1136" height="1256" data-path="images/pairing-with-tuple/local-audio-recording-alpha/recording-indicator-in-call-list.png" />

  ## Working with recordings

  Once recording has finished, the following files will be written to disk:

  * For each participant on the call, there will be a file named `{USER_ID}_{STARTING_TIMESTAMP}.opus`. These files utilize the [Opus audio codec](https://opus-codec.org/)
  * There will also be a file named `events.jsonl`. This file contains all of the "events" that occur in a call (see below for more info)
  * If transcription is enabled, there will also be a `transcriptions.jsonl` file (see [Transcription](#transcription) below)

  Files are written to `~/Library/Caches/app.tuple.app/CallArtifacts/{CALL_ID}`. Within that directory will be subfolders for each recording "session" (i.e. if someone starts and stops recording within the same call). Each of those subfolders is named with the timestamp that the session began:

  ```
  ~/Library/Caches/app.tuple.app/CallArtifacts/
    └── <call_id>/
        └── <recording_start_timestamp>/
            ├── events.jsonl
            ├── transcriptions.jsonl
            └── <user_id>_<timestamp>.opus

  ```

  A new timestamp directory is created each time recording starts (or resumes after being suspended), so a single call can have multiple recording session directories.

  There's now a trigger named `call-transcription-complete` ([docs](https://tuple.app/triggers/docs/api-reference?utm_source=docs#call-transcription-complete)), which gets fired after the files have finished writing to disk. The trigger will fire for each distinct "session". You can use this trigger to process the recordings locally; for inspiration, check out this [trigger](https://tuple.app/triggers/directory/transcribe-call?utm_source=docs) which transcribes the audio files and interleaves them with the events file to create a composite summary of the call.

  ## Transcription

  You can enable automatic speech-to-text transcription for call recordings. Transcription runs entirely on your machine using a local [Whisper](https://github.com/ggerganov/whisper.cpp) model — no audio is sent to any external service.

  ### Setting up transcription

  Transcription requires a Whisper GGML model file. To get started:

  1. Download a model from [Hugging Face](https://huggingface.co/ggerganov/whisper.cpp/tree/main). The `base.en` model is a good starting point — it handles real-time English transcription well on most hardware.
  2. Set the path to your downloaded model file using the `whisperModelPath` user default:

  ```bash theme={null}
  defaults write app.tuple.app whisperModelPath "/path/to/ggml-base.en.bin"
  ```

  When transcription is enabled and a model is loaded, speech from each participant is automatically transcribed during recording. The results are saved as a `transcriptions.jsonl` file in the recording session directory.

  ### Transcription output format

  Each line in `transcriptions.jsonl` is a JSON object with the following fields:

  | Field     | Type   | Description                                  |
  | --------- | ------ | -------------------------------------------- |
  | `user_id` | string | The ID of the participant who spoke          |
  | `text`    | string | The transcribed text                         |
  | `start`   | string | ISO 8601 timestamp for when the speech began |
  | `end`     | string | ISO 8601 timestamp for when the speech ended |

  Example:

  ```json theme={null}
  {"user_id": "12345", "text": "Let me share my screen and walk you through this.", "start": "2026-04-03T10:30:15Z", "end": "2026-04-03T10:30:19Z"}
  ```

  ## Call recording events

  The `events.jsonl` file is written to each recording session directory. Each line is a JSON object with the following fields:

  | Field      | Type   | Description                                        |
  | ---------- | ------ | -------------------------------------------------- |
  | `time`     | string | ISO 8601 timestamp                                 |
  | `category` | string | Event category (see below)                         |
  | `message`  | string | Human-readable description                         |
  | `user`     | object | The user associated with the event (if applicable) |

  ## Event categories

  ### Recording lifecycle

  | Category            | Description                  |
  | ------------------- | ---------------------------- |
  | `recording_started` | Recording began for a call   |
  | `recording_ended`   | Recording stopped for a call |

  ### Participant presence

  | Category      | Description                                                                |
  | ------------- | -------------------------------------------------------------------------- |
  | `user_joined` | A user joined the call (local user, existing peers at start, or new peers) |
  | `user_left`   | A peer left the call                                                       |

  ### Media state changes

  | Category                      | Description                         |
  | ----------------------------- | ----------------------------------- |
  | `user_audio_started`          | A user started sending audio        |
  | `user_audio_stopped`          | A user stopped sending audio        |
  | `user_webcam_started`         | A user started sharing their webcam |
  | `user_webcam_stopped`         | A user stopped sharing their webcam |
  | `user_screen_sharing_started` | A user started sharing their screen |
  | `user_screen_sharing_stopped` | A user stopped sharing their screen |

  Media state events are emitted for both local and remote users.

  ## Want access?

  This feature is currently in private alpha. If you'd like access to it, [email us](mailto:support@tuple.app) and we'll get you set up.
</View>
