is it possible to get mp4 audio only recording out...
# ask-ai
s
is it possible to get mp4 audio only recording output. how can i config that
t
Thanks for reaching out, Gurkirat. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m responding to your question about whether you can produce an MP4 audio‑only recording and how to configure it. Yes — you can create an audio‑only MP4 using LiveKit’s Track Composite egress. The egress service will transcode the WebRTC/Opus audio into an MP4 container (typically with an AAC audio stream) when you request MP4 output. How to configure it 1. Use the Track Composite egress. 2. Provide only the audio track (set
AudioTrackId
) and do NOT include a
VideoTrackId
. 3. Set the output file type to
MP4
and provide your output destination (local path, S3, etc.). Example (Go SDK)
Copy code
info, err := egressClient.StartTrackCompositeEgress(ctx, &livekit.TrackCompositeEgressRequest{
    RoomName:     "my-room",
    AudioTrackId: "audio-track-id", // only audio
    Output: &livekit.TrackCompositeEgressRequest_File{
        File: &livekit.EncodedFileOutput{
            FileType: livekit.EncodedFileType_MP4,
            Filepath: "output/audio-only.mp4",
            Output: &livekit.EncodedFileOutput_S3{
                S3: &livekit.S3Upload{
                    AccessKey: "key",
                    Secret:    "secret",
                    Bucket:    "my-bucket",
                    Region:    "us-east-1",
                },
            },
        },
    },
})
Key points to note • Setting only
AudioTrackId
ensures no video is included. • LiveKit handles transcoding from Opus to a codec compatible with MP4 (e.g., AAC). • You can also use Room Composite with a layout that excludes video, but Track Composite is the more direct and efficient option for audio‑only exports. If you’d like, tell me: • Which SDK/language you’re using (Go, Node, REST API, etc.), and • Whether you’re outputting to S3 or a local file. I’ll provide a tailored code example or the exact request payload for your environment. Sources: Universal Egress | Universal Egress
s
so how much this gonna cost me. 0.02 per min or 0.005 per min
t
Thanks — you’re asking whether the MP4 audio‑only recording costs $0.02/min or $0.005/min. Here’s the clear breakdown so you can pick the number that applies to your case. • Recording storage (audio/video exports): $0.005 per minute — this is the rate for stored recordings that exceed any included minutes in your plan. If you’re specifically asking about the cost to store the MP4 audio file, this is the relevant rate. • Agent runtime / session minutes: $0.01 per minute — this is the cost when an agent session is running (separate from recording storage). If you combine agent runtime with inference, telephony, and other usages, a sample estimate can reach about $0.02 per minute total. So: • Use $0.005/min when referring only to recording storage for the MP4 audio file. • Use $0.02/min only when you mean the combined runtime + inference + telephony example total shown in pricing examples. If you tell me whether you’re asking about: • just the cost to store/export the MP4 file, or • the full per‑minute cost of running an agent (including inference/telephony), I’ll confirm the exact line items that apply to your scenario. Sources: Deploy and scale agents on LiveKit Cloud | Pricing | LiveKit
s
I am asking for cost of Time spent running RoomComposite and Participant Egresses. for both case audio only true and false
t
Thanks — I’m responding to your question about the cost for time spent running Room Composite and Participant Composite egresses for both audio‑only and audio+video. Here are the rates that apply to those egress types: • Room Composite / Participant Composite — video included (audio+video): $0.02 per minute (standard rate). ◦ On the Scale plan this reduces to $0.015 per minute. • Room Composite / Participant Composite — audio only: $0.005 per minute (standard rate). ◦ On the Scale plan this reduces to $0.004 per minute. Additional notes: • These charges are for the duration the egress runs (transcoding minutes), independent of participant count or output destination. • Track egress (raw single-track export without transcoding) is a different, lower‑cost option (charged separately) and does not apply to Room/Participant Composite egresses. If you’d like, tell me: • which plan you’re on (Standard vs Scale), and • whether you plan to run Room Composite or Participant Composite egresses (or both), and I’ll calculate a sample cost for a specific duration (for example, per hour or per 1,000 minutes). Sources: Pricing | LiveKit | Understanding and Estimating Pricing for Video Conference and Livestream Us...
s
do encoding config also affect cost?
t
Thanks — I’m responding to your question about whether encoding configuration affects cost for Room Composite and Participant Composite egresses (audio-only vs audio+video). Short answer: Yes — encoding configuration does affect cost in two ways: transcoding minutes and downstream data transfer (bandwidth). What changes cost • Transcoding minutes: ◦ Room Composite and Participant Composite egresses are billed by transcoding minutes. ◦ Audio+video transcoding: $0.02 per minute (standard). ▪︎ Reduced to $0.015/min on the Scale plan. ◦ Audio-only transcoding: $0.005 per minute (standard). ▪︎ Reduced to $0.004/min on the Scale plan. ◦ So choosing audio-only instead of audio+video reduces the per-minute transcoding charge significantly. • Downstream data transfer (bandwidth): ◦ Encoding choices (bitrate, resolution, codec) affect how much data is sent out. Bandwidth is billed per GB. ◦ Video streams consume far more bandwidth than audio-only streams; higher resolution/bitrate or less efficient codecs increase transfer costs. ◦ Using more efficient codecs or lower bitrates reduces bandwidth billing. Practical implications • If you run an egress as audio-only, you’ll pay the lower transcoding rate ($0.005/min) and use far less bandwidth — so your overall bill drops. • If you include video, expect the higher transcoding rate ($0.02/min) and much greater downstream transfer costs. • If you need a precise estimate, I can calculate total cost for a given scenario if you tell me: ◦ Which egress type(s) you’ll run (Room Composite, Participant Composite, or both) ◦ Expected duration (minutes) ◦ Whether it’s audio-only or audio+video ◦ Expected output bitrate/resolution or viewer/data egress GB (if known) ◦ Your plan (Standard vs Scale) Would you like me to run sample cost calculations for a specific duration or configuration? Sources: Pricing | LiveKit | A Tale of Two Protocols: WebRTC vs. HLS for Live Streaming | Understanding and Estimating Pricing for Video Conference and Livestream Us...
s
Now issue is whenever i toggle audio_only= True. its not getting recorded
t
Thanks — I’m replying about your issue where recordings stop working when you set
audio_only = True
. Quick checklist and next steps so we can pinpoint the problem: 1) Confirm how you start egress • Which egress API/SDK are you using? (REST, Go, Node, or the Universal Egress API) • Which egress type are you calling when
audio_only=True
? (Room Composite, Participant Composite, Track Egress, or Track Composite) 2) Common causes and what to verify now • Track vs composite: Audio‑only recordings are typically done with a Track Egress (raw track) or a Track Composite/Participant Composite configured for audio-only. If your code toggles
audio_only
but still calls a Room Composite with only that flag changed, it may not translate into a valid audio track egress. • Active audio track: Ensure the audio track ID you target exists and is published (not muted) at the time egress starts. • Egress request translation: Confirm your
audio_only=True
flag actually produces an egress request that omits video/video track IDs and requests an audio output type (e.g., MP4 audio or OGG). • Errors & webhooks: Check egress startup logs and webhook events (
egress_started
,
egress_ended
). Any errors returned when StartEgress is called will help identify the failure. • Output format: If you rely on Track Egress (raw), outputs may be OGG/Opus. If you want MP4 audio, you should use Track Composite with
FileType: MP4
and only set
AudioTrackId
. 3) Quick debugging steps to run now • Start a minimal audio-only egress manually (example: StartTrackEgress or StartTrackCompositeEgress) targeting a known active audio track and a local file output. • Inspect the StartEgress response for errors and the returned egress ID. • Watch for
egress_ended
webhook or check egress worker logs for why it stopped. • If you have a saved request payload, paste it here (remove secrets). I can review it for missing fields (TrackId, FileType, AudioTrackId, etc.). 4) If you want, share: • The exact code or request payload you use when
audio_only=True
(remove keys/secrets). • The SDK/language and which egress type you expect to run. • Any error messages, webhook events, or logs you see after starting egress. If you send the request payload or code snippet, I’ll point out any mismatches and give the exact corrected request you should send to produce a working audio-only recording. Sources: Universal Egress | server-sdk-js | livekit/livekit_composite | DeepWiki | Universal Egress
s
async def _build_room_egress_config(call_ctx: CallSessionCtx | None) -> api.RoomEgress | None: """Build auto egress configuration for room recording. Creates a RoomComposite egress config that records all tracks into a single MP4 file. Files are stored in Cloudflare R2 with naming format: <account_id>_<inbox_id>_<conversation_id>_<room_name>_<timestamp>.mp4 Args: call_ctx: Call session context containing account_id, inbox_id, conversation_id, etc. Returns: RoomEgress configuration object, or None if recording is disabled or config incomplete. Note: Audio encoding optimized for voice calls: - Audio only (no video processing) - 64kbps bitrate (standard voice quality) - 24kHz sample rate - AAC codec (MP4 compatible) """ # Skip recording if no call context provided if call_ctx is None: logger.debug("No call context provided, skipping recording setup") return None # Build storage object path for the recording filepath = _build_recording_filepath(call_ctx) # Cloudflare R2 storage if not all([ settings.cloudflare_r2_access_key_id, settings.cloudflare_r2_secret_access_key, settings.cloudflare_r2_media_bucket, settings.cloudflare_r2_endpoint_url, ]): logger.warning("Recording enabled but Cloudflare R2 config incomplete") return None endpoint = settings.cloudflare_r2_endpoint_url s3_upload = api.S3Upload( access_key=settings.cloudflare_r2_access_key_id, secret=settings.cloudflare_r2_secret_access_key, bucket=settings.cloudflare_r2_media_bucket, endpoint=endpoint, force_path_style=True, # Needs to be True for non AWS S3 compatible endpoints ) file_output = api.EncodedFileOutput( filepath=filepath, s3=s3_upload, ) egress_config = None try: encoding_options = api.EncodingOptions( audio_codec=api.AudioCodec.AAC, audio_bitrate=64000, # 64kbps for standard voice quality audio_frequency=24000, # 24kHz sample rate ) room_composite_request = api.RoomCompositeEgressRequest( file_outputs=[file_output], audio_only=True, advanced=encoding_options, ) egress_config = api.RoomEgress(room=room_composite_request) logger.info(f"Created audio-only egress config for room {call_ctx.room_name}") except Exception as e: logger.warning(f"Failed to create RoomEgress with advanced encoding options: {e}") try: room_composite_request = api.RoomCompositeEgressRequest( file_outputs=[file_output], audio_only=True, ) egress_config = api.RoomEgress(room=room_composite_request) logger.info(f"Created audio-only egress config (default encoding) for room {call_ctx.room_name}") except Exception as e2: logger.error(f"Failed to create audio-only RoomEgress: {e2}") try: room_composite_request = api.RoomCompositeEgressRequest( file_outputs=[file_output], ) egress_config = api.RoomEgress(room=room_composite_request) logger.warning(f"Using basic egress config (not audio-optimized) for room {call_ctx.room_name}") except Exception as e3: logger.error(f"Failed to create any RoomEgress config: {e3}") raise # Updating Call config with call recording filepath, so that recordings can be handled in Spacy if egress_config: # Store public URL in call context call_ctx.call_recording_url = _build_recording_url(filepath) logger.info(f"Call recording URL: {call_ctx.call_recording_url}") from app.services.common import store_call_context await store_call_context(call_ctx.room_name, call_ctx, call_ctx.call_id) return egress_config
t
Thanks — I looked over your RoomComposite egress builder and your issue where setting
audio_only=True
causes no recording. I’ll point out the most likely causes, what to change, and concrete next steps so you can get audio-only recordings working. What I’m responding to • Your async function builds a RoomComposite egress with
audio_only=True
, AAC encoding, and R2 S3 output, but when
audio_only=True
no file is produced. Most likely causes • Room Composite uses a headless browser + layout template to compose the room. If the layout/template expects video elements (or the template’s JS fails when there are no video tracks), Chrome can exit or the composition can fail and no file is created. • The
audio_only
flag itself is valid, but it must be used with a layout/template that works when there is no video. • If your code toggles
audio_only
but still relies on a video-dependent layout or template, the compositor may have nothing to render and stop. What to try (quick, ordered checklist) 1. Run a minimal audio-only RoomComposite test ◦ Create a RoomComposite request with
audio_only=True
, but omit any
layout
or set it to a minimal template that does NOT reference video elements. ◦ Confirm the StartEgress response contains an egress ID and check webhooks for
egress_started
/
egress_ended
. 1. Use a custom audio-only template (recommended if you must use RoomComposite) ◦ Make a template HTML that does not try to render video elements; keep it simple (background + JS that connects the hidden participant and starts composition). The template should not crash if no video tracks exist. 1. Try Track Egress / Track Composite as a simpler alternative ◦ If you only need a mixed audio file (or single participant audio), TrackEgress or TrackComposite is simpler and more reliable for pure audio: ▪︎ TrackEgress exports a single raw track (ogg/opus) and avoids the browser compositor. ▪︎ TrackComposite (or ParticipantComposite) can produce MP4 audio-only outputs by specifying only the
AudioTrackId
and
FileType: MP4
. ◦ TrackEgress is also cheaper and has fewer failure points. 1. Verify the audio track is available when egress starts ◦ Ensure the participant’s audio track is published and not muted at egress start. Use list/inspect APIs to confirm track SIDs. 1. Check logs and webhooks ◦ Look at egress worker logs and any
egress_ended
webhook for an error message. That will usually indicate template/renderer crashes or missing tracks. Specific issues in your snippet to double-check • You set
audio_only=True
and
advanced=encoding_options
. That’s fine if your proto/SDK maps
EncodingOptions
correctly. If the SDK version you use doesn’t support advanced audio fields for RoomComposite, the request may fail; fallback code you have is good but inspect the exception content (log it) to see if encoding options are rejected. • If your layout field defaults (elsewhere in your code) include a template expecting video, that will break audio-only. Make sure no implicit layout is injected. • Confirm the encoded output settings (you set AAC + 64kbps + 24kHz). If the compositor cannot produce AAC for some reason, GStreamer will usually error — check egress error details. Minimal test examples • Minimal RoomComposite (audio-only, no layout): ◦ Request:
RoomCompositeEgressRequest(file_outputs=[file_output], audio_only=True)
— start this manually and watch webhooks. • TrackEgress example (single audio track): ◦ Request a TrackEgress for a known audio
track_id
to a local or S3 file (OGG or MP4 via TrackComposite) and confirm it writes a file. If you want, I can: • Provide a minimal audio-only HTML template you can upload to your templates and reference in RoomComposite. • Show a concrete
TrackEgress
or
TrackComposite
request payload for your Python SDK to test immediately. • Inspect any error log or webhook payload you have (paste it with secrets removed) and point out the failure reason. Which do you want next? • A minimal audio-only HTML template, or • A Python TrackEgress / TrackComposite example you can run right away, or • I can review the egress webhook/error you received (paste it here, remove secrets) Tell me which and I’ll give the exact code/payload to run. Sources: Universal Egress | Pricing | LiveKit | server-sdk-js | livekit/livekit_composite | DeepWiki
s
my call disconnected i got the recording but on livekit dashboard why its still showoing egress session is active
t
Thanks — you said your call disconnected, you received the recording, but the LiveKit dashboard still shows the egress session as active. I’ll explain why that happens and give concise steps to make the egress stop and the dashboard reflect the final state. Why the egress can remain active after the call disconnects • Egress sessions are separate processes from participant connections. Even after the caller leaves and the recording file is produced, the egress worker can remain running until it’s explicitly stopped or the room is fully torn down. • Rooms are not always deleted as soon as the last participant leaves. There’s a short timeout and room cleanup behavior that can keep the room (and thus egress) active. • If you started egress programmatically, it may not auto-stop just because media stopped flowing — it waits for an explicit stop or room deletion, or until the egress process finishes and reports completion. What to check now (quick) • Do you see an
egress_ended
webhook for that egress ID? If it arrived with a success status, the dashboard should update soon. • Check the egress logs or the
egress_ended
webhook payload for an
error
field — that can show why the egress didn’t fully stop. • Use the
ListEgress
or
GetEgress
API to confirm the server-side state for that egress ID. How to make the egress stop (recommended options) 1) Delete the room when the call ends (recommended if you don’t need the room afterwards) • Deleting the room forces all participants and any active egress to disconnect and finalizes egress. • Example: call your room delete API for that room name/ID after the call finishes. 2) Explicitly stop the egress • If you want to keep the room open, call the egress stop API with the egress ID. • Stopping the egress triggers finalization and the dashboard will change to the completed/ended state once the stop finishes. Additional debugging tips • Confirm webhooks are delivered and processed (watch for
egress_started
and
egress_ended
). • If you see the recording file uploaded successfully but no
egress_ended
event, confirm your webhook receiver didn’t drop or fail to acknowledge the event. • Check for small propagation delays in the dashboard — sometimes status updates take a short time to display. If you’d like, send: • The egress ID (or the
egress_ended
webhook payload you received with sensitive fields removed), and • Whether your app deletes rooms on disconnect or calls
stopEgress
. I can help interpret the webhook or API output and point to the exact action to finalize the egress so the dashboard shows the correct state. Sources: Why is there extra audio at the end of my recordings of an agent session? |... | Job lifecycle | LiveKit Documentation | server-sdk-ruby | livekit/livekit_composite | DeepWiki | Backup Egress Recordings | server-sdk-js | livekit/livekit_composite | DeepWiki
s
whats the difference between roomcomposite and participate engress?
t
Good question — here’s a concise comparison so you can pick the right egress for your needs. Scope and output • Room Composite Egress ◦ Captures the entire room and composes all participants into a single synchronized output (MP4/WebM or RTMP). ◦ Uses a layout/template so you control placement (gallery, speaker view, custom HTML). ◦ Best when you want a single “meeting” or livestream view of everyone. • Participant (Track) Composite Egress ◦ Captures a single participant’s tracks (their audio + their video) and produces a file or stream for that participant only. ◦ No browser/layout required — it synchronizes the participant’s tracks directly. ◦ Best when you need isolated feeds (speaker recordings, presenter uploads, individual post‑processing). Technical and resource differences • Room Composite uses a headless browser (hidden Chrome) to render the layout, then encodes that rendering. That makes it more CPU/memory intensive and potentially more failure points (templates must handle missing video when audio-only). • Participant Composite does not use a browser, so it’s simpler, lower latency, and less resource-heavy. Cost/efficiency impact • Both are billed by transcoding minutes, but because Room Composite performs browser rendering and often encodes video layouts, it typically costs more when video is included. • If you only need audio, audio‑only modes reduce transcoding cost (audio-only rate is lower). For pure single-track exports, Track Egress (raw track export) is the cheapest option. When to use which • Use Room Composite when: ◦ You want a single composed view/layout of the whole session (archival or livestream). ◦ You need custom template-driven visuals (overlays, branding, grid layouts). • Use Participant Composite (Track Composite) when: ◦ You need one participant’s feed recorded or streamed (interviews, host recordings). ◦ You prefer lower resource usage and simpler configuration. APIs • Room Composite: StartRoomCompositeEgress with layout & file/stream outputs. • Participant/Track Composite: StartTrackCompositeEgress (provide
AudioTrackId
and/or
VideoTrackId
) or Track Egress for raw single-track exports. If you tell me your exact use case (single host recording, multi-person meeting archive, livestream, audio-only call recording, etc.), I can recommend the simplest and most cost‑effective egress type and give a sample request payload. Sources: Universal Egress