summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2021-03-03 05:57:31 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2021-03-03 05:57:31 +0000
commit0aaab56eba431583969e73f177a0efdcebf46cac (patch)
treed5ef5f1d516d12301b0a65b5dbfea16938588270
parente46060c4528226af1a1089a123a21e537544aaa0 (diff)
parent26b34cb4fe3996e9d05e4111ad98a64875ed06dd (diff)
downloadadhd-0aaab56eba431583969e73f177a0efdcebf46cac.tar.gz
Merge "Revert^2 "Merge branch 'upstream-master'""
-rw-r--r--audio_streams/README.md2
-rw-r--r--audio_streams/src/audio_streams.rs65
-rw-r--r--audio_streams/src/capture.rs24
-rw-r--r--cras/README.dbus-api4
-rw-r--r--cras/client/cras-sys/generator/src/main.rs5
-rw-r--r--cras/client/cras-sys/src/gen.rs325
-rw-r--r--cras/client/cras_tests/src/audio.rs8
-rw-r--r--cras/client/libcras/src/cras_client_message.rs2
-rw-r--r--cras/client/libcras/src/libcras.rs18
-rw-r--r--cras/src/Makefile.am17
-rw-r--r--cras/src/alsa_plugin/pcm_cras.c4
-rw-r--r--cras/src/common/cras_config.c6
-rw-r--r--cras/src/common/cras_config.h3
-rw-r--r--cras/src/common/cras_messages.h22
-rw-r--r--cras/src/common/cras_observer_ops.h4
-rw-r--r--cras/src/common/cras_types.h18
-rw-r--r--cras/src/common/packet_status_logger.c35
-rw-r--r--cras/src/common/packet_status_logger.h127
-rw-r--r--cras/src/plc/cras_plc.c117
-rw-r--r--cras/src/plc/cras_plc_test.c138
-rw-r--r--cras/src/server/audio_thread.c11
-rw-r--r--cras/src/server/config/cras_board_config.c10
-rw-r--r--cras/src/server/config/cras_board_config.h1
-rw-r--r--cras/src/server/cras_a2dp_iodev.c4
-rw-r--r--cras/src/server/cras_alsa_helpers.c45
-rw-r--r--cras/src/server/cras_alsa_helpers.h5
-rw-r--r--cras/src/server/cras_alsa_io.c20
-rw-r--r--cras/src/server/cras_alsa_jack.c23
-rw-r--r--cras/src/server/cras_alsa_plugin_io.c17
-rw-r--r--cras/src/server/cras_alsa_ucm.c13
-rw-r--r--cras/src/server/cras_alsa_ucm.h8
-rw-r--r--cras/src/server/cras_apm_list.h2
-rw-r--r--cras/src/server/cras_bt_device.c98
-rw-r--r--cras/src/server/cras_bt_device.h7
-rw-r--r--cras/src/server/cras_bt_io.c2
-rw-r--r--cras/src/server/cras_control_rclient.c12
-rw-r--r--cras/src/server/cras_dbus_control.c115
-rw-r--r--cras/src/server/cras_dsp.c14
-rw-r--r--cras/src/server/cras_dsp.h6
-rw-r--r--cras/src/server/cras_dsp_ini.c23
-rw-r--r--cras/src/server/cras_dsp_ini.h4
-rw-r--r--cras/src/server/cras_empty_iodev.c2
-rw-r--r--cras/src/server/cras_fmt_conv.c100
-rw-r--r--cras/src/server/cras_fmt_conv_ops.c69
-rw-r--r--cras/src/server/cras_fmt_conv_ops.h5
-rw-r--r--cras/src/server/cras_hfp_ag_profile.c8
-rw-r--r--cras/src/server/cras_hfp_ag_profile.h3
-rw-r--r--cras/src/server/cras_hfp_alsa_iodev.c4
-rw-r--r--cras/src/server/cras_hfp_info.c28
-rw-r--r--cras/src/server/cras_hfp_info.h4
-rw-r--r--cras/src/server/cras_hfp_iodev.c2
-rw-r--r--cras/src/server/cras_hfp_slc.c19
-rw-r--r--cras/src/server/cras_iodev.c16
-rw-r--r--cras/src/server/cras_iodev.h4
-rw-r--r--cras/src/server/cras_iodev_list.c3
-rw-r--r--cras/src/server/cras_loopback_iodev.c2
-rw-r--r--cras/src/server/cras_observer.c38
-rw-r--r--cras/src/server/cras_observer.h4
-rw-r--r--cras/src/server/cras_rclient.c15
-rw-r--r--cras/src/server/cras_rclient.h4
-rw-r--r--cras/src/server/cras_rclient_util.c14
-rw-r--r--cras/src/server/cras_rclient_util.h29
-rw-r--r--cras/src/server/cras_rstream.c13
-rw-r--r--cras/src/server/cras_rstream.h3
-rw-r--r--cras/src/server/cras_server_metrics.c2
-rw-r--r--cras/src/server/cras_system_state.c32
-rw-r--r--cras/src/server/cras_system_state.h24
-rw-r--r--cras/src/server/dev_io.c24
-rw-r--r--cras/src/server/dev_stream.c10
-rw-r--r--cras/src/server/ewma_power.c81
-rw-r--r--cras/src/server/ewma_power.h65
-rw-r--r--cras/src/server/server_stream.c17
-rw-r--r--cras/src/server/server_stream.h4
-rw-r--r--cras/src/server/test_iodev.c2
-rw-r--r--cras/src/tests/a2dp_iodev_unittest.cc19
-rw-r--r--cras/src/tests/alsa_helpers_unittest.cc34
-rw-r--r--cras/src/tests/alsa_io_unittest.cc8
-rw-r--r--cras/src/tests/alsa_ucm_unittest.cc22
-rw-r--r--cras/src/tests/audio_thread_unittest_obsolete.cc52
-rw-r--r--cras/src/tests/bt_device_unittest.cc43
-rw-r--r--cras/src/tests/bt_io_unittest.cc3
-rw-r--r--cras/src/tests/capture_rclient_unittest.cc50
-rw-r--r--cras/src/tests/control_rclient_unittest.cc40
-rw-r--r--cras/src/tests/dev_stream_unittest.cc8
-rw-r--r--cras/src/tests/empty_iodev_unittest.cc4
-rw-r--r--cras/src/tests/ewma_power_unittest.cc129
-rw-r--r--cras/src/tests/fmt_conv_ops_unittest.cc59
-rw-r--r--cras/src/tests/fmt_conv_unittest.cc76
-rw-r--r--cras/src/tests/hfp_ag_profile_unittest.cc3
-rw-r--r--cras/src/tests/hfp_alsa_iodev_unittest.cc3
-rw-r--r--cras/src/tests/hfp_info_unittest.cc29
-rw-r--r--cras/src/tests/hfp_iodev_unittest.cc19
-rw-r--r--cras/src/tests/hfp_slc_unittest.cc2
-rw-r--r--cras/src/tests/iodev_list_unittest.cc33
-rw-r--r--cras/src/tests/iodev_unittest.cc32
-rw-r--r--cras/src/tests/loopback_iodev_unittest.cc12
-rw-r--r--cras/src/tests/observer_unittest.cc51
-rw-r--r--cras/src/tests/playback_rclient_unittest.cc50
-rw-r--r--cras/src/tests/polled_interval_checker_unittest.cc4
-rw-r--r--cras/src/tests/rstream_unittest.cc16
-rw-r--r--cras/src/tests/system_state_unittest.cc27
-rw-r--r--cras/src/tools/cras_test_client/cras_test_client.c101
-rw-r--r--init/cras.conf14
-rw-r--r--init/cras.sh2
-rw-r--r--scripts/audio_tuning/frontend/audio.js4
-rw-r--r--scripts/volume_tuning/volume.js2
-rw-r--r--seccomp/cras-seccomp-arm.policy1
-rw-r--r--seccomp/cras-seccomp-arm64.policy1
-rw-r--r--sound_card_init/.gitignore2
-rw-r--r--sound_card_init/Cargo.lock11
-rw-r--r--sound_card_init/Cargo.toml1
-rw-r--r--sound_card_init/max98390d/Cargo.toml1
-rw-r--r--sound_card_init/max98390d/src/amp_calibration.rs70
-rw-r--r--sound_card_init/max98390d/src/datastore.rs3
-rw-r--r--sound_card_init/max98390d/src/error.rs11
-rw-r--r--sound_card_init/max98390d/src/lib.rs103
-rw-r--r--sound_card_init/seccomp/sound_card_init-seccomp-amd64.policy1
-rw-r--r--sound_card_init/sound_card_init.conf5
-rw-r--r--sound_card_init/src/main.rs26
-rw-r--r--sound_card_init/utils/Cargo.lock109
-rw-r--r--sound_card_init/utils/Cargo.toml11
-rw-r--r--sound_card_init/utils/src/error.rs39
-rw-r--r--sound_card_init/utils/src/lib.rs87
-rw-r--r--ucm-config/for_all_boards/C505 HD Webcam/C505 HD Webcam.conf6
-rw-r--r--ucm-config/for_all_boards/C505 HD Webcam/HiFi.conf25
-rw-r--r--ucm-config/for_all_boards/Chat 150 C/HiFi.conf2
-rw-r--r--ucm-config/for_all_boards/Jabra SPEAK 810/HiFi.conf2
-rw-r--r--unblocked_terms.txt11
128 files changed, 2527 insertions, 986 deletions
diff --git a/audio_streams/README.md b/audio_streams/README.md
index b62c2946..d3a02e8f 100644
--- a/audio_streams/README.md
+++ b/audio_streams/README.md
@@ -2,5 +2,5 @@
The `audio_streams` crate provides a basic interface for playing audio.
This will be used to enable playback to various audio subsystems such as
-Alsa and cras. To start, an empty playback example `DummyStreamSource`
+Alsa and cras. To start, an empty playback example `NoopStreamSource`
is provided.
diff --git a/audio_streams/src/audio_streams.rs b/audio_streams/src/audio_streams.rs
index 3cb11739..5290357e 100644
--- a/audio_streams/src/audio_streams.rs
+++ b/audio_streams/src/audio_streams.rs
@@ -13,14 +13,14 @@
//! the samples written to it are committed to the `PlaybackBufferStream` it came from.
//!
//! ```
-//! use audio_streams::{BoxError, SampleFormat, StreamSource, DummyStreamSource};
+//! use audio_streams::{BoxError, SampleFormat, StreamSource, NoopStreamSource};
//! use std::io::Write;
//!
//! const buffer_size: usize = 120;
//! const num_channels: usize = 2;
//!
//! # fn main() -> std::result::Result<(), BoxError> {
-//! let mut stream_source = DummyStreamSource::new();
+//! let mut stream_source = NoopStreamSource::new();
//! let sample_format = SampleFormat::S16LE;
//! let frame_size = num_channels * sample_format.sample_bytes();
//!
@@ -55,7 +55,7 @@ pub enum SampleFormat {
}
impl SampleFormat {
- pub fn sample_bytes(&self) -> usize {
+ pub fn sample_bytes(self) -> usize {
use SampleFormat::*;
match self {
U8 => 1,
@@ -145,7 +145,7 @@ pub trait StreamSource: Send {
/// Returns a stream control and buffer generator object. These are separate as the buffer
/// generator might want to be passed to the audio stream.
- /// Default implementation returns `DummyStreamControl` and `DummyCaptureStream`.
+ /// Default implementation returns `NoopStreamControl` and `NoopCaptureStream`.
#[allow(clippy::type_complexity)]
fn new_capture_stream(
&mut self,
@@ -161,8 +161,8 @@ pub trait StreamSource: Send {
BoxError,
> {
Ok((
- Box::new(DummyStreamControl::new()),
- Box::new(capture::DummyCaptureStream::new(
+ Box::new(NoopStreamControl::new()),
+ Box::new(capture::NoopCaptureStream::new(
num_channels,
format,
frame_rate,
@@ -295,28 +295,28 @@ impl<'a> Drop for PlaybackBuffer<'a> {
}
/// Stream that accepts playback samples but drops them.
-pub struct DummyStream {
+pub struct NoopStream {
buffer: Vec<u8>,
frame_size: usize,
interval: Duration,
next_frame: Duration,
start_time: Option<Instant>,
- buffer_drop: DummyBufferDrop,
+ buffer_drop: NoopBufferDrop,
}
-/// DummyStream data that is needed from the buffer complete callback.
-struct DummyBufferDrop {
+/// NoopStream data that is needed from the buffer complete callback.
+struct NoopBufferDrop {
which_buffer: bool,
}
-impl BufferDrop for DummyBufferDrop {
+impl BufferDrop for NoopBufferDrop {
fn trigger(&mut self, _nwritten: usize) {
// When a buffer completes, switch to the other one.
self.which_buffer ^= true;
}
}
-impl DummyStream {
+impl NoopStream {
pub fn new(
num_channels: usize,
format: SampleFormat,
@@ -325,20 +325,20 @@ impl DummyStream {
) -> Self {
let frame_size = format.sample_bytes() * num_channels;
let interval = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64);
- DummyStream {
+ NoopStream {
buffer: vec![0; buffer_size * frame_size],
frame_size,
interval,
next_frame: interval,
start_time: None,
- buffer_drop: DummyBufferDrop {
+ buffer_drop: NoopBufferDrop {
which_buffer: false,
},
}
}
}
-impl PlaybackBufferStream for DummyStream {
+impl PlaybackBufferStream for NoopStream {
fn next_playback_buffer(&mut self) -> Result<PlaybackBuffer, BoxError> {
if let Some(start_time) = self.start_time {
if start_time.elapsed() < self.next_frame {
@@ -357,7 +357,8 @@ impl PlaybackBufferStream for DummyStream {
}
}
-/// No-op control for `DummyStream`s.
+/// No-op control for `NoopStream`s.
+/// Should be deprecated once all existing use of DummyStreamControl removed.
#[derive(Default)]
pub struct DummyStreamControl;
@@ -369,17 +370,29 @@ impl DummyStreamControl {
impl StreamControl for DummyStreamControl {}
-/// Source of `DummyStream` and `DummyStreamControl` objects.
+/// No-op control for `NoopStream`s.
#[derive(Default)]
-pub struct DummyStreamSource;
+pub struct NoopStreamControl;
-impl DummyStreamSource {
+impl NoopStreamControl {
pub fn new() -> Self {
- DummyStreamSource {}
+ NoopStreamControl {}
}
}
-impl StreamSource for DummyStreamSource {
+impl StreamControl for NoopStreamControl {}
+
+/// Source of `NoopStream` and `NoopStreamControl` objects.
+#[derive(Default)]
+pub struct NoopStreamSource;
+
+impl NoopStreamSource {
+ pub fn new() -> Self {
+ NoopStreamSource {}
+ }
+}
+
+impl StreamSource for NoopStreamSource {
#[allow(clippy::type_complexity)]
fn new_playback_stream(
&mut self,
@@ -389,8 +402,8 @@ impl StreamSource for DummyStreamSource {
buffer_size: usize,
) -> Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError> {
Ok((
- Box::new(DummyStreamControl::new()),
- Box::new(DummyStream::new(
+ Box::new(NoopStreamControl::new()),
+ Box::new(NoopStream::new(
num_channels,
format,
frame_rate,
@@ -408,7 +421,7 @@ mod tests {
fn invalid_buffer_length() {
// Playback buffers can't be created with a size that isn't divisible by the frame size.
let mut pb_buf = [0xa5u8; 480 * 2 * 2 + 1];
- let mut buffer_drop = DummyBufferDrop {
+ let mut buffer_drop = NoopBufferDrop {
which_buffer: false,
};
assert!(PlaybackBuffer::new(2, &mut pb_buf, &mut buffer_drop).is_err());
@@ -436,7 +449,7 @@ mod tests {
#[test]
fn sixteen_bit_stereo() {
- let mut server = DummyStreamSource::new();
+ let mut server = NoopStreamSource::new();
let (_, mut stream) = server
.new_playback_stream(2, SampleFormat::S16LE, 48000, 480)
.unwrap();
@@ -448,7 +461,7 @@ mod tests {
#[test]
fn consumption_rate() {
- let mut server = DummyStreamSource::new();
+ let mut server = NoopStreamSource::new();
let (_, mut stream) = server
.new_playback_stream(2, SampleFormat::S16LE, 48000, 480)
.unwrap();
diff --git a/audio_streams/src/capture.rs b/audio_streams/src/capture.rs
index 3f2de3f3..930f1828 100644
--- a/audio_streams/src/capture.rs
+++ b/audio_streams/src/capture.rs
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! ```
-//! use audio_streams::{BoxError, SampleFormat, StreamSource, DummyStreamSource};
+//! use audio_streams::{BoxError, SampleFormat, StreamSource, NoopStreamSource};
//! use std::io::Read;
//!
//! const buffer_size: usize = 120;
//! const num_channels: usize = 2;
//!
//! # fn main() -> std::result::Result<(),BoxError> {
-//! let mut stream_source = DummyStreamSource::new();
+//! let mut stream_source = NoopStreamSource::new();
//! let sample_format = SampleFormat::S16LE;
//! let frame_size = num_channels * sample_format.sample_bytes();
//!
@@ -34,7 +34,7 @@ use std::{
time::{Duration, Instant},
};
-use super::{AudioBuffer, BoxError, BufferDrop, DummyBufferDrop, SampleFormat};
+use super::{AudioBuffer, BoxError, BufferDrop, NoopBufferDrop, SampleFormat};
/// `CaptureBufferStream` provides `CaptureBuffer`s to read with audio samples from capture.
pub trait CaptureBufferStream: Send {
@@ -123,16 +123,16 @@ impl<'a> Drop for CaptureBuffer<'a> {
}
/// Stream that provides null capture samples.
-pub struct DummyCaptureStream {
+pub struct NoopCaptureStream {
buffer: Vec<u8>,
frame_size: usize,
interval: Duration,
next_frame: Duration,
start_time: Option<Instant>,
- buffer_drop: DummyBufferDrop,
+ buffer_drop: NoopBufferDrop,
}
-impl DummyCaptureStream {
+impl NoopCaptureStream {
pub fn new(
num_channels: usize,
format: SampleFormat,
@@ -141,20 +141,20 @@ impl DummyCaptureStream {
) -> Self {
let frame_size = format.sample_bytes() * num_channels;
let interval = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64);
- DummyCaptureStream {
+ NoopCaptureStream {
buffer: vec![0; buffer_size * frame_size],
frame_size,
interval,
next_frame: interval,
start_time: None,
- buffer_drop: DummyBufferDrop {
+ buffer_drop: NoopBufferDrop {
which_buffer: false,
},
}
}
}
-impl CaptureBufferStream for DummyCaptureStream {
+impl CaptureBufferStream for NoopCaptureStream {
fn next_capture_buffer(&mut self) -> Result<CaptureBuffer, BoxError> {
if let Some(start_time) = self.start_time {
if start_time.elapsed() < self.next_frame {
@@ -182,7 +182,7 @@ mod tests {
fn invalid_buffer_length() {
// Capture buffers can't be created with a size that isn't divisible by the frame size.
let mut cp_buf = [0xa5u8; 480 * 2 * 2 + 1];
- let mut buffer_drop = DummyBufferDrop {
+ let mut buffer_drop = NoopBufferDrop {
which_buffer: false,
};
assert!(CaptureBuffer::new(2, &mut cp_buf, &mut buffer_drop).is_err());
@@ -212,7 +212,7 @@ mod tests {
#[test]
fn sixteen_bit_stereo() {
- let mut server = DummyStreamSource::new();
+ let mut server = NoopStreamSource::new();
let (_, mut stream) = server
.new_capture_stream(2, SampleFormat::S16LE, 48000, 480)
.unwrap();
@@ -224,7 +224,7 @@ mod tests {
#[test]
fn consumption_rate() {
- let mut server = DummyStreamSource::new();
+ let mut server = NoopStreamSource::new();
let (_, mut stream) = server
.new_capture_stream(2, SampleFormat::S16LE, 48000, 480)
.unwrap();
diff --git a/cras/README.dbus-api b/cras/README.dbus-api
index 243107a0..c55a8df6 100644
--- a/cras/README.dbus-api
+++ b/cras/README.dbus-api
@@ -151,9 +151,9 @@ Methods void SetOutputVolume(int32 volume)
int32 IsAudioOutputActive()
Returns 1 if there are currently any active output streams,
- excluding 'dummy' streams that are not actually outputting any
+ excluding 'fake' streams that are not actually outputting any
audio. Returns 0 if there are no active streams, or all active
- streams are 'dummy' streams.
+ streams are 'fake' streams.
void SetGlobalOutputChannelRemix(int32 num_channels,
array:double coefficient)
diff --git a/cras/client/cras-sys/generator/src/main.rs b/cras/client/cras-sys/generator/src/main.rs
index 1a022459..e562691d 100644
--- a/cras/client/cras-sys/generator/src/main.rs
+++ b/cras/client/cras-sys/generator/src/main.rs
@@ -36,6 +36,7 @@ fn copy_headers(src_dir: &Path, dst_dir: &Path) -> Result<(), String> {
"cras_shm.h",
"cras_types.h",
"cras_util.h",
+ "packet_status_logger.h",
];
for header in &header_files {
@@ -133,7 +134,11 @@ fn write_output(output_path: &Path, output: String) -> std::io::Result<()> {
* cras_shm.h
* cras_types.h
* cras_util.h
+ * packet_status_logger.h
*/
+
+#![allow(clippy::unreadable_literal)]
+#![allow(clippy::cognitive_complexity)]
";
let mut output_file = File::create(output_path)?;
diff --git a/cras/client/cras-sys/src/gen.rs b/cras/client/cras-sys/src/gen.rs
index 129a91a8..0375a0bd 100644
--- a/cras/client/cras-sys/src/gen.rs
+++ b/cras/client/cras-sys/src/gen.rs
@@ -10,7 +10,11 @@
* cras_shm.h
* cras_types.h
* cras_util.h
+ * packet_status_logger.h
*/
+
+#![allow(clippy::unreadable_literal)]
+#![allow(clippy::cognitive_complexity)]
/* automatically generated by rust-bindgen */
pub const CRAS_IODEV_NAME_BUFFER_SIZE: u32 = 64;
@@ -609,6 +613,78 @@ fn bindgen_test_layout_cras_audio_format_packed() {
)
);
}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct packet_status_logger {
+ pub data: [u8; 64usize],
+ pub size: ::std::os::raw::c_int,
+ pub wp: ::std::os::raw::c_int,
+ pub num_wraps: ::std::os::raw::c_int,
+ pub ts: timespec,
+}
+#[test]
+fn bindgen_test_layout_packet_status_logger() {
+ assert_eq!(
+ ::std::mem::size_of::<packet_status_logger>(),
+ 96usize,
+ concat!("Size of: ", stringify!(packet_status_logger))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<packet_status_logger>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(packet_status_logger))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<packet_status_logger>())).data as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(packet_status_logger),
+ "::",
+ stringify!(data)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<packet_status_logger>())).size as *const _ as usize },
+ 64usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(packet_status_logger),
+ "::",
+ stringify!(size)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<packet_status_logger>())).wp as *const _ as usize },
+ 68usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(packet_status_logger),
+ "::",
+ stringify!(wp)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<packet_status_logger>())).num_wraps as *const _ as usize },
+ 72usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(packet_status_logger),
+ "::",
+ stringify!(num_wraps)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<packet_status_logger>())).ts as *const _ as usize },
+ 80usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(packet_status_logger),
+ "::",
+ stringify!(ts)
+ )
+ );
+}
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
pub struct cras_timespec {
@@ -845,13 +921,17 @@ pub enum CRAS_BT_LOG_EVENTS {
BT_HFP_REQUEST_DISCONNECT = 13,
BT_HFP_SUPPORTED_FEATURES = 14,
BT_HFP_HF_INDICATOR = 15,
- BT_HSP_NEW_CONNECTION = 16,
- BT_HSP_REQUEST_DISCONNECT = 17,
- BT_NEW_AUDIO_PROFILE_AFTER_CONNECT = 18,
- BT_RESET = 19,
- BT_SCO_CONNECT = 20,
- BT_TRANSPORT_ACQUIRE = 21,
- BT_TRANSPORT_RELEASE = 22,
+ BT_HFP_SET_SPEAKER_GAIN = 16,
+ BT_HFP_UPDATE_SPEAKER_GAIN = 17,
+ BT_HSP_NEW_CONNECTION = 18,
+ BT_HSP_REQUEST_DISCONNECT = 19,
+ BT_NEW_AUDIO_PROFILE_AFTER_CONNECT = 20,
+ BT_RESET = 21,
+ BT_SCO_CONNECT = 22,
+ BT_TRANSPORT_ACQUIRE = 23,
+ BT_TRANSPORT_RELEASE = 24,
+ BT_TRANSPORT_SET_VOLUME = 25,
+ BT_TRANSPORT_UPDATE_VOLUME = 26,
}
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
@@ -1589,12 +1669,13 @@ pub struct main_thread_event {
pub nsec: u32,
pub data1: u32,
pub data2: u32,
+ pub data3: u32,
}
#[test]
fn bindgen_test_layout_main_thread_event() {
assert_eq!(
::std::mem::size_of::<main_thread_event>(),
- 16usize,
+ 20usize,
concat!("Size of: ", stringify!(main_thread_event))
);
assert_eq!(
@@ -1642,6 +1723,16 @@ fn bindgen_test_layout_main_thread_event() {
stringify!(data2)
)
);
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<main_thread_event>())).data3 as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(main_thread_event),
+ "::",
+ stringify!(data3)
+ )
+ );
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
@@ -1654,7 +1745,7 @@ pub struct main_thread_event_log {
fn bindgen_test_layout_main_thread_event_log() {
assert_eq!(
::std::mem::size_of::<main_thread_event_log>(),
- 16392usize,
+ 20488usize,
concat!("Size of: ", stringify!(main_thread_event_log))
);
assert_eq!(
@@ -1702,7 +1793,7 @@ pub struct main_thread_debug_info {
fn bindgen_test_layout_main_thread_debug_info() {
assert_eq!(
::std::mem::size_of::<main_thread_debug_info>(),
- 16392usize,
+ 20488usize,
concat!("Size of: ", stringify!(main_thread_debug_info))
);
assert_eq!(
@@ -1836,12 +1927,13 @@ fn bindgen_test_layout_cras_bt_event_log() {
#[derive(Copy, Clone)]
pub struct cras_bt_debug_info {
pub bt_log: cras_bt_event_log,
+ pub wbs_logger: packet_status_logger,
}
#[test]
fn bindgen_test_layout_cras_bt_debug_info() {
assert_eq!(
::std::mem::size_of::<cras_bt_debug_info>(),
- 16392usize,
+ 16488usize,
concat!("Size of: ", stringify!(cras_bt_debug_info))
);
assert_eq!(
@@ -1859,6 +1951,16 @@ fn bindgen_test_layout_cras_bt_debug_info() {
stringify!(bt_log)
)
);
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<cras_bt_debug_info>())).wbs_logger as *const _ as usize },
+ 16392usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(cras_bt_debug_info),
+ "::",
+ stringify!(wbs_logger)
+ )
+ );
}
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
@@ -2013,13 +2115,14 @@ pub struct cras_server_state {
pub snapshot_buffer: cras_audio_thread_snapshot_buffer,
pub bt_debug_info: cras_bt_debug_info,
pub bt_wbs_enabled: i32,
+ pub deprioritize_bt_wbs_mic: i32,
pub main_thread_debug_info: main_thread_debug_info,
}
#[test]
fn bindgen_test_layout_cras_server_state() {
assert_eq!(
::std::mem::size_of::<cras_server_state>(),
- 1410096usize,
+ 1414292usize,
concat!("Size of: ", stringify!(cras_server_state))
);
assert_eq!(
@@ -2383,7 +2486,7 @@ fn bindgen_test_layout_cras_server_state() {
unsafe {
&(*(::std::ptr::null::<cras_server_state>())).bt_wbs_enabled as *const _ as usize
},
- 1393700usize,
+ 1393796usize,
concat!(
"Offset of field: ",
stringify!(cras_server_state),
@@ -2393,10 +2496,23 @@ fn bindgen_test_layout_cras_server_state() {
);
assert_eq!(
unsafe {
+ &(*(::std::ptr::null::<cras_server_state>())).deprioritize_bt_wbs_mic as *const _
+ as usize
+ },
+ 1393800usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(cras_server_state),
+ "::",
+ stringify!(deprioritize_bt_wbs_mic)
+ )
+ );
+ assert_eq!(
+ unsafe {
&(*(::std::ptr::null::<cras_server_state>())).main_thread_debug_info as *const _
as usize
},
- 1393704usize,
+ 1393804usize,
concat!(
"Offset of field: ",
stringify!(cras_server_state),
@@ -2857,187 +2973,6 @@ fn bindgen_test_layout_cras_connect_message() {
}
#[repr(C, packed)]
#[derive(Debug, Copy, Clone)]
-pub struct cras_connect_message_old {
- pub header: cras_server_message,
- pub proto_version: u32,
- pub direction: CRAS_STREAM_DIRECTION,
- pub stream_id: cras_stream_id_t,
- pub stream_type: CRAS_STREAM_TYPE,
- pub buffer_frames: u32,
- pub cb_threshold: u32,
- pub flags: u32,
- pub format: cras_audio_format_packed,
- pub dev_idx: u32,
- pub effects: u64,
- pub client_type: CRAS_CLIENT_TYPE,
- pub client_shm_size: u32,
-}
-#[test]
-fn bindgen_test_layout_cras_connect_message_old() {
- assert_eq!(
- ::std::mem::size_of::<cras_connect_message_old>(),
- 79usize,
- concat!("Size of: ", stringify!(cras_connect_message_old))
- );
- assert_eq!(
- ::std::mem::align_of::<cras_connect_message_old>(),
- 1usize,
- concat!("Alignment of ", stringify!(cras_connect_message_old))
- );
- assert_eq!(
- unsafe { &(*(::std::ptr::null::<cras_connect_message_old>())).header as *const _ as usize },
- 0usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(header)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).proto_version as *const _ as usize
- },
- 8usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(proto_version)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).direction as *const _ as usize
- },
- 12usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(direction)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).stream_id as *const _ as usize
- },
- 16usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(stream_id)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).stream_type as *const _ as usize
- },
- 20usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(stream_type)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).buffer_frames as *const _ as usize
- },
- 24usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(buffer_frames)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).cb_threshold as *const _ as usize
- },
- 28usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(cb_threshold)
- )
- );
- assert_eq!(
- unsafe { &(*(::std::ptr::null::<cras_connect_message_old>())).flags as *const _ as usize },
- 32usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(flags)
- )
- );
- assert_eq!(
- unsafe { &(*(::std::ptr::null::<cras_connect_message_old>())).format as *const _ as usize },
- 36usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(format)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).dev_idx as *const _ as usize
- },
- 59usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(dev_idx)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).effects as *const _ as usize
- },
- 63usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(effects)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).client_type as *const _ as usize
- },
- 71usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(client_type)
- )
- );
- assert_eq!(
- unsafe {
- &(*(::std::ptr::null::<cras_connect_message_old>())).client_shm_size as *const _
- as usize
- },
- 75usize,
- concat!(
- "Offset of field: ",
- stringify!(cras_connect_message_old),
- "::",
- stringify!(client_shm_size)
- )
- );
-}
-#[repr(C, packed)]
-#[derive(Debug, Copy, Clone)]
pub struct cras_disconnect_stream_message {
pub header: cras_server_message,
pub stream_id: cras_stream_id_t,
diff --git a/cras/client/cras_tests/src/audio.rs b/cras/client/cras_tests/src/audio.rs
index 261ad631..5ab22474 100644
--- a/cras/client/cras_tests/src/audio.rs
+++ b/cras/client/cras_tests/src/audio.rs
@@ -317,9 +317,11 @@ impl Write for WavSink {
samples[sample_bytes * i + 3],
]);
- // Upsample to 32 bit since CRAS doesn't support S24_3LE,
- // even though the wav encoder does.
- // TODO(fletcherw): add S24_LE support to hound.
+ // Upsample to 32 bit since CRAS doesn't support S24_3LE.
+ // Our wav encoder/decoder, hound, does have support for
+ // S24_LE, but it hasn't released a new version since the
+ // support was added. If getting that support is an issue,
+ // push upstream to cut a new a release.
if self.format == SampleFormat::S24LE {
sample <<= 8;
}
diff --git a/cras/client/libcras/src/cras_client_message.rs b/cras/client/libcras/src/cras_client_message.rs
index d42b6f95..c1c5ec5c 100644
--- a/cras/client/libcras/src/cras_client_message.rs
+++ b/cras/client/libcras/src/cras_client_message.rs
@@ -195,6 +195,6 @@ impl CrasClientMessage {
if self.len != mem::size_of::<T>() {
return Err(Error::InvalidSize);
}
- T::from_slice(&self.data[..mem::size_of::<T>()]).ok_or_else(|| Error::MessageFromSliceError)
+ T::from_slice(&self.data[..mem::size_of::<T>()]).ok_or(Error::MessageFromSliceError)
}
}
diff --git a/cras/client/libcras/src/libcras.rs b/cras/client/libcras/src/libcras.rs
index 62e8fdda..80d2cff7 100644
--- a/cras/client/libcras/src/libcras.rs
+++ b/cras/client/libcras/src/libcras.rs
@@ -126,9 +126,9 @@ use std::{error, fmt};
pub use audio_streams::BoxError;
use audio_streams::{
- capture::{CaptureBufferStream, DummyCaptureStream},
+ capture::{CaptureBufferStream, NoopCaptureStream},
shm_streams::{NullShmStream, ShmStream, ShmStreamSource},
- BufferDrop, DummyStreamControl, PlaybackBufferStream, SampleFormat, StreamControl,
+ BufferDrop, NoopStreamControl, PlaybackBufferStream, SampleFormat, StreamControl,
StreamDirection, StreamEffect, StreamSource,
};
use cras_sys::gen::*;
@@ -475,7 +475,7 @@ impl<'a> CrasClient<'a> {
) -> std::result::Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError>
{
Ok((
- Box::new(DummyStreamControl::new()),
+ Box::new(NoopStreamControl::new()),
Box::new(self.create_stream::<CrasPlaybackData>(
Some(device_index),
buffer_size as u32,
@@ -509,7 +509,7 @@ impl<'a> CrasClient<'a> {
buffer_size: usize,
) -> std::result::Result<(Box<dyn StreamControl>, Box<dyn CaptureBufferStream>), BoxError> {
Ok((
- Box::new(DummyStreamControl::new()),
+ Box::new(NoopStreamControl::new()),
Box::new(self.create_stream::<CrasCaptureData>(
Some(device_index),
buffer_size as u32,
@@ -535,7 +535,7 @@ impl<'a> CrasClient<'a> {
let tokens: Vec<Token> = events.iter_readable().map(|e| e.token()).collect();
tokens
.get(0)
- .ok_or_else(|| Error::UnexpectedExit)
+ .ok_or(Error::UnexpectedExit)
.and_then(|ref token| {
match token {
Token::ServerMsg => ServerResult::handle_server_message(socket),
@@ -562,7 +562,7 @@ impl<'a> StreamSource for CrasClient<'a> {
) -> std::result::Result<(Box<dyn StreamControl>, Box<dyn PlaybackBufferStream>), BoxError>
{
Ok((
- Box::new(DummyStreamControl::new()),
+ Box::new(NoopStreamControl::new()),
Box::new(self.create_stream::<CrasPlaybackData>(
None,
buffer_size as u32,
@@ -584,7 +584,7 @@ impl<'a> StreamSource for CrasClient<'a> {
) -> std::result::Result<(Box<dyn StreamControl>, Box<dyn CaptureBufferStream>), BoxError> {
if self.cras_capture {
Ok((
- Box::new(DummyStreamControl::new()),
+ Box::new(NoopStreamControl::new()),
Box::new(self.create_stream::<CrasCaptureData>(
None,
buffer_size as u32,
@@ -596,8 +596,8 @@ impl<'a> StreamSource for CrasClient<'a> {
))
} else {
Ok((
- Box::new(DummyStreamControl::new()),
- Box::new(DummyCaptureStream::new(
+ Box::new(NoopStreamControl::new()),
+ Box::new(NoopCaptureStream::new(
num_channels,
format,
frame_rate,
diff --git a/cras/src/Makefile.am b/cras/src/Makefile.am
index 874389c6..69fea5ff 100644
--- a/cras/src/Makefile.am
+++ b/cras/src/Makefile.am
@@ -46,6 +46,7 @@ noinst_PROGRAMS =
if HAVE_DBUS
CRAS_DBUS_SOURCES = \
common/cras_sbc_codec.c \
+ common/packet_status_logger.c \
server/cras_bt_manager.c \
server/cras_bt_adapter.c \
server/cras_bt_device.c \
@@ -155,6 +156,7 @@ cras_server_SOURCES = \
server/cras_volume_curve.c \
server/dev_io.c \
server/dev_stream.c \
+ server/ewma_power.c \
server/input_data.c \
server/linear_resampler.c \
server/polled_interval_checker.c \
@@ -280,6 +282,7 @@ include_HEADERS = \
common/cras_types.h \
common/cras_util.h \
common/edid_utils.h \
+ common/packet_status_logger.h \
common/utlist.h \
libcras/cras_client.h \
libcras/cras_helpers.h
@@ -437,6 +440,7 @@ TESTS = \
edid_utils_unittest \
empty_iodev_unittest \
expr_unittest \
+ ewma_power_unittest \
file_wait_unittest \
float_buffer_unittest \
fmt_conv_unittest \
@@ -880,6 +884,14 @@ buffer_share_unittest_CPPFLAGS = $(COMMON_CPPFLAGS) \
-I$(top_srcdir)/src/common -I$(top_srcdir)/src/server
buffer_share_unittest_LDADD = -lgtest -liniparser -lpthread
+ewma_power_unittest_SOURCES = tests/ewma_power_unittest.cc \
+ common/cras_audio_format.c server/cras_audio_area.c \
+ server/ewma_power.c
+
+ewma_power_unittest_CPPFLAGS = $(COMMON_CPPFLAGS) \
+ -I$(top_srcdir)/src/common -I$(top_srcdir)/src/server
+ewma_power_unittest_LDADD = -lgtest
+
iodev_list_unittest_SOURCES = tests/iodev_list_unittest.cc \
server/cras_iodev_list.c
iodev_list_unittest_CPPFLAGS = $(COMMON_CPPFLAGS) -I$(top_srcdir)/src/common \
@@ -949,8 +961,9 @@ control_rclient_unittest_SOURCES = tests/control_rclient_unittest.cc \
server/cras_rstream_config.c
control_rclient_unittest_CPPFLAGS = $(COMMON_CPPFLAGS) \
-I$(top_srcdir)/src/common \
- -I$(top_srcdir)/src/server $(CRAS_UT_TMPDIR_CFLAGS)
-control_rclient_unittest_LDADD = -lgtest -lpthread
+ -I$(top_srcdir)/src/server $(CRAS_UT_TMPDIR_CFLAGS) \
+ $(DBUS_CFLAGS)
+control_rclient_unittest_LDADD = -lgtest -lpthread $(DBUS_LIBS)
playback_rclient_unittest_SOURCES = tests/playback_rclient_unittest.cc \
server/cras_rstream_config.c
diff --git a/cras/src/alsa_plugin/pcm_cras.c b/cras/src/alsa_plugin/pcm_cras.c
index 715db2cc..7bc960bc 100644
--- a/cras/src/alsa_plugin/pcm_cras.c
+++ b/cras/src/alsa_plugin/pcm_cras.c
@@ -124,7 +124,7 @@ static int pcm_cras_process_cb(struct cras_client *client,
struct snd_pcm_cras *pcm_cras;
const snd_pcm_channel_area_t *areas;
snd_pcm_uframes_t copied_frames;
- char dummy_byte;
+ char empty_byte;
size_t chan, frame_bytes, sample_bytes;
int rc;
uint8_t *samples;
@@ -196,7 +196,7 @@ static int pcm_cras_process_cb(struct cras_client *client,
copied_frames += frames;
}
- rc = write(pcm_cras->fd, &dummy_byte, 1); /* Wake up polling clients. */
+ rc = write(pcm_cras->fd, &empty_byte, 1); /* Wake up polling clients. */
if (rc < 0 && errno != EWOULDBLOCK && errno != EAGAIN)
fprintf(stderr, "%s write failed %d\n", __func__, errno);
diff --git a/cras/src/common/cras_config.c b/cras/src/common/cras_config.c
index 55caee2f..75fa24e7 100644
--- a/cras/src/common/cras_config.c
+++ b/cras/src/common/cras_config.c
@@ -44,6 +44,12 @@ int cras_fill_socket_path(enum CRAS_CONNECTION_TYPE conn_type, char *sock_path)
case CRAS_VMS_UNIFIED:
sock_file = CRAS_VMS_UNIFIED_SOCKET_FILE;
break;
+ case CRAS_PLUGIN_PLAYBACK:
+ sock_file = CRAS_PLUGIN_PLAYBACK_SOCKET_FILE;
+ break;
+ case CRAS_PLUGIN_UNIFIED:
+ sock_file = CRAS_PLUGIN_UNIFIED_SOCKET_FILE;
+ break;
default:
return -EINVAL;
}
diff --git a/cras/src/common/cras_config.h b/cras/src/common/cras_config.h
index 7f0aa23f..1c8e55fa 100644
--- a/cras/src/common/cras_config.h
+++ b/cras/src/common/cras_config.h
@@ -20,6 +20,9 @@
/* Socket file paths for VMs. */
#define CRAS_VMS_LEGACY_SOCKET_FILE "vms/.cras_socket"
#define CRAS_VMS_UNIFIED_SOCKET_FILE "vms/.cras_unified"
+/* Socket file paths for pluginVM. */
+#define CRAS_PLUGIN_PLAYBACK_SOCKET_FILE "vms/plugin/playback/.cras_socket"
+#define CRAS_PLUGIN_UNIFIED_SOCKET_FILE "vms/plugin/unified/.cras_socket"
/* Maximum socket_path size, which is equals to sizeof(sun_path) in sockaddr_un
* structure.
diff --git a/cras/src/common/cras_messages.h b/cras/src/common/cras_messages.h
index ee09d930..50cbe7cd 100644
--- a/cras/src/common/cras_messages.h
+++ b/cras/src/common/cras_messages.h
@@ -120,28 +120,6 @@ struct __attribute__((__packed__)) cras_connect_message {
uint64_t buffer_offsets[2];
};
-/*
- * Old version of connect message without 'buffer_offsets'.
- * Used to check against when receiving invalid size of connect message.
- * Expected to have proto_version set to 5.
- * TODO(fletcherw): remove when all clients migrate to latest libcras.
- */
-struct __attribute__((__packed__)) cras_connect_message_old {
- struct cras_server_message header;
- uint32_t proto_version;
- enum CRAS_STREAM_DIRECTION direction; /* input/output/loopback */
- cras_stream_id_t stream_id; /* unique id for this stream */
- enum CRAS_STREAM_TYPE stream_type; /* media, or call, etc. */
- uint32_t buffer_frames; /* Buffer size in frames. */
- uint32_t cb_threshold; /* callback client when this much is left */
- uint32_t flags;
- struct cras_audio_format_packed format; /* rate, channel, sample size */
- uint32_t dev_idx; /* device to attach stream, 0 if none */
- uint64_t effects; /* Bit map of requested effects. */
- enum CRAS_CLIENT_TYPE client_type; /* chrome, or arc, etc. */
- uint32_t client_shm_size; /* Size of client-provided samples shm, if any */
-};
-
static inline void cras_fill_connect_message(
struct cras_connect_message *m, enum CRAS_STREAM_DIRECTION direction,
cras_stream_id_t stream_id, enum CRAS_STREAM_TYPE stream_type,
diff --git a/cras/src/common/cras_observer_ops.h b/cras/src/common/cras_observer_ops.h
index a54d044c..e73845c9 100644
--- a/cras/src/common/cras_observer_ops.h
+++ b/cras/src/common/cras_observer_ops.h
@@ -47,6 +47,10 @@ struct cras_observer_ops {
void (*num_active_streams_changed)(void *context,
enum CRAS_STREAM_DIRECTION dir,
uint32_t num_active_streams);
+ /* Number of input streams with permission changed. */
+ void (*num_input_streams_with_permission_changed)(
+ void *context,
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE]);
/* Hotword triggered. */
void (*hotword_triggered)(void *context, int64_t tv_sec,
int64_t tv_nsec);
diff --git a/cras/src/common/cras_types.h b/cras/src/common/cras_types.h
index c3482e8d..90a04741 100644
--- a/cras/src/common/cras_types.h
+++ b/cras/src/common/cras_types.h
@@ -15,6 +15,7 @@
#include "cras_audio_format.h"
#include "cras_iodev_info.h"
+#include "packet_status_logger.h"
/* Architecture independent timespec */
struct __attribute__((__packed__)) cras_timespec {
@@ -50,6 +51,8 @@ enum CRAS_CONNECTION_TYPE {
CRAS_CAPTURE, // For capture client.
CRAS_VMS_LEGACY, // For legacy client in vms.
CRAS_VMS_UNIFIED, // For unified client in vms.
+ CRAS_PLUGIN_PLAYBACK, // For playback client in vms/plugin.
+ CRAS_PLUGIN_UNIFIED, // For unified client in vms/plugin.
CRAS_NUM_CONN_TYPE,
};
@@ -165,8 +168,15 @@ enum CRAS_CLIENT_TYPE {
CRAS_CLIENT_TYPE_CROSVM, /* CROSVM */
CRAS_CLIENT_TYPE_SERVER_STREAM, /* Server stream */
CRAS_CLIENT_TYPE_LACROS, /* LaCrOS */
+ CRAS_CLIENT_TYPE_PLUGIN, /* PluginVM */
+ CRAS_NUM_CLIENT_TYPE, /* numbers of CRAS_CLIENT_TYPE */
};
+static inline bool cras_validate_client_type(enum CRAS_CLIENT_TYPE client_type)
+{
+ return 0 <= client_type && client_type < CRAS_NUM_CLIENT_TYPE;
+}
+
#define ENUM_STR(x) \
case x: \
return #x;
@@ -202,6 +212,7 @@ cras_client_type_str(enum CRAS_CLIENT_TYPE client_type)
ENUM_STR(CRAS_CLIENT_TYPE_CROSVM)
ENUM_STR(CRAS_CLIENT_TYPE_SERVER_STREAM)
ENUM_STR(CRAS_CLIENT_TYPE_LACROS)
+ ENUM_STR(CRAS_CLIENT_TYPE_PLUGIN)
default:
return "INVALID_CLIENT_TYPE";
}
@@ -479,6 +490,7 @@ struct __attribute__((__packed__)) cras_bt_event_log {
struct __attribute__((__packed__)) cras_bt_debug_info {
struct cras_bt_event_log bt_log;
+ struct packet_status_logger wbs_logger;
};
/*
@@ -556,7 +568,11 @@ struct __attribute__((__packed__)) cras_audio_thread_snapshot_buffer {
* snapshot_buffer - ring buffer for storing audio thread snapshots.
* bt_debug_info - ring buffer for storing bluetooth event logs.
* bt_wbs_enabled - Whether or not bluetooth wideband speech is enabled.
+ * deprioritize_bt_wbs_mic - Whether Bluetooth wideband speech mic
+ * should be deprioritized for selecting as default audio input.
* main_thread_debug_info - ring buffer for storing main thread event logs.
+ * num_input_streams_with_permission - An array containing numbers of input
+ * streams with permission in each client type.
*/
#define CRAS_SERVER_STATE_VERSION 2
struct __attribute__((packed, aligned(4))) cras_server_state {
@@ -593,7 +609,9 @@ struct __attribute__((packed, aligned(4))) cras_server_state {
struct cras_audio_thread_snapshot_buffer snapshot_buffer;
struct cras_bt_debug_info bt_debug_info;
int32_t bt_wbs_enabled;
+ int32_t deprioritize_bt_wbs_mic;
struct main_thread_debug_info main_thread_debug_info;
+ uint32_t num_input_streams_with_permission[CRAS_NUM_CLIENT_TYPE];
};
/* Actions for card add/remove/change. */
diff --git a/cras/src/common/packet_status_logger.c b/cras/src/common/packet_status_logger.c
new file mode 100644
index 00000000..f1be6965
--- /dev/null
+++ b/cras/src/common/packet_status_logger.c
@@ -0,0 +1,35 @@
+/* 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.
+ */
+
+#include <string.h>
+#include <time.h>
+
+#include "cras_util.h"
+#include "packet_status_logger.h"
+
+void packet_status_logger_init(struct packet_status_logger *logger)
+{
+ memset(logger->data, 0, PACKET_STATUS_LEN_BYTES);
+ logger->size = PACKET_STATUS_LEN_BYTES * 8;
+ logger->wp = 0;
+ logger->num_wraps = 0;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &logger->ts);
+}
+
+void packet_status_logger_update(struct packet_status_logger *logger, bool val)
+{
+ if (val) {
+ logger->data[logger->wp / 8] |= 1UL << (logger->wp % 8);
+ } else {
+ logger->data[logger->wp / 8] &= ~(1UL << (logger->wp % 8));
+ }
+ logger->wp++;
+ if (logger->wp >= logger->size) {
+ logger->wp %= logger->size;
+ logger->num_wraps += 1;
+ }
+ if (logger->wp == 0 || (logger->num_wraps == 0 && logger->wp == 1))
+ clock_gettime(CLOCK_MONOTONIC_RAW, &logger->ts);
+}
diff --git a/cras/src/common/packet_status_logger.h b/cras/src/common/packet_status_logger.h
new file mode 100644
index 00000000..3bc90041
--- /dev/null
+++ b/cras/src/common/packet_status_logger.h
@@ -0,0 +1,127 @@
+/* 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.
+ */
+
+#ifndef PACKET_STATUS_LOGGER_
+#define PACKET_STATUS_LOGGER_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define PACKET_STATUS_LEN_BYTES 64
+#define WBS_FRAME_NS 7500000
+
+/* Avoid 32, 40, 64 consecutive hex characters so CrOS feedback redact
+ * tool doesn't trim our dump. */
+#define PACKET_STATUS_LOG_LINE_WRAP 50
+
+/*
+ * Object to log consecutive packets' status.
+ * Members:
+ * data - Bytes to store packets' status.
+ * size - Total number of bits in |data|.
+ * wp - Position of the next bit to log packet status.
+ * num_wraps - Number of times the ring buffer has wrapped.
+ * ts - The timestamp of the last time when the first bit of |data| updated.
+ */
+struct packet_status_logger {
+ uint8_t data[PACKET_STATUS_LEN_BYTES];
+ int size;
+ int wp;
+ int num_wraps;
+ struct timespec ts;
+};
+
+/* Initializes the packet status logger. */
+void packet_status_logger_init(struct packet_status_logger *logger);
+
+/* Updates the next packet status to logger. */
+void packet_status_logger_update(struct packet_status_logger *logger, bool val);
+
+/* Rewinds logger's time stamp to calculate the beginning.
+ * If logger's ring buffer hasn't wrapped, simply return logger_ts.
+ * Otherwise beginning_ts = logger_ts - WBS_FRAME_NS * (size - wp)
+ */
+static inline void
+packet_status_logger_begin_ts(const struct packet_status_logger *logger,
+ struct timespec *ts)
+{
+ long nsec = WBS_FRAME_NS * (logger->size - logger->wp);
+
+ *ts = logger->ts;
+ if (logger->num_wraps == 0)
+ return;
+ while (nsec > 1000000000L) {
+ ts->tv_sec--;
+ nsec -= 1000000000L;
+ }
+ ts->tv_nsec -= nsec;
+ if (ts->tv_nsec < 0) {
+ ts->tv_sec--;
+ ts->tv_nsec += 1000000000L;
+ }
+}
+
+/* Fast-forwards the logger's time stamp to calculate the end.
+ * In other words, end_ts = logger_ts + WBS_FRAME_NS * wp
+ */
+static inline void
+packet_status_logger_end_ts(const struct packet_status_logger *logger,
+ struct timespec *ts)
+{
+ *ts = logger->ts;
+ ts->tv_nsec += WBS_FRAME_NS * logger->wp;
+ while (ts->tv_nsec > 1000000000L) {
+ ts->tv_sec++;
+ ts->tv_nsec -= 1000000000L;
+ }
+}
+
+/* Prints the logger data in hex format */
+static inline void
+packet_status_logger_dump_hex(const struct packet_status_logger *logger)
+{
+ int i = logger->wp / 8;
+
+ /* Print the bits after wp only if buffer has wrapped. */
+ if (logger->num_wraps) {
+ if (logger->wp % 8)
+ printf("%.2x",
+ logger->data[i] & (0xff << (logger->wp % 8)));
+ for (; i < PACKET_STATUS_LEN_BYTES; i++)
+ printf("%.2x", logger->data[i]);
+ }
+ for (i = 0; i < logger->wp / 8; i++)
+ printf("%.2x", logger->data[i]);
+ if (logger->wp % 8)
+ printf("%.2x", logger->data[i] & (~(0xff << (logger->wp % 8))));
+ printf("\n");
+}
+
+/* Prints the logger data in binary format */
+static inline void
+packet_status_logger_dump_binary(const struct packet_status_logger *logger)
+{
+ /* Don't print the bits after wp if buffer hasn't wrapped. */
+ int head = logger->num_wraps ? logger->wp : 0;
+ int len = logger->num_wraps ? logger->size : logger->wp;
+ int i, j;
+
+ for (i = 0; i < len; ++i) {
+ j = (head + i) % logger->size;
+ printf("%d", (logger->data[j / 8] >> (j % 8)) & 1U);
+ if ((i + 1) % PACKET_STATUS_LOG_LINE_WRAP == 0)
+ printf("\n");
+ }
+ /* Fill indicator digit 'D' until the last line wraps. */
+ if (len % PACKET_STATUS_LOG_LINE_WRAP) {
+ while (len % PACKET_STATUS_LOG_LINE_WRAP) {
+ printf("D");
+ ++len;
+ }
+ printf("\n");
+ }
+}
+
+#endif /* PACKET_STATUS_LOGGER_ */
diff --git a/cras/src/plc/cras_plc.c b/cras/src/plc/cras_plc.c
index 4bc9fb76..74c3568b 100644
--- a/cras/src/plc/cras_plc.c
+++ b/cras/src/plc/cras_plc.c
@@ -22,6 +22,9 @@
#define PLC_SBCRL 36 /* SBC Reconvergence sample Length */
#define PLC_OLAL 16 /* OverLap-Add Length */
+#define PLC_WINDOW_SIZE 5
+#define PLC_PL_THRESHOLD 2
+
/* The pre-computed zero input bit stream of mSBC codec, per HFP 1.7 spec.
* This mSBC frame will be decoded into all-zero input PCM. */
static const uint8_t msbc_zero_frame[] = {
@@ -40,6 +43,18 @@ static const float rcos[PLC_OLAL] = { 0.99148655f, 0.96623611f, 0.92510857f,
0.13049554f, 0.07489143f, 0.03376389f,
0.00851345f };
+/* This structure tracks the packet loss information for last PLC_WINDOW_SIZE
+ * of packets:
+ * loss_hist - The packet loss history of receiving packets. 1 means lost.
+ * ptr - The index of the to be updated packet loss status.
+ * count - The count of lost packets in the window.
+ */
+struct packet_window {
+ uint8_t loss_hist[PLC_WINDOW_SIZE];
+ unsigned int ptr;
+ unsigned int count;
+};
+
/* The PLC is specifically designed for mSBC. The algorithm searches the
* history of receiving samples to find the best match samples and constructs
* substitutions for the lost samples. The selection is based on pattern
@@ -57,23 +72,30 @@ static const float rcos[PLC_OLAL] = { 0.99148655f, 0.96623611f, 0.92510857f,
* frame.
* zero_frame - A buffer used for storing the samples from decoding the
* mSBC zero frame packet.
+ * pl_window - A window monitoring how many packets are bad within the recent
+ * PLC_WINDOW_SIZE of packets. This is used to determine if we
+ * want to disable the PLC temporarily.
*/
struct cras_msbc_plc {
int16_t hist[PLC_HL + MSBC_FS + PLC_SBCRL + PLC_OLAL];
unsigned int best_lag;
int handled_bad_frames;
int16_t zero_frame[MSBC_FS];
+ struct packet_window *pl_window;
};
struct cras_msbc_plc *cras_msbc_plc_create()
{
struct cras_msbc_plc *plc =
(struct cras_msbc_plc *)calloc(1, sizeof(*plc));
+ plc->pl_window =
+ (struct packet_window *)calloc(1, sizeof(*plc->pl_window));
return plc;
}
void cras_msbc_plc_destroy(struct cras_msbc_plc *plc)
{
+ free(plc->pl_window);
free(plc);
}
@@ -94,14 +116,33 @@ void overlap_add(int16_t *output, float scaler_d, const int16_t *desc,
}
}
+void update_plc_state(struct packet_window *w, uint8_t is_packet_loss)
+{
+ uint8_t *curr = &w->loss_hist[w->ptr];
+ if (is_packet_loss != *curr) {
+ w->count += (is_packet_loss - *curr);
+ *curr = is_packet_loss;
+ }
+ w->ptr = (w->ptr + 1) % PLC_WINDOW_SIZE;
+}
+
+int possibly_pause_plc(struct packet_window *w)
+{
+ /* The packet loss count comes from a time window and we use it as an
+ * indicator of our confidence of the PLC algorithm. It is known to
+ * generate poorer and robotic feeling sounds, when the majority of
+ * samples in the PLC history buffer are from the concealment results.
+ */
+ return w->count >= PLC_PL_THRESHOLD;
+}
+
int cras_msbc_plc_handle_good_frames(struct cras_msbc_plc *state,
const uint8_t *input, uint8_t *output)
{
int16_t *frame_head, *input_samples, *output_samples;
if (state->handled_bad_frames == 0) {
- /* If there was no packet loss before this good frame, there
- * is nothing we need to do to the frame so we'll just pass
- * the input to output.
+ /* If there was no packet concealment before this good frame,
+ * we just simply copy the input to output without reconverge.
*/
memmove(output, input, MSBC_FS * MSBC_SAMPLE_SIZE);
} else {
@@ -129,6 +170,7 @@ int cras_msbc_plc_handle_good_frames(struct cras_msbc_plc *state,
(PLC_HL - MSBC_FS) * MSBC_SAMPLE_SIZE);
memcpy(&state->hist[PLC_HL - MSBC_FS], output,
MSBC_FS * MSBC_SAMPLE_SIZE);
+ update_plc_state(state->pl_window, 0);
return MSBC_CODE_SIZE;
}
@@ -184,37 +226,60 @@ int cras_msbc_plc_handle_bad_frames(struct cras_msbc_plc *state,
int16_t *frame_head = &state->hist[PLC_HL];
size_t pcm_decoded = 0;
+ /* mSBC codec is stateful, the history of signal would contribute to the
+ * decode result state->zero_frame.
+ */
codec->decode(codec, msbc_zero_frame, MSBC_PKT_LEN, state->zero_frame,
MSBC_FS, &pcm_decoded);
- if (state->handled_bad_frames == 0) {
- /* Finds the best matching samples and amplitude */
- state->best_lag = pattern_match(state->hist) + PLC_TL;
- best_match_hist = &state->hist[state->best_lag];
- scaler = amplitude_match(&state->hist[PLC_HL - MSBC_FS],
- best_match_hist);
-
- /* Constructs the substitution samples */
- overlap_add(frame_head, 1.0, state->zero_frame, scaler,
- best_match_hist);
- for (int i = PLC_OLAL; i < MSBC_FS; i++)
- state->hist[PLC_HL + i] =
- f_to_s16(scaler * best_match_hist[i]);
- overlap_add(&frame_head[MSBC_FS], scaler,
- &best_match_hist[MSBC_FS], 1.0,
- &best_match_hist[MSBC_FS]);
-
- memmove(&frame_head[MSBC_FS + PLC_OLAL],
- &best_match_hist[MSBC_FS + PLC_OLAL],
- PLC_SBCRL * MSBC_SAMPLE_SIZE);
+ /* The PLC algorithm is more likely to generate bad results that sound
+ * robotic after severe packet losses happened. Only applying it when
+ * we are confident.
+ */
+ if (!possibly_pause_plc(state->pl_window)) {
+ if (state->handled_bad_frames == 0) {
+ /* Finds the best matching samples and amplitude */
+ state->best_lag = pattern_match(state->hist) + PLC_TL;
+ best_match_hist = &state->hist[state->best_lag];
+ scaler = amplitude_match(&state->hist[PLC_HL - MSBC_FS],
+ best_match_hist);
+
+ /* Constructs the substitution samples */
+ overlap_add(frame_head, 1.0, state->zero_frame, scaler,
+ best_match_hist);
+ for (int i = PLC_OLAL; i < MSBC_FS; i++)
+ state->hist[PLC_HL + i] =
+ f_to_s16(scaler * best_match_hist[i]);
+ overlap_add(&frame_head[MSBC_FS], scaler,
+ &best_match_hist[MSBC_FS], 1.0,
+ &best_match_hist[MSBC_FS]);
+
+ memmove(&frame_head[MSBC_FS + PLC_OLAL],
+ &best_match_hist[MSBC_FS + PLC_OLAL],
+ PLC_SBCRL * MSBC_SAMPLE_SIZE);
+ } else {
+ memmove(frame_head, &state->hist[state->best_lag],
+ (MSBC_FS + PLC_SBCRL + PLC_OLAL) *
+ MSBC_SAMPLE_SIZE);
+ }
+ state->handled_bad_frames++;
} else {
- memmove(frame_head, &state->hist[state->best_lag],
- (MSBC_FS + PLC_SBCRL + PLC_OLAL) * MSBC_SAMPLE_SIZE);
+ /* This is a case similar to receiving a good frame with all
+ * zeros, we set handled_bad_frames to zero to prevent the
+ * following good frame from being concealed to reconverge with
+ * the zero frames we fill in. The concealment result sounds
+ * more artificial and weird than simply writing zeros and
+ * following samples.
+ */
+ memmove(frame_head, state->zero_frame, MSBC_CODE_SIZE);
+ memset(frame_head + MSBC_CODE_SIZE, 0,
+ (PLC_SBCRL + PLC_OLAL) * MSBC_SAMPLE_SIZE);
+ state->handled_bad_frames = 0;
}
- state->handled_bad_frames++;
memcpy(output, frame_head, MSBC_CODE_SIZE);
memmove(state->hist, &state->hist[MSBC_FS],
(PLC_HL + PLC_SBCRL + PLC_OLAL) * MSBC_SAMPLE_SIZE);
+ update_plc_state(state->pl_window, 1);
return MSBC_CODE_SIZE;
}
diff --git a/cras/src/plc/cras_plc_test.c b/cras/src/plc/cras_plc_test.c
index 458f1254..4b7a6a77 100644
--- a/cras/src/plc/cras_plc_test.c
+++ b/cras/src/plc/cras_plc_test.c
@@ -4,11 +4,13 @@
*/
#include <errno.h>
+#include <getopt.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -29,32 +31,65 @@ static const uint8_t msbc_zero_frame[] = {
0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c
};
-bool *generate_pl_seq(unsigned pk_count, unsigned loss_count)
+bool *generate_pl_seq(int input_file_size, float pl_percent)
{
- bool *seq = (bool *)calloc(pk_count, sizeof(*seq));
+ unsigned pk_count, pl_count;
+ bool *seq;
+
+ pk_count = input_file_size / MSBC_CODE_SIZE;
+ pl_count = pk_count * (pl_percent / 100.0);
+ seq = (bool *)calloc(pk_count, sizeof(*seq));
srand(RND_SEED);
- while (loss_count > 0) {
+ while (pl_count > 0) {
bool *missed = &seq[rand() % pk_count];
if (!*missed) {
*missed = true;
- loss_count--;
+ pl_count--;
+ }
+ }
+ return seq;
+}
+
+/* pl_hex is expected to be consecutive bytes(two chars) in hex format.*/
+bool *parse_pl_hex(int input_file_size, const char *pl_hex)
+{
+ char tmp[3];
+ uint8_t val = 0;
+ int i, pl_hex_len, seq_len;
+ bool *seq;
+
+ pl_hex_len = strlen(pl_hex);
+ seq_len = MAX(1 + input_file_size / MSBC_CODE_SIZE, pl_hex_len * 4);
+ seq = (bool *)calloc(seq_len, sizeof(*seq));
+
+ for (i = 0; i < seq_len; i++) {
+ /* If sequence is longer then the provided pl_hex, leave the
+ * rest to all zeros. */
+ if (i > pl_hex_len * 4)
+ break;
+ if (i % 8 == 0) {
+ memcpy(tmp, pl_hex + i / 4, 2);
+ tmp[2] = '\0';
+ val = strtol(tmp, NULL, 16);
}
+ seq[i] = val & 1U;
+ val >>= 1;
}
+ printf("pl_hex string maps to %ld ms, total sequence size %f ms\n",
+ strlen(pl_hex) * 30, seq_len * 7.5f);
return seq;
}
-void plc_experiment(char *input_filename, float pl_percent, bool with_plc)
+void plc_experiment(const char *input_filename, bool *pl_seq, bool with_plc)
{
char output_filename[255];
int input_fd, output_fd, rc;
- struct stat st;
- bool *pl_seq;
struct cras_audio_codec *msbc_input = cras_msbc_codec_create();
struct cras_audio_codec *msbc_output = cras_msbc_codec_create();
struct cras_msbc_plc *plc = cras_msbc_plc_create();
uint8_t buffer[MSBC_CODE_SIZE], packet_buffer[MSBC_PKT_FRAME_LEN];
size_t encoded, decoded;
- unsigned pk_count, pl_count, count = 0;
+ unsigned count = 0;
input_fd = open(input_filename, O_RDONLY);
if (input_fd == -1) {
@@ -63,9 +98,9 @@ void plc_experiment(char *input_filename, float pl_percent, bool with_plc)
}
if (with_plc)
- sprintf(output_filename, "output_%2.2f_plc.raw", pl_percent);
+ sprintf(output_filename, "output_with_plc.raw");
else
- sprintf(output_filename, "output_%2.2f_zero.raw", pl_percent);
+ sprintf(output_filename, "output_with_zero.raw");
output_fd = open(output_filename, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (output_fd == -1) {
@@ -74,11 +109,6 @@ void plc_experiment(char *input_filename, float pl_percent, bool with_plc)
return;
}
- fstat(input_fd, &st);
- pk_count = st.st_size / MSBC_CODE_SIZE;
- pl_count = pk_count * (pl_percent / 100.0);
- pl_seq = generate_pl_seq(pk_count, pl_count);
-
while (1) {
rc = read(input_fd, buffer, MSBC_CODE_SIZE);
if (rc < 0) {
@@ -117,19 +147,77 @@ void plc_experiment(char *input_filename, float pl_percent, bool with_plc)
}
}
+static void show_usage()
+{
+ printf("This test only supports reading/writing raw audio with format:\n"
+ "\t16000 sample rate, mono channel, S16_LE\n");
+ printf("--help - Print this usage.\n");
+ printf("--input_file - path to an audio file.\n");
+ printf("--pattern - Hex string representing consecutive packets'"
+ "status.\n");
+ printf("--random - Percentage of packet loss.\n");
+}
+
int main(int argc, char **argv)
{
- if (argc != 3) {
- printf("Usage: cras_plc_test input.raw pl_percentage\n"
- "This test only supports reading/writing files with "
- "format:\n"
- "- raw pcm\n"
- "- 16000 sample rate\n"
- "- mono channel\n"
- "- S16_LE sample format\n");
+ int fd;
+ struct stat st;
+ float pl_percent;
+ int pl_percent_set = 0;
+ int option_character;
+ int option_index = 0;
+ const char *input_file = NULL;
+ const char *pl_hex = NULL;
+ bool *pl_seq = NULL;
+ static struct option long_options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "input", required_argument, NULL, 'i' },
+ { "pattern", required_argument, NULL, 'p' },
+ { "random", required_argument, NULL, 'r' },
+ { NULL, 0, NULL, 0 },
+ };
+
+ while (true) {
+ option_character = getopt_long(argc, argv, "i:r:p:h",
+ long_options, &option_index);
+ if (option_character == -1)
+ break;
+ switch (option_character) {
+ case 'h':
+ show_usage();
+ break;
+ case 'i':
+ input_file = optarg;
+ break;
+ case 'p':
+ pl_hex = optarg;
+ break;
+ case 'r':
+ pl_percent = atof(optarg);
+ pl_percent_set = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((!pl_percent_set && !pl_hex) || !input_file) {
+ show_usage();
return 1;
}
- plc_experiment(argv[1], atof(argv[2]), true);
- plc_experiment(argv[1], atof(argv[2]), false);
+ fd = open(input_file, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "Cannout open input file %s\n", input_file);
+ return 1;
+ }
+ fstat(fd, &st);
+ close(fd);
+ if (pl_percent_set)
+ pl_seq = generate_pl_seq(st.st_size, pl_percent);
+ else if (pl_hex)
+ pl_seq = parse_pl_hex(st.st_size, pl_hex);
+
+ plc_experiment(input_file, pl_seq, true);
+ plc_experiment(input_file, pl_seq, false);
}
diff --git a/cras/src/server/audio_thread.c b/cras/src/server/audio_thread.c
index df713ca5..cd155e82 100644
--- a/cras/src/server/audio_thread.c
+++ b/cras/src/server/audio_thread.c
@@ -555,8 +555,11 @@ static void append_stream_dump_info(struct audio_debug_info *info,
si->runtime_nsec = time_since.tv_nsec;
}
-/* Handle a message sent to the playback thread */
-static int handle_playback_thread_message(struct audio_thread *thread)
+/* Handle a message sent from main thread to the audio thread.
+ * Returns:
+ * Error code when reading or sending message fails.
+ */
+static int handle_audio_thread_message(struct audio_thread *thread)
{
uint8_t buf[256];
struct audio_thread_msg *msg = (struct audio_thread_msg *)buf;
@@ -711,7 +714,7 @@ static int handle_playback_thread_message(struct audio_thread *thread)
err = audio_thread_send_response(thread, ret);
if (err < 0)
return err;
- return ret;
+ return 0;
}
/* Returns the number of active streams plus the number of active devices. */
@@ -912,7 +915,7 @@ static void *audio_io_thread(void *arg)
continue;
if (thread->pollfds[0].revents & POLLIN) {
- rc = handle_playback_thread_message(thread);
+ rc = handle_audio_thread_message(thread);
if (rc < 0)
syslog(LOG_ERR, "handle message %d", rc);
}
diff --git a/cras/src/server/config/cras_board_config.c b/cras/src/server/config/cras_board_config.c
index d04d626b..14d3fa0c 100644
--- a/cras/src/server/config/cras_board_config.c
+++ b/cras/src/server/config/cras_board_config.c
@@ -13,12 +13,14 @@ static const int32_t DEFAULT_OUTPUT_BUFFER_SIZE = 512;
static const int32_t AEC_SUPPORTED_DEFAULT = 0;
static const int32_t AEC_GROUP_ID_DEFAULT = -1;
static const int32_t BLUETOOTH_WBS_ENABLED_INI_DEFAULT = 1;
+static const int32_t BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_DEFAULT = 0;
#define CONFIG_NAME "board.ini"
#define DEFAULT_OUTPUT_BUF_SIZE_INI_KEY "output:default_output_buffer_size"
#define AEC_SUPPORTED_INI_KEY "processing:aec_supported"
#define AEC_GROUP_ID_INI_KEY "processing:group_id"
#define BLUETOOTH_WBS_ENABLED_INI_KEY "bluetooth:wbs_enabled"
+#define BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_KEY "bluetooth:deprioritize_wbs_mic"
#define UCM_IGNORE_SUFFIX_KEY "ucm:ignore_suffix"
void cras_board_config_get(const char *config_path,
@@ -34,6 +36,8 @@ void cras_board_config_get(const char *config_path,
board_config->aec_group_id = AEC_GROUP_ID_DEFAULT;
board_config->ucm_ignore_suffix = NULL;
board_config->bt_wbs_enabled = BLUETOOTH_WBS_ENABLED_INI_DEFAULT;
+ board_config->deprioritize_bt_wbs_mic =
+ BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_DEFAULT;
if (config_path == NULL)
return;
@@ -66,6 +70,12 @@ void cras_board_config_get(const char *config_path,
board_config->bt_wbs_enabled = iniparser_getint(
ini, ini_key, BLUETOOTH_WBS_ENABLED_INI_DEFAULT);
+ snprintf(ini_key, MAX_INI_KEY_LENGTH,
+ BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_KEY);
+ ini_key[MAX_INI_KEY_LENGTH] = 0;
+ board_config->deprioritize_bt_wbs_mic = iniparser_getint(
+ ini, ini_key, BLUETOOTH_DEPRIORITIZE_WBS_MIC_INI_DEFAULT);
+
snprintf(ini_key, MAX_INI_KEY_LENGTH, UCM_IGNORE_SUFFIX_KEY);
ini_key[MAX_INI_KEY_LENGTH] = 0;
ptr = iniparser_getstring(ini, ini_key, "");
diff --git a/cras/src/server/config/cras_board_config.h b/cras/src/server/config/cras_board_config.h
index ed80bec5..2ecde265 100644
--- a/cras/src/server/config/cras_board_config.h
+++ b/cras/src/server/config/cras_board_config.h
@@ -13,6 +13,7 @@ struct cras_board_config {
int32_t aec_supported;
int32_t aec_group_id;
int32_t bt_wbs_enabled;
+ int32_t deprioritize_bt_wbs_mic;
char *ucm_ignore_suffix;
};
diff --git a/cras/src/server/cras_a2dp_iodev.c b/cras/src/server/cras_a2dp_iodev.c
index 683fa31f..6c434758 100644
--- a/cras/src/server/cras_a2dp_iodev.c
+++ b/cras/src/server/cras_a2dp_iodev.c
@@ -664,7 +664,7 @@ struct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport)
iodev->start = start;
iodev->frames_to_play_in_sleep = frames_to_play_in_sleep;
- /* Create a dummy ionode */
+ /* Create an empty ionode */
node = (struct cras_ionode *)calloc(1, sizeof(*node));
node->dev = iodev;
strcpy(node->name, iodev->info.name);
@@ -684,6 +684,8 @@ struct cras_iodev *a2dp_iodev_create(struct cras_bt_transport *transport)
iodev->info.max_supported_channels =
(a2dp.channel_mode == SBC_CHANNEL_MODE_MONO) ? 1 : 2;
+ ewma_power_disable(&iodev->ewma);
+
return iodev;
error:
if (a2dpio) {
diff --git a/cras/src/server/cras_alsa_helpers.c b/cras/src/server/cras_alsa_helpers.c
index 4f402498..6cdc165a 100644
--- a/cras/src/server/cras_alsa_helpers.c
+++ b/cras/src/server/cras_alsa_helpers.c
@@ -556,7 +556,7 @@ int cras_alsa_set_hwparams(snd_pcm_t *handle, struct cras_audio_format *format,
return 0;
}
-int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp)
+int cras_alsa_set_swparams(snd_pcm_t *handle)
{
int err;
snd_pcm_sw_params_t *swparams;
@@ -593,50 +593,7 @@ int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp)
return err;
}
- if (*enable_htimestamp) {
- /* Use MONOTONIC_RAW time-stamps. */
- err = snd_pcm_sw_params_set_tstamp_type(
- handle, swparams, SND_PCM_TSTAMP_TYPE_MONOTONIC_RAW);
- if (err < 0) {
- syslog(LOG_ERR, "set_tstamp_type: %s\n",
- snd_strerror(err));
- return err;
- }
- err = snd_pcm_sw_params_set_tstamp_mode(handle, swparams,
- SND_PCM_TSTAMP_ENABLE);
- if (err < 0) {
- syslog(LOG_ERR, "set_tstamp_mode: %s\n",
- snd_strerror(err));
- return err;
- }
- }
-
- /* This hack is required because ALSA-LIB does not provide any way to
- * detect whether MONOTONIC_RAW timestamps are supported by the kernel.
- * In ALSA-LIB, the code checks the hardware protocol version. */
err = snd_pcm_sw_params(handle, swparams);
- if (err == -EINVAL && *enable_htimestamp) {
- *enable_htimestamp = 0;
- syslog(LOG_WARNING,
- "MONOTONIC_RAW timestamps are not supported.");
-
- err = snd_pcm_sw_params_set_tstamp_type(
- handle, swparams, SND_PCM_TSTAMP_TYPE_GETTIMEOFDAY);
- if (err < 0) {
- syslog(LOG_ERR, "set_tstamp_type: %s\n",
- snd_strerror(err));
- return err;
- }
- err = snd_pcm_sw_params_set_tstamp_mode(handle, swparams,
- SND_PCM_TSTAMP_NONE);
- if (err < 0) {
- syslog(LOG_ERR, "set_tstamp_mode: %s\n",
- snd_strerror(err));
- return err;
- }
-
- err = snd_pcm_sw_params(handle, swparams);
- }
if (err < 0) {
syslog(LOG_ERR, "sw_params: %s\n", snd_strerror(err));
diff --git a/cras/src/server/cras_alsa_helpers.h b/cras/src/server/cras_alsa_helpers.h
index 38976749..01a42aea 100644
--- a/cras/src/server/cras_alsa_helpers.h
+++ b/cras/src/server/cras_alsa_helpers.h
@@ -135,13 +135,10 @@ int cras_alsa_set_hwparams(snd_pcm_t *handle, struct cras_audio_format *format,
/* Sets up the swparams to alsa.
* Args:
* handle - The open PCM to configure.
- * enable_htimestamp - If non-zero, enable and configure hardware timestamps,
- * updated to reflect whether MONOTONIC RAW htimestamps
- * are supported by the kernel implementation.
* Returns:
* 0 on success, negative error on failure.
*/
-int cras_alsa_set_swparams(snd_pcm_t *handle, int *enable_htimestamp);
+int cras_alsa_set_swparams(snd_pcm_t *handle);
/* Get the number of used frames in the alsa buffer.
*
diff --git a/cras/src/server/cras_alsa_io.c b/cras/src/server/cras_alsa_io.c
index 792305bb..da4ef630 100644
--- a/cras/src/server/cras_alsa_io.c
+++ b/cras/src/server/cras_alsa_io.c
@@ -113,7 +113,6 @@ struct alsa_input_node {
* is_first - true if this is the first iodev on the card.
* fully_specified - true if this device and it's nodes were fully specified.
* That is, don't automatically create nodes for it.
- * enable_htimestamp - True when the device's htimestamp is used.
* handle - Handle to the opened ALSA device.
* num_severe_underruns - Number of times we have run out of data badly.
Unlike num_underruns which records for the duration
@@ -148,7 +147,6 @@ struct alsa_io {
enum CRAS_ALSA_CARD_TYPE card_type;
int is_first;
int fully_specified;
- int enable_htimestamp;
snd_pcm_t *handle;
unsigned int num_severe_underruns;
snd_pcm_stream_t alsa_stream;
@@ -331,8 +329,7 @@ static int frames_queued(const struct cras_iodev *iodev,
aio->num_severe_underruns++;
return rc;
}
- if (!aio->enable_htimestamp)
- clock_gettime(CLOCK_MONOTONIC_RAW, tstamp);
+ clock_gettime(CLOCK_MONOTONIC_RAW, tstamp);
if (iodev->direction == CRAS_STREAM_INPUT)
return (int)frames;
@@ -374,7 +371,7 @@ static int close_dev(struct cras_iodev *iodev)
return 0;
}
-static int dummy_hotword_cb(void *arg, int revents)
+static int empty_hotword_cb(void *arg, int revents)
{
/* Only need this once. */
struct alsa_io *aio = (struct alsa_io *)arg;
@@ -449,7 +446,7 @@ static int configure_dev(struct cras_iodev *iodev)
return rc;
/* Configure software params. */
- rc = cras_alsa_set_swparams(aio->handle, &aio->enable_htimestamp);
+ rc = cras_alsa_set_swparams(aio->handle);
if (rc < 0)
return rc;
@@ -490,7 +487,7 @@ static int configure_dev(struct cras_iodev *iodev)
if (aio->poll_fd >= 0)
audio_thread_add_events_callback(
- aio->poll_fd, dummy_hotword_cb, aio, POLLIN);
+ aio->poll_fd, empty_hotword_cb, aio, POLLIN);
}
/* Capture starts right away, playback will wait for samples. */
@@ -1549,7 +1546,7 @@ static void jack_output_plug_event(const struct cras_alsa_jack *jack,
* For HDMI plug event cases, update max supported channels according
* to the current active node.
*/
- if (node->base.type == CRAS_NODE_TYPE_HDMI)
+ if (node->base.type == CRAS_NODE_TYPE_HDMI && plugged)
update_max_supported_channels(&aio->base);
}
@@ -2134,8 +2131,6 @@ alsa_iodev_create(size_t card_index, const char *card_name, size_t device_index,
rc = ucm_get_min_buffer_level(ucm, &level);
if (!rc && direction == CRAS_STREAM_OUTPUT)
iodev->min_buffer_level = level;
-
- aio->enable_htimestamp = ucm_get_enable_htimestamp_flag(ucm);
}
set_iodev_name(iodev, card_name, dev_name, card_index, device_index,
@@ -2355,8 +2350,11 @@ void alsa_iodev_ucm_complete_init(struct cras_iodev *iodev)
set_default_hotword_model(iodev);
+ node = iodev->active_node;
+
/* Record max supported channels into cras_iodev_info. */
- update_max_supported_channels(iodev);
+ if (node && node->plugged)
+ update_max_supported_channels(iodev);
}
void alsa_iodev_destroy(struct cras_iodev *iodev)
diff --git a/cras/src/server/cras_alsa_jack.c b/cras/src/server/cras_alsa_jack.c
index 52a227e7..6d4d7bf5 100644
--- a/cras/src/server/cras_alsa_jack.c
+++ b/cras/src/server/cras_alsa_jack.c
@@ -734,6 +734,16 @@ static snd_hctl_elem_t *find_eld_control_by_dev_index(snd_hctl_t *hctl,
return snd_hctl_find_elem(hctl, elem_id);
}
+/* For non-gpio jack, check if it's of type hdmi/dp by
+ * matching jack name. */
+static int is_jack_hdmi_dp(const char *jack_name)
+{
+ // TODO(hychao): Use the information provided in UCM instead of
+ // name matching.
+ static const char *hdmi_dp = "HDMI";
+ return !!strstr(jack_name, hdmi_dp);
+}
+
/* Find GPIO jacks for this jack_list.
* Args:
* jack_list - Jack list to add to.
@@ -772,8 +782,9 @@ static int find_gpio_jacks(struct cras_alsa_jack_list *jack_list,
if (result_jack) {
*result_jack = data.result_jack;
- /* Find ELD control for HDMI/DP gpio jack. */
- if (*result_jack)
+ /* Find ELD control only for HDMI/DP gpio jack. */
+ if (*result_jack &&
+ is_jack_hdmi_dp((*result_jack)->gpio.device_name))
(*result_jack)->eld_control =
find_eld_control_by_dev_index(
jack_list->hctl,
@@ -833,14 +844,6 @@ static unsigned int hctl_jack_device_index(const char *name)
return (unsigned int)device_index;
}
-/* For non-gpio jack, check if it's of type hdmi/dp by
- * matching jack name. */
-static int is_jack_hdmi_dp(const char *jack_name)
-{
- static const char *hdmi_dp = "HDMI/DP";
- return strncmp(jack_name, hdmi_dp, strlen(hdmi_dp)) == 0;
-}
-
/* Checks if the given control name is in the supplied list of possible jack
* control base names. */
static int is_jack_control_in_list(const char *const *list,
diff --git a/cras/src/server/cras_alsa_plugin_io.c b/cras/src/server/cras_alsa_plugin_io.c
index 9c557a40..32c1ae11 100644
--- a/cras/src/server/cras_alsa_plugin_io.c
+++ b/cras/src/server/cras_alsa_plugin_io.c
@@ -24,9 +24,9 @@
#define PLUGIN_KEY_PCM "pcm"
#define PLUGIN_KEY_CARD "card"
-#define DUMMY_USB_VID 0x00
-#define DUMMY_USB_PID 0x00
-#define DUMMY_USB_SERIAL_NUMBER "serial-number-not-used"
+#define NULL_USB_VID 0x00
+#define NULL_USB_PID 0x00
+#define NULL_USB_SERIAL_NUMBER "serial-number-not-used"
struct hctl_poll_fd {
int fd;
@@ -159,12 +159,11 @@ void alsa_plugin_io_create(enum CRAS_STREAM_DIRECTION direction,
"section %s mixer_name %s",
section->name, section->mixer_name);
}
- plugin->iodev =
- alsa_iodev_create(0, card_name, 0, pcm_name, "", "",
- ALSA_CARD_TYPE_USB, 1, /* is first */
- plugin->mixer, NULL, plugin->ucm,
- plugin->hctl, direction, DUMMY_USB_VID,
- DUMMY_USB_PID, DUMMY_USB_SERIAL_NUMBER);
+ plugin->iodev = alsa_iodev_create(0, card_name, 0, pcm_name, "", "",
+ ALSA_CARD_TYPE_USB, 1, /* is first */
+ plugin->mixer, NULL, plugin->ucm,
+ plugin->hctl, direction, NULL_USB_VID,
+ NULL_USB_PID, NULL_USB_SERIAL_NUMBER);
DL_FOREACH (ucm_sections, section) {
if (section->dir != plugin->iodev->direction)
diff --git a/cras/src/server/cras_alsa_ucm.c b/cras/src/server/cras_alsa_ucm.c
index 3782cb24..9759a50f 100644
--- a/cras/src/server/cras_alsa_ucm.c
+++ b/cras/src/server/cras_alsa_ucm.c
@@ -57,7 +57,6 @@ static const char default_node_gain[] = "DefaultNodeGain";
static const char hotword_model_prefix[] = "Hotword Model";
static const char fully_specified_ucm_var[] = "FullySpecifiedUCM";
static const char main_volume_names[] = "MainVolumeNames";
-static const char enable_htimestamp_var[] = "EnableHtimestamp";
/* Use case verbs corresponding to CRAS_STREAM_TYPE. */
static const char *use_case_verbs[] = {
@@ -1121,15 +1120,3 @@ unsigned int ucm_get_dma_period_for_dev(struct cras_use_case_mgr *mgr,
return 0;
return value;
}
-
-unsigned int ucm_get_enable_htimestamp_flag(struct cras_use_case_mgr *mgr)
-{
- char *flag;
- int ret = 0;
- flag = ucm_get_flag(mgr, enable_htimestamp_var);
- if (!flag)
- return 0;
- ret = !strcmp(flag, "1");
- free(flag);
- return ret;
-}
diff --git a/cras/src/server/cras_alsa_ucm.h b/cras/src/server/cras_alsa_ucm.h
index 48dc6550..99a8b440 100644
--- a/cras/src/server/cras_alsa_ucm.h
+++ b/cras/src/server/cras_alsa_ucm.h
@@ -472,12 +472,4 @@ unsigned int ucm_get_dma_period_for_dev(struct cras_use_case_mgr *mgr,
*/
unsigned int ucm_get_optimize_no_stream_flag(struct cras_use_case_mgr *mgr);
-/* Retrieve the flag that enables use of htimestamp.
- * Args:
- * mgr - The cras_use_case_mgr pointer returned from alsa_ucm_create.
- * Returns:
- * 1 if the flag is enabled. 0 otherwise.
- */
-unsigned int ucm_get_enable_htimestamp_flag(struct cras_use_case_mgr *mgr);
-
#endif /* _CRAS_ALSA_UCM_H */
diff --git a/cras/src/server/cras_apm_list.h b/cras/src/server/cras_apm_list.h
index b9a7fe2f..7a36ceae 100644
--- a/cras/src/server/cras_apm_list.h
+++ b/cras/src/server/cras_apm_list.h
@@ -162,7 +162,7 @@ void cras_apm_list_set_aec_dump(struct cras_apm_list *list, void *dev_ptr,
/*
* If webrtc audio processing library is not available then define all
- * cras_apm_list functions as dummy. As long as cras_apm_list_add returns
+ * cras_apm_list functions as empty. As long as cras_apm_list_add returns
* NULL, non of the other functions should be called.
*/
static inline int cras_apm_list_init(const char *device_config_dir)
diff --git a/cras/src/server/cras_bt_device.c b/cras/src/server/cras_bt_device.c
index 0607ac8e..70c87479 100644
--- a/cras/src/server/cras_bt_device.c
+++ b/cras/src/server/cras_bt_device.c
@@ -61,9 +61,7 @@ static const unsigned int CONN_WATCH_MAX_RETRIES = 30;
static const unsigned int SCO_SUSPEND_DELAY_MS = 5000;
static const unsigned int CRAS_SUPPORTED_PROFILES =
- CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
- CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE |
- CRAS_BT_DEVICE_PROFILE_HSP_AUDIOGATEWAY;
+ CRAS_BT_DEVICE_PROFILE_A2DP_SINK | CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE;
/* Object to represent a general bluetooth device, and used to
* associate with some CRAS modules if it supports audio.
@@ -79,6 +77,8 @@ static const unsigned int CRAS_SUPPORTED_PROFILES =
* connected - If this devices is connected.
* connected_profiles - OR'ed all connected audio profiles.
* profiles - OR'ed by all audio profiles this device supports.
+ * hidden_profiles - OR'ed by all audio profiles this device actually
+ * supports but is not scanned by BlueZ.
* bt_iodevs - The pointer to the cras_iodevs of this device.
* active_profile - The flag to indicate the active audio profile this
* device is currently using.
@@ -102,8 +102,9 @@ struct cras_bt_device {
int paired;
int trusted;
int connected;
- enum cras_bt_device_profile connected_profiles;
- enum cras_bt_device_profile profiles;
+ unsigned int connected_profiles;
+ unsigned int profiles;
+ unsigned int hidden_profiles;
struct cras_iodev *bt_iodevs[CRAS_NUM_DIRECTIONS];
unsigned int active_profile;
int use_hardware_volume;
@@ -512,14 +513,18 @@ int cras_bt_device_audio_gateway_initialized(struct cras_bt_device *device)
* behavior on qualification test software. */
if (!cras_bt_device_supports_profile(
device, CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE)) {
- cras_bt_device_add_supported_profiles(device, HFP_HF_UUID);
+ unsigned int profiles =
+ device->profiles | CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE;
+ cras_bt_device_set_supported_profiles(device, profiles);
+ device->hidden_profiles |= CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE;
bt_device_conn_watch_cb(NULL, (void *)device);
}
return 0;
}
-int cras_bt_device_get_active_profile(const struct cras_bt_device *device)
+unsigned int
+cras_bt_device_get_active_profile(const struct cras_bt_device *device)
{
return device->active_profile;
}
@@ -569,6 +574,19 @@ static void cras_bt_device_log_profile(const struct cras_bt_device *device,
}
}
+static void cras_bt_device_log_profiles(const struct cras_bt_device *device,
+ unsigned int profiles)
+{
+ unsigned int profile;
+
+ while (profiles) {
+ /* Get the LSB of profiles */
+ profile = profiles & -profiles;
+ cras_bt_device_log_profile(device, profile);
+ profiles ^= profile;
+ }
+}
+
static int
cras_bt_device_is_profile_connected(const struct cras_bt_device *device,
enum cras_bt_device_profile profile)
@@ -708,7 +726,7 @@ void cras_bt_device_set_connected(struct cras_bt_device *device, int value)
void cras_bt_device_notify_profile_dropped(struct cras_bt_device *device,
enum cras_bt_device_profile profile)
{
- device->connected_profiles &= !profile;
+ device->connected_profiles &= ~profile;
/* Do nothing if device already disconnected. */
if (!device->connected)
@@ -723,37 +741,33 @@ void cras_bt_device_notify_profile_dropped(struct cras_bt_device *device,
UNEXPECTED_PROFILE_DROP);
}
-/*
- * Check if the uuid is of a new audio profile that isn't listed
- * as supported by device.
+/* Refresh the list of known supported profiles.
* Args:
- * device - The BT device holding supported profiles bitmap.
- * uuid - UUID string from the device properties notified by BlueZ.
+ * device - The BT device holding scanned profiles bitmap.
+ * profiles - The OR'ed profiles the device claims to support as is notified
+ * by BlueZ.
* Returns:
- * True if uuid is a new audio profiles not already supported by device.
+ * The OR'ed profiles that are both supported by Cras and isn't previously
+ * supported by the device.
*/
-int cras_bt_device_add_supported_profiles(struct cras_bt_device *device,
- const char *uuid)
+int cras_bt_device_set_supported_profiles(struct cras_bt_device *device,
+ unsigned int profiles)
{
- enum cras_bt_device_profile profile =
- cras_bt_device_profile_from_uuid(uuid);
-
- if (profile == 0)
+ /* Do nothing if no new profiles. */
+ if ((device->profiles & profiles) == profiles)
return 0;
- /* Do nothing if this profile is not new. */
- if (device->profiles & profile)
- return 0;
+ unsigned int new_profiles = profiles & ~device->profiles;
/* Log this event as we might need to re-intialize the BT audio nodes
* if new audio profile is reported for already connected device. */
- if (device->connected && (profile & CRAS_SUPPORTED_PROFILES))
+ if (device->connected && (new_profiles & CRAS_SUPPORTED_PROFILES))
BTLOG(btlog, BT_NEW_AUDIO_PROFILE_AFTER_CONNECT,
- device->profiles, profile);
- device->profiles |= profile;
- cras_bt_device_log_profile(device, profile);
+ device->profiles, new_profiles);
+ cras_bt_device_log_profiles(device, new_profiles);
+ device->profiles = profiles | device->hidden_profiles;
- return (profile & CRAS_SUPPORTED_PROFILES);
+ return (new_profiles & CRAS_SUPPORTED_PROFILES);
}
void cras_bt_device_update_properties(struct cras_bt_device *device,
@@ -821,6 +835,7 @@ void cras_bt_device_update_properties(struct cras_bt_device *device,
"as") == 0 &&
strcmp(key, "UUIDs") == 0) {
DBusMessageIter uuid_array_iter;
+ unsigned int profiles = 0;
dbus_message_iter_recurse(&variant_iter,
&uuid_array_iter);
@@ -830,22 +845,21 @@ void cras_bt_device_update_properties(struct cras_bt_device *device,
dbus_message_iter_get_basic(&uuid_array_iter,
&uuid);
-
- /*
- * If updated properties includes new audio
- * profile, and device is connected, we need
- * to start connection watcher. This is needed
- * because on some bluetooth device, supported
- * profiles do not present when device
- * interface is added and they are updated
- * later.
- */
- if (cras_bt_device_add_supported_profiles(
- device, uuid))
- watch_needed = device->connected;
+ profiles |=
+ cras_bt_device_profile_from_uuid(uuid);
dbus_message_iter_next(&uuid_array_iter);
}
+
+ /* If updated properties includes new audio profile and
+ * device is connected, we need to start connection
+ * watcher. This is needed because on some bluetooth
+ * devices, supported profiles do not present when
+ * device interface is added and they are updated later.
+ */
+ if (cras_bt_device_set_supported_profiles(device,
+ profiles))
+ watch_needed = device->connected;
}
dbus_message_iter_next(properties_array_iter);
@@ -876,7 +890,7 @@ void cras_bt_device_update_properties(struct cras_bt_device *device,
} else if (strcmp(key, "Connected") == 0) {
device->connected = 0;
} else if (strcmp(key, "UUIDs") == 0) {
- device->profiles = 0;
+ device->profiles = device->hidden_profiles;
}
dbus_message_iter_next(invalidated_array_iter);
diff --git a/cras/src/server/cras_bt_device.h b/cras/src/server/cras_bt_device.h
index 3800927e..4202bc93 100644
--- a/cras/src/server/cras_bt_device.h
+++ b/cras/src/server/cras_bt_device.h
@@ -63,8 +63,8 @@ void cras_bt_device_update_properties(struct cras_bt_device *device,
DBusMessageIter *invalidated_array_iter);
/* Updates the supported profiles on dev. Expose for unit test. */
-int cras_bt_device_add_supported_profiles(struct cras_bt_device *device,
- const char *uuid);
+int cras_bt_device_set_supported_profiles(struct cras_bt_device *device,
+ unsigned int profiles);
/* Checks if profile is claimed supported by the device. */
int cras_bt_device_supports_profile(const struct cras_bt_device *device,
@@ -133,7 +133,8 @@ void cras_bt_device_rm_iodev(struct cras_bt_device *device,
struct cras_iodev *iodev);
/* Gets the active profile of the bt device. */
-int cras_bt_device_get_active_profile(const struct cras_bt_device *device);
+unsigned int
+cras_bt_device_get_active_profile(const struct cras_bt_device *device);
/* Sets the active profile of the bt device. */
void cras_bt_device_set_active_profile(struct cras_bt_device *device,
diff --git a/cras/src/server/cras_bt_io.c b/cras/src/server/cras_bt_io.c
index 3cffe148..9f5c2f79 100644
--- a/cras/src/server/cras_bt_io.c
+++ b/cras/src/server/cras_bt_io.c
@@ -518,7 +518,7 @@ struct cras_iodev *cras_bt_io_create(struct cras_bt_device *device,
iodev->set_volume = set_bt_volume;
}
- /* Create the dummy node so it's the only node exposed to UI, and
+ /* Create the fake node so it's the only node exposed to UI, and
* point it to the first profile dev. */
active = (struct bt_node *)calloc(1, sizeof(*active));
if (!active)
diff --git a/cras/src/server/cras_control_rclient.c b/cras/src/server/cras_control_rclient.c
index 3906a23b..cd0c4d3b 100644
--- a/cras/src/server/cras_control_rclient.c
+++ b/cras/src/server/cras_control_rclient.c
@@ -15,6 +15,7 @@
#include "cras_dsp.h"
#include "cras_iodev.h"
#include "cras_iodev_list.h"
+#include "cras_hfp_ag_profile.h"
#include "cras_main_thread_log.h"
#include "cras_messages.h"
#include "cras_observer.h"
@@ -298,15 +299,11 @@ static int ccr_handle_message_from_client(struct cras_rclient *client,
switch (msg->id) {
case CRAS_SERVER_CONNECT_STREAM: {
int client_shm_fd = num_fds > 1 ? fds[1] : -1;
- struct cras_connect_message cmsg;
if (MSG_LEN_VALID(msg, struct cras_connect_message)) {
rclient_handle_client_stream_connect(
client,
(const struct cras_connect_message *)msg, fd,
client_shm_fd);
- } else if (!convert_connect_message_old(msg, &cmsg)) {
- rclient_handle_client_stream_connect(client, &cmsg, fd,
- client_shm_fd);
} else {
return -EINVAL;
}
@@ -422,10 +419,15 @@ static int ccr_handle_message_from_client(struct cras_rclient *client,
state = cras_system_state_get_no_lock();
#ifdef CRAS_DBUS
memcpy(&state->bt_debug_info.bt_log, btlog,
- sizeof(struct cras_bt_debug_info));
+ sizeof(struct cras_bt_event_log));
+ memcpy(&state->bt_debug_info.wbs_logger,
+ cras_hfp_ag_get_wbs_logger(),
+ sizeof(struct packet_status_logger));
#else
memset(&state->bt_debug_info.bt_log, 0,
sizeof(struct cras_bt_debug_info));
+ memset(&state->bt_debug_info.wbs_logger, 0,
+ sizeof(struct packet_status_logger));
#endif
cras_fill_client_audio_debug_info_ready(&msg);
diff --git a/cras/src/server/cras_dbus_control.c b/cras/src/server/cras_dbus_control.c
index 628ec221..3479c3c6 100644
--- a/cras/src/server/cras_dbus_control.c
+++ b/cras/src/server/cras_dbus_control.c
@@ -75,6 +75,9 @@
" <method name=\"GetSystemAecGroupId\">\n" \
" <arg name=\"group_id\" type=\"i\" direction=\"out\"/>\n" \
" </method>\n" \
+ " <method name=\"GetDeprioritizeBtWbsMic\">\n" \
+ " <arg name=\"deprioritized\" type=\"b\" direction=\"out\"/>\n" \
+ " </method>\n" \
" <method name=\"SetActiveOutputNode\">\n" \
" <arg name=\"node_id\" type=\"t\" direction=\"in\"/>\n" \
" </method>\n" \
@@ -105,6 +108,9 @@
" <method name=\"GetNumberOfActiveInputStreams\">\n" \
" <arg name=\"num\" type=\"i\" direction=\"out\"/>\n" \
" </method>\n" \
+ " <method name=\"GetNumberOfInputStreamsWithPermission\">\n" \
+ " <arg name=\"num\" type=\"a{sv}\" direction=\"out\"/>\n" \
+ " </method>\n" \
" <method name=\"SetGlobalOutputChannelRemix\">\n" \
" <arg name=\"num_channels\" type=\"i\" direction=\"in\"/>\n" \
" <arg name=\"coefficient\" type=\"ad\" direction=\"in\"/>\n" \
@@ -671,6 +677,27 @@ static DBusHandlerResult handle_get_system_aec_group_id(DBusConnection *conn,
}
static DBusHandlerResult
+handle_get_deprioritize_bt_wbs_mic(DBusConnection *conn, DBusMessage *message,
+ void *arg)
+{
+ DBusMessage *reply;
+ dbus_uint32_t serial = 0;
+ dbus_bool_t deprioritized;
+
+ reply = dbus_message_new_method_return(message);
+
+ deprioritized = cras_system_get_deprioritize_bt_wbs_mic();
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &deprioritized,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send(conn, reply, &serial);
+
+ dbus_message_unref(reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
handle_set_active_node(DBusConnection *conn, DBusMessage *message, void *arg,
enum CRAS_STREAM_DIRECTION direction)
{
@@ -784,6 +811,65 @@ handle_get_num_active_streams_use_output_hw(DBusConnection *conn,
return DBUS_HANDLER_RESULT_HANDLED;
}
+static bool append_num_input_streams_with_permission(
+ DBusMessage *message, uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
+{
+ DBusMessageIter array;
+ DBusMessageIter dict;
+ unsigned type;
+
+ dbus_message_iter_init_append(message, &array);
+ for (type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type) {
+ const char *client_type_str = cras_client_type_str(type);
+ if (!is_utf8_string(client_type_str)) {
+ syslog(LOG_ERR,
+ "Non-utf8 clinet_type_str '%s' cannot be sent "
+ "via dbus",
+ client_type_str);
+ client_type_str = "";
+ }
+
+ if (!dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
+ "{sv}", &dict))
+ return false;
+ if (!append_key_value(&dict, "ClientType", DBUS_TYPE_STRING,
+ DBUS_TYPE_STRING_AS_STRING,
+ &client_type_str))
+ return false;
+ if (!append_key_value(&dict, "NumStreamsWithPermission",
+ DBUS_TYPE_UINT32,
+ DBUS_TYPE_UINT32_AS_STRING,
+ &num_input_streams[type]))
+ return false;
+ if (!dbus_message_iter_close_container(&array, &dict))
+ return false;
+ }
+ return true;
+}
+
+static DBusHandlerResult
+handle_get_num_input_streams_with_permission(DBusConnection *conn,
+ DBusMessage *message, void *arg)
+{
+ DBusMessage *reply;
+ dbus_uint32_t serial = 0;
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE] = {};
+
+ reply = dbus_message_new_method_return(message);
+
+ cras_system_state_get_input_streams_with_permission(num_input_streams);
+ if (!append_num_input_streams_with_permission(reply, num_input_streams))
+ goto error;
+
+ dbus_connection_send(conn, reply, &serial);
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+error:
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
static DBusHandlerResult
handle_set_global_output_channel_remix(DBusConnection *conn,
DBusMessage *message, void *arg)
@@ -1052,6 +1138,9 @@ static DBusHandlerResult handle_control_message(DBusConnection *conn,
"GetSystemAecGroupId")) {
return handle_get_system_aec_group_id(conn, message, arg);
} else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
+ "GetDeprioritizeBtWbsMic")) {
+ return handle_get_deprioritize_bt_wbs_mic(conn, message, arg);
+ } else if (dbus_message_is_method_call(message, CRAS_CONTROL_INTERFACE,
"SetActiveOutputNode")) {
return handle_set_active_node(conn, message, arg,
CRAS_STREAM_OUTPUT);
@@ -1088,6 +1177,11 @@ static DBusHandlerResult handle_control_message(DBusConnection *conn,
arg);
} else if (dbus_message_is_method_call(
message, CRAS_CONTROL_INTERFACE,
+ "GetNumberOfInputStreamsWithPermission")) {
+ return handle_get_num_input_streams_with_permission(
+ conn, message, arg);
+ } else if (dbus_message_is_method_call(
+ message, CRAS_CONTROL_INTERFACE,
"GetNumberOfActiveOutputStreams")) {
return handle_get_num_active_streams_use_output_hw(
conn, message, arg);
@@ -1315,6 +1409,25 @@ static void signal_num_active_streams_changed(void *context,
dbus_message_unref(msg);
}
+static void signal_num_input_streams_with_permission_changed(
+ void *context, uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
+{
+ struct cras_dbus_control *control = (struct cras_dbus_control *)context;
+ dbus_uint32_t serial = 0;
+ DBusMessage *msg;
+
+ msg = create_dbus_message("NumberOfInputStreamsWithPermissionChanged");
+ if (!msg)
+ return;
+
+ if (!append_num_input_streams_with_permission(msg, num_input_streams))
+ goto error;
+
+ dbus_connection_send(control->conn, msg, &serial);
+error:
+ dbus_message_unref(msg);
+}
+
static void signal_hotword_triggered(void *context, int64_t tv_sec,
int64_t tv_nsec)
{
@@ -1399,6 +1512,8 @@ void cras_dbus_control_start(DBusConnection *conn)
observer_ops.capture_mute_changed = signal_capture_mute;
observer_ops.num_active_streams_changed =
signal_num_active_streams_changed;
+ observer_ops.num_input_streams_with_permission_changed =
+ signal_num_input_streams_with_permission_changed;
observer_ops.nodes_changed = signal_nodes_changed;
observer_ops.active_node_changed = signal_active_node_changed;
observer_ops.input_node_gain_changed = signal_node_capture_gain_changed;
diff --git a/cras/src/server/cras_dsp.c b/cras/src/server/cras_dsp.c
index d0b26264..9c4cc7b5 100644
--- a/cras/src/server/cras_dsp.c
+++ b/cras/src/server/cras_dsp.c
@@ -208,15 +208,15 @@ void cras_dsp_load_pipeline(struct cras_dsp_context *ctx)
cmd_load_pipeline(ctx, global_ini);
}
-void cras_dsp_load_dummy_pipeline(struct cras_dsp_context *ctx,
- unsigned int num_channels)
+void cras_dsp_load_mock_pipeline(struct cras_dsp_context *ctx,
+ unsigned int num_channels)
{
- struct ini *dummy_ini;
- dummy_ini = create_dummy_ini(ctx->purpose, num_channels);
- if (dummy_ini == NULL)
- syslog(LOG_ERR, "Failed to create dummy ini");
+ struct ini *mock_ini;
+ mock_ini = create_mock_ini(ctx->purpose, num_channels);
+ if (mock_ini == NULL)
+ syslog(LOG_ERR, "Failed to create mock ini");
else
- cmd_load_pipeline(ctx, dummy_ini);
+ cmd_load_pipeline(ctx, mock_ini);
}
struct pipeline *cras_dsp_get_pipeline(struct cras_dsp_context *ctx)
diff --git a/cras/src/server/cras_dsp.h b/cras/src/server/cras_dsp.h
index 9a72f42b..366e2e67 100644
--- a/cras/src/server/cras_dsp.h
+++ b/cras/src/server/cras_dsp.h
@@ -54,11 +54,11 @@ void cras_dsp_set_variable_boolean(struct cras_dsp_context *ctx,
* blocking the audio thread. */
void cras_dsp_load_pipeline(struct cras_dsp_context *ctx);
-/* Loads a dummy pipeline of source directly connects to sink, of given
+/* Loads a mock pipeline of source directly connects to sink, of given
* number of channels.
*/
-void cras_dsp_load_dummy_pipeline(struct cras_dsp_context *ctx,
- unsigned int num_channels);
+void cras_dsp_load_mock_pipeline(struct cras_dsp_context *ctx,
+ unsigned int num_channels);
/* Locks the pipeline in the context for access. Returns NULL if the
* pipeline is still being loaded or cannot be loaded. */
diff --git a/cras/src/server/cras_dsp_ini.c b/cras/src/server/cras_dsp_ini.c
index 0b844d16..a331acf8 100644
--- a/cras/src/server/cras_dsp_ini.c
+++ b/cras/src/server/cras_dsp_ini.c
@@ -11,7 +11,7 @@
#define MAX_NR_PORT 128 /* the max number of ports for a plugin */
#define MAX_PORT_NAME_LENGTH 20 /* names like "output_32" */
-#define MAX_DUMMY_INI_CH 20 /* Max number of channels to create dummy ini */
+#define MAX_MOCK_INI_CH 20 /* Max number of channels to create mock ini */
/* Format of the ini file (See dsp.ini.sample for an example).
@@ -305,22 +305,21 @@ static int insert_swap_lr_plugin(struct ini *ini)
return 0;
}
-struct ini *create_dummy_ini(const char *purpose, unsigned int num_channels)
+struct ini *create_mock_ini(const char *purpose, unsigned int num_channels)
{
- static char dummy_flow_names[MAX_DUMMY_INI_CH][9] = {
- "{tmp:0}", "{tmp:1}", "{tmp:2}", "{tmp:3}",
- "{tmp:4}", "{tmp:5}", "{tmp:6}", "{tmp:7}",
- "{tmp:8}", "{tmp:9}", "{tmp:10}", "{tmp:11}",
- "{tmp:12}", "{tmp:13}", "{tmp:14}", "{tmp:15}",
- "{tmp:16}", "{tmp:17}", "{tmp:18}", "{tmp:19}",
+ static char mock_flow_names[MAX_MOCK_INI_CH][9] = {
+ "{tmp:0}", "{tmp:1}", "{tmp:2}", "{tmp:3}", "{tmp:4}",
+ "{tmp:5}", "{tmp:6}", "{tmp:7}", "{tmp:8}", "{tmp:9}",
+ "{tmp:10}", "{tmp:11}", "{tmp:12}", "{tmp:13}", "{tmp:14}",
+ "{tmp:15}", "{tmp:16}", "{tmp:17}", "{tmp:18}", "{tmp:19}",
};
struct ini *ini;
struct plugin *source, *sink;
- int tmp_flow_ids[MAX_DUMMY_INI_CH];
+ int tmp_flow_ids[MAX_MOCK_INI_CH];
int i;
- if (num_channels > MAX_DUMMY_INI_CH) {
- syslog(LOG_ERR, "Unable to create %u channels of dummy ini",
+ if (num_channels > MAX_MOCK_INI_CH) {
+ syslog(LOG_ERR, "Unable to create %u channels of mock ini",
num_channels);
return NULL;
}
@@ -332,7 +331,7 @@ struct ini *create_dummy_ini(const char *purpose, unsigned int num_channels)
}
for (i = 0; i < num_channels; i++)
- tmp_flow_ids[i] = add_new_flow(ini, dummy_flow_names[i]);
+ tmp_flow_ids[i] = add_new_flow(ini, mock_flow_names[i]);
source = ARRAY_APPEND_ZERO(&ini->plugins);
source->title = "source";
diff --git a/cras/src/server/cras_dsp_ini.h b/cras/src/server/cras_dsp_ini.h
index 51deefd6..c839d4b0 100644
--- a/cras/src/server/cras_dsp_ini.h
+++ b/cras/src/server/cras_dsp_ini.h
@@ -71,7 +71,7 @@ struct ini {
};
/*
- * Creates a dummy ini structure equivalent to:
+ * Creates a mock ini structure equivalent to:
*
* [src]
* out0={tmp:0}
@@ -86,7 +86,7 @@ struct ini {
* The caller of this function is responsible to free the returned
* ini by calling cras_dsp_ini_free().
*/
-struct ini *create_dummy_ini(const char *purpose, unsigned int num_channels);
+struct ini *create_mock_ini(const char *purpose, unsigned int num_channels);
/* Reads the ini file into the ini structure */
struct ini *cras_dsp_ini_create(const char *ini_filename);
diff --git a/cras/src/server/cras_empty_iodev.c b/cras/src/server/cras_empty_iodev.c
index 76eab6c1..3471c756 100644
--- a/cras/src/server/cras_empty_iodev.c
+++ b/cras/src/server/cras_empty_iodev.c
@@ -199,7 +199,7 @@ struct cras_iodev *empty_iodev_create(enum CRAS_STREAM_DIRECTION direction,
iodev->update_active_node = update_active_node;
iodev->no_stream = cras_iodev_default_no_stream_playback;
- /* Create a dummy ionode */
+ /* Create an empty ionode */
node = (struct cras_ionode *)calloc(1, sizeof(*node));
node->dev = iodev;
node->type = node_type;
diff --git a/cras/src/server/cras_fmt_conv.c b/cras/src/server/cras_fmt_conv.c
index 478452d4..509db1eb 100644
--- a/cras/src/server/cras_fmt_conv.c
+++ b/cras/src/server/cras_fmt_conv.c
@@ -9,6 +9,7 @@
#include <syslog.h>
#include <endian.h>
#include <limits.h>
+#include <math.h>
#include "cras_fmt_conv.h"
#include "cras_fmt_conv_ops.h"
@@ -58,21 +59,35 @@ static int is_channel_layout_equal(const struct cras_audio_format *a,
return 1;
}
-static void normalize_buf(float *buf, size_t size)
+/*
+ * Calculates the normalize_factor abs_sum(ci) from given coefficients.
+ * Since sum(ci / abs_sum(ci)) <= 1, this could prevent sample overflow while
+ * upmixing or downmixing.
+ */
+static float normalize_factor(float *buf, size_t n)
{
int i;
- float squre_sum = 0.0;
- for (i = 0; i < size; i++)
- squre_sum += buf[i] * buf[i];
+ float abs_sum = 0.0;
+ for (i = 0; i < n; i++)
+ abs_sum += fabs(buf[i]);
- if (squre_sum == 0.0)
- return;
+ return 1.0 / abs_sum;
+}
- for (i = 0; i < size; i++)
- buf[i] /= squre_sum;
+/*
+ * Normalize all channels with the same factor to maintain
+ * the energy ratio between original channels.
+ */
+static void normalize(float **mtx, size_t m, size_t n, float factor)
+{
+ int i, j;
+ for (i = 0; i < m; i++)
+ for (j = 0; j < n; j++)
+ mtx[i][j] *= factor;
}
-/* Populates the down mix matrix by rules:
+/*
+ * Populates the down mix matrix by rules:
* 1. Front/side left(right) channel will mix to left(right) of
* full scale.
* 2. Center and LFE will be split equally to left and right.
@@ -106,9 +121,46 @@ static void surround51_to_stereo_downmix_mtx(float **mtx,
mtx[STEREO_L][layout[CRAS_CH_LFE]] = 0.707;
mtx[STEREO_R][layout[CRAS_CH_LFE]] = 0.707;
}
+ normalize(mtx, 2, 6, normalize_factor(mtx[STEREO_L], 6));
+}
+
+/* Populates the down mix matrix by rules:
+ * 1. Front left(right) channel will mix to the front left(right) of
+ * full scale.
+ * 2. Rear and side left(right) channel will mix to the rear left(right) of
+ * full scale.
+ * 3. Center will be split equally to the front left and right.
+ * 4. LFE will be split equally to the other channels.
+ */
+static void surround51_to_quad_downmix_mtx(float **mtx,
+ int8_t layout[CRAS_CH_MAX])
+{
+ if (layout[CRAS_CH_FL] != -1 && layout[CRAS_CH_FR] != -1) {
+ mtx[CRAS_CH_FL][layout[CRAS_CH_FL]] = 1.0;
+ mtx[CRAS_CH_FR][layout[CRAS_CH_FR]] = 1.0;
+ }
+ if (layout[CRAS_CH_RL] != -1 && layout[CRAS_CH_RR] != -1) {
+ mtx[CRAS_CH_RL][layout[CRAS_CH_RL]] = 1.0;
+ mtx[CRAS_CH_RR][layout[CRAS_CH_RR]] = 1.0;
+ }
+ if (layout[CRAS_CH_SL] != -1 && layout[CRAS_CH_SR] != -1) {
+ mtx[CRAS_CH_RL][layout[CRAS_CH_SL]] = 1.0;
+ mtx[CRAS_CH_RR][layout[CRAS_CH_SR]] = 1.0;
+ }
+ if (layout[CRAS_CH_FC] != -1) {
+ /* Split 1/2 power to the front L/R */
+ mtx[CRAS_CH_FL][layout[CRAS_CH_FC]] = 0.707;
+ mtx[CRAS_CH_FR][layout[CRAS_CH_FC]] = 0.707;
+ }
+ if (layout[CRAS_CH_LFE] != -1) {
+ /* Split 1/4 power to the other channel */
+ mtx[CRAS_CH_FL][layout[CRAS_CH_LFE]] = 0.5;
+ mtx[CRAS_CH_FR][layout[CRAS_CH_LFE]] = 0.5;
+ mtx[CRAS_CH_RL][layout[CRAS_CH_LFE]] = 0.5;
+ mtx[CRAS_CH_RR][layout[CRAS_CH_LFE]] = 0.5;
+ }
- normalize_buf(mtx[STEREO_L], 6);
- normalize_buf(mtx[STEREO_R], 6);
+ normalize(mtx, 4, 6, normalize_factor(mtx[CRAS_CH_FL], 6));
}
static int is_supported_format(const struct cras_audio_format *fmt)
@@ -170,6 +222,12 @@ static size_t _51_to_stereo(struct cras_fmt_conv *conv, const uint8_t *in,
return s16_51_to_stereo(in, in_frames, out);
}
+static size_t _51_to_quad(struct cras_fmt_conv *conv, const uint8_t *in,
+ size_t in_frames, uint8_t *out)
+{
+ return s16_51_to_quad(in, in_frames, out);
+}
+
static size_t stereo_to_quad(struct cras_fmt_conv *conv, const uint8_t *in,
size_t in_frames, uint8_t *out)
{
@@ -340,7 +398,8 @@ struct cras_fmt_conv *cras_fmt_conv_create(const struct cras_audio_format *in,
conv->channel_converter = quad_to_stereo;
} else if (in->num_channels == 2 && out->num_channels == 6) {
conv->channel_converter = stereo_to_51;
- } else if (in->num_channels == 6 && out->num_channels == 2) {
+ } else if (in->num_channels == 6 &&
+ (out->num_channels == 2 || out->num_channels == 4)) {
int in_channel_layout_set = 0;
/* Checks if channel_layout is set in the incoming format */
@@ -361,11 +420,20 @@ struct cras_fmt_conv *cras_fmt_conv_create(const struct cras_audio_format *in,
return NULL;
}
conv->channel_converter = convert_channels;
- surround51_to_stereo_downmix_mtx(
- conv->ch_conv_mtx,
- conv->in_fmt.channel_layout);
+ if (out->num_channels == 4) {
+ surround51_to_quad_downmix_mtx(
+ conv->ch_conv_mtx,
+ conv->in_fmt.channel_layout);
+ } else {
+ surround51_to_stereo_downmix_mtx(
+ conv->ch_conv_mtx,
+ conv->in_fmt.channel_layout);
+ }
} else {
- conv->channel_converter = _51_to_stereo;
+ if (out->num_channels == 4)
+ conv->channel_converter = _51_to_quad;
+ else
+ conv->channel_converter = _51_to_stereo;
}
} else if (in->num_channels <= 8 && out->num_channels <= 8) {
// For average channel counts mix from all to all.
diff --git a/cras/src/server/cras_fmt_conv_ops.c b/cras/src/server/cras_fmt_conv_ops.c
index 87358af2..a306d216 100644
--- a/cras/src/server/cras_fmt_conv_ops.c
+++ b/cras/src/server/cras_fmt_conv_ops.c
@@ -235,20 +235,69 @@ size_t s16_51_to_stereo(const uint8_t *_in, size_t in_frames, uint8_t *_out)
int16_t *out = (int16_t *)_out;
static const unsigned int left_idx = 0;
static const unsigned int right_idx = 1;
- /* static const unsigned int left_surround_idx = 2; */
- /* static const unsigned int right_surround_idx = 3; */
- static const unsigned int center_idx = 4;
- /* static const unsigned int lfe_idx = 5; */
- size_t i;
+ static const unsigned int center_idx = 2;
+ /* static const unsigned int lfe_idx = 3; */
+ /* static const unsigned int left_surround_idx = 4; */
+ /* static const unsigned int right_surround_idx = 5; */
+ size_t i;
+ int16_t half_center;
+ /* Use the normalized_factor from the left channel = 1 / (|1| + |0.707|)
+ * to prevent mixing overflow.
+ */
+ const float normalized_factor = 0.585;
for (i = 0; i < in_frames; i++) {
- unsigned int half_center;
-
- half_center = in[6 * i + center_idx] / 2;
+ half_center =
+ in[6 * i + center_idx] * 0.707 * normalized_factor;
out[2 * i + left_idx] =
- s16_add_and_clip(in[6 * i + left_idx], half_center);
+ in[6 * i + left_idx] * normalized_factor + half_center;
out[2 * i + right_idx] =
- s16_add_and_clip(in[6 * i + right_idx], half_center);
+ in[6 * i + right_idx] * normalized_factor + half_center;
+ }
+ return in_frames;
+}
+
+/*
+ * Channel converter: 5.1 surround to quad (front L/R, rear L/R).
+ *
+ * The out buffer can have room for just quad samples. This convert function
+ * is used as the default behavior when channel layout is not set from the
+ * client side.
+ */
+size_t s16_51_to_quad(const uint8_t *_in, size_t in_frames, uint8_t *_out)
+{
+ const int16_t *in = (const int16_t *)_in;
+ int16_t *out = (int16_t *)_out;
+ static const unsigned int l_quad = 0;
+ static const unsigned int r_quad = 1;
+ static const unsigned int rl_quad = 2;
+ static const unsigned int rr_quad = 3;
+
+ static const unsigned int l_51 = 0;
+ static const unsigned int r_51 = 1;
+ static const unsigned int center_51 = 2;
+ static const unsigned int lfe_51 = 3;
+ static const unsigned int rl_51 = 4;
+ static const unsigned int rr_51 = 5;
+
+ /* Use normalized_factor from the left channel = 1 / (|1| + |0.707| + |0.5|)
+ * to prevent overflow. */
+ const float normalized_factor = 0.453;
+ size_t i;
+ for (i = 0; i < in_frames; i++) {
+ int16_t half_center;
+ int16_t lfe;
+
+ half_center = in[6 * i + center_51] * 0.707 * normalized_factor;
+ lfe = in[6 * i + lfe_51] * 0.5 * normalized_factor;
+ out[4 * i + l_quad] = normalized_factor * in[6 * i + l_51] +
+ half_center + lfe;
+ out[4 * i + r_quad] = normalized_factor * in[6 * i + r_51] +
+ half_center + lfe;
+ out[4 * i + rl_quad] =
+ normalized_factor * in[6 * i + rl_51] + lfe;
+ out[4 * i + rr_quad] =
+ normalized_factor * in[6 * i + rr_51] + lfe;
}
return in_frames;
}
diff --git a/cras/src/server/cras_fmt_conv_ops.h b/cras/src/server/cras_fmt_conv_ops.h
index 8042ad59..a1a57487 100644
--- a/cras/src/server/cras_fmt_conv_ops.h
+++ b/cras/src/server/cras_fmt_conv_ops.h
@@ -51,6 +51,11 @@ size_t s16_stereo_to_51(size_t left, size_t right, size_t center,
size_t s16_51_to_stereo(const uint8_t *in, size_t in_frames, uint8_t *out);
/*
+ * Channel converter: 5.1 surround to quad.
+ */
+size_t s16_51_to_quad(const uint8_t *in, size_t in_frames, uint8_t *out);
+
+/*
* Channel converter: stereo to quad (front L/R, rear L/R).
*/
size_t s16_stereo_to_quad(size_t front_left, size_t front_right,
diff --git a/cras/src/server/cras_hfp_ag_profile.c b/cras/src/server/cras_hfp_ag_profile.c
index 8cf4a431..9d59d40e 100644
--- a/cras/src/server/cras_hfp_ag_profile.c
+++ b/cras/src/server/cras_hfp_ag_profile.c
@@ -22,6 +22,7 @@
#include "cras_iodev_list.h"
#include "cras_observer.h"
#include "utlist.h"
+#include "packet_status_logger.h"
#define HFP_AG_PROFILE_NAME "Hands-Free Voice gateway"
#define HFP_AG_PROFILE_PATH "/org/chromium/Cras/Bluetooth/HFPAG"
@@ -103,6 +104,7 @@ struct audio_gateway {
};
static struct audio_gateway *connected_ags;
+static struct packet_status_logger wbs_logger;
static int need_go_sco_pcm(struct cras_bt_device *device)
{
@@ -411,6 +413,7 @@ int cras_hfp_ag_start(struct cras_bt_device *device)
ag->slc_handle, ag->profile);
} else {
ag->info = hfp_info_create();
+ hfp_info_set_wbs_logger(ag->info, &wbs_logger);
ag->idev =
hfp_iodev_create(CRAS_STREAM_INPUT, ag->device,
ag->slc_handle, ag->profile, ag->info);
@@ -453,6 +456,11 @@ struct hfp_slc_handle *cras_hfp_ag_get_slc(struct cras_bt_device *device)
return NULL;
}
+struct packet_status_logger *cras_hfp_ag_get_wbs_logger()
+{
+ return &wbs_logger;
+}
+
void cras_hfp_ag_resend_device_battery_level()
{
struct audio_gateway *ag;
diff --git a/cras/src/server/cras_hfp_ag_profile.h b/cras/src/server/cras_hfp_ag_profile.h
index fb58efb6..50d27e05 100644
--- a/cras/src/server/cras_hfp_ag_profile.h
+++ b/cras/src/server/cras_hfp_ag_profile.h
@@ -53,6 +53,9 @@ struct hfp_slc_handle *cras_hfp_ag_get_active_handle();
/* Gets the SLC handle for given cras_bt_device. */
struct hfp_slc_handle *cras_hfp_ag_get_slc(struct cras_bt_device *device);
+/* Gets the logger for WBS packet status. */
+struct packet_status_logger *cras_hfp_ag_get_wbs_logger();
+
/* Iterate all possible AGs (theoratically only one) and signal its battery
* level */
void cras_hfp_ag_resend_device_battery_level();
diff --git a/cras/src/server/cras_hfp_alsa_iodev.c b/cras/src/server/cras_hfp_alsa_iodev.c
index 532b6c40..b80a88c7 100644
--- a/cras/src/server/cras_hfp_alsa_iodev.c
+++ b/cras/src/server/cras_hfp_alsa_iodev.c
@@ -309,6 +309,10 @@ struct cras_iodev *hfp_alsa_iodev_create(struct cras_iodev *aio,
/* Record max supported channels into cras_iodev_info. */
iodev->info.max_supported_channels = 1;
+ /* Specifically disable EWMA calculation on this and the child iodev. */
+ ewma_power_disable(&iodev->ewma);
+ ewma_power_disable(&aio->ewma);
+
return iodev;
}
diff --git a/cras/src/server/cras_hfp_info.c b/cras/src/server/cras_hfp_info.c
index 550de586..fc407b29 100644
--- a/cras/src/server/cras_hfp_info.c
+++ b/cras/src/server/cras_hfp_info.c
@@ -19,6 +19,7 @@
#include "cras_sbc_codec.h"
#include "cras_server_metrics.h"
#include "utlist.h"
+#include "packet_status_logger.h"
/* The max buffer size. Note that the actual used size must set to multiple
* of SCO packet size, and the packet size does not necessarily be equal to
@@ -93,6 +94,7 @@ static const uint8_t h2_header_frames_count[] = { 0x08, 0x38, 0xc8, 0xf8 };
* read_align_cb - Callback used to align mSBC frame reading with read buf.
* msbc_read_current_corrupted - Flag to mark if the current mSBC frame
* read is corrupted.
+ * wbs_logger - The logger for packet status in WBS.
*/
struct hfp_info {
int fd;
@@ -119,6 +121,7 @@ struct hfp_info {
size_t read_rp;
int (*read_align_cb)(uint8_t *buf);
bool msbc_read_current_corrupted;
+ struct packet_status_logger *wbs_logger;
};
int hfp_info_add_iodev(struct hfp_info *info,
@@ -403,6 +406,20 @@ static const uint8_t *extract_msbc_frame(const uint8_t *input, int len,
return NULL;
}
+/* Log value 0 when packet is received. */
+static void log_wbs_packet_received(struct hfp_info *info)
+{
+ if (info->wbs_logger)
+ packet_status_logger_update(info->wbs_logger, 0);
+}
+
+/* Log value 1 when packet is lost. */
+static void log_wbs_packet_lost(struct hfp_info *info)
+{
+ if (info->wbs_logger)
+ packet_status_logger_update(info->wbs_logger, 1);
+}
+
/*
* Handle the case when mSBC frame is considered lost.
* Args:
@@ -419,6 +436,8 @@ static int handle_packet_loss(struct hfp_info *info)
info->msbc_num_in_frames++;
info->msbc_num_lost_frames++;
+ log_wbs_packet_lost(info);
+
in_bytes = buf_write_pointer_size(info->capture_buf, &pcm_avail);
if (pcm_avail < MSBC_CODE_SIZE)
return 0;
@@ -580,6 +599,7 @@ recv_msbc_bytes:
pcm_read += err;
} else {
/* Good mSBC frame decoded. */
+ log_wbs_packet_received(info);
buf_increment_write(info->capture_buf, pcm_decoded);
info->msbc_num_in_frames++;
cras_msbc_plc_handle_good_frames(info->msbc_plc, capture_buf,
@@ -723,6 +743,12 @@ error:
return NULL;
}
+void hfp_info_set_wbs_logger(struct hfp_info *info,
+ struct packet_status_logger *wbs_logger)
+{
+ info->wbs_logger = wbs_logger;
+}
+
int hfp_info_running(struct hfp_info *info)
{
return info->started;
@@ -760,6 +786,8 @@ int hfp_info_start(int fd, unsigned int mtu, int codec, struct hfp_info *info)
info->msbc_read = cras_msbc_codec_create();
info->msbc_write = cras_msbc_codec_create();
info->msbc_plc = cras_msbc_plc_create();
+
+ packet_status_logger_init(info->wbs_logger);
} else {
info->write_cb = hfp_write;
info->read_cb = hfp_read;
diff --git a/cras/src/server/cras_hfp_info.h b/cras/src/server/cras_hfp_info.h
index 96110e2a..3472aeab 100644
--- a/cras/src/server/cras_hfp_info.h
+++ b/cras/src/server/cras_hfp_info.h
@@ -30,6 +30,10 @@ struct hfp_info *hfp_info_create();
/* Destroys given hfp_info instance. */
void hfp_info_destroy(struct hfp_info *info);
+/* Sets the wbs_logger to hfp_info instance. */
+void hfp_info_set_wbs_logger(struct hfp_info *info,
+ struct packet_status_logger *wbs_logger);
+
/* Checks if given hfp_info is running. */
int hfp_info_running(struct hfp_info *info);
diff --git a/cras/src/server/cras_hfp_iodev.c b/cras/src/server/cras_hfp_iodev.c
index bf609cfb..7cce3736 100644
--- a/cras/src/server/cras_hfp_iodev.c
+++ b/cras/src/server/cras_hfp_iodev.c
@@ -350,6 +350,8 @@ struct cras_iodev *hfp_iodev_create(enum CRAS_STREAM_DIRECTION dir,
/* Record max supported channels into cras_iodev_info. */
iodev->info.max_supported_channels = 1;
+ ewma_power_disable(&iodev->ewma);
+
return iodev;
error:
diff --git a/cras/src/server/cras_hfp_slc.c b/cras/src/server/cras_hfp_slc.c
index 1cf003a1..e4f0127d 100644
--- a/cras/src/server/cras_hfp_slc.c
+++ b/cras/src/server/cras_hfp_slc.c
@@ -708,7 +708,14 @@ static int indicator_support(struct hfp_slc_handle *handle, const char *cmd)
* check the Bluetooth SIG Assigned Numbers web page.
*/
BTLOG(btlog, BT_HFP_HF_INDICATOR, 1, 0);
- err = hfp_send(handle, AT_CMD("+BIND: (2)"));
+ /* "2" is for HF Battery Level that we support. We don't
+ * support "1" but this is a workaround for Pixel Buds 2
+ * which expects this exact combination for battery
+ * reporting (HFP 1.7 standard) to work. This workaround
+ * is fine since we don't enable Safety Drive with
+ * +BIND: 1,1 (b/172680041).
+ */
+ err = hfp_send(handle, AT_CMD("+BIND: (1,2)"));
if (err < 0)
return err;
}
@@ -738,6 +745,14 @@ static int indicator_support(struct hfp_slc_handle *handle, const char *cmd)
* indicator
* 1 = enabled, value changes may be sent for this indicator
*/
+
+ /* We don't support Enhanced Driver Status, so explicitly
+ * disable it (b/172680041).
+ */
+ err = hfp_send(handle, AT_CMD("+BIND: 1,0"));
+ if (err < 0)
+ return err;
+
BTLOG(btlog, BT_HFP_HF_INDICATOR, 0, 0);
err = hfp_send(handle, AT_CMD("+BIND: 2,1"));
@@ -927,7 +942,7 @@ static int terminate_call(struct hfp_slc_handle *handle, const char *cmd)
*
* An initialized service level connection is the pre-condition for all
* call related procedures. Note that for the call related commands,
- * we are good to just respond with a dummy "OK".
+ * we are good to just respond with a meaningless "OK".
*
* The procedure to establish a service level connection is described below:
*
diff --git a/cras/src/server/cras_iodev.c b/cras/src/server/cras_iodev.c
index f426eb5f..fd1ce805 100644
--- a/cras/src/server/cras_iodev.c
+++ b/cras/src/server/cras_iodev.c
@@ -239,7 +239,7 @@ int cras_iodev_is_zero_volume(const struct cras_iodev *odev)
* | ---------------- | device from
* | | S1 Open | | audio_thread and
* | ---------------- | closes device
- * | Device with dummy start | |
+ * | Device with empty start | |
* | ops transits into | Sample is ready |
* | no stream state right V |
* | after open. ---------------- |
@@ -527,8 +527,8 @@ static void add_ext_dsp_module_to_pipeline(struct cras_iodev *iodev)
if (!pipeline) {
cras_iodev_alloc_dsp(iodev);
- cras_dsp_load_dummy_pipeline(iodev->dsp_context,
- iodev->format->num_channels);
+ cras_dsp_load_mock_pipeline(iodev->dsp_context,
+ iodev->format->num_channels);
pipeline = cras_dsp_get_pipeline(iodev->dsp_context);
}
/* dsp_context mutex locked. Now it's safe to modify dsp
@@ -953,6 +953,8 @@ int cras_iodev_open(struct cras_iodev *iodev, unsigned int cb_level,
iodev->highest_hw_level = 0;
iodev->input_dsp_offset = 0;
+ ewma_power_init(&iodev->ewma, iodev->format->frame_rate);
+
if (iodev->direction == CRAS_STREAM_OUTPUT) {
/* If device supports start ops, device can be in open state.
* Otherwise, device starts running right after opening. */
@@ -1097,6 +1099,9 @@ int cras_iodev_put_output_buffer(struct cras_iodev *iodev, uint8_t *frames,
loopback->cb_data);
}
+ ewma_power_calculate(&iodev->ewma, (int16_t *)frames,
+ iodev->format->num_channels, nframes);
+
rc = apply_dsp(iodev, frames, nframes);
if (rc)
return rc;
@@ -1200,6 +1205,11 @@ int cras_iodev_get_input_buffer(struct cras_iodev *iodev, unsigned int *frames)
*frames - iodev->input_dsp_offset);
if (rc)
return rc;
+ ewma_power_calculate_area(
+ &iodev->ewma,
+ (int16_t *)(hw_buffer +
+ iodev->input_dsp_offset * frame_bytes),
+ data->area, *frames - iodev->input_dsp_offset);
}
if (cras_system_get_capture_mute())
diff --git a/cras/src/server/cras_iodev.h b/cras/src/server/cras_iodev.h
index 553cb807..db16a0f8 100644
--- a/cras/src/server/cras_iodev.h
+++ b/cras/src/server/cras_iodev.h
@@ -19,6 +19,7 @@
#include "cras_dsp.h"
#include "cras_iodev_info.h"
#include "cras_messages.h"
+#include "ewma_power.h"
struct buffer_share;
struct cras_fmt_conv;
@@ -237,7 +238,7 @@ struct cras_ionode {
* stream side processing.
* initial_ramp_request - The value indicates which type of ramp the device
* should perform when some samples are ready for playback.
- *
+ * ewma - The ewma instance to calculate iodev volume.
*/
struct cras_iodev {
void (*set_volume)(struct cras_iodev *iodev);
@@ -312,6 +313,7 @@ struct cras_iodev {
unsigned int input_dsp_offset;
unsigned int initial_ramp_request;
struct input_data *input_data;
+ struct ewma_power ewma;
struct cras_iodev *prev, *next;
};
diff --git a/cras/src/server/cras_iodev_list.c b/cras/src/server/cras_iodev_list.c
index bba793d1..ada29719 100644
--- a/cras/src/server/cras_iodev_list.c
+++ b/cras/src/server/cras_iodev_list.c
@@ -361,7 +361,8 @@ static void possibly_enable_echo_reference(struct cras_iodev *dev)
if (dev->echo_reference_dev == NULL)
return;
- server_stream_create(stream_list, dev->echo_reference_dev->info.idx);
+ server_stream_create(stream_list, dev->echo_reference_dev->info.idx,
+ dev->format);
}
/*
diff --git a/cras/src/server/cras_loopback_iodev.c b/cras/src/server/cras_loopback_iodev.c
index 0947313f..cf3ba4ae 100644
--- a/cras/src/server/cras_loopback_iodev.c
+++ b/cras/src/server/cras_loopback_iodev.c
@@ -331,7 +331,7 @@ struct cras_iodev *loopback_iodev_create(enum CRAS_LOOPBACK_TYPE type)
if (iodev == NULL)
return NULL;
- /* Create a dummy ionode */
+ /* Create an empty ionode */
node = (struct cras_ionode *)calloc(1, sizeof(*node));
node->dev = iodev;
node->type = node_type;
diff --git a/cras/src/server/cras_observer.c b/cras/src/server/cras_observer.c
index a73bcccf..0f17dc92 100644
--- a/cras/src/server/cras_observer.c
+++ b/cras/src/server/cras_observer.c
@@ -7,6 +7,7 @@
#include "cras_alert.h"
#include "cras_iodev_list.h"
+#include "cras_types.h"
#include "utlist.h"
struct cras_observer_client {
@@ -35,6 +36,7 @@ struct cras_observer_alerts {
struct cras_alert *num_active_streams[CRAS_NUM_DIRECTIONS];
struct cras_alert *non_empty_audio_state_changed;
struct cras_alert *bt_battery_changed;
+ struct cras_alert *num_input_streams_with_permission;
};
struct cras_observer_server {
@@ -76,6 +78,10 @@ struct cras_observer_alert_data_streams {
uint32_t num_active_streams;
};
+struct cras_observer_alert_data_input_streams {
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE];
+};
+
struct cras_observer_alert_data_hotword_triggered {
int64_t tv_sec;
int64_t tv_nsec;
@@ -253,6 +259,20 @@ static void num_active_streams_alert(void *arg, void *data)
}
}
+static void num_input_streams_with_permission_alert(void *arg, void *data)
+{
+ struct cras_observer_client *client;
+ struct cras_observer_alert_data_input_streams *input_streams_data =
+ (struct cras_observer_alert_data_input_streams *)data;
+
+ DL_FOREACH (g_observer->clients, client) {
+ if (client->ops.num_input_streams_with_permission_changed)
+ client->ops.num_input_streams_with_permission_changed(
+ client->context,
+ input_streams_data->num_input_streams);
+ }
+}
+
static void hotword_triggered_alert(void *arg, void *data)
{
struct cras_observer_client *client;
@@ -353,6 +373,7 @@ int cras_observer_server_init()
CRAS_OBSERVER_SET_ALERT(hotword_triggered, NULL, 0);
CRAS_OBSERVER_SET_ALERT(non_empty_audio_state_changed, NULL, 0);
CRAS_OBSERVER_SET_ALERT(bt_battery_changed, NULL, 0);
+ CRAS_OBSERVER_SET_ALERT(num_input_streams_with_permission, NULL, 0);
CRAS_OBSERVER_SET_ALERT_WITH_DIRECTION(num_active_streams,
CRAS_STREAM_OUTPUT);
@@ -386,6 +407,8 @@ void cras_observer_server_free()
cras_alert_destroy(g_observer->alerts.non_empty_audio_state_changed);
cras_alert_destroy(g_observer->alerts.bt_battery_changed);
cras_alert_destroy(
+ g_observer->alerts.num_input_streams_with_permission);
+ cras_alert_destroy(
g_observer->alerts.num_active_streams[CRAS_STREAM_OUTPUT]);
cras_alert_destroy(
g_observer->alerts.num_active_streams[CRAS_STREAM_INPUT]);
@@ -562,6 +585,21 @@ void cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,
cras_alert_pending_data(alert, &data, sizeof(data));
}
+void cras_observer_notify_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
+{
+ struct cras_observer_alert_data_input_streams data;
+ struct cras_alert *alert;
+
+ memcpy(&data.num_input_streams, num_input_streams,
+ sizeof(*num_input_streams) * CRAS_NUM_CLIENT_TYPE);
+ alert = g_observer->alerts.num_input_streams_with_permission;
+ if (!alert)
+ return;
+
+ cras_alert_pending_data(alert, &data, sizeof(data));
+}
+
void cras_observer_notify_hotword_triggered(int64_t tv_sec, int64_t tv_nsec)
{
struct cras_observer_alert_data_hotword_triggered data;
diff --git a/cras/src/server/cras_observer.h b/cras/src/server/cras_observer.h
index 1da5eeaf..2dd013b8 100644
--- a/cras/src/server/cras_observer.h
+++ b/cras/src/server/cras_observer.h
@@ -92,6 +92,10 @@ void cras_observer_notify_suspend_changed(int suspended);
void cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,
uint32_t num_active_streams);
+/* Notify observers of the number of input streams with permission. */
+void cras_observer_notify_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE]);
+
/* Notify observers of the timestamp when hotword triggered. */
void cras_observer_notify_hotword_triggered(int64_t tv_sec, int64_t tv_nsec);
diff --git a/cras/src/server/cras_rclient.c b/cras/src/server/cras_rclient.c
index 22fbb05c..d2646e75 100644
--- a/cras/src/server/cras_rclient.c
+++ b/cras/src/server/cras_rclient.c
@@ -59,9 +59,16 @@ int cras_rclient_send_message(const struct cras_rclient *client,
return client->ops->send_message_to_client(client, msg, fds, num_fds);
}
+static void cras_rclient_set_client_type(struct cras_rclient *client,
+ enum CRAS_CLIENT_TYPE client_type)
+{
+ client->client_type = client_type;
+}
+
struct cras_rclient *cras_rclient_create(int fd, size_t id,
enum CRAS_CONNECTION_TYPE conn_type)
{
+ struct cras_rclient *client;
if (!cras_validate_connection_type(conn_type))
goto error;
@@ -76,6 +83,14 @@ struct cras_rclient *cras_rclient_create(int fd, size_t id,
return cras_playback_rclient_create(fd, id);
case CRAS_VMS_UNIFIED:
return cras_unified_rclient_create(fd, id);
+ case CRAS_PLUGIN_PLAYBACK:
+ client = cras_playback_rclient_create(fd, id);
+ cras_rclient_set_client_type(client, CRAS_CLIENT_TYPE_PLUGIN);
+ return client;
+ case CRAS_PLUGIN_UNIFIED:
+ client = cras_unified_rclient_create(fd, id);
+ cras_rclient_set_client_type(client, CRAS_CLIENT_TYPE_PLUGIN);
+ return client;
default:
goto error;
}
diff --git a/cras/src/server/cras_rclient.h b/cras/src/server/cras_rclient.h
index 6cffb7d8..3a3988c2 100644
--- a/cras/src/server/cras_rclient.h
+++ b/cras/src/server/cras_rclient.h
@@ -20,6 +20,9 @@ struct cras_server_message;
* fd - Connection for client communication.
* ops - cras_rclient_ops for the cras_rclient.
* supported_directions - Bit mask for supported stream directions.
+ * client_type - Client type of this rclient. If this is set to value other
+ * than CRAS_CLIENT_TYPE_UNKNOWN, rclient will overwrite incoming
+ * messages' client type.
*/
struct cras_rclient {
struct cras_observer_client *observer;
@@ -27,6 +30,7 @@ struct cras_rclient {
int fd;
const struct cras_rclient_ops *ops;
int supported_directions;
+ enum CRAS_CLIENT_TYPE client_type;
};
/* Operations for cras_rclient.
diff --git a/cras/src/server/cras_rclient_util.c b/cras/src/server/cras_rclient_util.c
index da991282..def645e3 100644
--- a/cras/src/server/cras_rclient_util.c
+++ b/cras/src/server/cras_rclient_util.c
@@ -80,6 +80,13 @@ rclient_validate_stream_connect_message(const struct cras_rclient *client,
msg->direction, client->id);
return -EINVAL;
}
+
+ if (!cras_validate_client_type(msg->client_type)) {
+ syslog(LOG_ERR,
+ "stream_connect: invalid stream client_type: %x for "
+ "client: %zx.\n",
+ msg->client_type, client->id);
+ }
return 0;
}
@@ -155,6 +162,9 @@ int rclient_handle_client_stream_connect(struct cras_rclient *client,
stream_config = cras_rstream_config_init_with_message(
client, msg, &aud_fd, &client_shm_fd, &remote_fmt);
+ /* Overwrite client_type if client->client_type is set. */
+ if (client->client_type != CRAS_CLIENT_TYPE_UNKNOWN)
+ stream_config.client_type = client->client_type;
rc = stream_list_add(cras_iodev_list_get_stream_list(), &stream_config,
&stream);
if (rc)
@@ -279,15 +289,11 @@ int rclient_handle_message_from_client(struct cras_rclient *client,
switch (msg->id) {
case CRAS_SERVER_CONNECT_STREAM: {
int client_shm_fd = num_fds > 1 ? fds[1] : -1;
- struct cras_connect_message cmsg;
if (MSG_LEN_VALID(msg, struct cras_connect_message)) {
rclient_handle_client_stream_connect(
client,
(const struct cras_connect_message *)msg, fd,
client_shm_fd);
- } else if (!convert_connect_message_old(msg, &cmsg)) {
- rclient_handle_client_stream_connect(client, &cmsg, fd,
- client_shm_fd);
} else {
return -EINVAL;
}
diff --git a/cras/src/server/cras_rclient_util.h b/cras/src/server/cras_rclient_util.h
index e00f87c9..089c2ecb 100644
--- a/cras/src/server/cras_rclient_util.h
+++ b/cras/src/server/cras_rclient_util.h
@@ -122,33 +122,4 @@ int rclient_handle_message_from_client(struct cras_rclient *client,
const struct cras_server_message *msg,
int *fds, unsigned int num_fds);
-/*
- * Converts an old version of connect message to the correct
- * cras_connect_message. Returns zero on success, negative on failure.
- * Note that this is special check only for libcras transition in
- * clients, from CRAS_PROTO_VER 5 to 7.
- * TODO(fletcherw): clean up the function once transition is done.
- */
-static inline int
-convert_connect_message_old(const struct cras_server_message *msg,
- struct cras_connect_message *cmsg)
-{
- struct cras_connect_message_old *old;
-
- if (!MSG_LEN_VALID(msg, struct cras_connect_message_old))
- return -EINVAL;
-
- old = (struct cras_connect_message_old *)msg;
- if (old->proto_version != 5 || CRAS_PROTO_VER != 7)
- return -EINVAL;
-
- // We want to copy everything except the client_shm_size field, since
- // that overlaps slightly with the now larger client_shm_size.
- memcpy(cmsg, old, sizeof(*old) - sizeof(old->client_shm_size));
- cmsg->client_shm_size = old->client_shm_size;
- cmsg->buffer_offsets[0] = 0;
- cmsg->buffer_offsets[1] = 0;
- return 0;
-}
-
#endif /* CRAS_RCLIENT_UTIL_H_ */
diff --git a/cras/src/server/cras_rstream.c b/cras/src/server/cras_rstream.c
index b5a64901..94adcead 100644
--- a/cras/src/server/cras_rstream.c
+++ b/cras/src/server/cras_rstream.c
@@ -292,6 +292,7 @@ int cras_rstream_create(struct cras_rstream_config *config,
stream->num_missed_cb = 0;
stream->is_pinned = (config->dev_idx != NO_DEVICE);
stream->pinned_dev_idx = config->dev_idx;
+ ewma_power_init(&stream->ewma, stream->format.frame_rate);
rc = setup_shm_area(stream, config);
if (rc < 0) {
@@ -312,7 +313,7 @@ int cras_rstream_create(struct cras_rstream_config *config,
config->stream_id, config->buffer_frames, config->cb_threshold);
*stream_out = stream;
- cras_system_state_stream_added(stream->direction);
+ cras_system_state_stream_added(stream->direction, stream->client_type);
clock_gettime(CLOCK_MONOTONIC_RAW, &stream->start_ts);
@@ -324,7 +325,8 @@ int cras_rstream_create(struct cras_rstream_config *config,
void cras_rstream_destroy(struct cras_rstream *stream)
{
cras_server_metrics_stream_destroy(stream);
- cras_system_state_stream_removed(stream->direction);
+ cras_system_state_stream_removed(stream->direction,
+ stream->client_type);
close(stream->fd);
cras_audio_shm_destroy(stream->shm);
cras_audio_area_destroy(stream->audio_area);
@@ -472,9 +474,16 @@ void cras_rstream_update_input_write_pointer(struct cras_rstream *rstream)
void cras_rstream_update_output_read_pointer(struct cras_rstream *rstream)
{
+ size_t nfr = 0;
+ uint8_t *src;
unsigned int nwritten =
buffer_share_get_new_write_point(rstream->buf_state);
+ /* Retrieve the read pointer |src| start from which to calculate
+ * the EWMA power. */
+ src = cras_shm_get_readable_frames(rstream->shm, 0, &nfr);
+ ewma_power_calculate(&rstream->ewma, (int16_t *)src,
+ rstream->format.num_channels, nwritten);
cras_shm_buffer_read(rstream->shm, nwritten);
}
diff --git a/cras/src/server/cras_rstream.h b/cras/src/server/cras_rstream.h
index 059f2bb7..3bf7df0b 100644
--- a/cras/src/server/cras_rstream.h
+++ b/cras/src/server/cras_rstream.h
@@ -14,6 +14,7 @@
#include "cras_shm.h"
#include "cras_types.h"
#include "cras_rstream_config.h"
+#include "ewma_power.h"
struct cras_connect_message;
struct cras_rclient;
@@ -55,6 +56,7 @@ struct master_dev_info {
* first_missed_cb_ts - The time when the first missed callback happens.
* buf_state - State of the buffer from all devices for this stream.
* apm_list - List of audio processing module instances.
+ * ewma - The ewma instance to calculate stream volume.
* num_attached_devs - Number of iodevs this stream has attached to.
* num_missed_cb - Number of callback schedules have been missed.
* queued_frames - Cached value of the number of queued frames in shm.
@@ -85,6 +87,7 @@ struct cras_rstream {
struct timespec first_missed_cb_ts;
struct buffer_share *buf_state;
struct cras_apm_list *apm_list;
+ struct ewma_power ewma;
int num_attached_devs;
int num_missed_cb;
int queued_frames;
diff --git a/cras/src/server/cras_server_metrics.c b/cras/src/server/cras_server_metrics.c
index 91556d86..ef4011bd 100644
--- a/cras/src/server/cras_server_metrics.c
+++ b/cras/src/server/cras_server_metrics.c
@@ -268,7 +268,7 @@ metrics_device_type_str(enum CRAS_METRICS_DEVICE_TYPE device_type)
return "NoDevice";
case CRAS_METRICS_DEVICE_ALSA_LOOPBACK:
return "AlsaLoopback";
- /* Other dummy devices. */
+ /* Other fallback devices. */
case CRAS_METRICS_DEVICE_NORMAL_FALLBACK:
return "NormalFallback";
case CRAS_METRICS_DEVICE_ABNORMAL_FALLBACK:
diff --git a/cras/src/server/cras_system_state.c b/cras/src/server/cras_system_state.c
index a5834197..331ecb11 100644
--- a/cras/src/server/cras_system_state.c
+++ b/cras/src/server/cras_system_state.c
@@ -156,6 +156,8 @@ void cras_system_state_init(const char *device_config_dir, const char *shm_name,
exp_state->aec_supported = board_config.aec_supported;
exp_state->aec_group_id = board_config.aec_group_id;
exp_state->bt_wbs_enabled = board_config.bt_wbs_enabled;
+ exp_state->deprioritize_bt_wbs_mic =
+ board_config.deprioritize_bt_wbs_mic;
if ((rc = pthread_mutex_init(&state.update_lock, 0) != 0)) {
syslog(LOG_ERR, "Fatal: system state mutex init");
@@ -382,6 +384,11 @@ bool cras_system_get_bt_wbs_enabled()
return !!state.exp_state->bt_wbs_enabled;
}
+bool cras_system_get_deprioritize_bt_wbs_mic()
+{
+ return !!state.exp_state->deprioritize_bt_wbs_mic;
+}
+
void cras_system_set_bt_fix_a2dp_packet_size_enabled(bool enabled)
{
state.bt_fix_a2dp_packet_size = enabled;
@@ -511,7 +518,8 @@ void cras_system_rm_select_fd(int fd)
state.fd_rm(fd, state.select_data);
}
-void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction)
+void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type)
{
struct cras_server_state *s;
@@ -521,13 +529,19 @@ void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction)
s->num_active_streams[direction]++;
s->num_streams_attached++;
+ if (direction == CRAS_STREAM_INPUT) {
+ s->num_input_streams_with_permission[client_type]++;
+ cras_observer_notify_input_streams_with_permission(
+ s->num_input_streams_with_permission);
+ }
cras_system_state_update_complete();
cras_observer_notify_num_active_streams(
direction, s->num_active_streams[direction]);
}
-void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction)
+void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type)
{
struct cras_server_state *s;
unsigned i, sum;
@@ -545,6 +559,11 @@ void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction)
cras_clock_gettime(CLOCK_MONOTONIC_RAW,
&s->last_active_stream_time);
s->num_active_streams[direction]--;
+ if (direction == CRAS_STREAM_INPUT) {
+ s->num_input_streams_with_permission[client_type]--;
+ cras_observer_notify_input_streams_with_permission(
+ s->num_input_streams_with_permission);
+ }
cras_system_state_update_complete();
cras_observer_notify_num_active_streams(
@@ -566,6 +585,15 @@ unsigned cras_system_state_get_active_streams_by_direction(
return state.exp_state->num_active_streams[direction];
}
+void cras_system_state_get_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE])
+{
+ unsigned type;
+ for (type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type)
+ num_input_streams[type] =
+ state.exp_state->num_input_streams_with_permission[type];
+}
+
void cras_system_state_get_last_stream_active_time(struct cras_timespec *ts)
{
*ts = state.exp_state->last_active_stream_time;
diff --git a/cras/src/server/cras_system_state.h b/cras/src/server/cras_system_state.h
index 7f92625e..ff04606a 100644
--- a/cras/src/server/cras_system_state.h
+++ b/cras/src/server/cras_system_state.h
@@ -122,6 +122,12 @@ void cras_system_set_bt_wbs_enabled(bool enabled);
/* Gets the elable flag of bluetooth wideband speech feature. */
bool cras_system_get_bt_wbs_enabled();
+/*
+ * Returns if Bluetooth WBS mic should be deprioritized for selecting
+ * as default audio input option.
+ */
+bool cras_system_get_deprioritize_bt_wbs_mic();
+
/* Sets the flag to enable or disable Bluetooth fixed A2DP packet size. */
void cras_system_set_bt_fix_a2dp_packet_size_enabled(bool enabled);
@@ -226,16 +232,20 @@ int cras_system_add_task(void (*callback)(void *data), void *callback_data);
* subsystem is idle.
* Args:
* direction - Directions of audio streams.
+ * client_type - CRAS_CLIENT_TYPE of the audio stream.
*/
-void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction);
+void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type);
/* Signals that an audio input or output stream has been removed from the
* system. This allows the count of active streams can be used to notice when
* the audio subsystem is idle.
* Args:
* direction - Directions of audio stream.
+ * client_type - CRAS_CLIENT_TYPE of the audio stream.
*/
-void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction);
+void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type);
/* Returns the number of active playback and capture streams. */
unsigned cras_system_state_get_active_streams();
@@ -247,6 +257,16 @@ unsigned cras_system_state_get_active_streams();
unsigned cras_system_state_get_active_streams_by_direction(
enum CRAS_STREAM_DIRECTION direction);
+/* Returns the number of input streams with permission per CRAS_CLIENT_TYPE.
+ *
+ * Returns:
+ * num_input_streams - An array with length = CRAS_NUM_CLIENT_TYPE and each
+ * element is the number of the current input
+ * streams with permission in each client type.
+ */
+void cras_system_state_get_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE]);
+
/* Fills ts with the time the last stream was removed from the system, the time
* the stream count went to zero.
*/
diff --git a/cras/src/server/dev_io.c b/cras/src/server/dev_io.c
index 20b25f7e..42fe9558 100644
--- a/cras/src/server/dev_io.c
+++ b/cras/src/server/dev_io.c
@@ -126,6 +126,19 @@ static bool is_time_to_fetch(const struct dev_stream *dev_stream,
return 0;
}
+/* The log only accepts uint32 arguments, so the float power
+ * must be written as bits and assumed to have a float when
+ * parsing the log.
+ */
+static uint32_t get_ewma_power_as_int(struct ewma_power *ewma)
+{
+ uint32_t pow_as_int = 0;
+
+ if (sizeof(uint32_t) == sizeof(float))
+ memcpy(&pow_as_int, &ewma->power, sizeof(uint32_t));
+ return pow_as_int;
+}
+
/* Asks any stream with room for more data. Sets the time stamp for all streams.
* Args:
* adev - The output device streams are attached to.
@@ -194,7 +207,8 @@ static int fetch_streams(struct open_dev *adev)
dev_stream_set_delay(dev_stream, delay);
ATLOG(atlog, AUDIO_THREAD_FETCH_STREAM, rstream->stream_id,
- cras_rstream_get_cb_threshold(rstream), delay);
+ cras_rstream_get_cb_threshold(rstream),
+ get_ewma_power_as_int(&rstream->ewma));
rc = dev_stream_request_playback_samples(dev_stream, &now);
if (rc < 0) {
@@ -550,7 +564,8 @@ static int capture_to_streams(struct open_dev *adev)
break;
}
- ATLOG(atlog, AUDIO_THREAD_READ_AUDIO_DONE, remainder, 0, 0);
+ ATLOG(atlog, AUDIO_THREAD_READ_AUDIO_DONE, remainder,
+ get_ewma_power_as_int(&idev->ewma), 0);
return 0;
}
@@ -733,7 +748,8 @@ int write_output_samples(struct open_dev **odevs, struct open_dev *adev,
if (cras_iodev_update_rate(odev, hw_level, &hw_tstamp))
update_estimated_rate(adev);
}
- ATLOG(atlog, AUDIO_THREAD_FILL_AUDIO, adev->dev->info.idx, hw_level, 0);
+ ATLOG(atlog, AUDIO_THREAD_FILL_AUDIO, adev->dev->info.idx, hw_level,
+ odev->min_cb_level);
/* Don't request more than hardware can hold. Note that min_buffer_level
* has been subtracted from the actual hw_level so we need to take it
@@ -797,7 +813,7 @@ int write_output_samples(struct open_dev **odevs, struct open_dev *adev,
}
ATLOG(atlog, AUDIO_THREAD_FILL_AUDIO_DONE, hw_level, total_written,
- odev->min_cb_level);
+ get_ewma_power_as_int(&odev->ewma));
return total_written;
}
diff --git a/cras/src/server/dev_stream.c b/cras/src/server/dev_stream.c
index f0fcb71e..025aeddd 100644
--- a/cras/src/server/dev_stream.c
+++ b/cras/src/server/dev_stream.c
@@ -87,9 +87,12 @@ struct dev_stream *dev_stream_create(struct cras_rstream *stream,
} else {
/*
* For input, take into account the stream specific processing
- * like AEC. Use the post processing format to configure format
- * converter.
+ * like AEC. APM exists only in input path, and has no dependency
+ * to dev_stream. Starts APM in dev_stream's constructor just to
+ * align with its life cycle, and then gets the post processing
+ * format to configure format converter.
*/
+ cras_apm_list_start_apm(stream->apm_list, dev_ptr);
ofmt = cras_rstream_post_processing_format(stream, dev_ptr) ?:
dev_fmt,
rc = config_format_converter(&out->conv, stream->direction,
@@ -123,9 +126,8 @@ struct dev_stream *dev_stream_create(struct cras_rstream *stream,
stream_fmt->frame_rate, &stream->sleep_interval_ts);
stream->next_cb_ts = *cb_ts;
- /* Sets up the stream & dev pair and then start APM. */
+ /* Sets up the stream & dev pair. */
cras_rstream_dev_attach(stream, dev_id, dev_ptr);
- cras_apm_list_start_apm(stream->apm_list, dev_ptr);
return out;
}
diff --git a/cras/src/server/ewma_power.c b/cras/src/server/ewma_power.c
new file mode 100644
index 00000000..5270ef0e
--- /dev/null
+++ b/cras/src/server/ewma_power.c
@@ -0,0 +1,81 @@
+/* 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.
+ */
+
+#include "ewma_power.h"
+#include "math.h"
+
+/* One sample per 1ms. */
+#define EWMA_SAMPLE_RATE 1000
+
+/* Smooth factor for EWMA, 1 - expf(-1.0/(rate * 0.01))
+ * where the 0.01 corresponds to 10ms interval that is chosen and
+ * being used in Chrome for a long time.
+ * Here the |rate| is set to the down sampled EWMA_SAMPLE_RATE and
+ * whenever it changes the calculated |smooth_factor| should be updated
+ * accordingly.
+ */
+const static float smooth_factor = 0.095;
+
+void ewma_power_disable(struct ewma_power *ewma)
+{
+ ewma->enabled = 0;
+}
+
+void ewma_power_init(struct ewma_power *ewma, unsigned int rate)
+{
+ ewma->enabled = 1;
+ ewma->power_set = 0;
+ ewma->step_fr = rate / EWMA_SAMPLE_RATE;
+}
+
+void ewma_power_calculate(struct ewma_power *ewma, const int16_t *buf,
+ unsigned int channels, unsigned int size)
+{
+ int i, ch;
+ float power, f;
+
+ if (!ewma->enabled)
+ return;
+ for (i = 0; i < size; i += ewma->step_fr * channels) {
+ power = 0.0f;
+ for (ch = 0; ch < channels; ch++) {
+ f = buf[i + ch] / 32768.0f;
+ power += f * f / channels;
+ }
+ if (!ewma->power_set) {
+ ewma->power = power;
+ ewma->power_set = 1;
+ } else {
+ ewma->power = smooth_factor * power +
+ (1 - smooth_factor) * ewma->power;
+ }
+ }
+}
+
+void ewma_power_calculate_area(struct ewma_power *ewma, const int16_t *buf,
+ struct cras_audio_area *area, unsigned int size)
+{
+ int i, ch;
+ float power, f;
+
+ if (!ewma->enabled)
+ return;
+ for (i = 0; i < size; i += ewma->step_fr * area->num_channels) {
+ power = 0.0f;
+ for (ch = 0; ch < area->num_channels; ch++) {
+ if (area->channels[ch].ch_set == 0)
+ continue;
+ f = buf[i + ch] / 32768.0f;
+ power += f * f / area->num_channels;
+ }
+ if (!ewma->power_set) {
+ ewma->power = power;
+ ewma->power_set = 1;
+ } else {
+ ewma->power = smooth_factor * power +
+ (1 - smooth_factor) * ewma->power;
+ }
+ }
+}
diff --git a/cras/src/server/ewma_power.h b/cras/src/server/ewma_power.h
new file mode 100644
index 00000000..78d2e504
--- /dev/null
+++ b/cras/src/server/ewma_power.h
@@ -0,0 +1,65 @@
+/* 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.
+ */
+
+#ifndef EWMA_POWER_H_
+#define EWMA_POWER_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "cras_audio_area.h"
+
+/*
+ * The exponentially weighted moving average power module used to
+ * calculate the energe level in audio stream.
+ * Members:
+ * power_set - Flag to note if the first power value has set.
+ * enabled - Flag to enable ewma calculation. Set to false to
+ * make all calculations no-ops.
+ * power - The power value.
+ * step_fr - How many frames to sample one for EWMA calculation.
+ */
+struct ewma_power {
+ bool power_set;
+ bool enabled;
+ float power;
+ unsigned int step_fr;
+};
+
+/*
+ * Disables the ewma instance.
+ */
+void ewma_power_disable(struct ewma_power *ewma);
+
+/*
+ * Initializes the ewma_power object.
+ * Args:
+ * ewma - The ewma_power object to initialize.
+ * rate - The sample rate of the audio data that the ewma object
+ * will calculate power from.
+ */
+void ewma_power_init(struct ewma_power *ewma, unsigned int rate);
+
+/*
+ * Feeds an audio buffer to ewma_power object to calculate the
+ * latest power value.
+ * Args:
+ * ewma - The ewma_power object to calculate power.
+ * buf - Pointer to the audio data.
+ * channels - Number of channels of the audio data.
+ * size - Length in frames of the audio data.
+ */
+void ewma_power_calculate(struct ewma_power *ewma, const int16_t *buf,
+ unsigned int channels, unsigned int size);
+
+/*
+ * Feeds non-interleaved audio data to ewma_power to calculate the
+ * latest power value. This is similar to ewma_power_calculate but
+ * accepts cras_audio_area.
+ */
+void ewma_power_calculate_area(struct ewma_power *ewma, const int16_t *buf,
+ struct cras_audio_area *area, unsigned int size);
+
+#endif /* EWMA_POWER_H_ */
diff --git a/cras/src/server/server_stream.c b/cras/src/server/server_stream.c
index 48dd6a30..6644c469 100644
--- a/cras/src/server/server_stream.c
+++ b/cras/src/server/server_stream.c
@@ -16,18 +16,6 @@
static unsigned int server_stream_block_size = 480;
/*
- * Server stream doesn't care what format is used, because no
- * client is reading data from stream. The main point is to
- * make pinned device open and let data flow through its dsp
- * pipeline.
- */
-static struct cras_audio_format format = {
- SND_PCM_FORMAT_S16_LE,
- 48000,
- 2,
-};
-
-/*
* Information of a stream created by server. Currently only
* one server stream is allowed, for echo reference use.
*/
@@ -45,7 +33,8 @@ static void server_stream_add_cb(void *data)
stream_list_add(stream_list, stream_config, &stream);
}
-void server_stream_create(struct stream_list *stream_list, unsigned int dev_idx)
+void server_stream_create(struct stream_list *stream_list, unsigned int dev_idx,
+ struct cras_audio_format *format)
{
int audio_fd = -1;
int client_shm_fd = -1;
@@ -64,7 +53,7 @@ void server_stream_create(struct stream_list *stream_list, unsigned int dev_idx)
CRAS_STREAM_TYPE_DEFAULT, CRAS_CLIENT_TYPE_SERVER_STREAM,
CRAS_STREAM_INPUT, dev_idx,
/*flags=*/SERVER_ONLY,
- /*effects=*/0, &format, server_stream_block_size,
+ /*effects=*/0, format, server_stream_block_size,
server_stream_block_size, &audio_fd, &client_shm_fd,
/*client_shm_size=*/0, buffer_offsets, stream_config);
diff --git a/cras/src/server/server_stream.h b/cras/src/server/server_stream.h
index 595987cb..e1eb8e10 100644
--- a/cras/src/server/server_stream.h
+++ b/cras/src/server/server_stream.h
@@ -14,8 +14,8 @@ struct stream_list;
* stream_list - List of stream to add new server stream to.
* dev_idx - The id of the device that new server stream will pin to.
*/
-void server_stream_create(struct stream_list *stream_list,
- unsigned int dev_idx);
+void server_stream_create(struct stream_list *stream_list, unsigned int dev_idx,
+ struct cras_audio_format *format);
/*
* Asynchronously destroys existing server stream pinned to device of given idx.
diff --git a/cras/src/server/test_iodev.c b/cras/src/server/test_iodev.c
index 266b62a8..cb7d5f3a 100644
--- a/cras/src/server/test_iodev.c
+++ b/cras/src/server/test_iodev.c
@@ -201,7 +201,7 @@ struct cras_iodev *test_iodev_create(enum CRAS_STREAM_DIRECTION direction,
*/
iodev->info.max_supported_channels = 1;
- /* Create a dummy ionode */
+ /* Create an empty ionode */
node = (struct cras_ionode *)calloc(1, sizeof(*node));
node->dev = iodev;
node->plugged = 1;
diff --git a/cras/src/tests/a2dp_iodev_unittest.cc b/cras/src/tests/a2dp_iodev_unittest.cc
index f03a6147..523a62e4 100644
--- a/cras/src/tests/a2dp_iodev_unittest.cc
+++ b/cras/src/tests/a2dp_iodev_unittest.cc
@@ -44,7 +44,7 @@ static size_t cras_iodev_free_resources_called;
static int a2dp_write_return_val[MAX_A2DP_WRITE_CALLS];
static unsigned int a2dp_write_index;
static int a2dp_encode_called;
-static cras_audio_area* dummy_audio_area;
+static cras_audio_area* mock_audio_area;
static thread_callback write_callback;
static void* write_callback_data;
static const char* fake_device_name = "fake device name";
@@ -79,9 +79,9 @@ void ResetStubData() {
fake_transport = reinterpret_cast<struct cras_bt_transport*>(0x123);
- if (!dummy_audio_area) {
- dummy_audio_area = (cras_audio_area*)calloc(
- 1, sizeof(*dummy_audio_area) + sizeof(cras_channel_area) * 2);
+ if (!mock_audio_area) {
+ mock_audio_area = (cras_audio_area*)calloc(
+ 1, sizeof(*mock_audio_area) + sizeof(cras_channel_area) * 2);
}
write_callback = NULL;
@@ -108,8 +108,8 @@ class A2dpIodev : public testing::Test {
}
virtual void TearDown() {
- free(dummy_audio_area);
- dummy_audio_area = NULL;
+ free(mock_audio_area);
+ mock_audio_area = NULL;
free(atlog);
}
};
@@ -899,7 +899,7 @@ int clock_gettime(clockid_t clk_id, struct timespec* tp) {
}
void cras_iodev_init_audio_area(struct cras_iodev* iodev, int num_channels) {
- iodev->area = dummy_audio_area;
+ iodev->area = mock_audio_area;
}
void cras_iodev_free_audio_area(struct cras_iodev* iodev) {}
@@ -917,12 +917,15 @@ int cras_iodev_fill_odev_zeros(struct cras_iodev* odev, unsigned int frames) {
void cras_audio_area_config_buf_pointers(struct cras_audio_area* area,
const struct cras_audio_format* fmt,
uint8_t* base_buffer) {
- dummy_audio_area->channels[0].buf = base_buffer;
+ mock_audio_area->channels[0].buf = base_buffer;
}
struct audio_thread* cras_iodev_list_get_audio_thread() {
return NULL;
}
+// From ewma_power
+void ewma_power_disable(struct ewma_power* ewma) {}
+
// From audio_thread
struct audio_thread_event_log* atlog;
diff --git a/cras/src/tests/alsa_helpers_unittest.cc b/cras/src/tests/alsa_helpers_unittest.cc
index 0e8112cd..32df30af 100644
--- a/cras/src/tests/alsa_helpers_unittest.cc
+++ b/cras/src/tests/alsa_helpers_unittest.cc
@@ -163,34 +163,12 @@ TEST(AlsaHelper, MatchChannelMapCapability51) {
}
TEST(AlsaHelper, Htimestamp) {
- snd_pcm_t* dummy_handle = reinterpret_cast<snd_pcm_t*>(0x1);
+ snd_pcm_t* mock_handle = reinterpret_cast<snd_pcm_t*>(0x1);
snd_pcm_uframes_t used;
snd_pcm_uframes_t severe_underrun_frames = 480;
struct timespec tstamp;
- int htimestamp_enabled = 1;
const char* dev_name = "dev_name";
- // Enable htimestamp use.
- ResetStubData();
- EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled));
- EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 1);
- EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 1);
- EXPECT_EQ(1, htimestamp_enabled);
-
- // Try to enable htimestamp use: not supported.
- ResetStubData();
- snd_pcm_sw_params_ret_vals.push_back(-EINVAL);
- EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled));
- EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 2);
- EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 2);
- EXPECT_EQ(0, htimestamp_enabled);
-
- // Disable htimestamp use.
- ResetStubData();
- EXPECT_EQ(0, cras_alsa_set_swparams(dummy_handle, &htimestamp_enabled));
- EXPECT_EQ(snd_pcm_sw_params_set_tstamp_mode_called, 0);
- EXPECT_EQ(snd_pcm_sw_params_set_tstamp_type_called, 0);
-
ResetStubData();
tstamp.tv_sec = 0;
tstamp.tv_nsec = 0;
@@ -198,7 +176,7 @@ TEST(AlsaHelper, Htimestamp) {
snd_pcm_htimestamp_tstamp_ret_val.tv_sec = 10;
snd_pcm_htimestamp_tstamp_ret_val.tv_nsec = 10000;
- cras_alsa_get_avail_frames(dummy_handle, 48000, severe_underrun_frames,
+ cras_alsa_get_avail_frames(mock_handle, 48000, severe_underrun_frames,
dev_name, &used, &tstamp);
EXPECT_EQ(used, snd_pcm_htimestamp_avail_ret_val);
EXPECT_EQ(tstamp.tv_sec, snd_pcm_htimestamp_tstamp_ret_val.tv_sec);
@@ -206,7 +184,7 @@ TEST(AlsaHelper, Htimestamp) {
}
TEST(AlsaHelper, GetAvailFramesSevereUnderrun) {
- snd_pcm_t* dummy_handle = reinterpret_cast<snd_pcm_t*>(0x1);
+ snd_pcm_t* mock_handle = reinterpret_cast<snd_pcm_t*>(0x1);
snd_pcm_uframes_t avail;
snd_pcm_uframes_t severe_underrun_frames = 480;
snd_pcm_uframes_t buffer_size = 48000;
@@ -216,7 +194,7 @@ TEST(AlsaHelper, GetAvailFramesSevereUnderrun) {
ResetStubData();
snd_pcm_htimestamp_avail_ret_val = buffer_size + severe_underrun_frames + 1;
- rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size,
+ rc = cras_alsa_get_avail_frames(mock_handle, buffer_size,
severe_underrun_frames, dev_name, &avail,
&tstamp);
// Returns -EPIPE when severe underrun happens.
@@ -224,7 +202,7 @@ TEST(AlsaHelper, GetAvailFramesSevereUnderrun) {
ResetStubData();
snd_pcm_htimestamp_avail_ret_val = buffer_size + severe_underrun_frames;
- rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size,
+ rc = cras_alsa_get_avail_frames(mock_handle, buffer_size,
severe_underrun_frames, dev_name, &avail,
&tstamp);
// Underrun which is not severe enough will be masked.
@@ -234,7 +212,7 @@ TEST(AlsaHelper, GetAvailFramesSevereUnderrun) {
ResetStubData();
snd_pcm_htimestamp_avail_ret_val = buffer_size - 1;
- rc = cras_alsa_get_avail_frames(dummy_handle, buffer_size,
+ rc = cras_alsa_get_avail_frames(mock_handle, buffer_size,
severe_underrun_frames, dev_name, &avail,
&tstamp);
// When avail < buffer_size, there is no underrun.
diff --git a/cras/src/tests/alsa_io_unittest.cc b/cras/src/tests/alsa_io_unittest.cc
index ba650a2f..b3059a23 100644
--- a/cras/src/tests/alsa_io_unittest.cc
+++ b/cras/src/tests/alsa_io_unittest.cc
@@ -137,7 +137,6 @@ static int cras_iodev_frames_queued_ret;
static int cras_iodev_buffer_avail_ret;
static int cras_alsa_resume_appl_ptr_called;
static int cras_alsa_resume_appl_ptr_ahead;
-static int ucm_get_enable_htimestamp_flag_ret;
static const struct cras_volume_curve* fake_get_dBFS_volume_curve_val;
static int cras_iodev_dsp_set_swap_mode_for_node_called;
static std::map<std::string, long> ucm_get_default_node_gain_values;
@@ -220,7 +219,6 @@ void ResetStubData() {
cras_iodev_buffer_avail_ret = 0;
cras_alsa_resume_appl_ptr_called = 0;
cras_alsa_resume_appl_ptr_ahead = 0;
- ucm_get_enable_htimestamp_flag_ret = 0;
fake_get_dBFS_volume_curve_val = NULL;
cras_iodev_dsp_set_swap_mode_for_node_called = 0;
ucm_get_default_node_gain_values.clear();
@@ -2473,7 +2471,7 @@ int cras_alsa_set_hwparams(snd_pcm_t* handle,
unsigned int dma_period_time) {
return 0;
}
-int cras_alsa_set_swparams(snd_pcm_t* handle, int* enable_htimestamp) {
+int cras_alsa_set_swparams(snd_pcm_t* handle) {
return 0;
}
int cras_alsa_get_avail_frames(snd_pcm_t* handle,
@@ -2768,10 +2766,6 @@ int ucm_get_min_buffer_level(struct cras_use_case_mgr* mgr,
return 0;
}
-unsigned int ucm_get_enable_htimestamp_flag(struct cras_use_case_mgr* mgr) {
- return ucm_get_enable_htimestamp_flag_ret;
-}
-
unsigned int ucm_get_disable_software_volume(struct cras_use_case_mgr* mgr) {
return 0;
}
diff --git a/cras/src/tests/alsa_ucm_unittest.cc b/cras/src/tests/alsa_ucm_unittest.cc
index efb82652..44c35879 100644
--- a/cras/src/tests/alsa_ucm_unittest.cc
+++ b/cras/src/tests/alsa_ucm_unittest.cc
@@ -862,28 +862,6 @@ TEST(AlsaUcm, UseFullySpecifiedUCMConfig) {
ASSERT_FALSE(fully_specified_flag);
}
-TEST(AlsaUcm, EnableHtimestampFlag) {
- struct cras_use_case_mgr* mgr = &cras_ucm_mgr;
- unsigned int enable_htimestamp_flag;
-
- std::string id = "=EnableHtimestamp//HiFi";
- ResetStubData();
-
- /* Flag is not set */
- enable_htimestamp_flag = ucm_get_enable_htimestamp_flag(mgr);
- ASSERT_FALSE(enable_htimestamp_flag);
-
- /* Flag is set to "1". */
- snd_use_case_get_value[id] = std::string("1");
- enable_htimestamp_flag = ucm_get_enable_htimestamp_flag(mgr);
- ASSERT_TRUE(enable_htimestamp_flag);
-
- /* Flag is set to "0". */
- snd_use_case_get_value[id] = std::string("0");
- enable_htimestamp_flag = ucm_get_enable_htimestamp_flag(mgr);
- ASSERT_FALSE(enable_htimestamp_flag);
-}
-
TEST(AlsaUcm, GetMixerNameForDevice) {
struct cras_use_case_mgr* mgr = &cras_ucm_mgr;
const char *mixer_name_1, *mixer_name_2;
diff --git a/cras/src/tests/audio_thread_unittest_obsolete.cc b/cras/src/tests/audio_thread_unittest_obsolete.cc
index 0baeb38f..ae9f5ef3 100644
--- a/cras/src/tests/audio_thread_unittest_obsolete.cc
+++ b/cras/src/tests/audio_thread_unittest_obsolete.cc
@@ -52,8 +52,8 @@ static unsigned int dev_stream_mix_called;
static struct timespec time_now;
static int cras_fmt_conversion_needed_return_val;
-static struct cras_audio_area* dummy_audio_area1;
-static struct cras_audio_area* dummy_audio_area2;
+static struct cras_audio_area* mock_audio_area1;
+static struct cras_audio_area* mock_audio_area2;
static struct cras_audio_format cras_iodev_set_format_val;
static struct dev_stream_capture_call dev_stream_capture_call;
@@ -95,18 +95,18 @@ class ReadStreamSuite : public testing::Test {
SetupRstream(&rstream2_, 2);
shm2_ = cras_rstream_input_shm(rstream2_);
- dummy_audio_area1 = (cras_audio_area*)calloc(
+ mock_audio_area1 = (cras_audio_area*)calloc(
1, sizeof(cras_audio_area) + 2 * sizeof(cras_channel_area));
- dummy_audio_area1->num_channels = 2;
- channel_area_set_channel(&dummy_audio_area1->channels[0], CRAS_CH_FL);
- channel_area_set_channel(&dummy_audio_area1->channels[1], CRAS_CH_FR);
- rstream_->input_audio_area = dummy_audio_area1;
- dummy_audio_area2 = (cras_audio_area*)calloc(
+ mock_audio_area1->num_channels = 2;
+ channel_area_set_channel(&mock_audio_area1->channels[0], CRAS_CH_FL);
+ channel_area_set_channel(&mock_audio_area1->channels[1], CRAS_CH_FR);
+ rstream_->input_audio_area = mock_audio_area1;
+ mock_audio_area2 = (cras_audio_area*)calloc(
1, sizeof(cras_audio_area) + 2 * sizeof(cras_channel_area));
- dummy_audio_area2->num_channels = 2;
- channel_area_set_channel(&dummy_audio_area2->channels[0], CRAS_CH_FL);
- channel_area_set_channel(&dummy_audio_area2->channels[1], CRAS_CH_FR);
- rstream2_->input_audio_area = dummy_audio_area2;
+ mock_audio_area2->num_channels = 2;
+ channel_area_set_channel(&mock_audio_area2->channels[0], CRAS_CH_FL);
+ channel_area_set_channel(&mock_audio_area2->channels[1], CRAS_CH_FR);
+ rstream2_->input_audio_area = mock_audio_area2;
dev_stream_mix_dont_fill_next = 0;
dev_stream_mix_count = 0;
@@ -123,8 +123,8 @@ class ReadStreamSuite : public testing::Test {
free(rstream_);
free(shm2_->area);
free(rstream2_);
- free(dummy_audio_area1);
- free(dummy_audio_area2);
+ free(mock_audio_area1);
+ free(mock_audio_area2);
}
void SetupRstream(struct cras_rstream** rstream, int fd) {
@@ -1444,18 +1444,18 @@ class ActiveDevicesSuite : public testing::Test {
rstream2_->buffer_frames -= 50;
rstream2_->cb_threshold -= 50;
- dummy_audio_area1 = (cras_audio_area*)calloc(
+ mock_audio_area1 = (cras_audio_area*)calloc(
1, sizeof(cras_audio_area) + 2 * sizeof(cras_channel_area));
- dummy_audio_area1->num_channels = 2;
- channel_area_set_channel(&dummy_audio_area1->channels[0], CRAS_CH_FL);
- channel_area_set_channel(&dummy_audio_area1->channels[1], CRAS_CH_FR);
- rstream_->input_audio_area = dummy_audio_area1;
- dummy_audio_area2 = (cras_audio_area*)calloc(
+ mock_audio_area1->num_channels = 2;
+ channel_area_set_channel(&mock_audio_area1->channels[0], CRAS_CH_FL);
+ channel_area_set_channel(&mock_audio_area1->channels[1], CRAS_CH_FR);
+ rstream_->input_audio_area = mock_audio_area1;
+ mock_audio_area2 = (cras_audio_area*)calloc(
1, sizeof(cras_audio_area) + 2 * sizeof(cras_channel_area));
- dummy_audio_area2->num_channels = 2;
- channel_area_set_channel(&dummy_audio_area2->channels[0], CRAS_CH_FL);
- channel_area_set_channel(&dummy_audio_area2->channels[1], CRAS_CH_FR);
- rstream2_->input_audio_area = dummy_audio_area2;
+ mock_audio_area2->num_channels = 2;
+ channel_area_set_channel(&mock_audio_area2->channels[0], CRAS_CH_FL);
+ channel_area_set_channel(&mock_audio_area2->channels[1], CRAS_CH_FR);
+ rstream2_->input_audio_area = mock_audio_area2;
cras_iodev_set_format_called = 0;
close_dev_called_ = 0;
@@ -1483,8 +1483,8 @@ class ActiveDevicesSuite : public testing::Test {
shm = cras_rstream_output_shm(rstream_);
free(shm->header);
free(rstream_);
- free(dummy_audio_area1);
- free(dummy_audio_area2);
+ free(mock_audio_area1);
+ free(mock_audio_area2);
}
void SetupRstream(struct cras_rstream** rstream) {
diff --git a/cras/src/tests/bt_device_unittest.cc b/cras/src/tests/bt_device_unittest.cc
index a9213f3d..ccb581cc 100644
--- a/cras/src/tests/bt_device_unittest.cc
+++ b/cras/src/tests/bt_device_unittest.cc
@@ -228,7 +228,8 @@ TEST_F(BtDeviceTestSuite, SetDeviceConnectedA2dpOnly) {
device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
EXPECT_NE((void*)NULL, device);
- cras_bt_device_add_supported_profiles(device, A2DP_SINK_UUID);
+ cras_bt_device_set_supported_profiles(device,
+ CRAS_BT_DEVICE_PROFILE_A2DP_SINK);
cur = msg_root = NewMockDBusConnectedMessage(1);
cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
@@ -268,8 +269,9 @@ TEST_F(BtDeviceTestSuite, SetDeviceConnectedHfpHspOnly) {
device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
EXPECT_NE((void*)NULL, device);
- cras_bt_device_add_supported_profiles(device, HSP_HS_UUID);
- cras_bt_device_add_supported_profiles(device, HFP_HF_UUID);
+ cras_bt_device_set_supported_profiles(
+ device, CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
+ CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
cur = msg_root = NewMockDBusConnectedMessage(1);
cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
@@ -310,9 +312,10 @@ TEST_F(BtDeviceTestSuite, SetDeviceConnectedA2dpHfpHsp) {
device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
EXPECT_NE((void*)NULL, device);
- cras_bt_device_add_supported_profiles(device, A2DP_SINK_UUID);
- cras_bt_device_add_supported_profiles(device, HSP_HS_UUID);
- cras_bt_device_add_supported_profiles(device, HFP_HF_UUID);
+ cras_bt_device_set_supported_profiles(
+ device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
+ CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
+ CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
cur = msg_root = NewMockDBusConnectedMessage(1);
cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
@@ -360,9 +363,10 @@ TEST_F(BtDeviceTestSuite, DevConnectedConflictCheck) {
device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
EXPECT_NE((void*)NULL, device);
- cras_bt_device_add_supported_profiles(device, A2DP_SINK_UUID);
- cras_bt_device_add_supported_profiles(device, HSP_HS_UUID);
- cras_bt_device_add_supported_profiles(device, HFP_HF_UUID);
+ cras_bt_device_set_supported_profiles(
+ device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
+ CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
+ CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
cur = msg_root = NewMockDBusConnectedMessage(1);
cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
@@ -398,9 +402,10 @@ TEST_F(BtDeviceTestSuite, A2dpDropped) {
device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
EXPECT_NE((void*)NULL, device);
- cras_bt_device_add_supported_profiles(device, A2DP_SINK_UUID);
- cras_bt_device_add_supported_profiles(device, HSP_HS_UUID);
- cras_bt_device_add_supported_profiles(device, HFP_HF_UUID);
+ cras_bt_device_set_supported_profiles(
+ device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
+ CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
+ CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
cur = msg_root = NewMockDBusConnectedMessage(1);
cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
@@ -433,9 +438,10 @@ TEST_F(BtDeviceTestSuite, DevConnectDisconnectBackToBack) {
device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
EXPECT_NE((void*)NULL, device);
- cras_bt_device_add_supported_profiles(device, A2DP_SINK_UUID);
- cras_bt_device_add_supported_profiles(device, HSP_HS_UUID);
- cras_bt_device_add_supported_profiles(device, HFP_HF_UUID);
+ cras_bt_device_set_supported_profiles(
+ device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
+ CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
+ CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
cur = msg_root = NewMockDBusConnectedMessage(1);
cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
@@ -500,9 +506,10 @@ TEST_F(BtDeviceTestSuite, ConnectionWatchTimeout) {
device = cras_bt_device_create(NULL, FAKE_OBJ_PATH);
EXPECT_NE((void*)NULL, device);
- cras_bt_device_add_supported_profiles(device, A2DP_SINK_UUID);
- cras_bt_device_add_supported_profiles(device, HSP_HS_UUID);
- cras_bt_device_add_supported_profiles(device, HFP_HF_UUID);
+ cras_bt_device_set_supported_profiles(
+ device, CRAS_BT_DEVICE_PROFILE_A2DP_SINK |
+ CRAS_BT_DEVICE_PROFILE_HSP_HEADSET |
+ CRAS_BT_DEVICE_PROFILE_HFP_HANDSFREE);
cur = msg_root = NewMockDBusConnectedMessage(1);
cras_bt_device_update_properties(device, (DBusMessageIter*)&cur, NULL);
diff --git a/cras/src/tests/bt_io_unittest.cc b/cras/src/tests/bt_io_unittest.cc
index 7ccb669e..ee013cf3 100644
--- a/cras/src/tests/bt_io_unittest.cc
+++ b/cras/src/tests/bt_io_unittest.cc
@@ -423,7 +423,8 @@ int cras_iodev_list_rm_input(struct cras_iodev* dev) {
}
// From bt device
-int cras_bt_device_get_active_profile(const struct cras_bt_device* device) {
+unsigned int cras_bt_device_get_active_profile(
+ const struct cras_bt_device* device) {
return cras_bt_device_get_active_profile_ret;
}
diff --git a/cras/src/tests/capture_rclient_unittest.cc b/cras/src/tests/capture_rclient_unittest.cc
index 4c1ab07f..b749f1a5 100644
--- a/cras/src/tests/capture_rclient_unittest.cc
+++ b/cras/src/tests/capture_rclient_unittest.cc
@@ -23,8 +23,8 @@ static unsigned int cras_observer_remove_called;
static int stream_list_add_called;
static int stream_list_add_return;
static unsigned int stream_list_rm_called;
-static struct cras_audio_shm dummy_shm;
-static struct cras_rstream dummy_rstream;
+static struct cras_audio_shm mock_shm;
+static struct cras_rstream mock_rstream;
void ResetStubData() {
cras_make_fd_nonblocking_called = 0;
@@ -177,44 +177,6 @@ TEST_F(CCRMessageSuite, StreamConnectMessageInvalidClientId) {
EXPECT_EQ(stream_id, out_msg.stream_id);
}
-/*
- * TODO(yuhsaun): Remove this test when there are no client uses the old
- * craslib. (CRAS_PROTO_VER = 5)
- */
-TEST_F(CCRMessageSuite, StreamConnectMessageOldProtocal) {
- struct cras_client_stream_connected out_msg;
- int rc;
-
- struct cras_connect_message_old msg;
- cras_stream_id_t stream_id = 0x10002;
-
- msg.proto_version = 5;
- msg.direction = CRAS_STREAM_INPUT;
- msg.stream_id = stream_id;
- msg.stream_type = CRAS_STREAM_TYPE_DEFAULT;
- msg.buffer_frames = 480;
- msg.cb_threshold = 240;
- msg.flags = 0;
- msg.effects = 0;
- pack_cras_audio_format(&msg.format, &fmt);
- msg.dev_idx = NO_DEVICE;
- msg.client_shm_size = 0;
- msg.client_type = CRAS_CLIENT_TYPE_TEST;
- msg.header.id = CRAS_SERVER_CONNECT_STREAM;
- msg.header.length = sizeof(struct cras_connect_message_old);
-
- fd_ = 100;
- rc =
- rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_, 1);
- EXPECT_EQ(1, cras_make_fd_nonblocking_called);
- EXPECT_EQ(1, stream_list_add_called);
- EXPECT_EQ(0, stream_list_rm_called);
-
- rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
- EXPECT_EQ(sizeof(out_msg), rc);
- EXPECT_EQ(stream_id, out_msg.stream_id);
-}
-
TEST_F(CCRMessageSuite, StreamDisconnectMessage) {
struct cras_disconnect_stream_message msg;
cras_stream_id_t stream_id = 0x10002;
@@ -290,16 +252,16 @@ int stream_list_add(struct stream_list* list,
struct cras_rstream** stream) {
int ret;
- *stream = &dummy_rstream;
+ *stream = &mock_rstream;
stream_list_add_called++;
ret = stream_list_add_return;
if (ret)
stream_list_add_return = -EINVAL;
- dummy_rstream.shm = &dummy_shm;
- dummy_rstream.direction = config->direction;
- dummy_rstream.stream_id = config->stream_id;
+ mock_rstream.shm = &mock_shm;
+ mock_rstream.direction = config->direction;
+ mock_rstream.stream_id = config->stream_id;
return ret;
}
diff --git a/cras/src/tests/control_rclient_unittest.cc b/cras/src/tests/control_rclient_unittest.cc
index b0d01fc6..d6b63aab 100644
--- a/cras/src/tests/control_rclient_unittest.cc
+++ b/cras/src/tests/control_rclient_unittest.cc
@@ -47,8 +47,8 @@ static unsigned int stream_list_add_stream_called;
static unsigned int stream_list_disconnect_stream_called;
static unsigned int cras_iodev_list_rm_input_called;
static unsigned int cras_iodev_list_rm_output_called;
-static struct cras_audio_shm dummy_shm;
-static struct cras_rstream dummy_rstream;
+static struct cras_audio_shm mock_shm;
+static struct cras_rstream mock_rstream;
static size_t cras_observer_num_ops_registered;
static size_t cras_observer_register_notify_called;
static size_t cras_observer_add_called;
@@ -222,30 +222,6 @@ TEST_F(RClientMessagesSuite, ConnectMsgWithBadFd) {
stream_list_disconnect_stream_called);
}
-TEST_F(RClientMessagesSuite, ConnectMsgFromOldClient) {
- struct cras_client_stream_connected out_msg;
- int rc;
-
- cras_rstream_create_stream_out = rstream_;
- cras_iodev_attach_stream_retval = 0;
-
- connect_msg_.header.length = sizeof(struct cras_connect_message_old);
- connect_msg_.proto_version = 5;
-
- fd_ = 100;
- rc = rclient_->ops->handle_message_from_client(rclient_, &connect_msg_.header,
- &fd_, 1);
- EXPECT_EQ(0, rc);
- EXPECT_EQ(1, cras_make_fd_nonblocking_called);
-
- rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
- EXPECT_EQ(sizeof(out_msg), rc);
- EXPECT_EQ(stream_id_, out_msg.stream_id);
- EXPECT_EQ(0, out_msg.err);
- EXPECT_EQ(1, stream_list_add_stream_called);
- EXPECT_EQ(0, stream_list_disconnect_stream_called);
-}
-
TEST_F(RClientMessagesSuite, StreamConnectMessageValidDirection) {
struct cras_client_stream_connected out_msg;
int rc;
@@ -911,16 +887,16 @@ int stream_list_add(struct stream_list* list,
struct cras_rstream** stream) {
int ret;
- *stream = &dummy_rstream;
+ *stream = &mock_rstream;
stream_list_add_stream_called++;
ret = stream_list_add_stream_return;
if (ret)
stream_list_add_stream_return = -EINVAL;
- dummy_rstream.shm = &dummy_shm;
- dummy_rstream.direction = config->direction;
- dummy_rstream.stream_id = config->stream_id;
+ mock_rstream.shm = &mock_shm;
+ mock_rstream.direction = config->direction;
+ mock_rstream.stream_id = config->stream_id;
return ret;
}
@@ -987,4 +963,8 @@ bool cras_audio_format_valid(const struct cras_audio_format* fmt) {
return true;
}
+struct packet_status_logger* cras_hfp_ag_get_wbs_logger() {
+ return NULL;
+}
+
} // extern "C"
diff --git a/cras/src/tests/dev_stream_unittest.cc b/cras/src/tests/dev_stream_unittest.cc
index 9210021e..640ca932 100644
--- a/cras/src/tests/dev_stream_unittest.cc
+++ b/cras/src/tests/dev_stream_unittest.cc
@@ -340,7 +340,7 @@ TEST_F(CreateSuite, CreateSRC44to48) {
// Converter tmp and output buffers are large enough for device output.
unsigned int device_frames =
cras_frames_at_rate(in_fmt.frame_rate, kBufferFrames, out_fmt.frame_rate);
- EXPECT_LE(kBufferFrames, device_frames); // Sanity check.
+ EXPECT_LE(kBufferFrames, device_frames); // Soundness check.
EXPECT_LE(device_frames, config_format_converter_frames);
EXPECT_LE(device_frames, dev_stream->conv_buffer_size_frames);
dev_stream_destroy(dev_stream);
@@ -364,7 +364,7 @@ TEST_F(CreateSuite, CreateSRC44from48Input) {
// Converter tmp and output buffers are large enough for device input.
unsigned int device_frames =
cras_frames_at_rate(out_fmt.frame_rate, kBufferFrames, in_fmt.frame_rate);
- EXPECT_LE(kBufferFrames, device_frames); // Sanity check.
+ EXPECT_LE(kBufferFrames, device_frames); // Soundness check.
EXPECT_LE(device_frames, config_format_converter_frames);
EXPECT_EQ(&processed_fmt, config_format_converter_from_fmt);
EXPECT_LE(device_frames, dev_stream->conv_buffer_size_frames);
@@ -420,7 +420,7 @@ TEST_F(CreateSuite, CreateSRC8to48) {
// Converter tmp and output buffers are large enough for device output.
unsigned int device_frames =
cras_frames_at_rate(in_fmt.frame_rate, kBufferFrames, out_fmt.frame_rate);
- EXPECT_LE(kBufferFrames, device_frames); // Sanity check.
+ EXPECT_LE(kBufferFrames, device_frames); // Soundness check.
EXPECT_LE(device_frames, config_format_converter_frames);
EXPECT_LE(device_frames, dev_stream->conv_buffer_size_frames);
dev_stream_destroy(dev_stream);
@@ -441,7 +441,7 @@ TEST_F(CreateSuite, CreateSRC8from48Input) {
// Converter tmp and output buffers are large enough for device input.
unsigned int device_frames =
cras_frames_at_rate(out_fmt.frame_rate, kBufferFrames, in_fmt.frame_rate);
- EXPECT_LE(kBufferFrames, device_frames); // Sanity check.
+ EXPECT_LE(kBufferFrames, device_frames); // Soundness check.
EXPECT_LE(device_frames, config_format_converter_frames);
EXPECT_LE(device_frames, dev_stream->conv_buffer_size_frames);
dev_stream_destroy(dev_stream);
diff --git a/cras/src/tests/empty_iodev_unittest.cc b/cras/src/tests/empty_iodev_unittest.cc
index 585fba32..148d5301 100644
--- a/cras/src/tests/empty_iodev_unittest.cc
+++ b/cras/src/tests/empty_iodev_unittest.cc
@@ -13,7 +13,7 @@ extern "C" {
static struct timespec clock_gettime_retspec;
static struct cras_audio_format fake_format;
-static cras_audio_area dummy_audio_area;
+static cras_audio_area mock_audio_area;
namespace {
@@ -57,7 +57,7 @@ int cras_iodev_default_no_stream_playback(struct cras_iodev* odev, int enable) {
}
void cras_iodev_init_audio_area(struct cras_iodev* iodev, int num_channels) {
- iodev->area = &dummy_audio_area;
+ iodev->area = &mock_audio_area;
}
void cras_iodev_free_audio_area(struct cras_iodev* iodev) {}
diff --git a/cras/src/tests/ewma_power_unittest.cc b/cras/src/tests/ewma_power_unittest.cc
new file mode 100644
index 00000000..10f03189
--- /dev/null
+++ b/cras/src/tests/ewma_power_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 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.
+
+#include <gtest/gtest.h>
+
+extern "C" {
+#include "ewma_power.h"
+}
+
+namespace {
+
+TEST(EWMAPower, RelativePowerValue) {
+ struct ewma_power ewma;
+ int16_t buf[480];
+ float f;
+ int i;
+
+ for (i = 0; i < 480; i++)
+ buf[i] = 0x00fe;
+
+ ewma_power_init(&ewma, 48000);
+ EXPECT_EQ(48, ewma.step_fr);
+
+ ewma_power_calculate(&ewma, buf, 1, 480);
+ EXPECT_LT(0.0f, ewma.power);
+
+ // After 10ms of silence the power value decreases.
+ f = ewma.power;
+ for (i = 0; i < 480; i++)
+ buf[i] = 0x00;
+ ewma_power_calculate(&ewma, buf, 1, 480);
+ EXPECT_LT(ewma.power, f);
+
+ // After 300ms of silence the power value decreases to insignificant low.
+ for (i = 0; i < 30; i++)
+ ewma_power_calculate(&ewma, buf, 1, 480);
+ EXPECT_LT(ewma.power, 1.0e-10);
+}
+
+TEST(EWMAPower, PowerInStereoData) {
+ struct ewma_power ewma;
+ int16_t buf[960];
+ int i;
+ float f;
+
+ ewma_power_init(&ewma, 48000);
+
+ for (i = 0; i < 960; i += 2) {
+ buf[i] = 0x0;
+ buf[i + 1] = 0x00fe;
+ }
+ ewma_power_calculate(&ewma, buf, 2, 480);
+ EXPECT_LT(0.0f, ewma.power);
+
+ // After 10ms of silence the power value decreases.
+ f = ewma.power;
+ for (i = 0; i < 960; i++)
+ buf[i] = 0x0;
+ ewma_power_calculate(&ewma, buf, 2, 480);
+ EXPECT_LT(ewma.power, f);
+
+ // After 300ms of silence the power value decreases to insignificant low.
+ for (i = 0; i < 30; i++)
+ ewma_power_calculate(&ewma, buf, 2, 480);
+ EXPECT_LT(ewma.power, 1.0e-10);
+
+ // Assume the data is silent in the other channel.
+ ewma_power_init(&ewma, 48000);
+
+ for (i = 0; i < 960; i += 2) {
+ buf[i] = 0x0ffe;
+ buf[i + 1] = 0x0;
+ }
+ ewma_power_calculate(&ewma, buf, 2, 480);
+ EXPECT_LT(0.0f, ewma.power);
+}
+
+TEST(EWMAPower, PowerInAudioArea) {
+ struct ewma_power ewma;
+ struct cras_audio_area* area = cras_audio_area_create(4);
+ struct cras_audio_format* fmt =
+ cras_audio_format_create(SND_PCM_FORMAT_S16_LE, 48000, 4);
+ int8_t layout[CRAS_CH_MAX] = {0, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+ int16_t buf[1920];
+ int i;
+ float f;
+
+ cras_audio_format_set_channel_layout(fmt, layout);
+ cras_audio_area_config_channels(area, fmt);
+
+ for (i = 0; i < 1920; i += 4) {
+ buf[i] = 0x0ffe;
+ buf[i + 1] = 0x0;
+ buf[i + 2] = 0x0;
+ buf[i + 3] = 0x0ffe;
+ }
+ ewma_power_init(&ewma, 48000);
+ ewma_power_calculate_area(&ewma, buf, area, 480);
+ f = ewma.power;
+ EXPECT_LT(0.0f, f);
+
+ /* Change the layout in the same audio area. Expect the power be lower because
+ * one of the channel is now silent. */
+ layout[CRAS_CH_FR] = 2;
+ cras_audio_format_set_channel_layout(fmt, layout);
+ cras_audio_area_config_channels(area, fmt);
+ ewma_power_init(&ewma, 48000);
+ ewma_power_calculate_area(&ewma, buf, area, 480);
+ EXPECT_GT(f, ewma.power);
+
+ /* Change layout to the two silent channels. Expect power is 0.0f. */
+ layout[CRAS_CH_FL] = 1;
+ cras_audio_format_set_channel_layout(fmt, layout);
+ cras_audio_area_config_channels(area, fmt);
+ ewma_power_init(&ewma, 48000);
+ ewma_power_calculate_area(&ewma, buf, area, 480);
+ EXPECT_EQ(0.0f, ewma.power);
+
+ cras_audio_format_destroy(fmt);
+ cras_audio_area_destroy(area);
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/cras/src/tests/fmt_conv_ops_unittest.cc b/cras/src/tests/fmt_conv_ops_unittest.cc
index d8feeab3..ebe8b65d 100644
--- a/cras/src/tests/fmt_conv_ops_unittest.cc
+++ b/cras/src/tests/fmt_conv_ops_unittest.cc
@@ -4,6 +4,8 @@
#include <gtest/gtest.h>
#include <limits.h>
+#include <math.h>
+#include <stdint.h>
#include <sys/param.h>
#include <memory>
@@ -477,7 +479,7 @@ TEST(FormatConverterOpsTest, _51ToStereoS16LE) {
const size_t out_ch = 2;
const size_t left = 0;
const size_t right = 1;
- const size_t center = 4;
+ const size_t center = 2;
S16LEPtr src = CreateS16LE(frames * in_ch);
S16LEPtr dst = CreateS16LE(frames * out_ch);
@@ -486,11 +488,58 @@ TEST(FormatConverterOpsTest, _51ToStereoS16LE) {
s16_51_to_stereo((uint8_t*)src.get(), frames, (uint8_t*)dst.get());
EXPECT_EQ(ret, frames);
+ /* Use the normalized_factor from the left channel = 1 / (|1| + |0.707|)
+ * to prevent mixing overflow.
+ */
+ const float normalized_factor = 0.585;
+
+ for (size_t i = 0; i < frames; ++i) {
+ int16_t half_center = src[i * 6 + center] * 0.707 * normalized_factor;
+ int16_t l = normalized_factor * src[i * 6 + left] + half_center;
+ int16_t r = normalized_factor * src[i * 6 + right] + half_center;
+
+ EXPECT_EQ(l, dst[i * 2 + left]);
+ EXPECT_EQ(r, dst[i * 2 + right]);
+ }
+}
+
+// Test 5.1 to Quad conversion. S16_LE.
+TEST(FormatConverterOpsTest, _51ToQuadS16LE) {
+ const size_t frames = 4096;
+ const size_t in_ch = 6;
+ const size_t out_ch = 4;
+ const unsigned int fl_quad = 0;
+ const unsigned int fr_quad = 1;
+ const unsigned int rl_quad = 2;
+ const unsigned int rr_quad = 3;
+
+ const unsigned int fl_51 = 0;
+ const unsigned int fr_51 = 1;
+ const unsigned int center_51 = 2;
+ const unsigned int lfe_51 = 3;
+ const unsigned int rl_51 = 4;
+ const unsigned int rr_51 = 5;
+
+ S16LEPtr src = CreateS16LE(frames * in_ch);
+ S16LEPtr dst = CreateS16LE(frames * out_ch);
+
+ size_t ret = s16_51_to_quad((uint8_t*)src.get(), frames, (uint8_t*)dst.get());
+ EXPECT_EQ(ret, frames);
+
+ /* Use normalized_factor from the left channel = 1 / (|1| + |0.707| + |0.5|)
+ * to prevent overflow. */
+ const float normalized_factor = 0.453;
for (size_t i = 0; i < frames; ++i) {
- int16_t half_center = src[i * 6 + center] / 2;
- EXPECT_EQ(S16AddAndClip(src[i * 6 + left], half_center), dst[i * 2 + left]);
- EXPECT_EQ(S16AddAndClip(src[i * 6 + right], half_center),
- dst[i * 2 + right]);
+ int16_t half_center = src[i * 6 + center_51] * 0.707 * normalized_factor;
+ int16_t lfe = src[6 * i + lfe_51] * 0.5 * normalized_factor;
+ int16_t fl = normalized_factor * src[6 * i + fl_51] + half_center + lfe;
+ int16_t fr = normalized_factor * src[6 * i + fr_51] + half_center + lfe;
+ int16_t rl = normalized_factor * src[6 * i + rl_51] + lfe;
+ int16_t rr = normalized_factor * src[6 * i + rr_51] + lfe;
+ EXPECT_EQ(fl, dst[4 * i + fl_quad]);
+ EXPECT_EQ(fr, dst[4 * i + fr_quad]);
+ EXPECT_EQ(rl, dst[4 * i + rl_quad]);
+ EXPECT_EQ(rr, dst[4 * i + rr_quad]);
}
}
diff --git a/cras/src/tests/fmt_conv_unittest.cc b/cras/src/tests/fmt_conv_unittest.cc
index 5474f172..c66984ee 100644
--- a/cras/src/tests/fmt_conv_unittest.cc
+++ b/cras/src/tests/fmt_conv_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <gtest/gtest.h>
+#include <math.h>
#include <sys/param.h>
extern "C" {
@@ -459,6 +460,81 @@ TEST(FormatConverterTest, SurroundToStereo) {
free(out_buff);
}
+// Test 5.1 to Quad mix.
+TEST(FormatConverterTest, SurroundToQuad) {
+ struct cras_fmt_conv* c;
+ struct cras_audio_format in_fmt;
+ struct cras_audio_format out_fmt;
+
+ size_t out_frames;
+ int16_t* in_buff;
+ int16_t* out_buff;
+ unsigned int i;
+ const size_t buf_size = 4096;
+ unsigned int in_buf_size = 4096;
+
+ ResetStub();
+ in_fmt.format = SND_PCM_FORMAT_S16_LE;
+ out_fmt.format = SND_PCM_FORMAT_S16_LE;
+ in_fmt.num_channels = 6;
+ out_fmt.num_channels = 4;
+ in_fmt.frame_rate = 48000;
+ out_fmt.frame_rate = 48000;
+ for (i = 0; i < CRAS_CH_MAX; i++)
+ in_fmt.channel_layout[i] = surround_channel_center_layout[i];
+
+ c = cras_fmt_conv_create(&in_fmt, &out_fmt, buf_size, 0);
+ ASSERT_NE(c, (void*)NULL);
+
+ out_frames = cras_fmt_conv_out_frames_to_in(c, buf_size);
+ EXPECT_EQ(buf_size, out_frames);
+
+ out_frames = cras_fmt_conv_in_frames_to_out(c, buf_size);
+ EXPECT_EQ(buf_size, out_frames);
+
+ in_buff = (int16_t*)malloc(buf_size * 2 * cras_get_format_bytes(&in_fmt));
+
+ const int16_t in_fl = 100;
+ const int16_t in_fr = 200;
+ const int16_t in_rl = 200;
+ const int16_t in_rr = 300;
+ const int16_t in_fc = 60;
+ const int16_t in_lfe = 90;
+
+ for (i = 0; i < buf_size; i++) {
+ in_buff[i * 6 + CRAS_CH_FL] = in_fl;
+ in_buff[i * 6 + CRAS_CH_FR] = in_fr;
+ in_buff[i * 6 + CRAS_CH_RL] = in_rl;
+ in_buff[i * 6 + CRAS_CH_RR] = in_rr;
+ in_buff[i * 6 + CRAS_CH_FC] = in_fc;
+ in_buff[i * 6 + CRAS_CH_LFE] = in_lfe;
+ }
+ out_buff = (int16_t*)malloc(buf_size * 2 * cras_get_format_bytes(&out_fmt));
+ out_frames = cras_fmt_conv_convert_frames(
+ c, (uint8_t*)in_buff, (uint8_t*)out_buff, &in_buf_size, buf_size);
+ EXPECT_EQ(buf_size, out_frames);
+
+ // This is the sum of mtx[CRAS_CH_FL] coefficients.
+ const float normalize_factor = 1.0 / (1 + 0.707 + 0.5);
+
+ for (i = 0; i < buf_size; i++) {
+ int16_t lfe = 0.5 * normalize_factor * in_lfe;
+ int16_t center = 0.707 * normalize_factor * in_fc;
+ int16_t fl = normalize_factor * in_fl + center + lfe;
+ int16_t fr = normalize_factor * in_fr + center + lfe;
+ int16_t rl = normalize_factor * in_rl + lfe;
+ int16_t rr = normalize_factor * in_rr + lfe;
+
+ EXPECT_EQ(fl, out_buff[i * 4 + CRAS_CH_FL]);
+ EXPECT_EQ(fr, out_buff[i * 4 + CRAS_CH_FR]);
+ EXPECT_EQ(rl, out_buff[i * 4 + CRAS_CH_RL]);
+ EXPECT_EQ(rr, out_buff[i * 4 + CRAS_CH_RR]);
+ }
+ cras_fmt_conv_destroy(&c);
+ free(in_buff);
+ free(out_buff);
+}
+
// Test Quad to Stereo mix.
TEST(FormatConverterTest, QuadToStereo) {
struct cras_fmt_conv* c;
diff --git a/cras/src/tests/hfp_ag_profile_unittest.cc b/cras/src/tests/hfp_ag_profile_unittest.cc
index 1a115f04..3ecd2407 100644
--- a/cras/src/tests/hfp_ag_profile_unittest.cc
+++ b/cras/src/tests/hfp_ag_profile_unittest.cc
@@ -286,6 +286,9 @@ void cras_bt_device_notify_profile_dropped(
cras_bt_device_notify_profile_dropped_profile = profile;
}
+void hfp_info_set_wbs_logger(struct hfp_info* info,
+ struct packet_status_logger* wbs_logger) {}
+
void cras_observer_notify_bt_battery_changed(const char* address,
uint32_t level) {
return;
diff --git a/cras/src/tests/hfp_alsa_iodev_unittest.cc b/cras/src/tests/hfp_alsa_iodev_unittest.cc
index 89756948..c5bd4e9a 100644
--- a/cras/src/tests/hfp_alsa_iodev_unittest.cc
+++ b/cras/src/tests/hfp_alsa_iodev_unittest.cc
@@ -477,6 +477,9 @@ void cras_iodev_set_active_node(struct cras_iodev* iodev,
iodev->active_node = node;
}
+// From ewma_power
+void ewma_power_disable(struct ewma_power* ewma) {}
+
size_t cras_system_get_volume() {
return 0;
}
diff --git a/cras/src/tests/hfp_info_unittest.cc b/cras/src/tests/hfp_info_unittest.cc
index 48a1c89c..24f536ae 100644
--- a/cras/src/tests/hfp_info_unittest.cc
+++ b/cras/src/tests/hfp_info_unittest.cc
@@ -3,10 +3,15 @@
* found in the LICENSE file.
*/
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdint.h>
#include <time.h>
+using testing::MatchesRegex;
+using testing::internal::CaptureStdout;
+using testing::internal::GetCapturedStdout;
+
extern "C" {
#include "cras_hfp_info.c"
#include "sbc_codec_stub.h"
@@ -504,6 +509,26 @@ TEST(HfpInfo, StartHfpInfoAndWriteMsbc) {
hfp_info_destroy(info);
}
+TEST(HfpInfo, WBSLoggerPacketStatusDumpBinary) {
+ struct packet_status_logger logger;
+ char log_regex[64];
+ int num_wraps[5] = {0, 0, 0, 1, 1};
+ int wp[5] = {40, 150, 162, 100, 32};
+
+ /* Expect the log line wraps at correct length to avoid feedback redact. */
+ snprintf(log_regex, 64, "([01D]{%d}\n)*", PACKET_STATUS_LOG_LINE_WRAP);
+
+ packet_status_logger_init(&logger);
+ logger.size = PACKET_STATUS_LEN_BYTES * 8;
+ for (int i = 0; i < 5; i++) {
+ CaptureStdout();
+ logger.num_wraps = num_wraps[i];
+ logger.wp = wp[i];
+ packet_status_logger_dump_binary(&logger);
+ EXPECT_THAT(GetCapturedStdout(), MatchesRegex(log_regex));
+ }
+}
+
} // namespace
extern "C" {
@@ -549,6 +574,10 @@ int cras_msbc_plc_handle_good_frames(struct cras_msbc_plc* plc,
cras_msbc_plc_handle_good_frames_called++;
return MSBC_CODE_SIZE;
}
+void packet_status_logger_init(struct packet_status_logger* logger) {}
+
+void packet_status_logger_update(struct packet_status_logger* logger,
+ bool val) {}
}
int main(int argc, char** argv) {
diff --git a/cras/src/tests/hfp_iodev_unittest.cc b/cras/src/tests/hfp_iodev_unittest.cc
index 2a61140e..18262bf9 100644
--- a/cras/src/tests/hfp_iodev_unittest.cc
+++ b/cras/src/tests/hfp_iodev_unittest.cc
@@ -43,7 +43,7 @@ static size_t hfp_fill_output_with_zeros_called;
static size_t hfp_force_output_level_called;
static size_t hfp_force_output_level_target;
static size_t fake_buffer_size = 500;
-static cras_audio_area* dummy_audio_area;
+static cras_audio_area* mock_audio_area;
void ResetStubData() {
cras_bt_device_append_iodev_called = 0;
@@ -73,9 +73,9 @@ void ResetStubData() {
fake_info = reinterpret_cast<struct hfp_info*>(0x123);
- if (!dummy_audio_area) {
- dummy_audio_area = (cras_audio_area*)calloc(
- 1, sizeof(*dummy_audio_area) + sizeof(cras_channel_area) * 2);
+ if (!mock_audio_area) {
+ mock_audio_area = (cras_audio_area*)calloc(
+ 1, sizeof(*mock_audio_area) + sizeof(cras_channel_area) * 2);
}
}
@@ -86,8 +86,8 @@ class HfpIodev : public testing::Test {
virtual void SetUp() { ResetStubData(); }
virtual void TearDown() {
- free(dummy_audio_area);
- dummy_audio_area = NULL;
+ free(mock_audio_area);
+ mock_audio_area = NULL;
}
};
@@ -243,6 +243,9 @@ void cras_iodev_set_active_node(struct cras_iodev* iodev,
iodev->active_node = node;
}
+// From ewma_power
+void ewma_power_disable(struct ewma_power* ewma) {}
+
// From system_state.
size_t cras_system_get_volume() {
return 0;
@@ -351,7 +354,7 @@ void hfp_force_output_level(struct hfp_info* info, unsigned int level) {
}
void cras_iodev_init_audio_area(struct cras_iodev* iodev, int num_channels) {
- iodev->area = dummy_audio_area;
+ iodev->area = mock_audio_area;
}
void cras_iodev_free_audio_area(struct cras_iodev* iodev) {}
@@ -367,7 +370,7 @@ int cras_iodev_fill_odev_zeros(struct cras_iodev* odev, unsigned int frames) {
void cras_audio_area_config_buf_pointers(struct cras_audio_area* area,
const struct cras_audio_format* fmt,
uint8_t* base_buffer) {
- dummy_audio_area->channels[0].buf = base_buffer;
+ mock_audio_area->channels[0].buf = base_buffer;
}
int hfp_set_call_status(struct hfp_slc_handle* handle, int call) {
diff --git a/cras/src/tests/hfp_slc_unittest.cc b/cras/src/tests/hfp_slc_unittest.cc
index 4501b07a..966278f4 100644
--- a/cras/src/tests/hfp_slc_unittest.cc
+++ b/cras/src/tests/hfp_slc_unittest.cc
@@ -202,7 +202,7 @@ TEST(HfpSlc, InitializeSlcSupportsHfIndicator) {
/* Assert "\r\n+BIND: (2)\r\n" response is received */
err = read(sock[1], buf, 256);
- chp = strstr(buf, "\r\n+BIND: (2)\r\n");
+ chp = strstr(buf, "\r\n+BIND: (1,2)\r\n");
ASSERT_NE((void*)NULL, (void*)chp);
chp = strstr(buf, "\r\nOK\r\n");
ASSERT_NE((void*)NULL, (void*)chp);
diff --git a/cras/src/tests/iodev_list_unittest.cc b/cras/src/tests/iodev_list_unittest.cc
index d40facab..272537fc 100644
--- a/cras/src/tests/iodev_list_unittest.cc
+++ b/cras/src/tests/iodev_list_unittest.cc
@@ -44,8 +44,8 @@ static struct audio_thread thread;
static struct cras_iodev loopback_input;
static int cras_iodev_close_called;
static struct cras_iodev* cras_iodev_close_dev;
-static struct cras_iodev dummy_hotword_iodev;
-static struct cras_iodev dummy_empty_iodev[2];
+static struct cras_iodev mock_hotword_iodev;
+static struct cras_iodev mock_empty_iodev[2];
static stream_callback* stream_add_cb;
static stream_callback* stream_rm_cb;
static struct cras_rstream* stream_list_get_ret;
@@ -233,11 +233,11 @@ class IoDevTestSuite : public testing::Test {
DL_APPEND(fake_sco_out_dev.nodes, &fake_sco_out_node);
fake_sco_in_node.is_sco_pcm = 0;
fake_sco_out_node.is_sco_pcm = 0;
- dummy_empty_iodev[0].state = CRAS_IODEV_STATE_CLOSE;
- dummy_empty_iodev[0].update_active_node = update_active_node;
- dummy_empty_iodev[1].state = CRAS_IODEV_STATE_CLOSE;
- dummy_empty_iodev[1].update_active_node = update_active_node;
- dummy_hotword_iodev.update_active_node = update_active_node;
+ mock_empty_iodev[0].state = CRAS_IODEV_STATE_CLOSE;
+ mock_empty_iodev[0].update_active_node = update_active_node;
+ mock_empty_iodev[1].state = CRAS_IODEV_STATE_CLOSE;
+ mock_empty_iodev[1].update_active_node = update_active_node;
+ mock_hotword_iodev.update_active_node = update_active_node;
}
virtual void TearDown() {
@@ -681,8 +681,7 @@ TEST_F(IoDevTestSuite, InitDevFailShouldScheduleRetry) {
EXPECT_EQ(2, cras_iodev_open_called);
EXPECT_EQ(1, audio_thread_add_stream_called);
EXPECT_EQ(0, update_active_node_called);
- EXPECT_EQ(&dummy_empty_iodev[CRAS_STREAM_OUTPUT],
- audio_thread_add_stream_dev);
+ EXPECT_EQ(&mock_empty_iodev[CRAS_STREAM_OUTPUT], audio_thread_add_stream_dev);
EXPECT_NE((void*)NULL, cras_tm_timer_cb);
EXPECT_EQ(1, cras_tm_create_timer_called);
@@ -693,7 +692,7 @@ TEST_F(IoDevTestSuite, InitDevFailShouldScheduleRetry) {
EXPECT_EQ(1, cras_tm_create_timer_called);
EXPECT_EQ(1, audio_thread_add_stream_called);
- dummy_empty_iodev[CRAS_STREAM_OUTPUT].format = &fmt_;
+ mock_empty_iodev[CRAS_STREAM_OUTPUT].format = &fmt_;
cras_tm_timer_cb = NULL;
cras_iodev_open_ret[3] = -5;
stream_add_cb(&rstream);
@@ -1752,7 +1751,7 @@ TEST_F(IoDevTestSuite, AddRemovePinnedStream) {
EXPECT_EQ(2, update_active_node_called);
// Unselect d1_ and select to d2_
EXPECT_EQ(&d2_, update_active_node_iodev_val[0]);
- EXPECT_EQ(&dummy_empty_iodev[CRAS_STREAM_OUTPUT],
+ EXPECT_EQ(&mock_empty_iodev[CRAS_STREAM_OUTPUT],
update_active_node_iodev_val[1]);
// Remove pinned stream from d1, check d1 is closed after stream removed.
@@ -1869,14 +1868,14 @@ TEST_F(IoDevTestSuite, HotwordStreamsAddedThenSuspendResume) {
EXPECT_EQ(&d1_, audio_thread_disconnect_stream_dev);
EXPECT_EQ(2, audio_thread_add_stream_called);
EXPECT_EQ(&rstream, audio_thread_add_stream_stream);
- EXPECT_EQ(&dummy_hotword_iodev, audio_thread_add_stream_dev);
+ EXPECT_EQ(&mock_hotword_iodev, audio_thread_add_stream_dev);
/* Resume hotword streams, verify the stream disconnects from
* the empty iodev and connects back to the real hotword iodev. */
EXPECT_EQ(0, cras_iodev_list_resume_hotword_stream());
EXPECT_EQ(2, audio_thread_disconnect_stream_called);
EXPECT_EQ(&rstream, audio_thread_disconnect_stream_stream);
- EXPECT_EQ(&dummy_hotword_iodev, audio_thread_disconnect_stream_dev);
+ EXPECT_EQ(&mock_hotword_iodev, audio_thread_disconnect_stream_dev);
EXPECT_EQ(3, audio_thread_add_stream_called);
EXPECT_EQ(&rstream, audio_thread_add_stream_stream);
EXPECT_EQ(&d1_, audio_thread_add_stream_dev);
@@ -1910,7 +1909,7 @@ TEST_F(IoDevTestSuite, HotwordStreamsAddedAfterSuspend) {
/* Hotword stream connected, verify it is added to the empty iodev. */
EXPECT_EQ(0, stream_add_cb(&rstream));
EXPECT_EQ(1, audio_thread_add_stream_called);
- EXPECT_EQ(&dummy_hotword_iodev, audio_thread_add_stream_dev);
+ EXPECT_EQ(&mock_hotword_iodev, audio_thread_add_stream_dev);
EXPECT_EQ(&rstream, audio_thread_add_stream_stream);
/* Resume hotword streams, now the existing hotword stream should disconnect
@@ -1918,7 +1917,7 @@ TEST_F(IoDevTestSuite, HotwordStreamsAddedAfterSuspend) {
EXPECT_EQ(0, cras_iodev_list_resume_hotword_stream());
EXPECT_EQ(1, audio_thread_disconnect_stream_called);
EXPECT_EQ(&rstream, audio_thread_disconnect_stream_stream);
- EXPECT_EQ(&dummy_hotword_iodev, audio_thread_disconnect_stream_dev);
+ EXPECT_EQ(&mock_hotword_iodev, audio_thread_disconnect_stream_dev);
EXPECT_EQ(2, audio_thread_add_stream_called);
EXPECT_EQ(&rstream, audio_thread_add_stream_stream);
EXPECT_EQ(&d1_, audio_thread_add_stream_dev);
@@ -2035,9 +2034,9 @@ struct cras_iodev* empty_iodev_create(enum CRAS_STREAM_DIRECTION direction,
enum CRAS_NODE_TYPE node_type) {
struct cras_iodev* dev;
if (node_type == CRAS_NODE_TYPE_HOTWORD) {
- dev = &dummy_hotword_iodev;
+ dev = &mock_hotword_iodev;
} else {
- dev = &dummy_empty_iodev[direction];
+ dev = &mock_empty_iodev[direction];
}
dev->direction = direction;
if (dev->active_node == NULL) {
diff --git a/cras/src/tests/iodev_unittest.cc b/cras/src/tests/iodev_unittest.cc
index 03cfee62..21dc4d57 100644
--- a/cras/src/tests/iodev_unittest.cc
+++ b/cras/src/tests/iodev_unittest.cc
@@ -60,7 +60,7 @@ static unsigned int cras_mix_mute_count;
static unsigned int cras_dsp_num_input_channels_return;
static unsigned int cras_dsp_num_output_channels_return;
struct cras_dsp_context* cras_dsp_context_new_return;
-static unsigned int cras_dsp_load_dummy_pipeline_called;
+static unsigned int cras_dsp_load_mock_pipeline_called;
static unsigned int rate_estimator_add_frames_num_frames;
static unsigned int rate_estimator_add_frames_called;
static int cras_system_get_mute_return;
@@ -148,7 +148,7 @@ void ResetStubData() {
cras_dsp_num_input_channels_return = 2;
cras_dsp_num_output_channels_return = 2;
cras_dsp_context_new_return = NULL;
- cras_dsp_load_dummy_pipeline_called = 0;
+ cras_dsp_load_mock_pipeline_called = 0;
rate_estimator_add_frames_num_frames = 0;
rate_estimator_add_frames_called = 0;
cras_system_get_mute_return = 0;
@@ -2240,12 +2240,12 @@ TEST(IoDev, SetExtDspMod) {
EXPECT_EQ(3, cras_dsp_get_pipeline_called);
EXPECT_EQ(3, cras_dsp_pipeline_set_sink_ext_module_called);
- /* If pipeline doesn't exist, dummy pipeline should be loaded. */
+ /* If pipeline doesn't exist, mock pipeline should be loaded. */
cras_dsp_get_pipeline_ret = 0x0;
cras_iodev_set_ext_dsp_module(&iodev, &ext);
EXPECT_EQ(3, ext_mod_configure_called);
EXPECT_EQ(5, cras_dsp_get_pipeline_called);
- EXPECT_EQ(1, cras_dsp_load_dummy_pipeline_called);
+ EXPECT_EQ(1, cras_dsp_load_mock_pipeline_called);
EXPECT_EQ(4, cras_dsp_pipeline_set_sink_ext_module_called);
}
@@ -2462,9 +2462,11 @@ unsigned int buffer_share_id_offset(const struct buffer_share* mix,
}
// From cras_system_state.
-void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction) {}
+void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type) {}
-void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction) {}
+void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type) {}
// From cras_dsp
struct cras_dsp_context* cras_dsp_context_new(int sample_rate,
@@ -2479,9 +2481,9 @@ void cras_dsp_context_free(struct cras_dsp_context* ctx) {
}
void cras_dsp_load_pipeline(struct cras_dsp_context* ctx) {}
-void cras_dsp_load_dummy_pipeline(struct cras_dsp_context* ctx,
- unsigned int num_channels) {
- cras_dsp_load_dummy_pipeline_called++;
+void cras_dsp_load_mock_pipeline(struct cras_dsp_context* ctx,
+ unsigned int num_channels) {
+ cras_dsp_load_mock_pipeline_called++;
}
void cras_dsp_set_variable_string(struct cras_dsp_context* ctx,
@@ -2760,6 +2762,18 @@ int cras_server_metrics_device_volume(struct cras_iodev* iodev) {
return 0;
}
+void ewma_power_init(struct ewma_power* ewma, unsigned int rate){};
+
+void ewma_power_calculate(struct ewma_power* ewma,
+ const int16_t* buf,
+ unsigned int channels,
+ unsigned int size){};
+
+void ewma_power_calculate_area(struct ewma_power* ewma,
+ const int16_t* buf,
+ struct cras_audio_area* area,
+ unsigned int size){};
+
} // extern "C"
} // namespace
diff --git a/cras/src/tests/loopback_iodev_unittest.cc b/cras/src/tests/loopback_iodev_unittest.cc
index 1c69ba57..fde50375 100644
--- a/cras/src/tests/loopback_iodev_unittest.cc
+++ b/cras/src/tests/loopback_iodev_unittest.cc
@@ -29,7 +29,7 @@ static const unsigned int kFrameBytes = 4;
static const unsigned int kBufferSize = kBufferFrames * kFrameBytes;
static struct timespec time_now;
-static cras_audio_area* dummy_audio_area;
+static cras_audio_area* mock_audio_area;
static loopback_hook_data_t loop_hook;
static struct cras_iodev* enabled_dev;
static unsigned int cras_iodev_list_add_input_called;
@@ -46,8 +46,8 @@ static char* atlog_name;
class LoopBackTestSuite : public testing::Test {
protected:
virtual void SetUp() {
- dummy_audio_area = (cras_audio_area*)calloc(
- 1, sizeof(*dummy_audio_area) + sizeof(cras_channel_area) * 2);
+ mock_audio_area = (cras_audio_area*)calloc(
+ 1, sizeof(*mock_audio_area) + sizeof(cras_channel_area) * 2);
for (unsigned int i = 0; i < kBufferSize; i++) {
buf_[i] = rand();
}
@@ -77,7 +77,7 @@ class LoopBackTestSuite : public testing::Test {
EXPECT_EQ(1, cras_iodev_list_rm_input_called);
EXPECT_EQ(NULL, device_enabled_callback_cb);
EXPECT_EQ(NULL, device_disabled_callback_cb);
- free(dummy_audio_area);
+ free(mock_audio_area);
audio_thread_event_log_deinit(atlog, atlog_name);
free(atlog_name);
}
@@ -224,7 +224,7 @@ extern "C" {
void cras_audio_area_config_buf_pointers(struct cras_audio_area* area,
const struct cras_audio_format* fmt,
uint8_t* base_buffer) {
- dummy_audio_area->channels[0].buf = base_buffer;
+ mock_audio_area->channels[0].buf = base_buffer;
}
void cras_iodev_free_audio_area(struct cras_iodev* iodev) {}
@@ -232,7 +232,7 @@ void cras_iodev_free_audio_area(struct cras_iodev* iodev) {}
void cras_iodev_free_format(struct cras_iodev* iodev) {}
void cras_iodev_init_audio_area(struct cras_iodev* iodev, int num_channels) {
- iodev->area = dummy_audio_area;
+ iodev->area = mock_audio_area;
}
void cras_iodev_add_node(struct cras_iodev* iodev, struct cras_ionode* node) {
diff --git a/cras/src/tests/observer_unittest.cc b/cras/src/tests/observer_unittest.cc
index 2053e940..2a8fae2c 100644
--- a/cras/src/tests/observer_unittest.cc
+++ b/cras/src/tests/observer_unittest.cc
@@ -11,6 +11,8 @@
extern "C" {
#include "cras_observer.c"
+#include "cras_observer.h"
+#include "cras_types.h"
}
namespace {
@@ -56,6 +58,9 @@ static size_t cb_num_active_streams_changed_called;
static std::vector<enum CRAS_STREAM_DIRECTION>
cb_num_active_streams_changed_dir;
static std::vector<uint32_t> cb_num_active_streams_changed_num;
+static size_t cb_num_input_streams_with_permission_called;
+static std::vector<std::vector<uint32_t>>
+ cb_num_input_streams_with_permission_array;
static void ResetStubData() {
cras_alert_destroy_called = 0;
@@ -99,6 +104,8 @@ static void ResetStubData() {
cb_num_active_streams_changed_called = 0;
cb_num_active_streams_changed_dir.clear();
cb_num_active_streams_changed_num.clear();
+ cb_num_input_streams_with_permission_called = 0;
+ cb_num_input_streams_with_permission_array.clear();
}
/* System output volume changed. */
@@ -190,6 +197,15 @@ void cb_num_active_streams_changed(void* context,
cb_num_active_streams_changed_num.push_back(num_active_streams);
}
+void cb_num_input_streams_with_permission_changed(
+ void* context,
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE]) {
+ cb_num_input_streams_with_permission_called++;
+ cb_context.push_back(context);
+ cb_num_input_streams_with_permission_array.push_back(std::vector<uint32_t>(
+ num_input_streams, num_input_streams + CRAS_NUM_CLIENT_TYPE));
+}
+
class ObserverTest : public testing::Test {
protected:
virtual void SetUp() {
@@ -198,7 +214,7 @@ class ObserverTest : public testing::Test {
ResetStubData();
rc = cras_observer_server_init();
ASSERT_EQ(0, rc);
- EXPECT_EQ(16, cras_alert_create_called);
+ EXPECT_EQ(17, cras_alert_create_called);
EXPECT_EQ(reinterpret_cast<void*>(output_volume_alert),
cras_alert_add_callback_map[g_observer->alerts.output_volume]);
EXPECT_EQ(reinterpret_cast<void*>(output_mute_alert),
@@ -256,7 +272,7 @@ class ObserverTest : public testing::Test {
virtual void TearDown() {
cras_observer_server_free();
- EXPECT_EQ(16, cras_alert_destroy_called);
+ EXPECT_EQ(17, cras_alert_destroy_called);
ResetStubData();
}
@@ -578,6 +594,37 @@ TEST_F(ObserverTest, NotifyNumActiveStreams) {
DoObserverRemoveClear(num_active_streams_alert, data);
};
+TEST_F(ObserverTest, NotifyNumInputStreamsWithPermission) {
+ struct cras_observer_alert_data_input_streams* data;
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE] = {};
+ for (unsigned type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type) {
+ num_input_streams[type] = (uint32_t)type;
+ }
+
+ cras_observer_notify_input_streams_with_permission(num_input_streams);
+ ASSERT_EQ(cras_alert_pending_data_size_value, sizeof(*data));
+ ASSERT_NE(cras_alert_pending_data_value, reinterpret_cast<void*>(NULL));
+ data = reinterpret_cast<struct cras_observer_alert_data_input_streams*>(
+ cras_alert_pending_data_value);
+ for (unsigned type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type) {
+ EXPECT_EQ(data->num_input_streams[type], num_input_streams[type]);
+ }
+
+ ops1_.num_input_streams_with_permission_changed =
+ cb_num_input_streams_with_permission_changed;
+ ops2_.num_input_streams_with_permission_changed =
+ cb_num_input_streams_with_permission_changed;
+ DoObserverAlert(num_input_streams_with_permission_alert, data);
+ ASSERT_EQ(2, cb_num_input_streams_with_permission_called);
+ for (auto cb_num_input_streams : cb_num_input_streams_with_permission_array) {
+ ASSERT_EQ(cb_num_input_streams.size(), (size_t)CRAS_NUM_CLIENT_TYPE);
+ for (unsigned type = 0; type < CRAS_NUM_CLIENT_TYPE; ++type) {
+ EXPECT_EQ(cb_num_input_streams[type], num_input_streams[type]);
+ }
+ }
+ DoObserverRemoveClear(num_input_streams_with_permission_alert, data);
+}
+
TEST_F(ObserverTest, NotifyHotwordTriggered) {
struct cras_observer_alert_data_hotword_triggered* data;
diff --git a/cras/src/tests/playback_rclient_unittest.cc b/cras/src/tests/playback_rclient_unittest.cc
index 7056d2fe..75cbe552 100644
--- a/cras/src/tests/playback_rclient_unittest.cc
+++ b/cras/src/tests/playback_rclient_unittest.cc
@@ -24,8 +24,8 @@ static unsigned int cras_observer_remove_called;
static int stream_list_add_called;
static int stream_list_add_return;
static unsigned int stream_list_rm_called;
-static struct cras_audio_shm dummy_shm;
-static struct cras_rstream dummy_rstream;
+static struct cras_audio_shm mock_shm;
+static struct cras_rstream mock_rstream;
void ResetStubData() {
audio_format_valid = true;
@@ -207,44 +207,6 @@ TEST_F(CPRMessageSuite, StreamConnectMessageInvalidAudioFormat) {
EXPECT_EQ(stream_id, out_msg.stream_id);
}
-/*
- * TODO(yuhsaun): Remove this test when there are no client uses the old
- * craslib. (CRAS_PROTO_VER = 5)
- */
-TEST_F(CPRMessageSuite, StreamConnectMessageOldProtocal) {
- struct cras_client_stream_connected out_msg;
- int rc;
-
- struct cras_connect_message_old msg;
- cras_stream_id_t stream_id = 0x10002;
-
- msg.proto_version = 5;
- msg.direction = CRAS_STREAM_OUTPUT;
- msg.stream_id = stream_id;
- msg.stream_type = CRAS_STREAM_TYPE_DEFAULT;
- msg.buffer_frames = 480;
- msg.cb_threshold = 240;
- msg.flags = 0;
- msg.effects = 0;
- pack_cras_audio_format(&msg.format, &fmt);
- msg.dev_idx = NO_DEVICE;
- msg.client_shm_size = 0;
- msg.client_type = CRAS_CLIENT_TYPE_TEST;
- msg.header.id = CRAS_SERVER_CONNECT_STREAM;
- msg.header.length = sizeof(struct cras_connect_message_old);
-
- fd_ = 100;
- rc =
- rclient_->ops->handle_message_from_client(rclient_, &msg.header, &fd_, 1);
- EXPECT_EQ(1, cras_make_fd_nonblocking_called);
- EXPECT_EQ(1, stream_list_add_called);
- EXPECT_EQ(0, stream_list_rm_called);
-
- rc = read(pipe_fds_[0], &out_msg, sizeof(out_msg));
- EXPECT_EQ(sizeof(out_msg), rc);
- EXPECT_EQ(stream_id, out_msg.stream_id);
-}
-
TEST_F(CPRMessageSuite, StreamDisconnectMessage) {
struct cras_disconnect_stream_message msg;
cras_stream_id_t stream_id = 0x10002;
@@ -320,16 +282,16 @@ int stream_list_add(struct stream_list* list,
struct cras_rstream** stream) {
int ret;
- *stream = &dummy_rstream;
+ *stream = &mock_rstream;
stream_list_add_called++;
ret = stream_list_add_return;
if (ret)
stream_list_add_return = -EINVAL;
- dummy_rstream.shm = &dummy_shm;
- dummy_rstream.direction = config->direction;
- dummy_rstream.stream_id = config->stream_id;
+ mock_rstream.shm = &mock_shm;
+ mock_rstream.direction = config->direction;
+ mock_rstream.stream_id = config->stream_id;
return ret;
}
diff --git a/cras/src/tests/polled_interval_checker_unittest.cc b/cras/src/tests/polled_interval_checker_unittest.cc
index c18fdf7e..a4aff09c 100644
--- a/cras/src/tests/polled_interval_checker_unittest.cc
+++ b/cras/src/tests/polled_interval_checker_unittest.cc
@@ -70,7 +70,7 @@ TEST(PolledIntervalCheckerTest, DoesNotResetAutomatically) {
struct polled_interval* interval = create_interval();
- // Sanity check.
+ // Initial check.
EXPECT_FALSE(pic_interval_elapsed(interval));
// Increment time so the interval elapses.
@@ -100,7 +100,7 @@ TEST(PolledIntervalCheckerTest, Reset) {
struct polled_interval* interval = create_interval();
- // Sanity check.
+ // Initial check.
EXPECT_FALSE(pic_interval_elapsed(interval));
// Increment time so the interval elapses.
diff --git a/cras/src/tests/rstream_unittest.cc b/cras/src/tests/rstream_unittest.cc
index 77dd6adb..593c805d 100644
--- a/cras/src/tests/rstream_unittest.cc
+++ b/cras/src/tests/rstream_unittest.cc
@@ -390,10 +390,18 @@ unsigned int buffer_share_id_offset(const struct buffer_share* mix,
unsigned int id) {
return 0;
}
+void ewma_power_init(struct ewma_power* ewma, unsigned int rate) {}
-void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction) {}
+void ewma_power_calculate(struct ewma_power* ewma,
+ const int16_t* buf,
+ unsigned int channels,
+ unsigned int size) {}
-void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction) {}
+void cras_system_state_stream_added(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type) {}
+
+void cras_system_state_stream_removed(enum CRAS_STREAM_DIRECTION direction,
+ enum CRAS_CLIENT_TYPE client_type) {}
int cras_server_metrics_stream_create(
const struct cras_rstream_config* config) {
@@ -405,9 +413,13 @@ int cras_server_metrics_stream_destroy(const struct cras_rstream* stream) {
}
#ifdef HAVE_WEBRTC_APM
+#define FAKE_CRAS_APM_PTR reinterpret_cast<struct cras_apm*>(0x99)
struct cras_apm_list* cras_apm_list_create(void* stream_ptr, uint64_t effects) {
return NULL;
}
+struct cras_apm* cras_apm_list_get_active_apm(void* stream_ptr, void* dev_ptr) {
+ return FAKE_CRAS_APM_PTR;
+}
int cras_apm_list_destroy(struct cras_apm_list* list) {
return 0;
}
diff --git a/cras/src/tests/system_state_unittest.cc b/cras/src/tests/system_state_unittest.cc
index e61a43e2..0450df38 100644
--- a/cras/src/tests/system_state_unittest.cc
+++ b/cras/src/tests/system_state_unittest.cc
@@ -38,6 +38,7 @@ static size_t cras_observer_notify_output_mute_called;
static size_t cras_observer_notify_capture_mute_called;
static size_t cras_observer_notify_suspend_changed_called;
static size_t cras_observer_notify_num_active_streams_called;
+static size_t cras_observer_notify_input_streams_with_permission_called;
static struct cras_board_config fake_board_config;
static void ResetStubData() {
@@ -58,6 +59,7 @@ static void ResetStubData() {
cras_observer_notify_capture_mute_called = 0;
cras_observer_notify_suspend_changed_called = 0;
cras_observer_notify_num_active_streams_called = 0;
+ cras_observer_notify_input_streams_with_permission_called = 0;
memset(&fake_board_config, 0, sizeof(fake_board_config));
}
@@ -371,11 +373,11 @@ TEST(SystemSettingsStreamCount, StreamCount) {
do_sys_init();
EXPECT_EQ(0, cras_system_state_get_active_streams());
- cras_system_state_stream_added(CRAS_STREAM_OUTPUT);
+ cras_system_state_stream_added(CRAS_STREAM_OUTPUT, CRAS_CLIENT_TYPE_CHROME);
EXPECT_EQ(1, cras_system_state_get_active_streams());
struct cras_timespec ts1;
cras_system_state_get_last_stream_active_time(&ts1);
- cras_system_state_stream_removed(CRAS_STREAM_OUTPUT);
+ cras_system_state_stream_removed(CRAS_STREAM_OUTPUT, CRAS_CLIENT_TYPE_CHROME);
EXPECT_EQ(0, cras_system_state_get_active_streams());
struct cras_timespec ts2;
cras_system_state_get_last_stream_active_time(&ts2);
@@ -388,9 +390,11 @@ TEST(SystemSettingsStreamCount, StreamCountByDirection) {
do_sys_init();
EXPECT_EQ(0, cras_system_state_get_active_streams());
- cras_system_state_stream_added(CRAS_STREAM_OUTPUT);
- cras_system_state_stream_added(CRAS_STREAM_INPUT);
- cras_system_state_stream_added(CRAS_STREAM_POST_MIX_PRE_DSP);
+ cras_system_state_stream_added(CRAS_STREAM_OUTPUT, CRAS_CLIENT_TYPE_CHROME);
+ cras_system_state_stream_added(CRAS_STREAM_INPUT, CRAS_CLIENT_TYPE_CHROME);
+ cras_system_state_stream_added(CRAS_STREAM_POST_MIX_PRE_DSP,
+ CRAS_CLIENT_TYPE_CHROME);
+ EXPECT_EQ(1, cras_observer_notify_input_streams_with_permission_called);
EXPECT_EQ(
1, cras_system_state_get_active_streams_by_direction(CRAS_STREAM_OUTPUT));
EXPECT_EQ(
@@ -399,9 +403,11 @@ TEST(SystemSettingsStreamCount, StreamCountByDirection) {
CRAS_STREAM_POST_MIX_PRE_DSP));
EXPECT_EQ(3, cras_system_state_get_active_streams());
EXPECT_EQ(3, cras_observer_notify_num_active_streams_called);
- cras_system_state_stream_removed(CRAS_STREAM_OUTPUT);
- cras_system_state_stream_removed(CRAS_STREAM_INPUT);
- cras_system_state_stream_removed(CRAS_STREAM_POST_MIX_PRE_DSP);
+ cras_system_state_stream_removed(CRAS_STREAM_OUTPUT, CRAS_CLIENT_TYPE_CHROME);
+ cras_system_state_stream_removed(CRAS_STREAM_INPUT, CRAS_CLIENT_TYPE_CHROME);
+ cras_system_state_stream_removed(CRAS_STREAM_POST_MIX_PRE_DSP,
+ CRAS_CLIENT_TYPE_CHROME);
+ EXPECT_EQ(2, cras_observer_notify_input_streams_with_permission_called);
EXPECT_EQ(
0, cras_system_state_get_active_streams_by_direction(CRAS_STREAM_OUTPUT));
EXPECT_EQ(
@@ -511,6 +517,11 @@ void cras_observer_notify_num_active_streams(enum CRAS_STREAM_DIRECTION dir,
cras_observer_notify_num_active_streams_called++;
}
+void cras_observer_notify_input_streams_with_permission(
+ uint32_t num_input_streams[CRAS_NUM_CLIENT_TYPE]) {
+ cras_observer_notify_input_streams_with_permission_called++;
+}
+
void cras_board_config_get(const char* config_path,
struct cras_board_config* board_config) {
*board_config = fake_board_config;
diff --git a/cras/src/tools/cras_test_client/cras_test_client.c b/cras/src/tools/cras_test_client/cras_test_client.c
index 947b9458..5a7b3e06 100644
--- a/cras/src/tools/cras_test_client/cras_test_client.c
+++ b/cras/src/tools/cras_test_client/cras_test_client.c
@@ -493,6 +493,26 @@ static void convert_time(unsigned int *sec, unsigned int *nsec,
*nsec = nsec_offset;
}
+static float get_ewma_power_as_float(uint32_t data)
+{
+ float f = 0.0f;
+
+ /* Convert from the uint32_t log type back to float.
+ * If data cannot be assigned to float, default value will
+ * be printed as -inf to hint the problem.
+ */
+ if (sizeof(uint32_t) == sizeof(float))
+ memcpy(&f, &data, sizeof(float));
+ else
+ printf("%-30s float to uint32_t\n", "MEMORY_NOT_ALIGNED");
+
+ /* Convert to dBFS and set to zero if it's
+ * insignificantly low. Picking the same threshold
+ * 1.0e-10f as in Chrome.
+ */
+ return (f < 1.0e-10f) ? -INFINITY : 10.0f * log10f(f);
+}
+
static void show_alog_tag(const struct audio_thread_event_log *log,
unsigned int tag_idx, int32_t sec_offset,
int32_t nsec_offset)
@@ -552,25 +572,30 @@ static void show_alog_tag(const struct audio_thread_event_log *log,
printf("%-30s dev:%u tstamp:%s.%09u\n", "READ_AUDIO_TSTAMP",
data1, time_str, nsec);
break;
- case AUDIO_THREAD_READ_AUDIO_DONE:
- printf("%-30s read_remainder:%u\n", "READ_AUDIO_DONE", data1);
+ case AUDIO_THREAD_READ_AUDIO_DONE: {
+ float f = get_ewma_power_as_float(data2);
+ printf("%-30s read_remainder:%u power:%f dBFS\n",
+ "READ_AUDIO_DONE", data1, f);
break;
+ }
case AUDIO_THREAD_READ_OVERRUN:
printf("%-30s dev:%u stream:%x num_overruns:%u\n",
"READ_AUDIO_OVERRUN", data1, data2, data3);
break;
case AUDIO_THREAD_FILL_AUDIO:
- printf("%-30s dev:%u hw_level:%u\n", "FILL_AUDIO", data1,
- data2);
+ printf("%-30s dev:%u hw_level:%u min_cb_level:%u\n",
+ "FILL_AUDIO", data1, data2, data3);
break;
case AUDIO_THREAD_FILL_AUDIO_TSTAMP:
printf("%-30s dev:%u tstamp:%s.%09u\n", "FILL_AUDIO_TSTAMP",
data1, time_str, nsec);
break;
- case AUDIO_THREAD_FILL_AUDIO_DONE:
- printf("%-30s hw_level:%u total_written:%u min_cb_level:%u\n",
- "FILL_AUDIO_DONE", data1, data2, data3);
+ case AUDIO_THREAD_FILL_AUDIO_DONE: {
+ float f = get_ewma_power_as_float(data3);
+ printf("%-30s hw_level:%u total_written:%u power:%f dBFS\n",
+ "FILL_AUDIO_DONE", data1, data2, f);
break;
+ }
case AUDIO_THREAD_WRITE_STREAMS_WAIT:
printf("%-30s stream:%x\n", "WRITE_STREAMS_WAIT", data1);
break;
@@ -588,10 +613,12 @@ static void show_alog_tag(const struct audio_thread_event_log *log,
printf("%-30s id:%x shm_frames:%u cb_pending:%u\n",
"WRITE_STREAMS_STREAM", data1, data2, data3);
break;
- case AUDIO_THREAD_FETCH_STREAM:
- printf("%-30s id:%x cbth:%u delay:%u\n",
- "WRITE_STREAMS_FETCH_STREAM", data1, data2, data3);
+ case AUDIO_THREAD_FETCH_STREAM: {
+ float f = get_ewma_power_as_float(data3);
+ printf("%-30s id:%x cbth:%u power:%f dBFS\n",
+ "WRITE_STREAMS_FETCH_STREAM", data1, data2, f);
break;
+ }
case AUDIO_THREAD_STREAM_ADDED:
printf("%-30s id:%x dev:%u\n", "STREAM_ADDED", data1, data2);
break;
@@ -966,7 +993,7 @@ static void show_btlog_tag(const struct cras_bt_event_log *log,
printf("%-30s\n", "ADAPTER_REMOVED");
break;
case BT_A2DP_CONFIGURED:
- printf("%-30s connected profiles %u\n", "A2DP_CONFIGURED",
+ printf("%-30s connected profiles 0x%.2x\n", "A2DP_CONFIGURED",
data1);
break;
case BT_A2DP_START:
@@ -976,8 +1003,8 @@ static void show_btlog_tag(const struct cras_bt_event_log *log,
printf("%-30s\n", "A2DP_SUSPENDED");
break;
case BT_AUDIO_GATEWAY_INIT:
- printf("%-30s supported profiles %u\n", "AUDIO_GATEWAY_INIT",
- data1);
+ printf("%-30s supported profiles 0x%.2x\n",
+ "AUDIO_GATEWAY_INIT", data1);
break;
case BT_AUDIO_GATEWAY_START:
printf("%-30s \n", "AUDIO_GATEWAY_START");
@@ -991,11 +1018,12 @@ static void show_btlog_tag(const struct cras_bt_event_log *log,
data2);
break;
case BT_DEV_CONNECTED_CHANGE:
- printf("%-30s profiles %u now %u\n", "DEV_CONNECTED_CHANGE",
- data1, data2);
+ printf("%-30s supported profiles 0x%.2x now %s\n",
+ "DEV_CONNECTED_CHANGE", data1,
+ data2 ? "connected" : "disconnected");
break;
case BT_DEV_CONN_WATCH_CB:
- printf("%-30s %u retries left, supported profiles %u\n",
+ printf("%-30s %u retries left, supported profiles 0x%.2x\n",
"DEV_CONN_WATCH_CB", data1, data2);
break;
case BT_DEV_SUSPEND_CB:
@@ -1021,8 +1049,8 @@ static void show_btlog_tag(const struct cras_bt_event_log *log,
printf("%-30s\n", "HFP_REQUEST_DISCONNECT");
break;
case BT_HFP_SUPPORTED_FEATURES:
- printf("%-30s role %s features %u\n", "HFP_SUPPORTED_FEATURES",
- data1 ? "AG" : "HF", data2);
+ printf("%-30s role %s features 0x%.4x\n",
+ "HFP_SUPPORTED_FEATURES", data1 ? "AG" : "HF", data2);
break;
case BT_HSP_NEW_CONNECTION:
printf("%-30s\n", "HSP_NEW_CONNECTION");
@@ -1031,7 +1059,7 @@ static void show_btlog_tag(const struct cras_bt_event_log *log,
printf("%-30s\n", "HSP_REQUEST_DISCONNECT");
break;
case BT_NEW_AUDIO_PROFILE_AFTER_CONNECT:
- printf("%-30s old %u, new %u\n",
+ printf("%-30s old 0x%.2x, new 0x%.2x\n",
"NEW_AUDIO_PROFILE_AFTER_CONNECT", data1, data2);
break;
case BT_RESET:
@@ -1060,12 +1088,30 @@ static void show_btlog_tag(const struct cras_bt_event_log *log,
}
}
+static void convert_to_time_str(const struct timespec *ts, time_t sec_offset,
+ int32_t nsec_offset)
+{
+ time_t lt = ts->tv_sec;
+ struct tm t;
+ unsigned int time_nsec;
+
+ /* Assuming tv_nsec doesn't exceed 10^9 */
+ time_nsec = ts->tv_nsec;
+ convert_time((unsigned int *)&lt, &time_nsec, sec_offset, nsec_offset);
+ localtime_r(&lt, &t);
+ strftime(time_str, 128, "%Y-%m-%dT%H:%M:%S", &t);
+ snprintf(time_str + strlen(time_str), 128 - strlen(time_str), ".%09u",
+ time_nsec);
+}
+
static void cras_bt_debug_info(struct cras_client *client)
{
const struct cras_bt_debug_info *info;
time_t sec_offset;
int32_t nsec_offset;
int i, j;
+ struct timespec ts;
+ struct packet_status_logger wbs_logger;
info = cras_client_get_bt_debug_info(client);
fill_time_offset(&sec_offset, &nsec_offset);
@@ -1078,6 +1124,23 @@ static void cras_bt_debug_info(struct cras_client *client)
j %= info->bt_log.len;
}
+ printf("-------------WBS packet loss------------\n");
+ wbs_logger = info->wbs_logger;
+
+ packet_status_logger_begin_ts(&wbs_logger, &ts);
+ convert_to_time_str(&ts, sec_offset, nsec_offset);
+ printf("%s [begin]\n", time_str);
+
+ packet_status_logger_end_ts(&wbs_logger, &ts);
+ convert_to_time_str(&ts, sec_offset, nsec_offset);
+ printf("%s [end]\n", time_str);
+
+ printf("In hex format:\n");
+ packet_status_logger_dump_hex(&wbs_logger);
+
+ printf("In binary format:\n");
+ packet_status_logger_dump_binary(&wbs_logger);
+
/* Signal main thread we are done after the last chunk. */
pthread_mutex_lock(&done_mutex);
pthread_cond_signal(&done_cond);
diff --git a/init/cras.conf b/init/cras.conf
index c61d7894..20847494 100644
--- a/init/cras.conf
+++ b/init/cras.conf
@@ -10,6 +10,8 @@ author "chromium-os-dev@chromium.org"
env CRAS_SOCKET_DIR=/run/cras
env CRAS_VMS_SOCKET_DIR=/run/cras/vms
+env CRAS_PLUGIN_DIR=/run/cras/vms/plugin
+env CRAS_ARGS=
start on starting system-services
stop on stopping system-services
@@ -23,6 +25,18 @@ pre-start script
chown -R cras:cras "${CRAS_SOCKET_DIR}"
mkdir -p -m 1770 "${CRAS_VMS_SOCKET_DIR}"
chown -R cras:cras "${CRAS_VMS_SOCKET_DIR}"
+ for socket_dir in playback unified; do
+ mkdir -p -m 1770 "${CRAS_PLUGIN_DIR}/${socket_dir}"
+ chown -R cras:cras "${CRAS_PLUGIN_DIR}/${socket_dir}"
+ done
+ mkdir -m 0755 -p /var/lib/cras
+ chown -R cras:cras /var/lib/cras
end script
exec /bin/sh /usr/share/cros/init/cras.sh
+
+# sound_card_init uses CRAS stop timestamp as a criterion to skip boot time
+# calibration for DSM.
+post-stop script
+ echo "$(date +---%\nsecs:\ %s%\nnanos:\ %N)" > /var/lib/cras/stop
+end script
diff --git a/init/cras.sh b/init/cras.sh
index b0ca430c..ca2d6b93 100644
--- a/init/cras.sh
+++ b/init/cras.sh
@@ -62,4 +62,4 @@ exec minijail0 -u cras -g cras -G --uts -v -l \
-- \
/usr/bin/cras \
${DSP_CONFIG} ${DEVICE_CONFIG_DIR} ${DISABLE_PROFILE} \
- ${INTERNAL_UCM_SUFFIX}
+ ${INTERNAL_UCM_SUFFIX} ${CRAS_ARGS}
diff --git a/scripts/audio_tuning/frontend/audio.js b/scripts/audio_tuning/frontend/audio.js
index 2476f1a9..b90be953 100644
--- a/scripts/audio_tuning/frontend/audio.js
+++ b/scripts/audio_tuning/frontend/audio.js
@@ -1105,7 +1105,7 @@ function check_button(div, handler) {
this.update = update;
}
-function dummy() {
+function empty() {
}
/* Changes the opacity of a div. */
@@ -1185,7 +1185,7 @@ function drc_card(parent, index, lower_freq, freq_label) {
var f_slider;
if (lower_freq == 0) { /* Special case for the lowest band */
f_slider = new slider_input_log(table, freq_label, lower_freq, 0, 1,
- 'Hz', 0, dummy);
+ 'Hz', 0, empty);
f_slider.hide(true);
} else {
f_slider = new slider_input_log(table, freq_label, lower_freq, 1,
diff --git a/scripts/volume_tuning/volume.js b/scripts/volume_tuning/volume.js
index c5f05266..88f39984 100644
--- a/scripts/volume_tuning/volume.js
+++ b/scripts/volume_tuning/volume.js
@@ -116,7 +116,7 @@ function redraw() {
var max = parseFloat(minmax_boxes[1].value);
var step = parseFloat(minmax_boxes[2].value);
- // Sanity checks
+ // Soundness checks
if (isNaN(min) || isNaN(max) || isNaN(step)) return;
if (min >= max || step <= 0 || (max - min) / step > 10000) return;
diff --git a/seccomp/cras-seccomp-arm.policy b/seccomp/cras-seccomp-arm.policy
index 16b6ca39..e823244b 100644
--- a/seccomp/cras-seccomp-arm.policy
+++ b/seccomp/cras-seccomp-arm.policy
@@ -85,7 +85,6 @@ getresgid32: 1
pipe2: 1
sched_get_priority_max: 1
sysinfo: 1
-flock: 1
# Allow ioctl command of type 'A' and 'U' for SNDRV_PCM_IOCTL_* and
# SNDRV_CTL_IOCTL_*, and EVIOCGSW(8), EVIOCGNAME(256), EVIOCGBIT(0x05, 8),
diff --git a/seccomp/cras-seccomp-arm64.policy b/seccomp/cras-seccomp-arm64.policy
index d505d175..d06a7411 100644
--- a/seccomp/cras-seccomp-arm64.policy
+++ b/seccomp/cras-seccomp-arm64.policy
@@ -53,7 +53,6 @@ exit_group: 1
fchmod: 1
fchmodat: 1
flock: 1
-flock: 1
getegid: 1
geteuid: 1
getgid: 1
diff --git a/sound_card_init/.gitignore b/sound_card_init/.gitignore
index f2e972dd..b6e87008 100644
--- a/sound_card_init/.gitignore
+++ b/sound_card_init/.gitignore
@@ -1,6 +1,6 @@
# Generated by Cargo
# will have compiled files and executables
-/target/
+**/target/
# These are backup files generated by rustfmt
**/*.rs.bk
diff --git a/sound_card_init/Cargo.lock b/sound_card_init/Cargo.lock
index 8d0eeea8..06448e9d 100644
--- a/sound_card_init/Cargo.lock
+++ b/sound_card_init/Cargo.lock
@@ -106,6 +106,7 @@ dependencies = [
"serde",
"serde_yaml",
"sys_util",
+ "utils",
]
[[package]]
@@ -197,6 +198,7 @@ dependencies = [
"serde",
"serde_yaml",
"sys_util",
+ "utils",
]
[[package]]
@@ -250,6 +252,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
[[package]]
+name = "utils"
+version = "0.1.0"
+dependencies = [
+ "remain",
+ "serde",
+ "serde_yaml",
+]
+
+[[package]]
name = "yaml-rust"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/sound_card_init/Cargo.toml b/sound_card_init/Cargo.toml
index d6ed9e2a..d4a2b376 100644
--- a/sound_card_init/Cargo.toml
+++ b/sound_card_init/Cargo.toml
@@ -12,6 +12,7 @@ getopts = "0.2"
libcras = "*"
remain = "0.2.1"
max98390d = { path = "max98390d" }
+utils = { path = "utils" }
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8.11"
sys_util = "*"
diff --git a/sound_card_init/max98390d/Cargo.toml b/sound_card_init/max98390d/Cargo.toml
index 15660589..f3bbae69 100644
--- a/sound_card_init/max98390d/Cargo.toml
+++ b/sound_card_init/max98390d/Cargo.toml
@@ -13,3 +13,4 @@ remain = "0.2.1"
serde = { version = "1.0", features = ["derive"]}
serde_yaml = "0.8.11"
sys_util = "*"
+utils = { path = "../utils" } \ No newline at end of file
diff --git a/sound_card_init/max98390d/src/amp_calibration.rs b/sound_card_init/max98390d/src/amp_calibration.rs
index 50f4227c..35340226 100644
--- a/sound_card_init/max98390d/src/amp_calibration.rs
+++ b/sound_card_init/max98390d/src/amp_calibration.rs
@@ -123,24 +123,10 @@ impl<'a> AmpCalibration<'a> {
};
if !self.validate_temperature(temp_cali) {
- match datastore {
- None => return Err(Error::InvalidTemperature(temp_cali)),
- Some(d) => match d {
- Datastore::UseVPD => {
- info!("invalid temperature: {}, use VPD values.", temp_cali);
- return Ok(());
- }
- Datastore::DSM { rdc, ambient_temp } => {
- info!("invalid temperature: {}, use datastore values.", temp_cali);
- self.card
- .control_by_name::<IntControl>(&self.setting.amp.rdc_ctrl)?
- .set(rdc)?;
- self.card
- .control_by_name::<IntControl>(&self.setting.amp.temp_ctrl)?
- .set(ambient_temp)?;
- return Ok(());
- }
- },
+ info!("invalid temperature: {}.", temp_cali);
+ return match datastore {
+ None => Err(Error::InvalidTemperature(temp_cali)),
+ Some(d) => self.apply_datastore(d),
};
}
@@ -149,22 +135,10 @@ impl<'a> AmpCalibration<'a> {
} else if diff < CALI_ERROR_LOWER_LIMIT {
match datastore {
None => Datastore::UseVPD.save(self.card.name(), &self.setting.calib_file)?,
- Some(d) => match d {
- Datastore::UseVPD => {
- info!("rdc diff: {}, use VPD values.", diff);
- }
- Datastore::DSM { rdc, ambient_temp } => {
- info!("rdc diff: {}, use datastore values.", diff);
- self.card
- .control_by_name::<IntControl>(&self.setting.amp.rdc_ctrl)?
- .set(rdc)?;
- self.card
- .control_by_name::<IntControl>(&self.setting.amp.temp_ctrl)?
- .set(ambient_temp)?;
- }
- },
+ Some(d) => self.apply_datastore(d)?,
}
} else {
+ info!("apply boot time calibration values.");
self.card
.control_by_name::<IntControl>(&self.setting.amp.rdc_ctrl)?
.set(rdc_cali)?;
@@ -180,6 +154,22 @@ impl<'a> AmpCalibration<'a> {
Ok(())
}
+ fn apply_datastore(&mut self, d: Datastore) -> Result<()> {
+ info!("apply datastore values.");
+ match d {
+ Datastore::UseVPD => Ok(()),
+ Datastore::DSM { rdc, ambient_temp } => {
+ self.card
+ .control_by_name::<IntControl>(&self.setting.amp.rdc_ctrl)?
+ .set(rdc)?;
+ self.card
+ .control_by_name::<IntControl>(&self.setting.amp.temp_ctrl)?
+ .set(ambient_temp)?;
+ Ok(())
+ }
+ }
+ }
+
fn validate_temperature(&self, temp: i32) -> bool {
temp < self.setting.amp.temp_upper_limit && temp > self.setting.amp.temp_lower_limit
}
@@ -213,7 +203,7 @@ impl<'a> AmpCalibration<'a> {
return Err(Error::StartPlaybackTimeout);
} else {
// Spurious wakes. Decrements the sleep duration by the amount slept.
- timeout = timeout - start_time.elapsed();
+ timeout -= start_time.elapsed();
}
}
}
@@ -312,4 +302,18 @@ impl<'a> AmpCalibration<'a> {
Ok(handle)
}
+
+ /// Skips max98390d boot time calibration when the speaker may be hot.
+ ///
+ /// If datastore exists, applies the stored value and sets volume to high.
+ /// If datastore does not exist, sets volume to low.
+ pub fn hot_speaker_workflow(&mut self) -> Result<()> {
+ if let Ok(sci_calib) = Datastore::from_file(self.card.name(), &self.setting.calib_file) {
+ self.apply_datastore(sci_calib)?;
+ self.set_volume(VolumeMode::High)?;
+ return Ok(());
+ }
+ info!("no datastore, set volume low");
+ self.set_volume(VolumeMode::Low)
+ }
}
diff --git a/sound_card_init/max98390d/src/datastore.rs b/sound_card_init/max98390d/src/datastore.rs
index 6e221635..12ebff73 100644
--- a/sound_card_init/max98390d/src/datastore.rs
+++ b/sound_card_init/max98390d/src/datastore.rs
@@ -7,11 +7,10 @@ use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use sys_util::info;
+use utils::DATASTORE_DIR;
use crate::error::{Error, Result};
-const DATASTORE_DIR: &str = "/var/lib/sound_card_init";
-
/// `Datastore`, which stores and reads calibration values in yaml format.
#[derive(Debug, Deserialize, Serialize, Copy, Clone)]
pub enum Datastore {
diff --git a/sound_card_init/max98390d/src/error.rs b/sound_card_init/max98390d/src/error.rs
index 572340de..778ff961 100644
--- a/sound_card_init/max98390d/src/error.rs
+++ b/sound_card_init/max98390d/src/error.rs
@@ -6,6 +6,7 @@ use std::fmt;
use std::io;
use std::num::ParseIntError;
use std::sync::PoisonError;
+use std::time;
use remain::sorted;
@@ -21,8 +22,10 @@ pub enum Error {
CrasClientFailed(libcras::Error),
DeserializationFailed(String, serde_yaml::Error),
FileIOFailed(String, io::Error),
+ HotSpeaker,
InternalSpeakerNotFound,
InvalidDatastore,
+ InvalidShutDownTime,
InvalidTemperature(i32),
LargeCalibrationDiff(i32, i32),
MissingDSMParam,
@@ -30,8 +33,10 @@ pub enum Error {
NewPlayStreamFailed(libcras::BoxError),
NextPlaybackBufferFailed(libcras::BoxError),
PlaybackFailed(io::Error),
+ ReadTimestampFailed(utils::error::Error),
SerializationFailed(serde_yaml::Error),
StartPlaybackTimeout,
+ SystemTimeError(time::SystemTimeError),
VPDParseFailed(String, ParseIntError),
WorkerPanics,
}
@@ -67,6 +72,7 @@ impl fmt::Display for Error {
CrasClientFailed(e) => write!(f, "failed to create cras client: {}", e),
DeserializationFailed(file, e) => write!(f, "failed to parse {}: {}", file, e),
FileIOFailed(file, e) => write!(f, "{}: {}", file, e),
+ InvalidShutDownTime => write!(f, "invalid shutdown time"),
InternalSpeakerNotFound => write!(f, "internal speaker is not found in cras"),
InvalidTemperature(temp) => write!(
f,
@@ -74,18 +80,21 @@ impl fmt::Display for Error {
temp
),
InvalidDatastore => write!(f, "invalid datastore format"),
+ HotSpeaker => write!(f, "skip boot time calibration as the speakers may be hot"),
LargeCalibrationDiff(rdc, temp) => write!(
f,
"calibration difference is too large, rdc: {}, temp: {}",
rdc, temp
),
- MutexPoisonError => write!(f, "mutex is poisoned"),
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),
+ ReadTimestampFailed(e) => write!(f, "{}", e),
SerializationFailed(e) => write!(f, "failed to serialize yaml: {}", e),
StartPlaybackTimeout => write!(f, "playback is not started in time"),
+ SystemTimeError(e) => write!(f, "{}", e),
VPDParseFailed(file, e) => write!(f, "failed to parse vpd {}: {}", file, e),
WorkerPanics => write!(f, "run_play_zero_worker panics"),
}
diff --git a/sound_card_init/max98390d/src/lib.rs b/sound_card_init/max98390d/src/lib.rs
index 7e445c59..44b1c611 100644
--- a/sound_card_init/max98390d/src/lib.rs
+++ b/sound_card_init/max98390d/src/lib.rs
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! `max98390d` crate implements the required initialization workflows.
-//! It currently supports boot time calibration for amplifiers.
+//! It currently supports boot time calibration for max98390d.
#![deny(missing_docs)]
mod amp_calibration;
mod datastore;
@@ -10,15 +10,20 @@ mod error;
mod settings;
mod vpd;
-use std::path::Path;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::time::{Duration, SystemTime, UNIX_EPOCH};
use cros_alsa::Card;
use sys_util::error;
+use utils::{run_time, shutdown_time, DATASTORE_DIR};
use crate::amp_calibration::{AmpCalibration, VolumeMode};
use crate::error::{Error, Result};
use crate::settings::DeviceSettings;
+const SPEAKER_COOL_DOWN_TIME: Duration = Duration::from_secs(180);
+
/// Performs max98390d boot time calibration.
///
///
@@ -35,20 +40,27 @@ pub fn run_max98390d(snd_card: &str, conf: &str) -> Result<()> {
let mut card = Card::new(snd_card)?;
if !Path::new(&settings.dsm_param).exists() {
- for s in &settings.amp_calibrations {
- let mut amp_calib = match AmpCalibration::new(&mut card, s.clone()) {
- Ok(amp) => amp,
- Err(e) => {
- error!("{}.", e);
- continue;
+ set_all_volume_low(&mut card, &settings);
+ return Err(Error::MissingDSMParam);
+ }
+
+ // Needs to check whether the speakers are over heated if it is not the first time boot.
+ if run_time::exists(snd_card) {
+ if let Err(err) = check_speaker_over_heated(snd_card, SPEAKER_COOL_DOWN_TIME) {
+ match err {
+ Error::HotSpeaker => run_all_hot_speaker_workflow(&mut card, &settings),
+ _ => {
+ // We cannot assume the speakers are not replaced or not over heated
+ // when the shutdown time file is invalid; therefore we can not use the datastore
+ // value anymore and we can not trigger boot time calibration.
+ del_all_datastore(snd_card, &settings);
+ set_all_volume_low(&mut card, &settings);
}
};
- if let Err(e) = amp_calib.set_volume(VolumeMode::Low) {
- error!("failed to set volume to low: {}.", e);
- }
- }
- return Err(Error::MissingDSMParam);
+ return Err(err);
+ };
}
+
// If some error occurs during the calibration, the iteration will continue running the
// calibration for the next amp.
let results: Vec<Result<()>> = settings
@@ -74,3 +86,68 @@ pub fn run_max98390d(snd_card: &str, conf: &str) -> Result<()> {
Ok(())
}
+
+fn del_all_datastore(snd_card: &str, settings: &DeviceSettings) {
+ for s in &settings.amp_calibrations {
+ if let Err(e) = fs::remove_file(
+ PathBuf::from(DATASTORE_DIR)
+ .join(snd_card)
+ .join(&s.calib_file),
+ ) {
+ error!("failed to remove datastore: {}.", e);
+ }
+ }
+}
+
+fn run_all_hot_speaker_workflow(card: &mut Card, settings: &DeviceSettings) {
+ for s in &settings.amp_calibrations {
+ let mut amp_calib = match AmpCalibration::new(card, s.clone()) {
+ Ok(amp) => amp,
+ Err(e) => {
+ error!("{}.", e);
+ continue;
+ }
+ };
+ if let Err(e) = amp_calib.hot_speaker_workflow() {
+ error!("failed to run hot_speaker_workflow: {}.", e);
+ }
+ }
+}
+
+fn set_all_volume_low(card: &mut Card, settings: &DeviceSettings) {
+ for s in &settings.amp_calibrations {
+ let mut amp_calib = match AmpCalibration::new(card, s.clone()) {
+ Ok(amp) => amp,
+ Err(e) => {
+ error!("{}.", e);
+ continue;
+ }
+ };
+ if let Err(e) = amp_calib.set_volume(VolumeMode::Low) {
+ error!("failed to set volume to low: {}.", e);
+ }
+ }
+}
+
+// If (Current time - the latest CRAS shutdown time) < cool_down_time, we assume that
+// the speakers may be over heated.
+fn check_speaker_over_heated(snd_card: &str, cool_down_time: Duration) -> Result<()> {
+ let last_run = run_time::from_file(snd_card).map_err(Error::ReadTimestampFailed)?;
+ let last_shutdown = shutdown_time::from_file().map_err(Error::ReadTimestampFailed)?;
+ 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 < cool_down_time {
+ return Err(Error::HotSpeaker);
+ }
+ Ok(())
+}
diff --git a/sound_card_init/seccomp/sound_card_init-seccomp-amd64.policy b/sound_card_init/seccomp/sound_card_init-seccomp-amd64.policy
index bddf6ea5..b1bcd6b8 100644
--- a/sound_card_init/seccomp/sound_card_init-seccomp-amd64.policy
+++ b/sound_card_init/seccomp/sound_card_init-seccomp-amd64.policy
@@ -34,6 +34,7 @@ getdents: 1
recvfrom: 1
set_robust_list: 1
umask: 1
+unlink: 1
sendto: 1
setgroups: 1
connect: 1
diff --git a/sound_card_init/sound_card_init.conf b/sound_card_init/sound_card_init.conf
index 7ad1a804..7ab0211e 100644
--- a/sound_card_init/sound_card_init.conf
+++ b/sound_card_init/sound_card_init.conf
@@ -48,8 +48,8 @@ end script
# -k: empty /sys tmpfs path.
# -b: need /sys/firmware/vpd/ro/ access to read the default calibration value in vpd.
# -k: get a writeable and empty /var tmpfs path.
-# -b: need /var/lib/sound_card_init/$SOUND_CARD_ID writable
-# access for datastore update.
+# -b: need /var/lib/sound_card_init/$SOUND_CARD_ID writable access for datastore update.
+# -b: need /var/lib/cras readable
exec minijail0 \
--uts \
-e \
@@ -68,6 +68,7 @@ exec minijail0 \
-b /sys/firmware/vpd/ro/ \
-k 'tmpfs,/var,tmpfs,MS_NODEV|MS_NOEXEC|MS_NOSUID,mode=755,size=10M' \
-b /var/lib/sound_card_init/"${SOUND_CARD_ID}"/,,1 \
+ -b /var/lib/cras/ \
-u sound_card_init -g sound_card_init -G \
-S /usr/share/policy/sound_card_init-seccomp.policy \
/usr/bin/sound_card_init "--id=${SOUND_CARD_ID}"
diff --git a/sound_card_init/src/main.rs b/sound_card_init/src/main.rs
index addde2df..3f49ed97 100644
--- a/sound_card_init/src/main.rs
+++ b/sound_card_init/src/main.rs
@@ -25,6 +25,7 @@ use remain::sorted;
use sys_util::{error, info, syslog};
use max98390d::run_max98390d;
+use utils::run_time;
type Result<T> = std::result::Result<T, Error>;
const CONF_DIR: &str = "/etc/sound_card_init";
@@ -99,24 +100,35 @@ fn get_config(args: &Args) -> Result<String> {
}
/// Parses the CONF_DIR/<sound_card_id>.yaml and starts sound card initialization.
-fn sound_card_init() -> std::result::Result<(), Box<dyn error::Error>> {
- let args = parse_args()?;
+fn sound_card_init(args: &Args) -> std::result::Result<(), Box<dyn error::Error>> {
info!("sound_card_id: {}", args.sound_card_id);
- let conf = get_config(&args)?;
+ let conf = get_config(args)?;
match args.sound_card_id.as_str() {
"sofcmlmax98390d" => {
run_max98390d(&args.sound_card_id, &conf)?;
info!("run_max98390d() finished successfully.");
+ Ok(())
}
- _ => return Err(Error::UnsupportedSoundCard(args.sound_card_id).into()),
- };
- Ok(())
+ _ => Err(Error::UnsupportedSoundCard(args.sound_card_id.clone()).into()),
+ }
}
fn main() {
syslog::init().expect("failed to initialize syslog");
- if let Err(e) = sound_card_init() {
+ let args = match parse_args() {
+ Ok(args) => args,
+ Err(e) => {
+ error!("failed to parse arguments: {}", e);
+ return;
+ }
+ };
+
+ if let Err(e) = sound_card_init(&args) {
error!("sound_card_init: {}", e);
}
+
+ if let Err(e) = run_time::now_to_file(&args.sound_card_id) {
+ error!("failed to create sound_card_init run time file: {}", e);
+ }
}
diff --git a/sound_card_init/utils/Cargo.lock b/sound_card_init/utils/Cargo.lock
new file mode 100644
index 00000000..fd53fb0f
--- /dev/null
+++ b/sound_card_init/utils/Cargo.lock
@@ -0,0 +1,109 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "dtoa"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
+
+[[package]]
+name = "linked-hash-map"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "remain"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ba1e78fa68412cb93ef642fd4d20b9a941be49ee9333875ebaf13112673ea7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.116"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.116"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_yaml"
+version = "0.8.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
+dependencies = [
+ "dtoa",
+ "linked-hash-map",
+ "serde",
+ "yaml-rust",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "utils"
+version = "0.1.0"
+dependencies = [
+ "remain",
+ "serde",
+ "serde_yaml",
+]
+
+[[package]]
+name = "yaml-rust"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
+dependencies = [
+ "linked-hash-map",
+]
diff --git a/sound_card_init/utils/Cargo.toml b/sound_card_init/utils/Cargo.toml
new file mode 100644
index 00000000..8c688de3
--- /dev/null
+++ b/sound_card_init/utils/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "utils"
+version = "0.1.0"
+authors = ["The Chromium OS Authors"]
+edition = "2018"
+description = "Utils for sound_card_init"
+
+[dependencies]
+remain = "0.2.1"
+serde = { version = "1.0", features = ["derive"]}
+serde_yaml = "0.8.11"
diff --git a/sound_card_init/utils/src/error.rs b/sound_card_init/utils/src/error.rs
new file mode 100644
index 00000000..93d53b9b
--- /dev/null
+++ b/sound_card_init/utils/src/error.rs
@@ -0,0 +1,39 @@
+// 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.
+
+//! This mod contains all possible errors that can occur within utils.
+use std::fmt;
+use std::io;
+use std::time;
+use std::{error, path::PathBuf};
+
+use remain::sorted;
+
+/// Alias for a `Result` with the error type `utils::Error`.
+pub type Result<T> = std::result::Result<T, Error>;
+
+/// This type represents all possible errors that can occur within utils.
+#[sorted]
+#[derive(Debug)]
+pub enum Error {
+ /// It wraps file path with the io::Error.
+ FileIOFailed(PathBuf, io::Error),
+ /// It wraps file path with the serde_yaml::Error.
+ SerdeError(PathBuf, serde_yaml::Error),
+ /// It wraps time::SystemTimeError.
+ SystemTimeError(time::SystemTimeError),
+}
+
+impl error::Error for Error {}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use Error::*;
+ match self {
+ FileIOFailed(file, e) => write!(f, "{:?}: {}", file, e),
+ SerdeError(file, e) => write!(f, "{:?}: {}", file, e),
+ SystemTimeError(e) => write!(f, "{}", e),
+ }
+ }
+}
diff --git a/sound_card_init/utils/src/lib.rs b/sound_card_init/utils/src/lib.rs
new file mode 100644
index 00000000..e8edce77
--- /dev/null
+++ b/sound_card_init/utils/src/lib.rs
@@ -0,0 +1,87 @@
+// 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)]
+
+//! The error definitions for utils.
+pub mod error;
+
+use std::fs::File;
+use std::io::{prelude::*, BufReader, BufWriter};
+use std::path::PathBuf;
+use std::time::Duration;
+
+use crate::error::{Error, Result};
+
+/// The path of datastore.
+pub const DATASTORE_DIR: &str = "/var/lib/sound_card_init";
+
+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_DIR)
+ .join(snd_card)
+ .join(RUN_TIME_FILE)
+ }
+}
diff --git a/ucm-config/for_all_boards/C505 HD Webcam/C505 HD Webcam.conf b/ucm-config/for_all_boards/C505 HD Webcam/C505 HD Webcam.conf
new file mode 100644
index 00000000..126ac331
--- /dev/null
+++ b/ucm-config/for_all_boards/C505 HD Webcam/C505 HD Webcam.conf
@@ -0,0 +1,6 @@
+Comment "Logitech Webcam C505"
+
+SectionUseCase."HiFi" {
+ File "HiFi.conf"
+ Comment "Default"
+}
diff --git a/ucm-config/for_all_boards/C505 HD Webcam/HiFi.conf b/ucm-config/for_all_boards/C505 HD Webcam/HiFi.conf
new file mode 100644
index 00000000..c7e13426
--- /dev/null
+++ b/ucm-config/for_all_boards/C505 HD Webcam/HiFi.conf
@@ -0,0 +1,25 @@
+SectionVerb {
+ Value {
+ FullySpecifiedUCM "1"
+ }
+
+ EnableSequence [
+ cdev "hw:Webcam"
+ cset "name='Mic Capture Volume' 0"
+ ]
+
+ DisableSequence [
+ ]
+}
+
+SectionDevice."Webcam" {
+ Value {
+ CapturePCM "hw:Webcam,0"
+ }
+
+ EnableSequence [
+ ]
+
+ DisableSequence [
+ ]
+}
diff --git a/ucm-config/for_all_boards/Chat 150 C/HiFi.conf b/ucm-config/for_all_boards/Chat 150 C/HiFi.conf
index 5a73702c..368796d7 100644
--- a/ucm-config/for_all_boards/Chat 150 C/HiFi.conf
+++ b/ucm-config/for_all_boards/Chat 150 C/HiFi.conf
@@ -10,7 +10,7 @@ SectionVerb {
]
}
-SectionDevice."Dummy".0 {
+SectionDevice."Chat 150 C".0 {
EnableSequence [
]
diff --git a/ucm-config/for_all_boards/Jabra SPEAK 810/HiFi.conf b/ucm-config/for_all_boards/Jabra SPEAK 810/HiFi.conf
index 5a73702c..313bffef 100644
--- a/ucm-config/for_all_boards/Jabra SPEAK 810/HiFi.conf
+++ b/ucm-config/for_all_boards/Jabra SPEAK 810/HiFi.conf
@@ -10,7 +10,7 @@ SectionVerb {
]
}
-SectionDevice."Dummy".0 {
+SectionDevice."Jabra Speak 810".0 {
EnableSequence [
]
diff --git a/unblocked_terms.txt b/unblocked_terms.txt
new file mode 100644
index 00000000..674e3d33
--- /dev/null
+++ b/unblocked_terms.txt
@@ -0,0 +1,11 @@
+# KEEP THIS COMMENT IN YOUR COPY.
+#
+# Don't delete this file if you want to keep keyword_check enabled even if it's
+# empty.
+#
+# See repohooks/README.md for more details.
+
+dummy
+master
+\bnative
+white.?list