diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 275 |
1 files changed, 186 insertions, 89 deletions
diff --git a/src/main.rs b/src/main.rs index 1804028..d385db3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ pub mod panic_hook; +use std::default::Default; use std::fmt; use std::fs::{File, OpenOptions}; use std::io::{BufRead, BufReader}; @@ -17,13 +18,14 @@ use std::thread::sleep; use std::time::Duration; use arch::Pstore; +use audio_streams::StreamEffect; use crosvm::{ argument::{self, print_help, set_arguments, Argument}, linux, BindMount, Config, DiskOption, Executable, GidMap, SharedDir, TouchDeviceOption, }; #[cfg(feature = "gpu")] use devices::virtio::gpu::{GpuMode, GpuParameters}; -use devices::{SerialParameters, SerialType}; +use devices::{Ac97Backend, Ac97Parameters, SerialParameters, SerialType}; use disk::QcowFile; use msg_socket::{MsgReceiver, MsgSender, MsgSocket}; use sys_util::{ @@ -78,21 +80,21 @@ fn parse_cpu_set(s: &str) -> argument::Result<Vec<usize>> { if range.len() == 0 || range.len() > 2 { return Err(argument::Error::InvalidValue { value: part.to_owned(), - expected: "invalid list syntax", + expected: String::from("invalid list syntax"), }); } let first_cpu: usize = range[0] .parse() .map_err(|_| argument::Error::InvalidValue { value: part.to_owned(), - expected: "CPU index must be a non-negative integer", + expected: String::from("CPU index must be a non-negative integer"), })?; let last_cpu: usize = if range.len() == 2 { range[1] .parse() .map_err(|_| argument::Error::InvalidValue { value: part.to_owned(), - expected: "CPU index must be a non-negative integer", + expected: String::from("CPU index must be a non-negative integer"), })? } else { first_cpu @@ -101,7 +103,7 @@ fn parse_cpu_set(s: &str) -> argument::Result<Vec<usize>> { if last_cpu < first_cpu { return Err(argument::Error::InvalidValue { value: part.to_owned(), - expected: "CPU ranges must be from low to high", + expected: String::from("CPU ranges must be from low to high"), }); } @@ -151,7 +153,9 @@ fn parse_gpu_options(s: Option<&str>) -> argument::Result<GpuParameters> { _ => { return Err(argument::Error::InvalidValue { value: v.to_string(), - expected: "gpu parameter 'backend' should be one of (2d|3d|gfxstream)", + expected: String::from( + "gpu parameter 'backend' should be one of (2d|3d|gfxstream)", + ), }); } }, @@ -165,7 +169,7 @@ fn parse_gpu_options(s: Option<&str>) -> argument::Result<GpuParameters> { _ => { return Err(argument::Error::InvalidValue { value: v.to_string(), - expected: "gpu parameter 'egl' should be a boolean", + expected: String::from("gpu parameter 'egl' should be a boolean"), }); } }, @@ -179,7 +183,7 @@ fn parse_gpu_options(s: Option<&str>) -> argument::Result<GpuParameters> { _ => { return Err(argument::Error::InvalidValue { value: v.to_string(), - expected: "gpu parameter 'gles' should be a boolean", + expected: String::from("gpu parameter 'gles' should be a boolean"), }); } }, @@ -193,7 +197,7 @@ fn parse_gpu_options(s: Option<&str>) -> argument::Result<GpuParameters> { _ => { return Err(argument::Error::InvalidValue { value: v.to_string(), - expected: "gpu parameter 'glx' should be a boolean", + expected: String::from("gpu parameter 'glx' should be a boolean"), }); } }, @@ -207,7 +211,9 @@ fn parse_gpu_options(s: Option<&str>) -> argument::Result<GpuParameters> { _ => { return Err(argument::Error::InvalidValue { value: v.to_string(), - expected: "gpu parameter 'surfaceless' should be a boolean", + expected: String::from( + "gpu parameter 'surfaceless' should be a boolean", + ), }); } }, @@ -216,7 +222,9 @@ fn parse_gpu_options(s: Option<&str>) -> argument::Result<GpuParameters> { v.parse::<u32>() .map_err(|_| argument::Error::InvalidValue { value: v.to_string(), - expected: "gpu parameter 'width' must be a valid integer", + expected: String::from( + "gpu parameter 'width' must be a valid integer", + ), })?; } "height" => { @@ -224,7 +232,9 @@ fn parse_gpu_options(s: Option<&str>) -> argument::Result<GpuParameters> { v.parse::<u32>() .map_err(|_| argument::Error::InvalidValue { value: v.to_string(), - expected: "gpu parameter 'height' must be a valid integer", + expected: String::from( + "gpu parameter 'height' must be a valid integer", + ), })?; } "" => {} @@ -241,6 +251,53 @@ fn parse_gpu_options(s: Option<&str>) -> argument::Result<GpuParameters> { Ok(gpu_params) } +fn parse_ac97_options(s: &str) -> argument::Result<Ac97Parameters> { + let mut ac97_params: Ac97Parameters = Default::default(); + + let opts = s + .split(",") + .map(|frag| frag.split("=")) + .map(|mut kv| (kv.next().unwrap_or(""), kv.next().unwrap_or(""))); + + for (k, v) in opts { + match k { + "backend" => { + ac97_params.backend = + v.parse::<Ac97Backend>() + .map_err(|e| argument::Error::InvalidValue { + value: v.to_string(), + expected: e.to_string(), + })?; + } + "capture" => { + ac97_params.capture = v.parse::<bool>().map_err(|e| { + argument::Error::Syntax(format!("invalid capture option: {}", e)) + })?; + } + "capture_effects" => { + ac97_params.capture_effects = v + .split("|") + .map(|val| { + val.parse::<StreamEffect>() + .map_err(|e| argument::Error::InvalidValue { + value: val.to_string(), + expected: e.to_string(), + }) + }) + .collect::<argument::Result<Vec<_>>>()?; + } + _ => { + return Err(argument::Error::UnknownArgument(format!( + "unknown ac97 parameter {}", + k + ))); + } + } + } + + Ok(ac97_params) +} + fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> { let mut serial_setting = SerialParameters { type_: SerialType::Sink, @@ -269,7 +326,7 @@ fn parse_serial_options(s: &str) -> argument::Result<SerialParameters> { if num < 1 || num > 4 { return Err(argument::Error::InvalidValue { value: num.to_string(), - expected: "Serial port num must be between 1 - 4", + expected: String::from("Serial port num must be between 1 - 4"), }); } serial_setting.num = num; @@ -305,7 +362,9 @@ fn parse_plugin_mount_option(value: &str) -> argument::Result<BindMount> { if components.is_empty() || components.len() > 3 || components[0].is_empty() { return Err(argument::Error::InvalidValue { value: value.to_owned(), - expected: "`plugin-mount` should be in a form of: <src>[:[<dst>][:<writable>]]", + expected: String::from( + "`plugin-mount` should be in a form of: <src>[:[<dst>][:<writable>]]", + ), }); } @@ -313,13 +372,13 @@ fn parse_plugin_mount_option(value: &str) -> argument::Result<BindMount> { if src.is_relative() { return Err(argument::Error::InvalidValue { value: components[0].to_owned(), - expected: "the source path for `plugin-mount` must be absolute", + expected: String::from("the source path for `plugin-mount` must be absolute"), }); } if !src.exists() { return Err(argument::Error::InvalidValue { value: components[0].to_owned(), - expected: "the source path for `plugin-mount` does not exist", + expected: String::from("the source path for `plugin-mount` does not exist"), }); } @@ -330,7 +389,7 @@ fn parse_plugin_mount_option(value: &str) -> argument::Result<BindMount> { if dst.is_relative() { return Err(argument::Error::InvalidValue { value: components[1].to_owned(), - expected: "the destination path for `plugin-mount` must be absolute", + expected: String::from("the destination path for `plugin-mount` must be absolute"), }); } @@ -338,7 +397,7 @@ fn parse_plugin_mount_option(value: &str) -> argument::Result<BindMount> { None => false, Some(s) => s.parse().map_err(|_| argument::Error::InvalidValue { value: components[2].to_owned(), - expected: "the <writable> component for `plugin-mount` is not valid bool", + expected: String::from("the <writable> component for `plugin-mount` is not valid bool"), })?, }; @@ -350,8 +409,9 @@ fn parse_plugin_gid_map_option(value: &str) -> argument::Result<GidMap> { if components.is_empty() || components.len() > 3 || components[0].is_empty() { return Err(argument::Error::InvalidValue { value: value.to_owned(), - expected: + expected: String::from( "`plugin-gid-map` must have exactly 3 components: <inner>[:[<outer>][:<count>]]", + ), }); } @@ -359,14 +419,14 @@ fn parse_plugin_gid_map_option(value: &str) -> argument::Result<GidMap> { .parse() .map_err(|_| argument::Error::InvalidValue { value: components[0].to_owned(), - expected: "the <inner> component for `plugin-gid-map` is not valid gid", + expected: String::from("the <inner> component for `plugin-gid-map` is not valid gid"), })?; let outer: libc::gid_t = match components.get(1) { None | Some(&"") => inner, Some(s) => s.parse().map_err(|_| argument::Error::InvalidValue { value: components[1].to_owned(), - expected: "the <outer> component for `plugin-gid-map` is not valid gid", + expected: String::from("the <outer> component for `plugin-gid-map` is not valid gid"), })?, }; @@ -374,7 +434,9 @@ fn parse_plugin_gid_map_option(value: &str) -> argument::Result<GidMap> { None => 1, Some(s) => s.parse().map_err(|_| argument::Error::InvalidValue { value: components[2].to_owned(), - expected: "the <count> component for `plugin-gid-map` is not valid number", + expected: String::from( + "the <count> component for `plugin-gid-map` is not valid number", + ), })?, }; @@ -398,7 +460,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if !kernel_path.exists() { return Err(argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "this kernel path does not exist", + expected: String::from("this kernel path does not exist"), }); } cfg.executable_path = Some(Executable::Kernel(kernel_path)); @@ -415,7 +477,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if !android_fstab.exists() { return Err(argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "this android fstab path does not exist", + expected: String::from("this android fstab path does not exist"), }); } cfg.android_fstab = Some(android_fstab); @@ -437,7 +499,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .parse() .map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "this value for `cpus` needs to be integer", + expected: String::from("this value for `cpus` needs to be integer"), })?, ) } @@ -462,18 +524,13 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .parse() .map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "this value for `mem` needs to be integer", + expected: String::from("this value for `mem` needs to be integer"), })?, ) } - "cras-audio" => { - cfg.cras_audio = true; - } - "cras-capture" => { - cfg.cras_capture = true; - } - "null-audio" => { - cfg.null_audio = true; + "ac97" => { + let ac97_params = parse_ac97_options(value.unwrap())?; + cfg.ac97_parameters.push(ac97_params); } "serial" => { let serial_params = parse_serial_options(value.unwrap())?; @@ -526,13 +583,13 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .next() .ok_or_else(|| argument::Error::InvalidValue { value: param.to_owned(), - expected: "missing disk path", + expected: String::from("missing disk path"), })?, ); if !disk_path.exists() { return Err(argument::Error::InvalidValue { value: param.to_owned(), - expected: "this disk path does not exist", + expected: String::from("this disk path does not exist"), }); } if name.ends_with("root") { @@ -559,18 +616,18 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: let mut o = opt.splitn(2, '='); let kind = o.next().ok_or_else(|| argument::Error::InvalidValue { value: opt.to_owned(), - expected: "disk options must not be empty", + expected: String::from("disk options must not be empty"), })?; let value = o.next().ok_or_else(|| argument::Error::InvalidValue { value: opt.to_owned(), - expected: "disk options must be of the form `kind=value`", + expected: String::from("disk options must be of the form `kind=value`"), })?; match kind { "sparse" => { let sparse = value.parse().map_err(|_| argument::Error::InvalidValue { value: value.to_owned(), - expected: "`sparse` must be a boolean", + expected: String::from("`sparse` must be a boolean"), })?; disk.sparse = sparse; } @@ -578,14 +635,14 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: let block_size = value.parse().map_err(|_| argument::Error::InvalidValue { value: value.to_owned(), - expected: "`block_size` must be an integer", + expected: String::from("`block_size` must be an integer"), })?; disk.block_size = block_size; } _ => { return Err(argument::Error::InvalidValue { value: kind.to_owned(), - expected: "unrecognized disk option", + expected: String::from("unrecognized disk option"), }); } } @@ -598,7 +655,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if !disk_path.exists() { return Err(argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "this disk path does not exist", + expected: String::from("this disk path does not exist"), }); } @@ -621,7 +678,9 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if components.len() != 2 { return Err(argument::Error::InvalidValue { value: value.to_owned(), - expected: "pstore must have exactly 2 components: path=<path>,size=<size>", + expected: String::from( + "pstore must have exactly 2 components: path=<path>,size=<size>", + ), }); } cfg.pstore = Some(Pstore { @@ -629,7 +688,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if components[0].len() <= 5 || !components[0].starts_with("path=") { return Err(argument::Error::InvalidValue { value: components[0].to_owned(), - expected: "pstore path must follow with `path=`", + expected: String::from("pstore path must follow with `path=`"), }); }; PathBuf::from(&components[0][5..]) @@ -638,14 +697,14 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if components[1].len() <= 5 || !components[1].starts_with("size=") { return Err(argument::Error::InvalidValue { value: components[1].to_owned(), - expected: "pstore size must follow with `size=`", + expected: String::from("pstore size must follow with `size=`"), }); }; components[1][5..] .parse() .map_err(|_| argument::Error::InvalidValue { value: value.to_owned(), - expected: "pstore size must be an integer", + expected: String::from("pstore size must be an integer"), })? }, }); @@ -663,7 +722,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .parse() .map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "`host_ip` needs to be in the form \"x.x.x.x\"", + expected: String::from("`host_ip` needs to be in the form \"x.x.x.x\""), })?, ) } @@ -680,7 +739,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .parse() .map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "`netmask` needs to be in the form \"x.x.x.x\"", + expected: String::from("`netmask` needs to be in the form \"x.x.x.x\""), })?, ) } @@ -697,7 +756,9 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .parse() .map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "`mac` needs to be in the form \"XX:XX:XX:XX:XX:XX\"", + expected: String::from( + "`mac` needs to be in the form \"XX:XX:XX:XX:XX:XX\"", + ), })?, ) } @@ -709,7 +770,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .next() .ok_or_else(|| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "missing socket path", + expected: String::from("missing socket path"), })?, ); let mut name = ""; @@ -720,7 +781,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: _ => { return Err(argument::Error::InvalidValue { value: c.to_owned(), - expected: "option must be of the form `kind=value`", + expected: String::from("option must be of the form `kind=value`"), }) } }; @@ -729,7 +790,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: _ => { return Err(argument::Error::InvalidValue { value: kind.to_owned(), - expected: "unrecognized option", + expected: String::from("unrecognized option"), }) } } @@ -771,7 +832,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if socket_path.exists() { return Err(argument::Error::InvalidValue { value: socket_path.to_string_lossy().into_owned(), - expected: "this socket path already exists", + expected: String::from("this socket path already exists"), }); } cfg.socket_path = Some(socket_path); @@ -791,7 +852,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .parse() .map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "this value for `cid` must be an unsigned integer", + expected: String::from("this value for `cid` must be an unsigned integer"), })?, ); } @@ -816,21 +877,21 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .next() .ok_or_else(|| argument::Error::InvalidValue { value: param.to_owned(), - expected: "missing source path for `shared-dir`", + expected: String::from("missing source path for `shared-dir`"), })?, ); let tag = components .next() .ok_or_else(|| argument::Error::InvalidValue { value: param.to_owned(), - expected: "missing tag for `shared-dir`", + expected: String::from("missing tag for `shared-dir`"), })? .to_owned(); if !src.is_dir() { return Err(argument::Error::InvalidValue { value: param.to_owned(), - expected: "source path for `shared-dir` must be a directory", + expected: String::from("source path for `shared-dir` must be a directory"), }); } @@ -843,11 +904,11 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: let mut o = opt.splitn(2, '='); let kind = o.next().ok_or_else(|| argument::Error::InvalidValue { value: opt.to_owned(), - expected: "`shared-dir` options must not be empty", + expected: String::from("`shared-dir` options must not be empty"), })?; let value = o.next().ok_or_else(|| argument::Error::InvalidValue { value: opt.to_owned(), - expected: "`shared-dir` options must be of the form `kind=value`", + expected: String::from("`shared-dir` options must be of the form `kind=value`"), })?; match kind { @@ -855,7 +916,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: shared_dir.kind = value.parse().map_err(|_| argument::Error::InvalidValue { value: value.to_owned(), - expected: "`type` must be one of `fs` or `9p`", + expected: String::from("`type` must be one of `fs` or `9p`"), })? } "uidmap" => shared_dir.uid_map = value.into(), @@ -863,7 +924,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: "timeout" => { let seconds = value.parse().map_err(|_| argument::Error::InvalidValue { value: value.to_owned(), - expected: "`timeout` must be an integer", + expected: String::from("`timeout` must be an integer"), })?; let dur = Duration::from_secs(seconds); @@ -873,7 +934,9 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: "cache" => { let policy = value.parse().map_err(|_| argument::Error::InvalidValue { value: value.to_owned(), - expected: "`cache` must be one of `never`, `always`, or `auto`", + expected: String::from( + "`cache` must be one of `never`, `always`, or `auto`", + ), })?; shared_dir.cfg.cache_policy = policy; } @@ -881,14 +944,14 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: let writeback = value.parse().map_err(|_| argument::Error::InvalidValue { value: value.to_owned(), - expected: "`writeback` must be a boolean", + expected: String::from("`writeback` must be a boolean"), })?; shared_dir.cfg.writeback = writeback; } _ => { return Err(argument::Error::InvalidValue { value: kind.to_owned(), - expected: "unrecognized option for `shared-dir`", + expected: String::from("unrecognized option for `shared-dir`"), }) } } @@ -930,7 +993,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if plugin.is_relative() { return Err(argument::Error::InvalidValue { value: plugin.to_string_lossy().into_owned(), - expected: "the plugin path must be an absolute path", + expected: String::from("the plugin path must be an absolute path"), }); } cfg.executable_path = Some(Executable::Plugin(plugin)); @@ -945,7 +1008,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: "plugin-mount-file" => { let file = File::open(value.unwrap()).map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "unable to open `plugin-mount-file` file", + expected: String::from("unable to open `plugin-mount-file` file"), })?; let reader = BufReader::new(file); for l in reader.lines() { @@ -964,7 +1027,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: "plugin-gid-map-file" => { let file = File::open(value.unwrap()).map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "unable to open `plugin-gid-map-file` file", + expected: String::from("unable to open `plugin-gid-map-file` file"), })?; let reader = BufReader::new(file); for l in reader.lines() { @@ -984,7 +1047,9 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: .parse() .map_err(|_| argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "this value for `tap-fd` must be an unsigned integer", + expected: String::from( + "this value for `tap-fd` must be an unsigned integer", + ), })?, ); } @@ -1053,7 +1118,7 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if !dev_path.exists() { return Err(argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "this input device path does not exist", + expected: String::from("this input device path does not exist"), }); } cfg.virtio_input_evdevs.push(dev_path); @@ -1078,13 +1143,13 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: if !vfio_path.exists() { return Err(argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "the vfio path does not exist", + expected: String::from("the vfio path does not exist"), }); } if !vfio_path.is_dir() { return Err(argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "the vfio path should be directory", + expected: String::from("the vfio path should be directory"), }); } @@ -1223,24 +1288,28 @@ Path to pstore buffer backend file follewed by size. ), Argument::value("netmask", "NETMASK", "Netmask for VM subnet."), Argument::value("mac", "MAC", "MAC address for VM."), - Argument::flag( - "cras-audio", - "\ -Add an audio device to the VM that plays samples through CRAS server. -", - ), - Argument::flag( - "cras-capture", - "\ -Enable capturing audio from CRAS server to the cras-audio device. -", - ), - Argument::flag( - "null-audio", - "\ -Add an audio device to the VM that plays samples to /dev/null. -", + Argument::value( + "ac97", + "[backend=BACKEND,capture=true,capture_effect=EFFECT]", + r#"Comma separated key=value pairs for setting up Ac97 devices. Can be +given more than once. + +Possible key values: + + backend=(null,cras) + Where to route the audio device. "null" for /dev/null, and "cras" + for CRAS server. + (default: null) + + capture + Enable audio capture. + + capture_effects + Separated effects to be enabled for recording. The only supported + effect value now is EchoCancellation or aec. +"#, ), + Argument::value( "serial", "type=TYPE,[num=NUM,path=PATH,console,stdin]", @@ -1683,7 +1752,7 @@ fn create_qcow2(args: std::env::Args) -> std::result::Result<(), ()> { size = Some(value.unwrap().parse::<u64>().map_err(|_| { argument::Error::InvalidValue { value: value.unwrap().to_owned(), - expected: "SIZE should be a nonnegative integer", + expected: String::from("SIZE should be a nonnegative integer"), } })?); } @@ -2100,6 +2169,34 @@ mod tests { } #[test] + fn parse_ac97_vaild() { + parse_ac97_options("backend=cras").expect("parse should have succeded"); + } + + #[test] + fn parse_ac97_null_vaild() { + parse_ac97_options("backend=null").expect("parse should have succeded"); + } + + #[test] + fn parse_ac97_dup_effect_vaild() { + parse_ac97_options("backend=cras,capture=true,capture_effects=aec|aec") + .expect("parse should have succeded"); + } + + #[test] + fn parse_ac97_effect_invaild() { + parse_ac97_options("backend=cras,capture=true,capture_effects=abc") + .expect_err("parse should have failed"); + } + + #[test] + fn parse_ac97_effect_vaild() { + parse_ac97_options("backend=cras,capture=true,capture_effects=aec") + .expect("parse should have succeded"); + } + + #[test] fn parse_serial_vaild() { parse_serial_options("type=syslog,num=1,console=true,stdin=true") .expect("parse should have succeded"); |