• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::collections::VecDeque;
6 use std::sync::atomic::AtomicBool;
7 use std::sync::atomic::Ordering;
8 use std::sync::Arc;
9 use std::thread;
10 use std::time::Duration;
11 use std::time::Instant;
12 
13 use audio_streams::shm_streams::ShmStream;
14 use audio_streams::BoxError;
15 use audio_streams::NoopStreamControl;
16 use audio_streams::SampleFormat;
17 use audio_streams::StreamDirection;
18 use audio_streams::StreamEffect;
19 use base::error;
20 use base::set_rt_prio_limit;
21 use base::set_rt_round_robin;
22 use base::warn;
23 use base::AsRawDescriptor;
24 use base::AsRawDescriptors;
25 use base::FromRawDescriptor;
26 use base::RawDescriptor;
27 use remain::sorted;
28 use sync::Condvar;
29 use sync::Mutex;
30 use thiserror::Error;
31 use vm_memory::GuestAddress;
32 use vm_memory::GuestMemory;
33 
34 use crate::pci::ac97::sys::AudioStreamSource;
35 use crate::pci::ac97_bus_master::buffer_completed;
36 use crate::pci::ac97_bus_master::current_buffer_size;
37 use crate::pci::ac97_bus_master::get_buffer_samples;
38 use crate::pci::ac97_bus_master::Ac97BusMaster;
39 use crate::pci::ac97_bus_master::Ac97BusMasterRegs;
40 use crate::pci::ac97_bus_master::AudioResult;
41 use crate::pci::ac97_bus_master::AudioThreadInfo;
42 use crate::pci::ac97_bus_master::GuestMemoryError;
43 use crate::pci::ac97_bus_master::GuestMemoryResult;
44 use crate::pci::ac97_mixer::Ac97Mixer;
45 use crate::pci::ac97_regs::*;
46 
47 // Internal error type used for reporting errors from the audio thread.
48 #[sorted]
49 #[derive(Error, Debug)]
50 pub(crate) enum AudioError {
51     // Failed to clone a descriptor.
52     #[error("Failed to clone a descriptor: {0}")]
53     CloneDescriptor(base::Error),
54     // Failed to create a shared memory.
55     #[error("Failed to create a shared memory: {0}.")]
56     CreateSharedMemory(base::Error),
57     // Failed to create a new stream.
58     #[error("Failed to create audio stream: {0}.")]
59     CreateStream(BoxError),
60     // Failure to get regions from guest memory.
61     #[error("Failed to get guest memory region: {0}.")]
62     GuestRegion(GuestMemoryError),
63     // Invalid buffer offset received from the audio server.
64     #[error("Offset > max usize")]
65     InvalidBufferOffset,
66     // Guest did not provide a buffer when needed.
67     #[error("No buffer was available from the Guest")]
68     NoBufferAvailable,
69     // Failure to read guest memory.
70     #[error("Failed to read guest memory: {0}.")]
71     ReadingGuestError(GuestMemoryError),
72     // Failure to respond to the ServerRequest.
73     #[error("Failed to respond to the ServerRequest: {0}")]
74     RespondRequest(BoxError),
75     // Failure to wait for a request from the stream.
76     #[error("Failed to wait for a message from the stream: {0}")]
77     WaitForAction(BoxError),
78 }
79 
80 // Unix specific members of Ac97BusMaster - a placeholder.
81 #[derive(Default)]
82 pub struct Ac97BusMasterSys {}
83 
84 impl AudioThreadInfo {
start(&mut self, mut worker: AudioWorker)85     fn start(&mut self, mut worker: AudioWorker) {
86         const AUDIO_THREAD_RTPRIO: u16 = 10; // Matches other cros audio clients.
87         self.thread_run.store(true, Ordering::Relaxed);
88         self.thread = Some(thread::spawn(move || {
89             if let Err(e) = set_rt_prio_limit(u64::from(AUDIO_THREAD_RTPRIO))
90                 .and_then(|_| set_rt_round_robin(i32::from(AUDIO_THREAD_RTPRIO)))
91             {
92                 warn!("Failed to set audio thread to real time: {}", e);
93             }
94 
95             if let Err(e) = worker.run() {
96                 error!("{:?} error: {}", worker.func, e);
97             }
98 
99             worker.thread_run.store(false, Ordering::Relaxed);
100         }));
101 
102         self.stream_control = Some(Box::new(NoopStreamControl::new()));
103     }
104 }
105 
106 impl Ac97BusMaster {
107     /// Creates an Ac97BusMaster` object that plays audio from `mem` to streams provided by
108     /// `audio_server`.
new(mem: GuestMemory, audio_server: AudioStreamSource) -> Self109     pub(crate) fn new(mem: GuestMemory, audio_server: AudioStreamSource) -> Self {
110         Ac97BusMaster {
111             mem,
112             regs: Arc::new(Mutex::new(Ac97BusMasterRegs::new())),
113             acc_sema: 0,
114 
115             po_info: AudioThreadInfo::new(),
116             pi_info: AudioThreadInfo::new(),
117             pmic_info: AudioThreadInfo::new(),
118             audio_server,
119 
120             irq_resample_thread: None,
121             sys: Default::default(),
122         }
123     }
124 
125     /// Returns any file descriptors that need to be kept open when entering a jail.
keep_rds(&self) -> Option<Vec<RawDescriptor>>126     pub fn keep_rds(&self) -> Option<Vec<RawDescriptor>> {
127         let mut rds = self.audio_server.keep_fds();
128         rds.append(&mut self.mem.as_raw_descriptors());
129         Some(rds)
130     }
131 
check_and_move_to_next_buffer( func_regs: &mut Ac97FunctionRegs, )132     pub(in crate::pci::ac97_bus_master) fn check_and_move_to_next_buffer(
133         func_regs: &mut Ac97FunctionRegs,
134     ) {
135         if func_regs.sr & SR_CELV != 0 {
136             // CELV means we'd already processed the buffer at CIV.
137             // Move CIV to the next buffer now that LVI has moved.
138             func_regs.move_to_next_buffer();
139         }
140     }
141 
thread_semaphore_notify(&self, func: Ac97Function)142     pub(in crate::pci::ac97_bus_master) fn thread_semaphore_notify(&self, func: Ac97Function) {
143         match func {
144             Ac97Function::Input => self.pi_info.thread_semaphore.notify_one(),
145             Ac97Function::Output => self.po_info.thread_semaphore.notify_one(),
146             Ac97Function::Microphone => self.pmic_info.thread_semaphore.notify_one(),
147         }
148     }
149 
stream_effects(func: Ac97Function) -> Vec<StreamEffect>150     fn stream_effects(func: Ac97Function) -> Vec<StreamEffect> {
151         match func {
152             Ac97Function::Microphone => vec![StreamEffect::EchoCancellation],
153             _ => vec![StreamEffect::NoEffect],
154         }
155     }
156 
create_audio_worker( &mut self, mixer: &Ac97Mixer, func: Ac97Function, ) -> AudioResult<AudioWorker>157     fn create_audio_worker(
158         &mut self,
159         mixer: &Ac97Mixer,
160         func: Ac97Function,
161     ) -> AudioResult<AudioWorker> {
162         let direction = match func {
163             Ac97Function::Microphone => StreamDirection::Capture,
164             Ac97Function::Input => StreamDirection::Capture,
165             Ac97Function::Output => StreamDirection::Playback,
166         };
167 
168         let locked_regs = self.regs.lock();
169         let sample_rate = self.current_sample_rate(func, mixer);
170         let buffer_samples = current_buffer_size(locked_regs.func_regs(func), &self.mem)?;
171         let num_channels = locked_regs.tube_count(func);
172         let buffer_frames = buffer_samples / num_channels;
173 
174         let mut pending_buffers = VecDeque::with_capacity(2);
175         let starting_offsets = match direction {
176             StreamDirection::Capture => {
177                 let mut offsets = [0, 0];
178                 for offset in &mut offsets {
179                     let buffer = next_guest_buffer(&locked_regs, &self.mem, func, 0)?
180                         .ok_or(AudioError::NoBufferAvailable)?;
181                     *offset = buffer.offset as u64;
182                     pending_buffers.push_back(Some(buffer));
183                 }
184                 offsets
185             }
186             StreamDirection::Playback => [0, 0],
187         };
188 
189         // Create a `base::SharedMemory` object from a descriptor backing `self.mem`.
190         // This creation is expected to succeed because we can assume that `self.mem` was created
191         // from a `SharedMemory` object and its type was generalized to `dyn AsRawDescriptor`.
192         let desc: &dyn AsRawDescriptor = self
193             .mem
194             .offset_region(starting_offsets[0])
195             .map_err(|e| AudioError::GuestRegion(GuestMemoryError::ReadingGuestBufferAddress(e)))?;
196         let shm = {
197             let rd = base::clone_descriptor(desc).map_err(AudioError::CloneDescriptor)?;
198             // Safe because the fd is owned.
199             let sd = unsafe { base::SafeDescriptor::from_raw_descriptor(rd) };
200             base::SharedMemory::from_safe_descriptor(sd, None)
201                 .map_err(AudioError::CreateSharedMemory)?
202         };
203 
204         let stream = self
205             .audio_server
206             .new_stream(
207                 direction,
208                 num_channels,
209                 SampleFormat::S16LE,
210                 sample_rate,
211                 buffer_frames,
212                 &Self::stream_effects(func),
213                 &shm,
214                 starting_offsets,
215             )
216             .map_err(AudioError::CreateStream)?;
217 
218         let params = AudioWorkerParams {
219             func,
220             stream,
221             pending_buffers,
222             message_interval: Duration::from_secs_f64(buffer_frames as f64 / sample_rate as f64),
223         };
224         Ok(AudioWorker::new(self, params))
225     }
226 
start_audio( &mut self, func: Ac97Function, mixer: &Ac97Mixer, ) -> AudioResult<()>227     pub(in crate::pci::ac97_bus_master) fn start_audio(
228         &mut self,
229         func: Ac97Function,
230         mixer: &Ac97Mixer,
231     ) -> AudioResult<()> {
232         let audio_worker = self.create_audio_worker(mixer, func)?;
233         self.thread_info_mut(func).start(audio_worker);
234         self.update_mixer_settings(mixer);
235         Ok(())
236     }
237 }
238 
239 #[derive(Debug)]
240 struct GuestBuffer {
241     offset: usize,
242     frames: usize,
243 }
244 
get_buffer_offset( func_regs: &Ac97FunctionRegs, mem: &GuestMemory, index: u8, ) -> GuestMemoryResult<u64>245 fn get_buffer_offset(
246     func_regs: &Ac97FunctionRegs,
247     mem: &GuestMemory,
248     index: u8,
249 ) -> GuestMemoryResult<u64> {
250     let descriptor_addr = func_regs.bdbar + u32::from(index) * DESCRIPTOR_LENGTH as u32;
251     let buffer_addr_reg: u32 = mem
252         .read_obj_from_addr(GuestAddress(u64::from(descriptor_addr)))
253         .map_err(GuestMemoryError::ReadingGuestBufferAddress)?;
254     let buffer_addr = GuestAddress((buffer_addr_reg & !0x03u32) as u64); // The address must be aligned to four bytes.
255 
256     mem.offset_from_base(buffer_addr)
257         .map_err(GuestMemoryError::ReadingGuestBufferAddress)
258 }
259 
260 // Gets the start address and length of the buffer at `civ + offset` from the
261 // guest.
262 // This will return `None` if `civ + offset` is past LVI; if the DMA controlled
263 // stopped bit is set, such as after an underrun where CIV hits LVI; or if
264 // `civ + offset == LVI and the CELV flag is set.
next_guest_buffer( regs: &Ac97BusMasterRegs, mem: &GuestMemory, func: Ac97Function, offset: usize, ) -> AudioResult<Option<GuestBuffer>>265 fn next_guest_buffer(
266     regs: &Ac97BusMasterRegs,
267     mem: &GuestMemory,
268     func: Ac97Function,
269     offset: usize,
270 ) -> AudioResult<Option<GuestBuffer>> {
271     let func_regs = regs.func_regs(func);
272     let offset = (offset % 32) as u8;
273     let index = (func_regs.civ + offset) % 32;
274 
275     // Check that value is between `low` and `high` modulo some `n`.
276     fn check_between(low: u8, high: u8, value: u8) -> bool {
277         // If low <= high, value must be in the interval between them:
278         // 0     l     h     n
279         // ......+++++++......
280         (low <= high && (low <= value && value <= high)) ||
281             // If low > high, value must not be in the interval between them:
282             // 0       h      l  n
283             // +++++++++......++++
284             (low > high && (low <= value || value <= high))
285     }
286 
287     // Check if
288     //  * we're halted
289     //  * `index` is not between CIV and LVI (mod 32)
290     //  * `index is LVI and we've already processed LVI (SR_CELV is set)
291     //  if any of these are true `index` isn't valid.
292     if func_regs.sr & SR_DCH != 0
293         || !check_between(func_regs.civ, func_regs.lvi, index)
294         || func_regs.sr & SR_CELV != 0
295     {
296         return Ok(None);
297     }
298 
299     let offset = get_buffer_offset(func_regs, mem, index)?
300         .try_into()
301         .map_err(|_| AudioError::InvalidBufferOffset)?;
302     let frames = get_buffer_samples(func_regs, mem, index)? / regs.tube_count(func);
303 
304     Ok(Some(GuestBuffer { offset, frames }))
305 }
306 
307 // Runs and updates the offset within the stream shm where samples can be
308 // found/placed for shm playback/capture streams, respectively
309 struct AudioWorker {
310     func: Ac97Function,
311     regs: Arc<Mutex<Ac97BusMasterRegs>>,
312     mem: GuestMemory,
313     thread_run: Arc<AtomicBool>,
314     lvi_semaphore: Arc<Condvar>,
315     message_interval: Duration,
316     stream: Box<dyn ShmStream>,
317     pending_buffers: VecDeque<Option<GuestBuffer>>,
318 }
319 
320 struct AudioWorkerParams {
321     func: Ac97Function,
322     stream: Box<dyn ShmStream>,
323     pending_buffers: VecDeque<Option<GuestBuffer>>,
324     message_interval: Duration,
325 }
326 
327 impl AudioWorker {
new(bus_master: &Ac97BusMaster, args: AudioWorkerParams) -> Self328     fn new(bus_master: &Ac97BusMaster, args: AudioWorkerParams) -> Self {
329         Self {
330             func: args.func,
331             regs: bus_master.regs.clone(),
332             mem: bus_master.mem.clone(),
333             thread_run: bus_master.thread_info(args.func).thread_run.clone(),
334             lvi_semaphore: bus_master.thread_info(args.func).thread_semaphore.clone(),
335             message_interval: args.message_interval,
336             stream: args.stream,
337             pending_buffers: args.pending_buffers,
338         }
339     }
340 
341     // Runs and updates the offset within the stream shm where samples can be
342     // found/placed for shm playback/capture streams, respectively
run(&mut self) -> AudioResult<()>343     fn run(&mut self) -> AudioResult<()> {
344         let func = self.func;
345         let message_interval = self.message_interval;
346         // Set up picb.
347         {
348             let mut locked_regs = self.regs.lock();
349             locked_regs.func_regs_mut(func).picb =
350                 current_buffer_size(locked_regs.func_regs(func), &self.mem)? as u16;
351         }
352 
353         'audio_loop: while self.thread_run.load(Ordering::Relaxed) {
354             {
355                 let mut locked_regs = self.regs.lock();
356                 while locked_regs.func_regs(func).sr & SR_DCH != 0 {
357                     locked_regs = self.lvi_semaphore.wait(locked_regs);
358                     if !self.thread_run.load(Ordering::Relaxed) {
359                         break 'audio_loop;
360                     }
361                 }
362             }
363 
364             let timeout = Duration::from_secs(1);
365             let action = self
366                 .stream
367                 .wait_for_next_action_with_timeout(timeout)
368                 .map_err(AudioError::WaitForAction)?;
369 
370             let request = match action {
371                 None => {
372                     warn!("No audio message received within timeout of {:?}", timeout);
373                     continue;
374                 }
375                 Some(request) => request,
376             };
377             let start = Instant::now();
378 
379             let next_buffer = {
380                 let mut locked_regs = self.regs.lock();
381                 if self.pending_buffers.len() == 2 {
382                     // When we have two pending buffers and receive a request for
383                     // another, we know that oldest buffer has been completed.
384                     // However, if that old buffer was an empty buffer we sent
385                     // because the guest driver had no available buffers, we don't
386                     // want to mark a buffer complete.
387                     if let Some(Some(_)) = self.pending_buffers.pop_front() {
388                         buffer_completed(&mut locked_regs, &self.mem, self.func)?;
389                     }
390                 }
391 
392                 // We count the number of pending, real buffers at the server, and
393                 // then use that as our offset from CIV.
394                 let offset = self.pending_buffers.iter().filter(|e| e.is_some()).count();
395 
396                 // Get a buffer to respond to our request. If there's no buffer
397                 // available, we'll wait one buffer interval and check again.
398                 loop {
399                     if let Some(buffer) = next_guest_buffer(&locked_regs, &self.mem, func, offset)?
400                     {
401                         break Some(buffer);
402                     }
403                     let elapsed = start.elapsed();
404                     if elapsed > message_interval {
405                         break None;
406                     }
407                     locked_regs = self
408                         .lvi_semaphore
409                         .wait_timeout(locked_regs, message_interval - elapsed)
410                         .0;
411                 }
412             };
413 
414             match next_buffer {
415                 Some(ref buffer) => {
416                     let requested_frames = request.requested_frames();
417                     if requested_frames != buffer.frames {
418                         // We should be able to handle when the number of frames in
419                         // the buffer doesn't match the number of frames requested,
420                         // but we don't yet.
421                         warn!(
422                             "Stream requested {} frames but buffer had {} frames: {:?}",
423                             requested_frames, buffer.frames, buffer
424                         );
425                     }
426 
427                     request
428                         .set_buffer_offset_and_frames(
429                             buffer.offset,
430                             std::cmp::min(requested_frames, buffer.frames),
431                         )
432                         .map_err(AudioError::RespondRequest)?;
433                 }
434                 None => {
435                     request
436                         .ignore_request()
437                         .map_err(AudioError::RespondRequest)?;
438                 }
439             }
440             self.pending_buffers.push_back(next_buffer);
441         }
442         Ok(())
443     }
444 }
445 
446 #[cfg(test)]
447 mod tests {
448     use audio_streams::shm_streams::MockShmStreamSource;
449 
450     use super::*;
451     use crate::pci::ac97_bus_master::tests::capture_release_cold_reset_and_setup_ping_pong_buffers;
452     use crate::pci::ac97_bus_master::tests::check_buffer_set_and_clear_bcis;
453     use crate::pci::ac97_bus_master::tests::clear_lvb_and_reset_lvi;
454     use crate::pci::ac97_bus_master::tests::playback_release_cold_reset_and_setup_ping_pong_buffers;
455     use crate::pci::ac97_bus_master::tests::stop;
456 
457     #[test]
run_multi_tube_playback_2()458     fn run_multi_tube_playback_2() {
459         start_playback(2, 48000);
460     }
461 
462     #[test]
run_multi_tube_playback_4()463     fn run_multi_tube_playback_4() {
464         start_playback(4, 48000);
465     }
466 
467     #[test]
run_multi_tube_playback_6()468     fn run_multi_tube_playback_6() {
469         start_playback(6, 48000);
470     }
471 
472     #[test]
run_multi_rate_playback_32()473     fn run_multi_rate_playback_32() {
474         start_playback(2, 32000);
475     }
476 
477     #[test]
run_multi_rate_playback_44()478     fn run_multi_rate_playback_44() {
479         start_playback(2, 44100);
480     }
481 
482     #[test]
run_multi_rate_playback_48()483     fn run_multi_rate_playback_48() {
484         start_playback(2, 32000);
485     }
486 
start_playback(num_channels: usize, rate: u16)487     fn start_playback(num_channels: usize, rate: u16) {
488         const TIMEOUT: Duration = Duration::from_millis(500);
489         const LVI_MASK: u8 = 0x1f; // Five bits for 32 total entries.
490         const IOC_MASK: u32 = 0x8000_0000; // Interrupt on completion.
491         let num_buffers = LVI_MASK as usize + 1;
492         const BUFFER_SIZE: usize = 32768;
493         const FRAGMENT_SIZE: usize = BUFFER_SIZE / 2;
494 
495         const GUEST_ADDR_BASE: u32 = 0x100_0000;
496         let mem = GuestMemory::new(&[(GuestAddress(GUEST_ADDR_BASE as u64), 1024 * 1024 * 8)])
497             .expect("Creating guest memory failed.");
498         let stream_source = MockShmStreamSource::new();
499         let mut bm = Ac97BusMaster::new(mem.clone(), Box::new(stream_source.clone()));
500         let mut mixer = Ac97Mixer::new();
501 
502         playback_release_cold_reset_and_setup_ping_pong_buffers(
503             PO_BASE_10,
504             &mut mixer,
505             &mut bm,
506             &mem,
507             num_buffers,
508             GUEST_ADDR_BASE,
509             FRAGMENT_SIZE,
510             LVI_MASK,
511             IOC_MASK,
512         );
513 
514         assert_eq!(bm.readb(PO_CIV_14), 0);
515 
516         // Set tube count and sample rate.
517         let mut cnt = bm.readl(GLOB_CNT_2C);
518         cnt &= !GLOB_CNT_PCM_246_MASK;
519         mixer.writew(MIXER_PCM_FRONT_DAC_RATE_2C, rate);
520         if num_channels == 4 {
521             cnt |= GLOB_CNT_PCM_4;
522             mixer.writew(MIXER_PCM_SURR_DAC_RATE_2E, rate);
523         } else if num_channels == 6 {
524             cnt |= GLOB_CNT_PCM_6;
525             mixer.writew(MIXER_PCM_LFE_DAC_RATE_30, rate);
526         }
527         bm.writel(GLOB_CNT_2C, cnt, &mut mixer);
528 
529         // Start.
530         bm.writeb(PO_CR_1B, CR_IOCE | CR_RPBM, &mixer);
531         // TODO(crbug.com/1058881): The test is flaky in builder.
532         // assert_eq!(bm.readw(PO_PICB_18), 0);
533 
534         let mut stream = stream_source.get_last_stream();
535         // Trigger callback and see that CIV has not changed, since only 1
536         // buffer has been sent.
537         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
538 
539         assert_eq!(stream.num_channels(), num_channels);
540         assert_eq!(stream.frame_rate(), rate as u32);
541 
542         let mut civ = bm.readb(PO_CIV_14);
543         assert_eq!(civ, 0);
544 
545         // After two more callbacks, CIV should now be 1 since we know that the
546         // first buffer must have been played.
547         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
548         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
549         civ = bm.readb(PO_CIV_14);
550         assert_eq!(civ, 1);
551 
552         check_buffer_set_and_clear_bcis(PO_BASE_10, &mixer, &mut bm);
553 
554         std::thread::sleep(Duration::from_millis(50));
555         let picb = bm.readw(PO_PICB_18, &mixer);
556         let pos = (FRAGMENT_SIZE - (picb as usize * 2)) / 4;
557 
558         // Check that frames are consumed at least at a reasonable rate.
559         // This can't be exact as during unit tests the thread scheduling is highly variable, so the
560         // test only checks that some samples are consumed.
561         assert!(pos > 0);
562         assert!(bm.readw(PO_SR_16, &mixer) & SR_DCH == 0); // DMA is running.
563 
564         // Set last valid to next buffer to be sent and trigger callback so we hit it.
565         bm.writeb(PO_LVI_15, civ + 2, &mixer);
566         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
567         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
568         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
569         assert!(bm.readw(PO_SR_16, &mixer) & SR_LVBCI != 0); // Hit last buffer
570         assert!(bm.readw(PO_SR_16, &mixer) & SR_DCH == SR_DCH); // DMA stopped because of lack of buffers.
571         assert!(bm.readw(PO_SR_16, &mixer) & SR_CELV == SR_CELV); // Processed the last buffer
572         assert_eq!(bm.readb(PO_LVI_15), bm.readb(PO_CIV_14));
573         assert!(
574             bm.readl(GLOB_STA_30) & GS_POINT != 0,
575             "POINT bit should be set."
576         );
577 
578         clear_lvb_and_reset_lvi(PO_BASE_10, &mixer, &mut bm, LVI_MASK);
579 
580         let restart_civ = bm.readb(PO_CIV_14);
581         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
582         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
583         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
584         assert!(bm.readb(PO_CIV_14) != restart_civ);
585 
586         stop(PO_BASE_10, GS_POINT, &mixer, &mut bm);
587     }
588 
589     #[test]
run_capture_input()590     fn run_capture_input() {
591         start_capture(Ac97Function::Input);
592     }
593 
594     #[test]
run_capture_microphone()595     fn run_capture_microphone() {
596         start_capture(Ac97Function::Microphone);
597     }
598 
start_capture(func: Ac97Function)599     fn start_capture(func: Ac97Function) {
600         const TIMEOUT: Duration = Duration::from_millis(500);
601         const LVI_MASK: u8 = 0x1f; // Five bits for 32 total entries.
602         const IOC_MASK: u32 = 0x8000_0000; // Interrupt on completion.
603         let num_buffers = LVI_MASK as usize + 1;
604         const BUFFER_SIZE: usize = 32768;
605         const FRAGMENT_SIZE: usize = BUFFER_SIZE / 2;
606 
607         const GUEST_ADDR_BASE: u32 = 0x100_0000;
608         let mem = GuestMemory::new(&[(GuestAddress(GUEST_ADDR_BASE as u64), 1024 * 1024 * 8)])
609             .expect("Creating guest memory failed.");
610         let stream_source = MockShmStreamSource::new();
611         let mut bm = Ac97BusMaster::new(mem.clone(), Box::new(stream_source.clone()));
612         let mut mixer = Ac97Mixer::new();
613 
614         let (base, bdbar_addr, lvi_addr, cr_addr, civ_addr, pcib_addr, sr_addr, int_mask) =
615             match func {
616                 Ac97Function::Input => (
617                     PI_BASE_00,
618                     PI_BDBAR_00,
619                     PI_LVI_05,
620                     PI_CR_0B,
621                     PI_CIV_04,
622                     PI_PICB_08,
623                     PI_SR_06,
624                     GS_PIINT,
625                 ),
626                 Ac97Function::Microphone => (
627                     MC_BASE_20,
628                     MC_BDBAR_20,
629                     MC_LVI_25,
630                     MC_CR_2B,
631                     MC_CIV_24,
632                     MC_PICB_28,
633                     MC_SR_26,
634                     GS_MINT,
635                 ),
636                 _ => {
637                     panic!("Invalid Ac97Function.");
638                 }
639             };
640 
641         capture_release_cold_reset_and_setup_ping_pong_buffers(
642             bdbar_addr,
643             &mut mixer,
644             &mut bm,
645             &mem,
646             num_buffers,
647             GUEST_ADDR_BASE,
648             FRAGMENT_SIZE,
649             LVI_MASK,
650             IOC_MASK,
651         );
652 
653         // Start.
654         bm.writeb(cr_addr, CR_IOCE | CR_RPBM, &mixer);
655         // TODO(crbug.com/1086337): Test flakiness in build time.
656         // assert_eq!(bm.readw(PI_PICB_08), 0);
657 
658         let mut stream = stream_source.get_last_stream();
659         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
660 
661         // CIV is 1 here since we preemptively sent two buffer indices to the
662         // server before creating the stream. When we triggered the callback
663         // above, that means the first of those buffers was filled, so CIV
664         // increments to 1.
665         let civ = bm.readb(civ_addr);
666         assert_eq!(civ, 1);
667         std::thread::sleep(Duration::from_millis(20));
668         let picb = bm.readw(pcib_addr, &mixer);
669         assert!(picb > 0);
670         assert!(bm.readw(sr_addr, &mixer) & SR_DCH == 0); // DMA is running.
671 
672         // Trigger 2 callbacks so that we'll move to buffer 3 since at that
673         // point we can be certain that buffers 1 and 2 have been captured to.
674         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
675         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
676         assert_eq!(bm.readb(civ_addr), 3);
677 
678         let civ = bm.readb(civ_addr);
679         // Sets LVI to CIV + 2 to trigger last buffer hit
680         bm.writeb(lvi_addr, civ + 2, &mixer);
681         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
682         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
683         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
684         assert_ne!(bm.readw(sr_addr, &mixer) & SR_LVBCI, 0); // Hit last buffer
685         assert_eq!(bm.readw(sr_addr, &mixer) & SR_DCH, SR_DCH); // DMA stopped because of lack of buffers.
686         assert_eq!(bm.readw(sr_addr, &mixer) & SR_CELV, SR_CELV);
687         assert_eq!(bm.readb(lvi_addr), bm.readb(civ_addr));
688         assert!(
689             bm.readl(GLOB_STA_30) & int_mask != 0,
690             "int_mask bit should be set."
691         );
692 
693         clear_lvb_and_reset_lvi(base, &mixer, &mut bm, LVI_MASK);
694 
695         let restart_civ = bm.readb(civ_addr);
696         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
697         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
698         assert!(stream.trigger_callback_with_timeout(TIMEOUT));
699         assert_ne!(bm.readb(civ_addr), restart_civ);
700 
701         stop(base, int_mask, &mixer, &mut bm);
702     }
703 }
704