blob: 4e8adcff7019d5468987de66c887ad0f582c7edd [file] [log] [blame]
// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package arc
import (
"context"
"os"
"path/filepath"
"time"
"chromiumos/tast/ctxutil"
"chromiumos/tast/errors"
"chromiumos/tast/fsutil"
"chromiumos/tast/local/arc"
"chromiumos/tast/local/audio"
"chromiumos/tast/local/bundles/cros/arc/apputil/vlc"
"chromiumos/tast/local/chrome/uiauto"
"chromiumos/tast/local/chrome/uiauto/filesapp"
"chromiumos/tast/local/input"
"chromiumos/tast/local/mtbf"
"chromiumos/tast/testing"
)
type volumeControl string
const (
volumeUp volumeControl = "volume up"
volumeDown volumeControl = "volume down"
volumeMute volumeControl = "mute"
volumeUnMute volumeControl = "unmute"
volumeReset volumeControl = "reset volume"
)
func init() {
testing.AddTest(&testing.Test{
Func: AudioFilesPlaying,
LacrosStatus: testing.LacrosVariantUnneeded,
Desc: "Play audio files via ARC++ app VLC player and verifies audio volume level is changed based on volume controls",
Contacts: []string{"ting.chen@cienet.com", "alfredyu@cienet.com", "cienet-development@googlegroups.com"},
Attr: []string{"group:mainline", "informational"},
Data: []string{"format_m4a.m4a", "format_mp3.mp3", "format_ogg.ogg", "format_wav.wav"},
SoftwareDeps: []string{"chrome", "chrome_internal", "arc"},
Fixture: mtbf.ArcLoginReuseFixture,
Timeout: 10 * time.Minute,
})
}
const audioFilesPlayingDefaultVol = 50
// AudioFilesPlaying plays audio files via ARC++ app VLC player and verifies audio volume level is changed based on volume controls.
func AudioFilesPlaying(ctx context.Context, s *testing.State) {
cr := s.FixtValue().(*arc.PreData).Chrome
a := s.FixtValue().(*arc.PreData).ARC
cleanupCtx := ctx
ctx, cancel := ctxutil.Shorten(ctx, 10*time.Second)
defer cancel()
recorder, err := mtbf.NewRecorder(ctx)
if err != nil {
s.Fatal("Failed to start record performance: ", err)
}
defer recorder.Record(cleanupCtx, s.OutDir())
tconn, err := cr.TestAPIConn(ctx)
if err != nil {
s.Fatal("Failed to create test API connection: ", err)
}
kb, err := input.Keyboard(ctx)
if err != nil {
s.Fatal("Failed to create the keyboard: ", err)
}
defer kb.Close()
files := map[string]string{
"m4a": "format_m4a.m4a",
"mp3": "format_mp3.mp3",
"ogg": "format_ogg.ogg",
"wav": "format_wav.wav",
}
audioPath := filesapp.DownloadPath + "audios"
if _, err := os.Stat(audioPath); os.IsNotExist(err) {
s.Log("Create folder 'audios'")
if err := os.Mkdir(audioPath, 0755); err != nil {
s.Fatal("Failed to create audios folder: ", err)
}
defer os.Remove(audioPath)
}
for _, file := range files {
audioFileLocation := filepath.Join(audioPath, file)
if _, err := os.Stat(audioFileLocation); os.IsNotExist(err) {
if err := fsutil.CopyFile(s.DataPath(file), audioFileLocation); err != nil {
s.Fatalf("Failed to copy the test video to %s: %v", audioFileLocation, err)
}
defer os.Remove(audioFileLocation)
}
}
vlcPlayer, err := vlc.NewVLCPlayer(ctx, cr, kb, tconn, a)
if err != nil {
s.Fatal("Failed to create VLC instance: ", err)
}
defer vlcPlayer.Close(cleanupCtx, cr, s.HasError, s.OutDir())
if err := vlcPlayer.Launch(ctx); err != nil {
s.Fatalf("Failed to launch app %q: %v", vlc.AppName, err)
}
vh, err := audio.NewVolumeHelper(ctx)
if err != nil {
s.Fatal("Failed to new a volume helper: ", err)
}
topRow, err := input.KeyboardTopRowLayout(ctx, kb)
if err != nil {
s.Fatal("Failed to obtain the top-row layout: ", err)
}
volumeAction := map[volumeControl]uiauto.Action{
volumeUp: kb.AccelAction(topRow.VolumeUp),
volumeDown: kb.AccelAction(topRow.VolumeDown),
volumeMute: kb.AccelAction(topRow.VolumeMute),
volumeUnMute: kb.AccelAction(topRow.VolumeUp),
volumeReset: func(ctx context.Context) error { return vh.SetVolume(ctx, audioFilesPlayingDefaultVol) },
}
s.Log("Get initial volume state")
volume, muted, err := getVolumeState(ctx, vh)
if err != nil {
s.Fatal("Failed to get volume state: ", err)
}
defer func(ctx context.Context) {
vh.SetVolume(ctx, volume)
if muted {
volumeAction[volumeMute](ctx)
} else {
volumeAction[volumeUnMute](ctx)
}
}(cleanupCtx)
s.Logf("Initial volume state: [volume: %d, muted: %t]", volume, muted)
s.Log("Set volume to default state")
if err := volumeAction[volumeUnMute](ctx); err != nil {
s.Fatal("Failed to set default unmute: ", err)
}
if err := volumeAction[volumeReset](ctx); err != nil {
s.Fatal("Failed to set default volume: ", err)
}
if err := playAudioFiles(ctx, vh, volumeAction, vlcPlayer, files); err != nil {
s.Fatal("Failed to play audio: ", err)
}
}
func playAudioFiles(ctx context.Context, vh *audio.Helper, volumeAction map[volumeControl]uiauto.Action, vlcPlayer *vlc.Vlc, files map[string]string) error {
testing.ContextLog(ctx, "Enter audio folder")
if err := vlcPlayer.EnterAudioFolder(ctx); err != nil {
testing.ContextLog(ctx, "Not entering audio folder or already in the folder")
}
for _, filename := range files {
if err := vlcPlayer.PlayAudio(ctx, filename); err != nil {
return err
}
// Mute action must be the last one since volume can't be changed after muted.
vcs := []volumeControl{volumeUp, volumeDown, volumeMute}
testing.ContextLog(ctx, "Change volume: ", vcs)
if err := pressAndCheckVolumeChange(ctx, vh, volumeAction, vcs); err != nil {
return errors.Wrapf(err, "failed to change volume by pressing %+v", vcs)
}
testing.ContextLog(ctx, "Unmute")
if err := volumeAction[volumeUnMute](ctx); err != nil {
return errors.Wrap(err, "failed to unmute")
}
volume, muted, err := getVolumeState(ctx, vh)
if err != nil {
return err
}
testing.ContextLogf(ctx, "Volume state after unmute: [volume: %d, muted: %t]", volume, muted)
}
return nil
}
func pressAndCheckVolumeChange(ctx context.Context, vh *audio.Helper, volumeAction map[volumeControl]uiauto.Action, controls []volumeControl) error {
for _, vc := range controls {
volumeBefore, err := vh.GetVolume(ctx)
if err != nil {
return err
}
if volumeBefore == 100 || volumeBefore == 0 {
if err := vh.SetVolume(ctx, audioFilesPlayingDefaultVol); err != nil {
return err
}
volumeBefore = audioFilesPlayingDefaultVol
}
if err := volumeAction[vc](ctx); err != nil {
return err
}
volumeAfter, mutedAfter, err := getVolumeState(ctx, vh)
if err != nil {
return err
}
testing.ContextLogf(ctx, "Volume changed from %d to %d, muted: %t", volumeBefore, volumeAfter, mutedAfter)
switch vc {
case volumeUp, volumeDown:
if volumeAfter == volumeBefore {
return errors.Errorf("volume level did not changed, expecting %v", vc)
}
case volumeMute:
if !mutedAfter {
return errors.New("system audio is not mute")
}
}
}
return nil
}
func getVolumeState(ctx context.Context, vh *audio.Helper) (vol int, muted bool, err error) {
vol, err = vh.GetVolume(ctx)
if err != nil {
return vol, muted, err
}
muted, err = vh.IsMuted(ctx)
return vol, muted, err
}