blob: 23c7105d961fbea03d6a23c1f4d7be41ff78c88d [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "runtime_probe/functions/audio_codec.h"
#include <string>
#include <string_view>
#include <utility>
#include <base/containers/contains.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/values.h>
#include "runtime_probe/system/context.h"
#include "runtime_probe/utils/file_utils.h"
namespace runtime_probe {
namespace {
constexpr size_t kCodecFileMaxSize = 65536;
constexpr char kHdaCodecPathPattern[] = "proc/asound/card*/codec*";
constexpr std::string_view kCodecKey = "Codec:";
AudioCodecFunction::DataType ProbeI2cCodecFromFile(
const base::FilePath& asoc_path) {
std::string asoc_content;
if (!base::ReadFileToStringWithMaxSize(asoc_path, &asoc_content,
kCodecFileMaxSize)) {
if (asoc_content.size() == kCodecFileMaxSize) {
LOG(ERROR) << "Cannot read " << asoc_path
<< " because its size is greater than " << kCodecFileMaxSize;
} else {
PLOG(ERROR) << "Cannot read " << asoc_path;
}
return {};
}
AudioCodecFunction::DataType result{};
for (std::string_view codec :
base::SplitStringPiece(asoc_content, "\n", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) {
base::Value::Dict value;
value.Set("name", codec);
result.Append(std::move(value));
}
return result;
}
AudioCodecFunction::DataType ProbeHdaCodecFromFile(
const base::FilePath& procfs_path) {
std::string codec_content;
if (!base::ReadFileToStringWithMaxSize(procfs_path, &codec_content,
kCodecFileMaxSize)) {
if (codec_content.size() == kCodecFileMaxSize) {
LOG(ERROR) << "Cannot read " << procfs_path
<< " because its size is greater than " << kCodecFileMaxSize;
} else {
PLOG(ERROR) << "Cannot read " << procfs_path;
}
return {};
}
AudioCodecFunction::DataType result{};
for (std::string line :
base::SplitString(codec_content, "\n", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY)) {
if (!base::StartsWith(line, kCodecKey, base::CompareCase::SENSITIVE)) {
continue;
}
std::string raw_codec = line.substr(kCodecKey.size());
auto codec =
base::TrimWhitespaceASCII(raw_codec, base::TrimPositions::TRIM_ALL);
base::Value::Dict value;
value.Set("name", codec);
result.Append(std::move(value));
}
return result;
}
} // namespace
AudioCodecFunction::DataType AudioCodecFunction::EvalImpl() const {
DataType results{};
for (const auto& asoc_path_str : kAsocPaths) {
base::FilePath asoc_path = GetRootedPath(asoc_path_str);
if (!PathExists(asoc_path))
continue;
results = ProbeI2cCodecFromFile(asoc_path);
}
base::FilePath procfs_pattern =
Context::Get()->root_dir().Append(kHdaCodecPathPattern);
for (const auto& procfs_path : Glob(procfs_pattern)) {
auto hda_result = ProbeHdaCodecFromFile(procfs_path);
for (auto& res : hda_result) {
results.Append(std::move(res));
}
}
if (results.empty()) {
LOG(ERROR) << "Cannot find any asoc files or ALSA proc files which contain "
"the codecs.";
}
return results;
}
void AudioCodecFunction::PostHelperEvalImpl(DataType* results) const {
auto helper_results = std::move(*results);
*results = DataType();
for (auto& helper_result : helper_results) {
auto* codec = helper_result.GetDict().FindString("name");
if (codec == nullptr || base::Contains(kKnownInvalidCodecNames, *codec) ||
codec->find("HDMI") != std::string::npos) {
continue;
}
results->Append(std::move(helper_result));
}
}
} // namespace runtime_probe