StreamFormat

Struct StreamFormat 

Source
pub struct StreamFormat {
    pub sample_rate: f64,
    pub sample_format: SampleFormat,
    pub flags: LinearPcmFlags,
    pub channels: u32,
}
Expand description

A representation of the AudioStreamBasicDescription specifically for use with the AudioUnit API.

By using a type specific to the audio unit API, we can remove a lot of unnecessary boilerplate that is normally associated with the AudioStreamBasicDescription.

Seeing as LinearPCM data (the AudioFormat used by the AudioUnit API) implies a single frame per packet, we can infer many of the fields in an ASBD from the sample type.

bytes_per_packet = size_of::<S>() bytes_per_frame = size_of::<S>() frames_per_packet = 1 bits_per_channel = size_of::<S>() / channels_per_frame * 8

A packet is a collection of one or more contiguous frames. In linear PCM audio, a packet is always a single frame.

from Core Audio Overview

The canonical formats in Core Audio are as follows:

  • iOS input and output: Linear PCM with 16-bit integer samples.
  • iOS audio units and other audio processing: Noninterleaved linear PCM with 8.24-bit fixed-point samples
  • Mac input and output: Linear PCM with 32-bit floating point samples.
  • Mac audio units and other audio processing: Noninterleaved linear PCM with 32-bit floating point samples.

Fields§

§sample_rate: f64

The number of frames of audio data per second used to represent a signal.

§sample_format: SampleFormat

The sample format used to represent the audio data.

In OS X, Core Audio expects audio data to be in native-endian, 32-bit floating-point, linear PCM format.

iOS uses integer and fixed-point audio data. The result is faster calculations and less battery drain when processing audio. iOS provides a Converter audio unit and inclues the interfaces from Audio Converter Services (TODO: look into exposing this).

§flags: LinearPcmFlags

The format flags for the given StreamFormat.

§channels: u32

The number of channels.

Implementations§

Source§

impl StreamFormat

Source

pub fn from_asbd( asbd: AudioStreamBasicDescription, ) -> Result<StreamFormat, Error>

Convert an AudioStreamBasicDescription into a StreamFormat.

Note: audio_unit::StreamFormat exclusively uses the LinearPCM AudioFormat. This is as specified in the documentation:

Specify kAudioFormatLinearPCM for the mFormatID field. Audio units use uncompressed audio data, so this is the correct format identifier to use whenever you work with audio units.

Audio Unit Hosting Guide for iOS

Returns an Error if the AudioFormat inferred by the ASBD is not LinearPCM.

Returns an Error if the sample format of the asbd cannot be matched to a format supported by SampleFormat.

Source

pub fn to_asbd(self) -> AudioStreamBasicDescription

Convert a StreamFormat into an AudioStreamBasicDescription. Note that this function assumes that only packed formats are used. This only affects I24, since all other formats supported by StreamFormat are always packed.

