fmod/core/system/recording.rs
1// Copyright (c) 2024 Lily Lyons
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7use std::{
8 ffi::{c_int, c_uint},
9 mem::MaybeUninit,
10};
11
12use fmod_sys::*;
13use lanyard::Utf8CString;
14
15use crate::{get_string, DriverState, Guid, Sound, SpeakerMode, System};
16
17impl System {
18 /// Retrieves the number of recording devices available for this output mode.
19 /// Use this to enumerate all recording devices possible so that the user can select one.
20 pub fn get_recording_driver_count(&self) -> Result<(c_int, c_int)> {
21 let mut drivers = 0;
22 let mut connected = 0;
23 unsafe {
24 FMOD_System_GetRecordNumDrivers(self.inner, &mut drivers, &mut connected)
25 .to_result()?;
26 }
27 Ok((drivers, connected))
28 }
29
30 /// Retrieves identification information about an audio device specified by its index, and specific to the output mode.
31 pub fn get_record_driver_info(
32 &self,
33 id: c_int,
34 ) -> Result<(Utf8CString, Guid, c_int, SpeakerMode, c_int, DriverState)> {
35 let mut guid = MaybeUninit::zeroed();
36 let mut system_rate = 0;
37 let mut speaker_mode = 0;
38 let mut speaker_mode_channels = 0;
39 let mut state = 0;
40 let name = get_string(|name| unsafe {
41 FMOD_System_GetRecordDriverInfo(
42 self.inner,
43 id,
44 name.as_mut_ptr().cast(),
45 name.len() as c_int,
46 guid.as_mut_ptr(),
47 &mut system_rate,
48 &mut speaker_mode,
49 &mut speaker_mode_channels,
50 &mut state,
51 )
52 })?;
53 unsafe {
54 let guid = guid.assume_init().into();
55 let speaker_mode = speaker_mode.try_into()?;
56 let state = state.into();
57 Ok((
58 name,
59 guid,
60 system_rate,
61 speaker_mode,
62 speaker_mode_channels,
63 state,
64 ))
65 }
66 }
67
68 /// Retrieves the current recording position of the record buffer in PCM samples.
69 ///
70 /// Will return [`FMOD_RESULT::FMOD_ERR_RECORD_DISCONNECTED`] if the driver is unplugged.
71 ///
72 /// The position will return to 0 when [`System::record_stop`] is called or when a non-looping recording reaches the end.
73 ///
74 /// PS4 specific note: Record devices are virtual so 'position' will continue to update if the device is unplugged (the OS is generating silence).
75 /// This function will still report [`FMOD_RESULT::FMOD_ERR_RECORD_DISCONNECTED`] for your information though.
76 pub fn get_record_position(&self, id: c_int) -> Result<c_uint> {
77 let mut position = 0;
78 unsafe {
79 FMOD_System_GetRecordPosition(self.inner, id, &mut position).to_result()?;
80 }
81 Ok(position)
82 }
83
84 /// Starts the recording engine recording to a pre-created Sound object.
85 ///
86 /// Will return [`FMOD_RESULT::FMOD_ERR_RECORD_DISCONNECTED`] if the driver is unplugged.
87 ///
88 /// Sound must be created as [`SoundMode::CREATE_SAMPLE`].
89 /// Raw PCM data can be accessed with Sound::lock, Sound::unlock and [`System::get_record_position`].
90 ///
91 /// Recording from the same driver a second time will stop the first recording.
92 ///
93 /// For lowest latency set the [`Sound`] sample rate to the rate returned by System::getRecordDriverInfo,
94 /// otherwise a resampler will be allocated to handle the difference in frequencies, which adds latency.
95 pub fn record_start(&self, id: c_int, sound: Sound, do_loop: bool) -> Result<()> {
96 unsafe { FMOD_System_RecordStart(self.inner, id, sound.into(), do_loop.into()).to_result() }
97 }
98
99 /// Stops the recording engine from recording to a pre-created Sound object.
100 ///
101 /// Returns no error if unplugged or already stopped.
102 pub fn record_stop(&self, id: c_int) -> Result<()> {
103 unsafe { FMOD_System_RecordStop(self.inner, id).to_result() }
104 }
105
106 /// Retrieves the state of the FMOD recording API, ie if it is currently recording or not.
107 ///
108 /// Recording can be started with [`System::record_start`] and stopped with [`System::record_stop`].
109 ///
110 /// Will return [`FMOD_RESULT::FMOD_ERR_RECORD_DISCONNECTED`] if the driver is unplugged.
111 ///
112 /// PS4 specific note: Record devices are virtual so 'position' will continue to update if the device is unplugged (the OS is generating silence).
113 /// This function will still report [`FMOD_RESULT::FMOD_ERR_RECORD_DISCONNECTED`] for your information though.
114 pub fn is_recording(&self, id: c_int) -> Result<bool> {
115 let mut recording = FMOD_BOOL::FALSE;
116 unsafe {
117 FMOD_System_IsRecording(self.inner, id, &mut recording).to_result()?;
118 }
119 Ok(recording.into())
120 }
121}