How to Configure HDMI Audio Output on Fedora

Set HDMI as the default audio output on Fedora using pactl to list sinks and switch the active device.

You plug in the monitor and the sound stays on the laptop

You connect your Fedora machine to an external display via HDMI. The video appears instantly. You open a video player, and the audio plays through the internal speakers instead of the monitor. You click the volume icon, switch the output device, and nothing changes. The terminal shows a list of sinks, but you are not sure which identifier maps to the physical cable. This happens frequently. Fedora defaults to the internal speakers for stability, and switching the routing requires understanding where the audio stack actually lives.

How Fedora routes audio under the hood

Fedora uses PipeWire as the default audio server. PipeWire replaces PulseAudio and JACK while keeping their APIs intact. When you run pactl or wpctl, you are talking to PipeWire through a compatibility layer. The audio stack does not guess which physical port you want. It exposes every capable interface as a sink. A sink is just a destination for audio streams. Your HDMI port appears as a sink only when the kernel detects a connected display and loads the correct driver.

Think of the audio stack like a postal sorting facility. Applications drop letters into the main inbox. The sorting machine reads the address label and routes each letter to a specific mailbox. If you want the letters delivered to the HDMI mailbox, you have to tell the sorting machine to use that address by default. The machine will keep using the old address until you explicitly change it or unplug the old device.

The kernel handles the physical connection. The snd_hda_intel or snd_hdmi_lpe_audio driver talks to the GPU. The GPU reports the audio capability to the kernel. PipeWire reads the kernel report and creates a sink object. If the driver is missing or the GPU firmware is outdated, the sink never appears. You cannot route audio to a device the kernel does not see. Fedora ships with the necessary firmware for most Intel and AMD hardware. NVIDIA users often need the proprietary driver stack to expose the HDMI audio controller.

Switch the default output from the terminal

Here is how to list the available sinks and switch the default output using the command line. Open a terminal and run the following command to see every active audio destination.

pactl list sinks short
# WHY: pactl queries the PipeWire/PulseAudio compatibility layer.
# WHY: The short flag strips verbose metadata and shows only index, name, and driver.
# WHY: This output lets you match the HDMI port to its exact sink identifier.

The output will look similar to this. The exact names depend on your hardware and kernel version.

0	alsa_output.pci-0000_00_1f.3.analog-stereo	module-alsa-card.c	s16le 2ch 48000Hz	SUSPENDED
1	alsa_output.pci-0000_03_00.1.hdmi-stereo	module-alsa-card.c	s16le 2ch 48000Hz	IDLE

Look for the line containing hdmi in the name column. Copy that exact string. Do not guess the index number. Index numbers change every time you reboot or reconnect the cable. The name string stays consistent across sessions.

Now set that sink as the system default. This tells PipeWire to route new audio streams to the HDMI port automatically.

pactl set-default-sink alsa_output.pci-0000_03_00.1.hdmi-stereo
# WHY: This command updates the default sink property in the PipeWire configuration.
# WHY: Existing streams will not switch automatically. You must restart the application.
# WHY: The change persists until you reboot or change it again.

If you prefer the native PipeWire CLI tool, wpctl works identically and does not rely on the PulseAudio compatibility shim.

wpctl set-default alsa_output.pci-0000_03_00.1.hdmi-stereo
# WHY: wpctl talks directly to the PipeWire protocol.
# WHY: The syntax is slightly shorter but the behavior matches pactl exactly.
# WHY: Use this if you want to avoid legacy PulseAudio command wrappers.

Make the routing permanent

The terminal commands above only change the runtime state. A reboot or a cable disconnect will reset the default sink. Fedora does not write runtime changes to disk by default. You need a persistent configuration file to survive reboots.

Create a drop-in configuration directory for your user session. Config files in /etc/ affect all users. Files in ~/.config/ affect only your login. Edit ~/.config/pipewire/pipewire.conf.d/default-sink.conf and never edit /usr/lib/.

