#!/bin/bash set -euo pipefail source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" run_node_test <<'JS' const audio = requireFromRoot('shell/plugins/panels/audio/Model.js') assert(audio.isPlaybackStream({ isStream: true, isSink: true }), 'audio detects sink-backed playback streams') assert(audio.isPlaybackStream({ isStream: true, type: 'Stream/Output/Audio' }), 'audio detects typed playback streams') assert(!audio.isPlaybackStream({ isStream: false, isSink: true }), 'audio rejects non-stream playback nodes') assert(audio.isAudioSource({ audio: {} }), 'audio detects nodes with audio as sources') assert(audio.isAudioSource({ type: 'Audio/Source' }), 'audio detects typed source nodes') // A destroyed PwNode stays truthy but reads back no id, which is the shape the // third entry stands in for: it must not reach a Repeater row. The first carries // an object like a live node's audio, so a row that is the node itself fails here. assertDeepEqual( audio.rowSnapshot([{ id: 0, name: 'alsa_output', audio: { volume: 1 } }, { id: 42 }, {}, null]), [{ id: 0, name: 'alsa_output' }, { id: 42, name: '' }], 'audio projects nodes to primitive rows and drops nodes without an id' ) assertDeepEqual(audio.rowSnapshot(undefined), [], 'audio projects a missing list to no rows') assert(audio.nodeRow({ id: 7, name: 'bluez_output' }).name === 'bluez_output', 'audio rows carry the node name that identifies them') assertEqual(audio.outputVolumeName(0, false), 'Silenced', 'audio labels silent output') assertEqual(audio.outputVolumeName(0.9, false), 'Party mode', 'audio labels loud output') assertEqual(audio.outputVolumeName(0.5, true), 'Muted', 'audio labels muted output') assertDeepEqual(audio.parseSinkAvailability('alsa_output\t1\nhdmi_output\t0\n'), { alsa_output: true, hdmi_output: false }, 'audio parses sink availability') assertEqual(audio.friendlyDeviceLabel('Built-in Audio Speakers Output'), 'Speakers', 'audio cleans device labels') assertEqual( audio.nodeLabel({ ready: true, properties: { 'node.nick': 'Built-in Audio Microphones Input' }, name: 'alsa_input' }), 'Microphone', 'audio chooses friendly node labels' ) const headphones = { ready: true, name: 'bluez_output.airpods', properties: { 'device.product.name': 'AirPods Headphones' } } assert(audio.isHeadphones(headphones), 'audio detects headphone devices') assertEqual(audio.sinkGlyph(headphones), '󰋋', 'audio uses headphone sink glyph') assert(audio.sourceGlyph({ ready: true, properties: { 'device.icon-name': 'camera-webcam' } }).length > 0, 'audio maps webcam source glyph') assertEqual(audio.friendlyStreamLabel('spotify'), 'Spotify', 'audio normalizes known stream labels') assert(audio.streamRepresentsMprisPlayer('Chromium', 'Chromium Browser'), 'audio matches related stream and MPRIS labels') const players = [ { identity: 'Spotify', canPlay: true, isPlaying: true, dbusName: 'org.mpris.MediaPlayer2.spotify' }, { identity: 'Chromium', canPlay: true, isPlaying: false, dbusName: 'org.mpris.MediaPlayer2.chromium' } ] const streams = [ { ready: true, properties: { 'application.name': 'Chromium' } }, { ready: true, properties: { 'application.name': 'audio-src' } } ] assertEqual(audio.matchingMprisStreamLabel('Chromium', players), 'Chromium', 'audio finds matching MPRIS labels') assertEqual(audio.unmatchedMprisStreamLabel('audio-src', players, streams), 'Spotify', 'audio uses unmatched MPRIS player for generic streams') assertEqual(audio.streamLabel(streams[1], players, streams), 'Spotify', 'audio labels generic streams from MPRIS') assert(audio.streamRepresentsPlayer(streams[1], players[0], players, streams), 'audio links generic streams to active player') JS