| // 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 |