context.properties = {
    default.audio.sink = "alsa_output.pci-0000_03_00.1.hdmi-stereo"
}
# WHY: This overrides the default sink property at the PipeWire context level.
# WHY: The string must match the exact sink name from pactl list sinks short.
# WHY: PipeWire reads this file on every session start and applies the routing.

Restart the audio server to apply the persistent change without logging out.

systemctl --user restart pipewire pipewire-pulse
# WHY: This reloads the PipeWire daemon and its PulseAudio compatibility layer.
# WHY: The --user flag targets the user session instead of the system service.
# WHY: Restarting applies the new configuration file immediately.

Run journalctl first. Read the actual error before guessing.

Verify it worked

Run a quick test to confirm the routing changed. Play a short audio file and check which sink is actively processing the stream.

pactl list sink-inputs short
# WHY: This shows every application currently sending audio to a sink.
# WHY: The third column displays the sink name receiving the stream.
# WHY: If the name matches your HDMI sink, the routing is active.

You can also force a specific application to use the HDMI output without changing the system default. This is useful when you want desktop notifications on the laptop speakers but video playback on the monitor.

pactl move-sink-input <input_index> alsa_output.pci-0000_03_00.1.hdmi-stereo
# WHY: This redirects a single active stream to a different sink.
# WHY: The input_index comes from the first column of the sink-inputs list.
# WHY: The change is temporary and resets when the application closes.

Check the system log if the audio still plays on the wrong device. PipeWire writes routing changes to the journal.

journalctl -xeu pipewire-pulse.service | tail -n 10
# WHY: The -x flag adds explanatory hints to journal entries.
# WHY: The -e flag jumps to the end of the log buffer.
# WHY: Filtering by the pipewire-pulse unit isolates audio routing events.

Reboot before you debug. Half the time the symptom is gone after a fresh kernel module load.

Common pitfalls and what the error looks like

The HDMI sink disappears entirely. This usually means the kernel driver failed to probe the GPU audio controller. Run lspci -k | grep -A 3 -i vga to verify the graphics card is recognized. If the kernel module is missing, install the firmware package for your GPU. NVIDIA users often need akmod-nvidia and the matching firmware package. AMD and Intel users rarely need extra firmware on modern Fedora releases.

You see Error: No such sink when running pactl set-default-sink. The sink name changed or the cable was unplugged during the session. PipeWire removes sinks dynamically when the kernel reports a disconnect. Run pactl list sinks short again to get the current identifier. Never hardcode sink names in scripts without verifying they exist first.

The audio plays but sounds distorted or cuts out at high volumes. HDMI audio uses the GPU internal DSP. Some monitors cap the bit depth or sample rate. Force a compatible profile by editing the PipeWire configuration. Create a drop-in file to override the default sample rate.

context.properties = {
    default.clock.rate = 48000
    default.clock.quantum = 1024
}
# WHY: This forces PipeWire to use a standard 48kHz sample rate.
# WHY: Many HDMI receivers reject 96kHz or 192kHz streams.
# WHY: Restart pipewire.service after saving the file.

SELinux blocks the audio server from accessing the HDMI device. This is rare but happens after custom kernel builds or third-party drivers. Check for denials before disabling the security module.

journalctl -t setroubleshoot | grep -i audio
# WHY: setroubleshoot translates SELinux AVC denials into readable warnings.
# WHY: The output shows exactly which process was blocked and why.
# WHY: Fix the policy with audit2allow instead of switching to permissive mode.

Trust the package manager. Manual file edits drift, snapshots stay.

When to use this vs alternatives

Use the terminal commands when you are managing a headless server with an HDMI dummy plug and need to script audio routing. Use pavucontrol when you are on a desktop and want visual feedback for multiple active streams. Use wpctl when you want to avoid the PulseAudio compatibility layer and prefer native PipeWire syntax. Use the GUI sound settings when you only need to switch the default output once and do not want to open a terminal. Stay on the default routing if you rarely disconnect the monitor and do not mind clicking the volume icon.

Where to go next