summaryrefslogtreecommitdiff
path: root/sound_card_init/dsm
diff options
context:
space:
mode:
Diffstat (limited to 'sound_card_init/dsm')
-rw-r--r--sound_card_init/dsm/Cargo.lock229
-rw-r--r--sound_card_init/dsm/Cargo.toml15
-rw-r--r--sound_card_init/dsm/src/datastore.rs72
-rw-r--r--sound_card_init/dsm/src/error.rs128
-rw-r--r--sound_card_init/dsm/src/lib.rs335
-rw-r--r--sound_card_init/dsm/src/utils.rs82
-rw-r--r--sound_card_init/dsm/src/vpd.rs41
-rw-r--r--sound_card_init/dsm/src/zero_player.rs209
8 files changed, 0 insertions, 1111 deletions
diff --git a/sound_card_init/dsm/Cargo.lock b/sound_card_init/dsm/Cargo.lock
deleted file mode 100644
index 411c7527..00000000
--- a/sound_card_init/dsm/Cargo.lock
+++ /dev/null
@@ -1,229 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-[[package]]
-name = "alsa-sys"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "644d308f5822c2b39fba5a6d850f74c208bf73c61d1d2dfad62505d6960e4977"
-dependencies = [
- "libc",
- "pkg-config",
-]
-
-[[package]]
-name = "assertions"
-version = "0.1.0"
-
-[[package]]
-name = "audio_streams"
-version = "0.1.0"
-dependencies = [
- "sync",
- "sys_util",
-]
-
-[[package]]
-name = "cras-sys"
-version = "0.1.0"
-dependencies = [
- "audio_streams",
- "data_model",
-]
-
-[[package]]
-name = "cros_alsa"
-version = "0.1.0"
-dependencies = [
- "alsa-sys",
- "libc",
- "remain",
- "sys_util",
-]
-
-[[package]]
-name = "data_model"
-version = "0.1.0"
-dependencies = [
- "assertions",
-]
-
-[[package]]
-name = "dtoa"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3"
-
-[[package]]
-name = "libc"
-version = "0.2.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
-
-[[package]]
-name = "libcras"
-version = "0.1.0"
-dependencies = [
- "audio_streams",
- "cras-sys",
- "data_model",
- "libc",
- "sys_util",
-]
-
-[[package]]
-name = "linked-hash-map"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
-
-[[package]]
-name = "max98390d"
-version = "0.1.0"
-dependencies = [
- "audio_streams",
- "cros_alsa",
- "libcras",
- "remain",
- "serde",
- "serde_yaml",
- "sound_card_util",
- "sys_util",
-]
-
-[[package]]
-name = "pkg-config"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
-
-[[package]]
-name = "poll_token_derive"
-version = "0.1.0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "remain"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99c861227fc40c8da6fdaa3d58144ac84c0537080a43eb1d7d45c28f88dcb888"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_yaml"
-version = "0.8.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
-dependencies = [
- "dtoa",
- "linked-hash-map",
- "serde",
- "yaml-rust",
-]
-
-[[package]]
-name = "sound_card_util"
-version = "0.1.0"
-dependencies = [
- "cros_alsa",
- "remain",
- "sys_util",
-]
-
-[[package]]
-name = "syn"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-xid",
-]
-
-[[package]]
-name = "sync"
-version = "0.1.0"
-
-[[package]]
-name = "sys_util"
-version = "0.1.0"
-dependencies = [
- "data_model",
- "libc",
- "poll_token_derive",
- "sync",
- "syscall_defines",
- "tempfile",
-]
-
-[[package]]
-name = "syscall_defines"
-version = "0.1.0"
-
-[[package]]
-name = "tempfile"
-version = "3.0.7"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
-
-[[package]]
-name = "yaml-rust"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
-dependencies = [
- "linked-hash-map",
-]
diff --git a/sound_card_init/dsm/Cargo.toml b/sound_card_init/dsm/Cargo.toml
deleted file mode 100644
index 280896d2..00000000
--- a/sound_card_init/dsm/Cargo.toml
+++ /dev/null
@@ -1,15 +0,0 @@
-[package]
-name = "dsm"
-version = "0.1.0"
-authors = ["The Chromium OS Authors"]
-edition = "2018"
-description = "The boot time calibration logic for smart amp"
-
-[dependencies]
-cros_alsa = "*"
-audio_streams = "*"
-libcras = "*"
-remain = "0.2.1"
-serde = { version = "1.0", features = ["derive"]}
-serde_yaml = "0.8.11"
-sys_util = "*" \ No newline at end of file
diff --git a/sound_card_init/dsm/src/datastore.rs b/sound_card_init/dsm/src/datastore.rs
deleted file mode 100644
index f0180cc2..00000000
--- a/sound_card_init/dsm/src/datastore.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2020 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.
-use std::fs::{remove_file, File};
-use std::io::{prelude::*, BufReader, BufWriter};
-use std::path::PathBuf;
-
-use serde::{Deserialize, Serialize};
-use sys_util::info;
-
-use crate::error::{Error, Result};
-
-/// `Datastore`, which stores and reads calibration values in yaml format.
-#[derive(Debug, Deserialize, Serialize, Copy, Clone)]
-pub enum Datastore {
- /// Indicates using values in VPD.
- UseVPD,
- DSM {
- rdc: i32,
- temp: i32,
- },
-}
-
-impl Datastore {
- /// The dir of datastore.
- pub const DATASTORE_DIR: &'static str = "/var/lib/sound_card_init";
-
- /// Creates a `Datastore` and initializes its fields from the datastore file.
- pub fn from_file(snd_card: &str, channel: usize) -> Result<Datastore> {
- let path = Self::path(snd_card, channel);
- let reader =
- BufReader::new(File::open(&path).map_err(|e| Error::FileIOFailed(path.to_owned(), e))?);
- let datastore: Datastore =
- serde_yaml::from_reader(reader).map_err(|e| Error::SerdeError(path.to_owned(), e))?;
- Ok(datastore)
- }
-
- /// Saves a `Datastore` to file.
- pub fn save(&self, snd_card: &str, channel: usize) -> Result<()> {
- let path = Self::path(snd_card, channel);
-
- let mut writer = BufWriter::new(
- File::create(&path).map_err(|e| Error::FileIOFailed(path.to_owned(), e))?,
- );
- writer
- .write(
- serde_yaml::to_string(self)
- .map_err(|e| Error::SerdeError(path.to_owned(), e))?
- .as_bytes(),
- )
- .map_err(|e| Error::FileIOFailed(path.to_owned(), e))?;
- writer
- .flush()
- .map_err(|e| Error::FileIOFailed(path.to_owned(), e))?;
- info!("update Datastore {}: {:?}", path.to_string_lossy(), self);
- Ok(())
- }
-
- /// Deletes the datastore file.
- pub fn delete(snd_card: &str, channel: usize) -> Result<()> {
- let path = Self::path(snd_card, channel);
- remove_file(&path).map_err(|e| Error::FileIOFailed(path.to_owned(), e))?;
- info!("datastore: {:#?} is deleted.", path);
- Ok(())
- }
-
- fn path(snd_card: &str, channel: usize) -> PathBuf {
- PathBuf::from(Self::DATASTORE_DIR)
- .join(snd_card)
- .join(format!("calib_{}", channel))
- }
-}
diff --git a/sound_card_init/dsm/src/error.rs b/sound_card_init/dsm/src/error.rs
deleted file mode 100644
index 4b6e8dc2..00000000
--- a/sound_card_init/dsm/src/error.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2020 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.
-use std::any::Any;
-use std::error;
-use std::fmt;
-use std::io;
-use std::num::ParseIntError;
-use std::path::PathBuf;
-use std::sync::PoisonError;
-use std::time;
-
-use remain::sorted;
-
-use crate::CalibData;
-
-pub type Result<T> = std::result::Result<T, Error>;
-
-#[sorted]
-#[derive(Debug)]
-pub enum Error {
- AlsaCardError(cros_alsa::CardError),
- AlsaControlError(cros_alsa::ControlError),
- AlsaControlTLVError(cros_alsa::ControlTLVError),
- CalibrationTimeout,
- CrasClientFailed(libcras::Error),
- DeserializationFailed(String, serde_yaml::Error),
- DSMParamUpdateFailed(cros_alsa::ControlTLVError),
- FileIOFailed(PathBuf, io::Error),
- InternalSpeakerNotFound,
- InvalidDatastore,
- InvalidDSMParam,
- InvalidShutDownTime,
- InvalidTemperature(f32),
- LargeCalibrationDiff(CalibData),
- MissingDSMParam,
- MutexPoisonError,
- NewPlayStreamFailed(libcras::BoxError),
- NextPlaybackBufferFailed(libcras::BoxError),
- PlaybackFailed(io::Error),
- SerdeError(PathBuf, serde_yaml::Error),
- StartPlaybackTimeout,
- SystemTimeError(time::SystemTimeError),
- UnsupportedSoundCard(String),
- VPDParseFailed(String, ParseIntError),
- WorkerPanics(Box<dyn Any + Send + 'static>),
- ZeroPlayerIsNotRunning,
- ZeroPlayerIsRunning,
-}
-
-impl PartialEq for Error {
- // Implement eq for more Error when needed.
- fn eq(&self, other: &Error) -> bool {
- match (self, other) {
- (Error::InvalidDSMParam, Error::InvalidDSMParam) => true,
- _ => false,
- }
- }
-}
-
-impl From<cros_alsa::CardError> for Error {
- fn from(err: cros_alsa::CardError) -> Error {
- Error::AlsaCardError(err)
- }
-}
-
-impl From<cros_alsa::ControlError> for Error {
- fn from(err: cros_alsa::ControlError) -> Error {
- Error::AlsaControlError(err)
- }
-}
-
-impl From<cros_alsa::ControlTLVError> for Error {
- fn from(err: cros_alsa::ControlTLVError) -> Error {
- Error::AlsaControlTLVError(err)
- }
-}
-
-impl<T> From<PoisonError<T>> for Error {
- fn from(_: PoisonError<T>) -> Error {
- Error::MutexPoisonError
- }
-}
-
-impl error::Error for Error {}
-
-impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- use Error::*;
- match self {
- AlsaCardError(e) => write!(f, "AlsaCardError: {}", e),
- AlsaControlError(e) => write!(f, "AlsaControlError: {}", e),
- AlsaControlTLVError(e) => write!(f, "AlsaControlTLVError: {}", e),
- CalibrationTimeout => write!(f, "calibration is not finished in time"),
- DSMParamUpdateFailed(e) => write!(f, "failed to update DsmParam, err: {}", e),
- CrasClientFailed(e) => write!(f, "failed to create cras client: {}", e),
- DeserializationFailed(file_path, e) => {
- write!(f, "failed to parse {}: {}", file_path, e)
- }
- FileIOFailed(file_path, e) => write!(f, "{:#?}: {}", file_path, e),
- InvalidShutDownTime => write!(f, "invalid shutdown time"),
- InternalSpeakerNotFound => write!(f, "internal speaker is not found in cras"),
- InvalidTemperature(temp) => write!(
- f,
- "invalid calibration temperature: {}, and there is no datastore",
- temp
- ),
- InvalidDatastore => write!(f, "invalid datastore format"),
- InvalidDSMParam => write!(f, "invalid dsm param from kcontrol"),
- LargeCalibrationDiff(calib) => {
- write!(f, "calibration difference is too large, calib: {:?}", calib)
- }
- MissingDSMParam => write!(f, "missing dsm_param.bin"),
- MutexPoisonError => write!(f, "mutex is poisoned"),
- NewPlayStreamFailed(e) => write!(f, "{}", e),
- NextPlaybackBufferFailed(e) => write!(f, "{}", e),
- PlaybackFailed(e) => write!(f, "{}", e),
- SerdeError(file_path, e) => write!(f, "{:?}: {}", file_path, e),
- StartPlaybackTimeout => write!(f, "playback is not started in time"),
- SystemTimeError(e) => write!(f, "{}", e),
- UnsupportedSoundCard(name) => write!(f, "unsupported sound card: {}", name),
- VPDParseFailed(file_path, e) => write!(f, "failed to parse vpd {}: {}", file_path, e),
- WorkerPanics(e) => write!(f, "run_play_zero_worker panics: {:#?}", e),
- ZeroPlayerIsNotRunning => write!(f, "zero player is not running"),
- ZeroPlayerIsRunning => write!(f, "zero player is running"),
- }
- }
-}
diff --git a/sound_card_init/dsm/src/lib.rs b/sound_card_init/dsm/src/lib.rs
deleted file mode 100644
index 0b3ec64c..00000000
--- a/sound_card_init/dsm/src/lib.rs
+++ /dev/null
@@ -1,335 +0,0 @@
-// Copyright 2020 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.
-//! `dsm` crate implements the required initialization workflows for smart amps.
-
-mod datastore;
-mod error;
-pub mod utils;
-mod vpd;
-mod zero_player;
-
-use std::{
- thread,
- time::{Duration, SystemTime, UNIX_EPOCH},
-};
-
-use libcras::{CrasClient, CrasNodeType};
-use sys_util::{error, info};
-
-use crate::datastore::Datastore;
-pub use crate::error::{Error, Result};
-use crate::utils::{run_time, shutdown_time};
-use crate::vpd::VPD;
-pub use crate::zero_player::ZeroPlayer;
-
-#[derive(Debug, Clone, Copy)]
-/// `CalibData` represents the calibration data.
-pub struct CalibData {
- /// The DC resistance of the speaker is DSM unit.
- pub rdc: i32,
- /// The ambient temperature in celsius unit at which the rdc is measured.
- pub temp: f32,
-}
-
-/// `TempConverter` converts the temperature value between celsius and unit in VPD::dsm_calib_temp.
-pub struct TempConverter {
- vpd_to_celsius: fn(i32) -> f32,
- celsius_to_vpd: fn(f32) -> i32,
-}
-
-impl Default for TempConverter {
- fn default() -> Self {
- let vpd_to_celsius = |x: i32| x as f32;
- let celsius_to_vpd = |x: f32| x.round() as i32;
- Self {
- vpd_to_celsius,
- celsius_to_vpd,
- }
- }
-}
-
-impl TempConverter {
- /// Creates a `TempConverter`
- ///
- /// # Arguments
- ///
- /// * `vpd_to_celsius` - function to convert VPD::dsm_calib_temp to celsius unit`
- /// * `celsius_to_vpd` - function to convert celsius unit to VPD::dsm_calib_temp`
- /// # Results
- ///
- /// * `TempConverter` - it converts the temperature value between celsius and unit in VPD::dsm_calib_temp.
- pub fn new(vpd_to_celsius: fn(i32) -> f32, celsius_to_vpd: fn(f32) -> i32) -> Self {
- Self {
- vpd_to_celsius,
- celsius_to_vpd,
- }
- }
-}
-
-/// `SpeakerStatus` are the possible return results of
-/// DSM::check_speaker_over_heated_workflow.
-pub enum SpeakerStatus {
- ///`SpeakerStatus::Cold` means the speakers are not overheated and the Amp can
- /// trigger the boot time calibration.
- Cold,
- /// `SpeakerStatus::Hot(Vec<CalibData>)` means the speakers may be too hot for calibration.
- /// The boot time calibration should be skipped and the Amp should use the previous
- /// calibration values returned by the enum.
- Hot(Vec<CalibData>),
-}
-
-/// `DSM`, which implements the required initialization workflows for smart amps.
-pub struct DSM {
- snd_card: String,
- num_channels: usize,
- temp_converter: TempConverter,
- rdc_to_ohm: fn(i32) -> f32,
- temp_upper_limit: f32,
- temp_lower_limit: f32,
-}
-
-impl DSM {
- const SPEAKER_COOL_DOWN_TIME: Duration = Duration::from_secs(180);
- const CALI_ERROR_UPPER_LIMIT: f32 = 0.3;
- const CALI_ERROR_LOWER_LIMIT: f32 = 0.03;
-
- /// Creates a `DSM`
- ///
- /// # Arguments
- ///
- /// * `snd_card` - `sound card name`.
- /// * `num_channels` - `number of channels`.
- /// * `rdc_to_ohm` - `fn(rdc: i32) -> f32 to convert the CalibData::rdc to ohm unit`.
- /// * `temp_upper_limit` - the high limit of the valid ambient temperature in dsm unit.
- /// * `temp_lower_limit` - the low limit of the valid ambient temperature in dsm unit.
- ///
- /// # Results
- ///
- /// * `DSM` - It implements the required initialization workflows for smart amps.
- pub fn new(
- snd_card: &str,
- num_channels: usize,
- rdc_to_ohm: fn(i32) -> f32,
- temp_upper_limit: f32,
- temp_lower_limit: f32,
- ) -> Self {
- Self {
- snd_card: snd_card.to_owned(),
- num_channels,
- rdc_to_ohm,
- temp_converter: TempConverter::default(),
- temp_upper_limit,
- temp_lower_limit,
- }
- }
-
- /// Sets self.temp_converter to the given temp_converter.
- ///
- /// # Arguments
- ///
- /// * `temp_converter` - the convert function to use.
- pub fn set_temp_converter(&mut self, temp_converter: TempConverter) {
- self.temp_converter = temp_converter;
- }
-
- /// Checks whether the speakers are overheated or not according to the previous shutdown time.
- /// The boot time calibration should be skipped when the speakers may be too hot
- /// and the Amp should use the previous calibration value returned by the
- /// SpeakerStatus::Hot(Vec<CalibData>).
- ///
- /// # Results
- ///
- /// * `SpeakerStatus::Cold` - which means the speakers are not overheated and the Amp can
- /// trigger the boot time calibration.
- /// * `SpeakerStatus::Hot(Vec<CalibData>)` - when the speakers may be too hot. The boot
- /// time calibration should be skipped and the Amp should use the previous calibration values
- /// returned by the enum.
- ///
- /// # Errors
- ///
- /// * The speakers are overheated and there are no previous calibration values stored.
- /// * Cannot determine whether the speakers are overheated as previous shutdown time record is
- /// invalid.
- pub fn check_speaker_over_heated_workflow(&self) -> Result<SpeakerStatus> {
- if self.is_first_boot() {
- return Ok(SpeakerStatus::Cold);
- }
- match self.is_speaker_over_heated() {
- Ok(overheated) => {
- if overheated {
- let calib: Vec<CalibData> = (0..self.num_channels)
- .map(|ch| -> Result<CalibData> { self.get_previous_calibration_value(ch) })
- .collect::<Result<Vec<CalibData>>>()?;
- info!("the speakers are hot, the boot time calibration should be skipped");
- return Ok(SpeakerStatus::Hot(calib));
- }
- Ok(SpeakerStatus::Cold)
- }
- Err(err) => {
- // We cannot assume the speakers are not replaced or not overheated
- // when the shutdown time file is invalid; therefore we can not use the datastore
- // value anymore and we can not trigger boot time calibration.
- for ch in 0..self.num_channels {
- if let Err(e) = Datastore::delete(&self.snd_card, ch) {
- error!("error delete datastore: {}", e);
- }
- }
- Err(err)
- }
- }
- }
-
- /// Decides a good calibration value and updates the stored value according to the following
- /// logic:
- /// * Returns the previous value if the ambient temperature is not within a valid range.
- /// * Returns Error::LargeCalibrationDiff if rdc difference is larger than
- /// `CALI_ERROR_UPPER_LIMIT`.
- /// * Returns the previous value if the rdc difference is smaller than `CALI_ERROR_LOWER_LIMIT`.
- /// * Returns the boot time calibration value and updates the datastore value if the rdc.
- /// difference is between `CALI_ERROR_UPPER_LIMIT` and `CALI_ERROR_LOWER_LIMIT`.
- ///
- /// # Arguments
- ///
- /// * `card` - `&Card`.
- /// * `channel` - `channel number`.
- /// * `calib_data` - `boot time calibrated data`.
- ///
- /// # Results
- ///
- /// * `CalibData` - the calibration data to be applied according to the deciding logic.
- ///
- /// # Errors
- ///
- /// * VPD does not exist.
- /// * rdc difference is larger than `CALI_ERROR_UPPER_LIMIT`.
- /// * Failed to update Datastore.
- pub fn decide_calibration_value_workflow(
- &self,
- channel: usize,
- calib_data: CalibData,
- ) -> Result<CalibData> {
- if calib_data.temp < self.temp_lower_limit || calib_data.temp > self.temp_upper_limit {
- info!("invalid temperature: {}.", calib_data.temp);
- return self
- .get_previous_calibration_value(channel)
- .map_err(|_| Error::InvalidTemperature(calib_data.temp));
- }
- let (datastore_exist, previous_calib) = match self.get_previous_calibration_value(channel) {
- Ok(previous_calib) => (true, previous_calib),
- Err(e) => {
- info!("{}, use vpd as previous calibration value", e);
- (false, self.get_vpd_calibration_value(channel)?)
- }
- };
-
- let diff = {
- let calib_rdc_ohm = (self.rdc_to_ohm)(calib_data.rdc);
- let previous_rdc_ohm = (self.rdc_to_ohm)(previous_calib.rdc);
- (calib_rdc_ohm - previous_rdc_ohm) / previous_rdc_ohm
- };
- if diff > Self::CALI_ERROR_UPPER_LIMIT {
- Err(Error::LargeCalibrationDiff(calib_data))
- } else if diff < Self::CALI_ERROR_LOWER_LIMIT {
- if !datastore_exist {
- Datastore::UseVPD.save(&self.snd_card, channel)?;
- }
- Ok(previous_calib)
- } else {
- Datastore::DSM {
- rdc: calib_data.rdc,
- temp: (self.temp_converter.celsius_to_vpd)(calib_data.temp),
- }
- .save(&self.snd_card, channel)?;
- Ok(calib_data)
- }
- }
-
- /// Gets the calibration values from vpd.
- ///
- /// # Results
- ///
- /// * `Vec<CalibData>` - the calibration values in vpd.
- ///
- /// # Errors
- ///
- /// * Failed to read vpd.
- pub fn get_all_vpd_calibration_value(&self) -> Result<Vec<CalibData>> {
- (0..self.num_channels)
- .map(|ch| self.get_vpd_calibration_value(ch))
- .collect::<Result<Vec<_>>>()
- }
-
- /// Blocks until the internal speakers are ready.
- ///
- /// # Errors
- ///
- /// * Failed to wait the internal speakers to be ready.
- pub fn wait_for_speakers_ready(&self) -> Result<()> {
- let find_speaker = || -> Result<()> {
- let cras_client = CrasClient::new().map_err(Error::CrasClientFailed)?;
- let _node = cras_client
- .output_nodes()
- .find(|node| node.node_type == CrasNodeType::CRAS_NODE_TYPE_INTERNAL_SPEAKER)
- .ok_or(Error::InternalSpeakerNotFound)?;
- Ok(())
- };
- // TODO(b/155007305): Implement cras_client.wait_node_change and use it here.
- const RETRY: usize = 3;
- const RETRY_INTERVAL: Duration = Duration::from_millis(500);
- for _ in 0..RETRY {
- match find_speaker() {
- Ok(_) => return Ok(()),
- Err(e) => error!("retry on finding speaker: {}", e),
- };
- thread::sleep(RETRY_INTERVAL);
- }
- Err(Error::InternalSpeakerNotFound)
- }
-
- fn is_first_boot(&self) -> bool {
- !run_time::exists(&self.snd_card)
- }
-
- // If (Current time - the latest CRAS shutdown time) < cool_down_time, we assume that
- // the speakers may be overheated.
- fn is_speaker_over_heated(&self) -> Result<bool> {
- let last_run = run_time::from_file(&self.snd_card)?;
- let last_shutdown = shutdown_time::from_file()?;
- if last_shutdown < last_run {
- return Err(Error::InvalidShutDownTime);
- }
-
- let now = SystemTime::now()
- .duration_since(UNIX_EPOCH)
- .map_err(Error::SystemTimeError)?;
-
- let elapsed = now
- .checked_sub(last_shutdown)
- .ok_or(Error::InvalidShutDownTime)?;
-
- if elapsed < Self::SPEAKER_COOL_DOWN_TIME {
- return Ok(true);
- }
- Ok(false)
- }
-
- fn get_previous_calibration_value(&self, ch: usize) -> Result<CalibData> {
- let sci_calib = Datastore::from_file(&self.snd_card, ch)?;
- match sci_calib {
- Datastore::UseVPD => self.get_vpd_calibration_value(ch),
- Datastore::DSM { rdc, temp } => Ok(CalibData {
- rdc,
- temp: (self.temp_converter.vpd_to_celsius)(temp),
- }),
- }
- }
-
- fn get_vpd_calibration_value(&self, channel: usize) -> Result<CalibData> {
- let vpd = VPD::new(channel)?;
- Ok(CalibData {
- rdc: vpd.dsm_calib_r0,
- temp: (self.temp_converter.vpd_to_celsius)(vpd.dsm_calib_temp),
- })
- }
-}
diff --git a/sound_card_init/dsm/src/utils.rs b/sound_card_init/dsm/src/utils.rs
deleted file mode 100644
index 64f6c972..00000000
--- a/sound_card_init/dsm/src/utils.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2020 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.
-//! It contains common utils shared within sound_card_init.
-#![deny(missing_docs)]
-
-use std::fs::File;
-use std::io::{prelude::*, BufReader, BufWriter};
-use std::path::PathBuf;
-use std::time::Duration;
-
-use crate::datastore::Datastore;
-use crate::error::{Error, Result};
-
-fn duration_from_file(path: &PathBuf) -> Result<Duration> {
- let reader =
- BufReader::new(File::open(&path).map_err(|e| Error::FileIOFailed(path.clone(), e))?);
- serde_yaml::from_reader(reader).map_err(|e| Error::SerdeError(path.clone(), e))
-}
-
-/// The utils to parse CRAS shutdown time file.
-pub mod shutdown_time {
- use super::*;
- // The path of CRAS shutdown time file.
- const SHUTDOWN_TIME_FILE: &str = "/var/lib/cras/stop";
-
- /// Reads the unix time from CRAS shutdown time file.
- pub fn from_file() -> Result<Duration> {
- duration_from_file(&PathBuf::from(SHUTDOWN_TIME_FILE))
- }
-}
-
-/// The utils to create and parse sound_card_init run time file.
-pub mod run_time {
- use std::time::SystemTime;
-
- use super::*;
- // The filename of sound_card_init run time file.
- const RUN_TIME_FILE: &str = "run";
-
- /// Returns the sound_card_init run time file existence.
- pub fn exists(snd_card: &str) -> bool {
- run_time_file(snd_card).exists()
- }
-
- /// Reads the unix time from sound_card_init run time file.
- pub fn from_file(snd_card: &str) -> Result<Duration> {
- duration_from_file(&run_time_file(snd_card))
- }
-
- /// Saves the current unix time to sound_card_init run time file.
- pub fn now_to_file(snd_card: &str) -> Result<()> {
- match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
- Ok(t) => to_file(snd_card, t),
- Err(e) => Err(Error::SystemTimeError(e)),
- }
- }
-
- /// Saves the unix time to sound_card_init run time file.
- pub fn to_file(snd_card: &str, duration: Duration) -> Result<()> {
- let path = run_time_file(snd_card);
- let mut writer =
- BufWriter::new(File::create(&path).map_err(|e| Error::FileIOFailed(path.clone(), e))?);
- writer
- .write_all(
- serde_yaml::to_string(&duration)
- .map_err(|e| Error::SerdeError(path.clone(), e))?
- .as_bytes(),
- )
- .map_err(|e| Error::FileIOFailed(path.clone(), e))?;
- writer
- .flush()
- .map_err(|e| Error::FileIOFailed(path.clone(), e))?;
- Ok(())
- }
-
- fn run_time_file(snd_card: &str) -> PathBuf {
- PathBuf::from(Datastore::DATASTORE_DIR)
- .join(snd_card)
- .join(RUN_TIME_FILE)
- }
-}
diff --git a/sound_card_init/dsm/src/vpd.rs b/sound_card_init/dsm/src/vpd.rs
deleted file mode 100644
index b00864cc..00000000
--- a/sound_card_init/dsm/src/vpd.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2020 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.
-use std::fs::File;
-use std::io::prelude::*;
-use std::io::BufReader;
-use std::path::PathBuf;
-
-use crate::error::{Error, Result};
-
-const VPD_DIR: &str = "/sys/firmware/vpd/ro/vpdfile";
-
-/// `VPD`, which represents the amplifier factory calibration values.
-#[derive(Default, Debug)]
-pub struct VPD {
- pub dsm_calib_r0: i32,
- pub dsm_calib_temp: i32,
-}
-
-impl VPD {
- /// Creates a `VPD` and initializes its fields from VPD_DIR/dsm_calib_r0_{channel}.
- /// # Arguments
- ///
- /// * `channel` - channel number.
- pub fn new(channel: usize) -> Result<VPD> {
- let mut vpd: VPD = Default::default();
- vpd.dsm_calib_r0 = read_vpd_files(&format!("dsm_calib_r0_{}", channel))?;
- vpd.dsm_calib_temp = read_vpd_files(&format!("dsm_calib_temp_{}", channel))?;
- Ok(vpd)
- }
-}
-
-fn read_vpd_files(file: &str) -> Result<i32> {
- let path = PathBuf::from(VPD_DIR).with_file_name(file);
- let io_err = |e| Error::FileIOFailed(path.to_owned(), e);
- let mut reader = BufReader::new(File::open(&path).map_err(io_err)?);
- let mut line = String::new();
- reader.read_line(&mut line).map_err(io_err)?;
- line.parse::<i32>()
- .map_err(|e| Error::VPDParseFailed(path.to_string_lossy().to_string(), e))
-}
diff --git a/sound_card_init/dsm/src/zero_player.rs b/sound_card_init/dsm/src/zero_player.rs
deleted file mode 100644
index 441f7ffa..00000000
--- a/sound_card_init/dsm/src/zero_player.rs
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2020 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.
-use std::io::Write;
-use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Condvar, Mutex};
-use std::thread;
-use std::thread::JoinHandle;
-use std::time::Duration;
-
-use audio_streams::SampleFormat;
-use libcras::{CrasClient, CrasNodeType};
-use sys_util::error;
-
-use crate::error::{Error, Result};
-
-/// `ZeroPlayer` provides the functionality to play zeros sample in the background thread.
-#[derive(Default)]
-pub struct ZeroPlayer {
- thread_info: Option<PlayZeroWorkerInfo>,
-}
-
-impl Drop for ZeroPlayer {
- fn drop(&mut self) {
- if self.thread_info.is_some() {
- if let Err(e) = self.stop() {
- error!("{}", e);
- }
- }
- }
-}
-
-impl ZeroPlayer {
- /// It takes about 400 ms to get CRAS_NODE_TYPE_INTERNAL_SPEAKER during the boot time.
- const TIMEOUT: Duration = Duration::from_millis(1000);
-
- /// Returns whether the ZeroPlayer is running.
- pub fn running(&self) -> bool {
- self.thread_info.is_some()
- }
-
- /// Starts to play zeros for at most `max_playback_time`.
- /// This function blocks and returns until playback has started for `min_playback_time`.
- /// This function must be called when self.running() returns false.
- ///
- /// # Arguments
- ///
- /// * `min_playback_time` - It blocks and returns until playback has started for
- /// `min_playback_time`.
- ///
- /// # Errors
- ///
- /// * If it's called when the `ZeroPlayer` is already running.
- /// * Failed to find internal speakers.
- /// * Failed to start the background thread.
- pub fn start(&mut self, min_playback_time: Duration) -> Result<()> {
- if self.running() {
- return Err(Error::ZeroPlayerIsRunning);
- }
- self.thread_info = Some(PlayZeroWorkerInfo::new(min_playback_time));
- if let Some(thread_info) = &mut self.thread_info {
- // Block until playback of zeros has started for min_playback_time or timeout.
- let (lock, cvar) = &*(thread_info.ready);
- let result = cvar.wait_timeout_while(
- lock.lock()?,
- min_playback_time + ZeroPlayer::TIMEOUT,
- |&mut is_ready| !is_ready,
- )?;
- if result.1.timed_out() {
- return Err(Error::StartPlaybackTimeout);
- }
- }
- Ok(())
- }
-
- /// Stops playing zeros in the background thread.
- /// This function must be called when self.running() returns true.
- ///
- /// # Errors
- ///
- /// * If it's called again when the `ZeroPlayer` is not running.
- /// * Failed to play zeros to internal speakers via CRAS client.
- /// * Failed to join the background thread.
- pub fn stop(&mut self) -> Result<()> {
- match self.thread_info.take() {
- Some(mut thread_info) => Ok(thread_info.destroy()?),
- None => Err(Error::ZeroPlayerIsNotRunning),
- }
- }
-}
-
-// Audio thread book-keeping data
-struct PlayZeroWorkerInfo {
- thread: Option<JoinHandle<Result<()>>>,
- // Uses `thread_run` to notify the background thread to stop.
- thread_run: Arc<AtomicBool>,
- // The background thread uses `ready` to notify the main thread that playback
- // of zeros has started for min_playback_time.
- ready: Arc<(Mutex<bool>, Condvar)>,
-}
-
-impl Drop for PlayZeroWorkerInfo {
- fn drop(&mut self) {
- if let Err(e) = self.destroy() {
- error!("{}", e);
- }
- }
-}
-
-impl PlayZeroWorkerInfo {
- // Spawns the PlayZeroWorker.
- fn new(min_playback_time: Duration) -> Self {
- let thread_run = Arc::new(AtomicBool::new(false));
- let ready = Arc::new((Mutex::new(false), Condvar::new()));
- let mut worker = PlayZeroWorker::new(min_playback_time, thread_run.clone(), ready.clone());
- Self {
- thread: Some(thread::spawn(move || -> Result<()> {
- worker.run()?;
- Ok(())
- })),
- thread_run,
- ready,
- }
- }
-
- // Joins the PlayZeroWorker.
- fn destroy(&mut self) -> Result<()> {
- self.thread_run.store(false, Ordering::Relaxed);
- if let Some(handle) = self.thread.take() {
- let res = handle.join().map_err(Error::WorkerPanics)?;
- return match res {
- Err(e) => Err(e),
- Ok(_) => Ok(()),
- };
- }
- Ok(())
- }
-}
-
-struct PlayZeroWorker {
- min_playback_time: Duration,
- // Uses `thread_run` to notify the background thread to stop.
- thread_run: Arc<AtomicBool>,
- // The background thread uses `ready` to notify the main thread that playback
- // of zeros has started for min_playback_time.
- ready: Arc<(Mutex<bool>, Condvar)>,
-}
-
-impl PlayZeroWorker {
- const FRAMES_PER_BUFFER: usize = 256;
- const FRAME_RATE: u32 = 48000;
- const NUM_CHANNELS: usize = 2;
- const FORMAT: SampleFormat = SampleFormat::S16LE;
-
- fn new(
- min_playback_time: Duration,
- thread_run: Arc<AtomicBool>,
- ready: Arc<(Mutex<bool>, Condvar)>,
- ) -> Self {
- Self {
- min_playback_time,
- thread_run,
- ready,
- }
- }
-
- fn run(&mut self) -> Result<()> {
- let mut cras_client = CrasClient::new().map_err(Error::CrasClientFailed)?;
- // TODO(b/155007305): Implement cras_client.wait_node_change and use it here.
- let node = cras_client
- .output_nodes()
- .find(|node| node.node_type == CrasNodeType::CRAS_NODE_TYPE_INTERNAL_SPEAKER)
- .ok_or(Error::InternalSpeakerNotFound)?;
- let local_buffer =
- vec![0u8; Self::FRAMES_PER_BUFFER * Self::NUM_CHANNELS * Self::FORMAT.sample_bytes()];
- let min_playback_iterations = (Self::FRAME_RATE
- * self.min_playback_time.as_millis() as u32)
- / Self::FRAMES_PER_BUFFER as u32
- / 1000;
- let (_control, mut stream) = cras_client
- .new_pinned_playback_stream(
- node.iodev_index,
- Self::NUM_CHANNELS,
- Self::FORMAT,
- Self::FRAME_RATE,
- Self::FRAMES_PER_BUFFER,
- )
- .map_err(|e| Error::NewPlayStreamFailed(e))?;
-
- let mut iter = 0;
- self.thread_run.store(true, Ordering::Relaxed);
- while self.thread_run.load(Ordering::Relaxed) {
- let mut buffer = stream
- .next_playback_buffer()
- .map_err(|e| Error::NextPlaybackBufferFailed(e))?;
- let _write_frames = buffer.write(&local_buffer).map_err(Error::PlaybackFailed)?;
-
- // Notifies the main thread that playback of zeros has started for min_playback_time.
- if iter == min_playback_iterations {
- let (lock, cvar) = &*self.ready;
- let mut is_ready = lock.lock()?;
- *is_ready = true;
- cvar.notify_one();
- }
- iter += 1;
- }
- Ok(())
- }
-}