@@ -489,3 +489,161 @@ JSON
489489 sound=$( afplay_sound)
490490 [[ " $sound " == * " /packs/peon/sounds/" * ]]
491491}
492+
493+ # ============================================================
494+ # Linux audio backend detection (order of preference)
495+ # ============================================================
496+
497+ @test " Linux detects pw-play first" {
498+ export PLATFORM=linux
499+ # Disable all other players to ensure pw-play is selected
500+ for player in paplay ffplay mpv play aplay; do
501+ touch " $TEST_DIR /.disabled_${player} "
502+ done
503+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
504+ [ " $PEON_EXIT " -eq 0 ]
505+ linux_audio_was_called
506+ cmdline=$( linux_audio_cmdline)
507+ [[ " $cmdline " == * " --volume" * ]]
508+ }
509+
510+ @test " Linux detects paplay when pw-play not available" {
511+ export PLATFORM=linux
512+ touch " $TEST_DIR /.disabled_pw-play"
513+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
514+ [ " $PEON_EXIT " -eq 0 ]
515+ linux_audio_was_called
516+ cmdline=$( linux_audio_cmdline)
517+ [[ " $cmdline " == * " --volume" * ]]
518+ }
519+
520+ @test " Linux detects ffplay when pw-play and paplay not available" {
521+ export PLATFORM=linux
522+ touch " $TEST_DIR /.disabled_pw-play" " $TEST_DIR /.disabled_paplay"
523+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
524+ [ " $PEON_EXIT " -eq 0 ]
525+ linux_audio_was_called
526+ cmdline=$( linux_audio_cmdline)
527+ [[ " $cmdline " == * " -volume" * ]]
528+ }
529+
530+ @test " Linux detects mpv when pw-play, paplay, and ffplay not available" {
531+ export PLATFORM=linux
532+ touch " $TEST_DIR /.disabled_pw-play" " $TEST_DIR /.disabled_paplay" " $TEST_DIR /.disabled_ffplay"
533+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
534+ [ " $PEON_EXIT " -eq 0 ]
535+ linux_audio_was_called
536+ cmdline=$( linux_audio_cmdline)
537+ [[ " $cmdline " == * " --volume" * ]]
538+ }
539+
540+ @test " Linux detects play (SoX) when pw-play through mpv not available" {
541+ export PLATFORM=linux
542+ touch " $TEST_DIR /.disabled_pw-play" " $TEST_DIR /.disabled_paplay" " $TEST_DIR /.disabled_ffplay" " $TEST_DIR /.disabled_mpv"
543+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
544+ [ " $PEON_EXIT " -eq 0 ]
545+ linux_audio_was_called
546+ cmdline=$( linux_audio_cmdline)
547+ [[ " $cmdline " == * " -v" * ]]
548+ }
549+
550+ @test " Linux falls back to aplay when no other backend available" {
551+ export PLATFORM=linux
552+ touch " $TEST_DIR /.disabled_pw-play" " $TEST_DIR /.disabled_paplay" " $TEST_DIR /.disabled_ffplay" " $TEST_DIR /.disabled_mpv" " $TEST_DIR /.disabled_play"
553+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
554+ [ " $PEON_EXIT " -eq 0 ]
555+ linux_audio_was_called
556+ cmdline=$( linux_audio_cmdline)
557+ [[ " $cmdline " == * " -q" * ]]
558+ }
559+
560+ @test " Linux continues gracefully when no audio backend available" {
561+ export PLATFORM=linux
562+ for player in pw-play paplay ffplay mpv play aplay; do
563+ touch " $TEST_DIR /.disabled_${player} "
564+ done
565+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
566+ [ " $PEON_EXIT " -eq 0 ]
567+ ! linux_audio_was_called
568+ [[ " $PEON_STDERR " == * " WARNING: No audio backend found" * ]]
569+ }
570+
571+ # ============================================================
572+ # Linux volume handling per backend
573+ # ============================================================
574+
575+ @test " Linux pw-play uses --volume with decimal" {
576+ export PLATFORM=linux
577+ for player in paplay ffplay mpv play aplay; do
578+ touch " $TEST_DIR /.disabled_${player} "
579+ done
580+ cat > " $TEST_DIR /config.json" << 'JSON '
581+ { "active_pack": "peon", "volume": 0.3, "enabled": true, "categories": {} }
582+ JSON
583+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
584+ linux_audio_was_called
585+ cmdline=$( linux_audio_cmdline)
586+ [[ " $cmdline " == * " --volume 0.3" * ]]
587+ }
588+
589+ @test " Linux paplay scales volume to PulseAudio range" {
590+ export PLATFORM=linux
591+ touch " $TEST_DIR /.disabled_pw-play"
592+ cat > " $TEST_DIR /config.json" << 'JSON '
593+ { "active_pack": "peon", "volume": 0.5, "enabled": true, "categories": {} }
594+ JSON
595+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
596+ linux_audio_was_called
597+ cmdline=$( linux_audio_cmdline)
598+ # 0.5 * 65536 = 32768
599+ [[ " $cmdline " == * " --volume=32768" * ]]
600+ }
601+
602+ @test " Linux ffplay scales volume to 0-100" {
603+ export PLATFORM=linux
604+ touch " $TEST_DIR /.disabled_pw-play" " $TEST_DIR /.disabled_paplay"
605+ cat > " $TEST_DIR /config.json" << 'JSON '
606+ { "active_pack": "peon", "volume": 0.5, "enabled": true, "categories": {} }
607+ JSON
608+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
609+ linux_audio_was_called
610+ cmdline=$( linux_audio_cmdline)
611+ # 0.5 * 100 = 50
612+ [[ " $cmdline " == * " -volume 50" * ]]
613+ }
614+
615+ @test " Linux mpv scales volume to 0-100" {
616+ export PLATFORM=linux
617+ touch " $TEST_DIR /.disabled_pw-play" " $TEST_DIR /.disabled_paplay" " $TEST_DIR /.disabled_ffplay"
618+ cat > " $TEST_DIR /config.json" << 'JSON '
619+ { "active_pack": "peon", "volume": 0.5, "enabled": true, "categories": {} }
620+ JSON
621+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
622+ linux_audio_was_called
623+ cmdline=$( linux_audio_cmdline)
624+ # 0.5 * 100 = 50
625+ [[ " $cmdline " == * " --volume=50" * ]]
626+ }
627+
628+ @test " Linux play (SoX) uses -v with decimal" {
629+ export PLATFORM=linux
630+ touch " $TEST_DIR /.disabled_pw-play" " $TEST_DIR /.disabled_paplay" " $TEST_DIR /.disabled_ffplay" " $TEST_DIR /.disabled_mpv"
631+ cat > " $TEST_DIR /config.json" << 'JSON '
632+ { "active_pack": "peon", "volume": 0.3, "enabled": true, "categories": {} }
633+ JSON
634+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
635+ linux_audio_was_called
636+ cmdline=$( linux_audio_cmdline)
637+ [[ " $cmdline " == * " -v 0.3" * ]]
638+ }
639+
640+ @test " Linux aplay does not support volume control" {
641+ export PLATFORM=linux
642+ touch " $TEST_DIR /.disabled_pw-play" " $TEST_DIR /.disabled_paplay" " $TEST_DIR /.disabled_ffplay" " $TEST_DIR /.disabled_mpv" " $TEST_DIR /.disabled_play"
643+ run_peon ' {"hook_event_name":"SessionStart","cwd":"/tmp/myproject","session_id":"s1","permission_mode":"default"}'
644+ linux_audio_was_called
645+ cmdline=$( linux_audio_cmdline)
646+ # aplay is used and no volume flags are passed
647+ [[ " $cmdline " != * " volume" * ]]
648+ [[ " $cmdline " != * " -v " * ]]
649+ }
0 commit comments