Examples found in repository?
examples/feedback.rs (line 58)
22fn main() -> Result<(), coreaudio::Error> {
23    let mut input_audio_unit =
24        audio_unit_from_device_id(get_default_device_id(true).unwrap(), true)?;
25    let mut output_audio_unit =
26        audio_unit_from_device_id(get_default_device_id(false).unwrap(), false)?;
27
28    let format_flag = match SAMPLE_FORMAT {
29        SampleFormat::F32 => LinearPcmFlags::IS_FLOAT,
30        SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => {
31            LinearPcmFlags::IS_SIGNED_INTEGER
32        }
33        _ => {
34            unimplemented!("Other formats are not implemented for this example.");
35        }
36    };
37
38    // Using IS_NON_INTERLEAVED everywhere because data::Interleaved is commented out / not implemented
39    let in_stream_format = StreamFormat {
40        sample_rate: SAMPLE_RATE,
41        sample_format: SAMPLE_FORMAT,
42        flags: format_flag | LinearPcmFlags::IS_PACKED | LinearPcmFlags::IS_NON_INTERLEAVED,
43        // audio_unit.set_input_callback is hardcoded to 1 buffer, and when using non_interleaved
44        // we are forced to 1 channel
45        channels: 1,
46    };
47
48    let out_stream_format = StreamFormat {
49        sample_rate: SAMPLE_RATE,
50        sample_format: SAMPLE_FORMAT,
51        flags: format_flag | LinearPcmFlags::IS_PACKED | LinearPcmFlags::IS_NON_INTERLEAVED,
52        // you can change this to 1
53        channels: 2,
54    };
55
56    println!("input={:#?}", &in_stream_format);
57    println!("output={:#?}", &out_stream_format);
58    println!("input_asbd={:#?}", &in_stream_format.to_asbd());
59    println!("output_asbd={:#?}", &out_stream_format.to_asbd());
60
61    let id = kAudioUnitProperty_StreamFormat;
62    let asbd = in_stream_format.to_asbd();
63    input_audio_unit.set_property(id, Scope::Output, Element::Input, Some(&asbd))?;
64
65    let asbd = out_stream_format.to_asbd();
66    output_audio_unit.set_property(id, Scope::Input, Element::Output, Some(&asbd))?;
67
68    let buffer_left = Arc::new(Mutex::new(VecDeque::<S>::new()));
69    let producer_left = buffer_left.clone();
70    let consumer_left = buffer_left.clone();
71    let buffer_right = Arc::new(Mutex::new(VecDeque::<S>::new()));
72    let producer_right = buffer_right.clone();
73    let consumer_right = buffer_right.clone();
74
75    // seed roughly 1 second of data to create a delay in the feedback loop for easier testing
76    for buffer in vec![buffer_left, buffer_right] {
77        let mut buffer = buffer.lock().unwrap();
78        for _ in 0..(out_stream_format.sample_rate as i32) {
79            buffer.push_back(0 as S);
80        }
81    }
82
83    type Args = render_callback::Args<data::NonInterleaved<S>>;
84
85    input_audio_unit.set_input_callback(move |args| {
86        let Args {
87            num_frames,
88            mut data,
89            ..
90        } = args;
91        // Print the number of frames the callback provides.
92        // Included to aid understanding, don't use println and other things
93        // that may block for an unknown amount of time inside the callback
94        // of a real application.
95        println!("input cb {} frames", num_frames);
96        let buffer_left = producer_left.lock().unwrap();
97        let buffer_right = producer_right.lock().unwrap();
98        let mut buffers = vec![buffer_left, buffer_right];
99        for i in 0..num_frames {
100            for (ch, channel) in data.channels_mut().enumerate() {
101                let value: S = channel[i];
102                buffers[ch].push_back(value);
103            }
104        }
105        Ok(())
106    })?;
107    input_audio_unit.start()?;
108
109    output_audio_unit.set_render_callback(move |args: Args| {
110        let Args {
111            num_frames,
112            mut data,
113            ..
114        } = args;
115        // Print the number of frames the callback requests.
116        // Included to aid understanding, don't use println and other things
117        // that may block for an unknown amount of time inside the callback
118        // of a real application.
119        println!("output cb {} frames", num_frames);
120        let buffer_left = consumer_left.lock().unwrap();
121        let buffer_right = consumer_right.lock().unwrap();
122        let mut buffers = vec![buffer_left, buffer_right];
123        for i in 0..num_frames {
124            // Default other channels to copy value from first channel as a fallback
125            let zero: S = 0 as S;
126            let f: S = *buffers[0].front().unwrap_or(&zero);
127            for (ch, channel) in data.channels_mut().enumerate() {
128                let sample: S = buffers[ch].pop_front().unwrap_or(f);
129                channel[i] = sample;
130            }
131        }
132        Ok(())
133    })?;
134    output_audio_unit.start()?;
135
136    std::thread::sleep(std::time::Duration::from_millis(100000));
137
138    Ok(())
139}
More examples
Hide additional examples
examples/feedback_interleaved.rs (line 64)
24fn main() -> Result<(), coreaudio::Error> {
25    let input_device_id = get_default_device_id(true).unwrap();
26    let output_device_id = get_default_device_id(false).unwrap();
27    println!(
28        "Input device: {}",
29        get_device_name(input_device_id).unwrap()
30    );
31    println!(
32        "Output device: {}",
33        get_device_name(output_device_id).unwrap()
34    );
35    let mut input_audio_unit = audio_unit_from_device_id(input_device_id, true)?;
36    let mut output_audio_unit = audio_unit_from_device_id(output_device_id, false)?;
37
38    let format_flag = match SAMPLE_FORMAT {
39        SampleFormat::F32 => LinearPcmFlags::IS_FLOAT | LinearPcmFlags::IS_PACKED,
40        SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => {
41            LinearPcmFlags::IS_SIGNED_INTEGER | LinearPcmFlags::IS_PACKED
42        }
43        _ => {
44            unimplemented!("Please use one of the packed formats");
45        }
46    };
47
48    let in_stream_format = StreamFormat {
49        sample_rate: SAMPLE_RATE,
50        sample_format: SAMPLE_FORMAT,
51        flags: format_flag,
52        channels: 2,
53    };
54
55    let out_stream_format = StreamFormat {
56        sample_rate: SAMPLE_RATE,
57        sample_format: SAMPLE_FORMAT,
58        flags: format_flag,
59        channels: 2,
60    };
61
62    println!("input={:#?}", &in_stream_format);
63    println!("output={:#?}", &out_stream_format);
64    println!("input_asbd={:#?}", &in_stream_format.to_asbd());
65    println!("output_asbd={:#?}", &out_stream_format.to_asbd());
66
67    let id = kAudioUnitProperty_StreamFormat;
68    let asbd = in_stream_format.to_asbd();
69    input_audio_unit.set_property(id, Scope::Output, Element::Input, Some(&asbd))?;
70
71    let asbd = out_stream_format.to_asbd();
72    output_audio_unit.set_property(id, Scope::Input, Element::Output, Some(&asbd))?;
73
74    let buffer_left = Arc::new(Mutex::new(VecDeque::<S>::new()));
75    let producer_left = buffer_left.clone();
76    let consumer_left = buffer_left.clone();
77    let buffer_right = Arc::new(Mutex::new(VecDeque::<S>::new()));
78    let producer_right = buffer_right.clone();
79    let consumer_right = buffer_right.clone();
80
81    // Register a rate listener for playback
82    let mut listener_pb = RateListener::new(output_device_id, None);
83    listener_pb.register()?;
84
85    // Register a rate listener for capture
86    let mut listener_cap = RateListener::new(input_device_id, None);
87    listener_cap.register()?;
88
89    // seed roughly 1 second of data to create a delay in the feedback loop for easier testing
90    for buffer in vec![buffer_left, buffer_right] {
91        let mut buffer = buffer.lock().unwrap();
92        for _ in 0..(out_stream_format.sample_rate as i32) {
93            buffer.push_back(0 as S);
94        }
95    }
96
97    type Args = render_callback::Args<data::Interleaved<S>>;
98
99    input_audio_unit.set_input_callback(move |args| {
100        let Args {
101            num_frames, data, ..
102        } = args;
103        // Print the number of frames the callback requests.
104        // Included to aid understanding, don't use println and other things
105        // that may block for an unknown amount of time inside the callback
106        // of a real application.
107        println!("input cb {} frames", num_frames);
108        let buffer_left = producer_left.lock().unwrap();
109        let buffer_right = producer_right.lock().unwrap();
110        let mut buffers = vec![buffer_left, buffer_right];
111        for i in 0..num_frames {
112            for channel in 0..2 {
113                let value: S = data.buffer[2 * i + channel];
114                buffers[channel].push_back(value);
115            }
116        }
117        Ok(())
118    })?;
119    input_audio_unit.start()?;
120
121    output_audio_unit.set_render_callback(move |args: Args| {
122        let Args {
123            num_frames, data, ..
124        } = args;
125        // Print the number of frames the callback requests.
126        println!("output cb {} frames", num_frames);
127        let buffer_left = consumer_left.lock().unwrap();
128        let buffer_right = consumer_right.lock().unwrap();
129        let mut buffers = vec![buffer_left, buffer_right];
130        for i in 0..num_frames {
131            // Default other channels to copy value from first channel as a fallback
132            let zero: S = 0 as S;
133            let f: S = *buffers[0].front().unwrap_or(&zero);
134            for channel in 0..2 {
135                let sample: S = buffers[channel].pop_front().unwrap_or(f);
136                data.buffer[2 * i + channel] = sample;
137            }
138        }
139        Ok(())
140    })?;
141    output_audio_unit.start()?;
142    for _ in 0..1000 {
143        std::thread::sleep(std::time::Duration::from_millis(100));
144        if listener_cap.get_nbr_values() > 0 {
145            println!("capture rate change: {:?}", listener_cap.drain_values());
146        }
147        if listener_pb.get_nbr_values() > 0 {
148            println!("playback rate change: {:?}", listener_pb.drain_values());
149        }
150    }
151    Ok(())
152}
examples/sine_advanced.rs (line 105)
54fn main() -> Result<(), coreaudio::Error> {
55    let frequency_hz_l = 1000.;
56    let frequency_hz_r = 1200.;
57    let volume = 0.95;
58    let mut samples_l = SineWaveGenerator::new(frequency_hz_l, volume);
59    let mut samples_r = SineWaveGenerator::new(frequency_hz_r, volume);
60
61    // Construct an Output audio unit that delivers audio to the default output device.
62    let audio_unit_id = get_default_device_id(false).unwrap();
63    let mut audio_unit = audio_unit_from_device_id(audio_unit_id, false)?;
64
65    let pid = get_hogging_pid(audio_unit_id)?;
66    if pid != -1 {
67        println!("Device is owned by another process with pid {}!", pid);
68    } else {
69        println!("Device is free, trying to get exclusive access..");
70        let new_pid = toggle_hog_mode(audio_unit_id)?;
71        let process_id = process::id();
72        if new_pid == process_id as i32 {
73            println!("We have exclusive access.");
74        } else {
75            println!(
76                "Could not get exclusive access. Process pid: {}, new pid value: {}",
77                process_id, new_pid
78            );
79        }
80    }
81
82    let mut format_flag = match SAMPLE_FORMAT {
83        SampleFormat::F32 => LinearPcmFlags::IS_FLOAT | LinearPcmFlags::IS_PACKED,
84        SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => {
85            LinearPcmFlags::IS_SIGNED_INTEGER | LinearPcmFlags::IS_PACKED
86        }
87        _ => {
88            unimplemented!("Please use one of the packed formats");
89        }
90    };
91
92    if !INTERLEAVED {
93        format_flag = format_flag | LinearPcmFlags::IS_NON_INTERLEAVED;
94    }
95
96    let stream_format = StreamFormat {
97        sample_rate: SAMPLE_RATE,
98        sample_format: SAMPLE_FORMAT,
99        flags: format_flag,
100        // you can change this to 1
101        channels: 2,
102    };
103
104    println!("stream format={:#?}", &stream_format);
105    println!("asbd={:#?}", &stream_format.to_asbd());
106
107    // Lets print all supported formats, disabled for now since it often crashes.
108    println!("All supported formats");
109    let formats = get_supported_physical_stream_formats(audio_unit_id)?;
110    for fmt in formats {
111        println!("{:?}", &fmt);
112    }
113
114    // set the sample rate. This isn't actually needed since the sample rate
115    // will anyway be changed when setting the sample format later.
116    // Keeping it here as an example.
117    //println!("set device sample rate");
118    //set_device_sample_rate(audio_unit_id, SAMPLE_RATE)?;
119
120    println!("setting hardware (physical) format");
121    let hw_stream_format = StreamFormat {
122        sample_rate: SAMPLE_RATE,
123        sample_format: SampleFormat::I16,
124        flags: LinearPcmFlags::empty(),
125        channels: 2,
126    };
127
128    let hw_asbd = find_matching_physical_format(audio_unit_id, hw_stream_format)
129        .ok_or(coreaudio::Error::UnsupportedStreamFormat)?;
130
131    println!("asbd: {:?}", hw_asbd);
132
133    // Note that using a StreamFormat here is convenient, but it only supports a few sample formats.
134    // Setting the format to for example 24 bit integers requires using an ASBD.
135    set_device_physical_stream_format(audio_unit_id, hw_asbd)?;
136
137    println!("write audio unit StreamFormat property");
138    let id = kAudioUnitProperty_StreamFormat;
139    let asbd = stream_format.to_asbd();
140    audio_unit.set_property(id, Scope::Input, Element::Output, Some(&asbd))?;
141
142    // For this example, our sine wave expects `f32` data.
143    assert!(SampleFormat::F32 == stream_format.sample_format);
144
145    // Register rate and alive listeners
146    let mut rate_listener = RateListener::new(audio_unit_id, None);
147    rate_listener.register()?;
148    let mut alive_listener = AliveListener::new(audio_unit_id);
149    alive_listener.register()?;
150
151    if INTERLEAVED {
152        println!("Register interleaved callback");
153        type Args = render_callback::Args<data::Interleaved<f32>>;
154        audio_unit.set_render_callback(move |args| {
155            let Args {
156                num_frames, data, ..
157            } = args;
158            // Print the number of frames the callback requests.
159            // Included to aid understanding, don't use println and other things
160            // that may block for an unknown amount of time inside the callback
161            // of a real application.
162            println!("frames: {}", num_frames);
163            for i in 0..num_frames {
164                let sample_l = samples_l.next().unwrap();
165                let sample_r = samples_r.next().unwrap();
166                data.buffer[2 * i] = sample_l;
167                data.buffer[2 * i + 1] = sample_r;
168            }
169            Ok(())
170        })?;
171    } else {
172        println!("Register non-interleaved callback");
173        type Args = render_callback::Args<data::NonInterleaved<f32>>;
174        audio_unit.set_render_callback(move |args| {
175            let Args {
176                num_frames,
177                mut data,
178                ..
179            } = args;
180            for i in 0..num_frames {
181                let sample_l = samples_l.next().unwrap();
182                let sample_r = samples_r.next().unwrap();
183                let mut channels = data.channels_mut();
184                let left = channels.next().unwrap();
185                left[i] = sample_l;
186                let right = channels.next().unwrap();
187                right[i] = sample_r;
188            }
189            Ok(())
190        })?;
191    }
192    audio_unit.start()?;
193
194    for _ in 0..100 {
195        std::thread::sleep(std::time::Duration::from_millis(100));
196        // print all sample change events
197        println!("rate events: {:?}", rate_listener.copy_values());
198        println!("alive state: {}", alive_listener.is_alive());
199    }
200
201    // Release exclusive access, not really needed as the process exits anyway after this.
202    let owner_pid = get_hogging_pid(audio_unit_id)?;
203    let process_id = process::id();
204    if owner_pid == process_id as i32 {
205        println!("Releasing exclusive access");
206        let new_pid = toggle_hog_mode(audio_unit_id)?;
207        if new_pid == -1 {
208            println!("Exclusive access released.");
209        } else {
210            println!(
211                "Could not release exclusive access. Process pid: {}, new pid value: {}",
212                process_id, new_pid
213            );
214        }
215    }
216    Ok(())
217}

Trait Implementations§

Source§

impl Clone for StreamFormat

Source§

fn clone(&self) -> StreamFormat

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for StreamFormat

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Copy for StreamFormat

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> AutoreleaseSafe for T
where T: ?Sized,