blob: 3ec2ff8969d689118d5f60a1c848947ec40fd8f4 [file] [log] [blame] [edit]
// Copyright 2021 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 capturefromelement provides common code for WebRTC's captureStream()
// tests; this API is used for <video> and <canvas> capture, see e.g.
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/captureStream
// and https://w3c.github.io/mediacapture-fromelement/.
package capturefromelement
import (
"context"
"net/http"
"net/http/httptest"
"sync"
"time"
"chromiumos/tast/common/perf"
"chromiumos/tast/errors"
"chromiumos/tast/local/chrome"
"chromiumos/tast/local/graphics"
"chromiumos/tast/testing"
)
const (
// htmlFile is the file containing the HTML+JS code exercising captureStream().
htmlFile = "capturefromelement.html"
)
// CanvasSource defines what is fed to the <canvas> that we can capture from.
type CanvasSource int
const (
// UseGlClearColor indicates flipping colours using WebGL's clearColor().
UseGlClearColor CanvasSource = iota
// UseVideo indicates using a GetUserMedia() captured stream as canvas source.
UseVideo
)
// RunCaptureStream drives the code verifying the captureStream() functionality.
// measurementDuration, if != 0, specifies the time to collect performance
// metrics; conversely if == 0 the test instructs JS code to verify the capture
// correctness and finishes immediately.
func RunCaptureStream(ctx context.Context, s *testing.State, cr *chrome.Chrome, source CanvasSource, measurementDuration time.Duration) error {
server := httptest.NewServer(http.FileServer(s.DataFileSystem()))
defer server.Close()
conn, err := cr.NewConn(ctx, server.URL+"/"+htmlFile)
if err != nil {
return errors.Wrapf(err, "failed to open %v", htmlFile)
}
defer conn.Close()
defer conn.CloseTarget(ctx)
// Only validate contents if we're not measuring perf.
validate := measurementDuration == 0
if source == UseGlClearColor {
if err := conn.Call(ctx, nil, "captureFromCanvasWithAlternatingColoursAndInspect", validate); err != nil {
return errors.Wrap(err, "failed to run test HTML")
}
} else if source == UseVideo {
if err := conn.Call(ctx, nil, "captureFromCanvasWithVideoAndInspect", validate); err != nil {
return errors.Wrap(err, "failed to run test HTML")
}
} else {
return errors.Errorf("unknown CanvasSource: %d", source)
}
// If the caller specifies no measurementDuration, then return immediately.
if validate {
return nil
}
p := perf.NewValues()
var gpuErr, cStateErr, cpuErr error
var wg sync.WaitGroup
wg.Add(3)
go func() {
defer wg.Done()
gpuErr = graphics.MeasureGPUCounters(ctx, measurementDuration, p)
}()
go func() {
defer wg.Done()
cStateErr = graphics.MeasurePackageCStateCounters(ctx, measurementDuration, p)
}()
go func() {
defer wg.Done()
cpuErr = graphics.MeasureCPUUsageAndPower(ctx, 0, measurementDuration, p)
}()
wg.Wait()
if gpuErr != nil {
return errors.Wrap(gpuErr, "failed to measure GPU counters")
}
if cStateErr != nil {
return errors.Wrap(cStateErr, "failed to measure Package C-State residency")
}
if cpuErr != nil {
return errors.Wrap(cpuErr, "failed to measure CPU/Package power")
}
p.Save(s.OutDir())
return nil
}
// DataFiles returns a list of files required to run the tests in this package.
func DataFiles() []string {
return []string{
htmlFile,
"third_party/blackframe.js",
"third_party/three.js/three.module.js",
}
}