adds support for buffersizes in webaudio and emscripten
This commit is contained in:
parent
cf1a928b84
commit
7c1adce330
|
@ -346,7 +346,6 @@ impl Device {
|
||||||
let buffer_size_range = SupportedBufferSize::Range {
|
let buffer_size_range = SupportedBufferSize::Range {
|
||||||
min: min_buffer_size as u32,
|
min: min_buffer_size as u32,
|
||||||
max: max_buffer_size as u32,
|
max: max_buffer_size as u32,
|
||||||
requires_power_of_two: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output = Vec::with_capacity(
|
let mut output = Vec::with_capacity(
|
||||||
|
|
|
@ -135,7 +135,6 @@ impl Device {
|
||||||
let buffer_size = SupportedBufferSize::Range {
|
let buffer_size = SupportedBufferSize::Range {
|
||||||
min: min as u32,
|
min: min as u32,
|
||||||
max: max as u32,
|
max: max as u32,
|
||||||
requires_power_of_two: false,
|
|
||||||
};
|
};
|
||||||
// Map th ASIO sample type to a CPAL sample type
|
// Map th ASIO sample type to a CPAL sample type
|
||||||
let data_type = self.driver.input_data_type().map_err(default_config_err)?;
|
let data_type = self.driver.input_data_type().map_err(default_config_err)?;
|
||||||
|
@ -157,7 +156,6 @@ impl Device {
|
||||||
let buffer_size = SupportedBufferSize::Range {
|
let buffer_size = SupportedBufferSize::Range {
|
||||||
min: min as u32,
|
min: min as u32,
|
||||||
max: max as u32,
|
max: max as u32,
|
||||||
requires_power_of_two: false,
|
|
||||||
};
|
};
|
||||||
let data_type = self.driver.output_data_type().map_err(default_config_err)?;
|
let data_type = self.driver.output_data_type().map_err(default_config_err)?;
|
||||||
let sample_format = convert_data_type(&data_type)
|
let sample_format = convert_data_type(&data_type)
|
||||||
|
|
|
@ -925,6 +925,5 @@ fn get_io_buffer_frame_size_range(
|
||||||
Ok(SupportedBufferSize::Range {
|
Ok(SupportedBufferSize::Range {
|
||||||
min: buffer_size_range.mMinimum as u32,
|
min: buffer_size_range.mMinimum as u32,
|
||||||
max: buffer_size_range.mMaximum as u32,
|
max: buffer_size_range.mMaximum as u32,
|
||||||
requires_power_of_two: false,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,10 @@ use stdweb::web::TypedArray;
|
||||||
use stdweb::Reference;
|
use stdweb::Reference;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
BufferSize, BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
|
||||||
InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError, SampleFormat,
|
InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError, SampleFormat,
|
||||||
StreamConfig, StreamError, SupportedStreamConfig, SupportedStreamConfigRange,
|
SampleRate, StreamConfig, StreamError, SupportedBufferSize, SupportedStreamConfig,
|
||||||
SupportedStreamConfigsError,
|
SupportedStreamConfigRange, SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
use traits::{DeviceTrait, HostTrait, StreamTrait};
|
||||||
|
|
||||||
|
@ -41,6 +41,16 @@ pub struct StreamId(usize);
|
||||||
pub type SupportedInputConfigs = ::std::vec::IntoIter<SupportedStreamConfigRange>;
|
pub type SupportedInputConfigs = ::std::vec::IntoIter<SupportedStreamConfigRange>;
|
||||||
pub type SupportedOutputConfigs = ::std::vec::IntoIter<SupportedStreamConfigRange>;
|
pub type SupportedOutputConfigs = ::std::vec::IntoIter<SupportedStreamConfigRange>;
|
||||||
|
|
||||||
|
const MIN_CHANNELS: u16 = 1;
|
||||||
|
const MAX_CHANNELS: u16 = 32;
|
||||||
|
const MIN_SAMPLE_RATE: SampleRate = SampleRate(8_000);
|
||||||
|
const MAX_SAMPLE_RATE: SampleRate = SampleRate(96_000);
|
||||||
|
const DEFAULT_SAMPLE_RATE: SampleRate = SampleRate(44_100);
|
||||||
|
const MIN_BUFFER_SIZE: u32 = 1;
|
||||||
|
const MAX_BUFFER_SIZE: u32 = std::u32::MAX;
|
||||||
|
const DEFAULT_BUFFER_SIZE: usize = 2048;
|
||||||
|
const SUPPORTED_SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
|
||||||
|
|
||||||
impl Host {
|
impl Host {
|
||||||
pub fn new() -> Result<Self, crate::HostUnavailable> {
|
pub fn new() -> Result<Self, crate::HostUnavailable> {
|
||||||
stdweb::initialize();
|
stdweb::initialize();
|
||||||
|
@ -71,21 +81,20 @@ impl Device {
|
||||||
fn supported_output_configs(
|
fn supported_output_configs(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
|
) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
|
||||||
// TODO: right now cpal's API doesn't allow flexibility here
|
let buffer_size = SupportedBufferSize::Range {
|
||||||
// "44100" and "2" (channels) have also been hard-coded in the rest of the code ; if
|
min: MIN_BUFFER_SIZE,
|
||||||
// this ever becomes more flexible, don't forget to change that
|
max: MAX_BUFFER_SIZE,
|
||||||
// According to https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/createBuffer
|
};
|
||||||
// browsers must support 1 to 32 channels at leats and 8,000 Hz to 96,000 Hz.
|
let configs: Vec<_> = (MIN_CHANNELS..=MAX_CHANNELS)
|
||||||
//
|
.map(|channels| SupportedStreamConfigRange {
|
||||||
// UPDATE: We can do this now. Might be best to use `crate::COMMON_SAMPLE_RATES` and
|
channels,
|
||||||
// filter out those that lay outside the range specified above.
|
min_sample_rate: MIN_SAMPLE_RATE,
|
||||||
Ok(vec![SupportedStreamConfigRange {
|
max_sample_rate: MAX_SAMPLE_RATE,
|
||||||
channels: 2,
|
buffer_size: buffer_size.clone(),
|
||||||
min_sample_rate: ::SampleRate(44100),
|
sample_format: SUPPORTED_SAMPLE_FORMAT,
|
||||||
max_sample_rate: ::SampleRate(44100),
|
})
|
||||||
sample_format: ::SampleFormat::F32,
|
.collect();
|
||||||
}]
|
Ok(configs.into_iter())
|
||||||
.into_iter())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
|
fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
|
||||||
|
@ -93,12 +102,15 @@ impl Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
|
fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
|
||||||
// TODO: because it is hard coded, see supported_output_configs.
|
const EXPECT: &str = "expected at least one valid webaudio stream config";
|
||||||
Ok(SupportedStreamConfig {
|
let mut configs: Vec<_> = self.supported_output_configs().expect(EXPECT).collect();
|
||||||
channels: 2,
|
configs.sort_by(|a, b| a.cmp_default_heuristics(b));
|
||||||
sample_rate: ::SampleRate(44100),
|
let config = configs
|
||||||
sample_format: ::SampleFormat::F32,
|
.into_iter()
|
||||||
})
|
.next()
|
||||||
|
.expect(EXPECT)
|
||||||
|
.with_sample_rate(DEFAULT_SAMPLE_RATE);
|
||||||
|
Ok(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +181,7 @@ impl DeviceTrait for Device {
|
||||||
|
|
||||||
fn build_output_stream_raw<D, E>(
|
fn build_output_stream_raw<D, E>(
|
||||||
&self,
|
&self,
|
||||||
_config: &StreamConfig,
|
config: &StreamConfig,
|
||||||
sample_format: SampleFormat,
|
sample_format: SampleFormat,
|
||||||
data_callback: D,
|
data_callback: D,
|
||||||
error_callback: E,
|
error_callback: E,
|
||||||
|
@ -178,11 +190,20 @@ impl DeviceTrait for Device {
|
||||||
D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
|
D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
|
||||||
E: FnMut(StreamError) + Send + 'static,
|
E: FnMut(StreamError) + Send + 'static,
|
||||||
{
|
{
|
||||||
assert_eq!(
|
if !valid_config(config, sample_format) {
|
||||||
sample_format,
|
return Err(BuildStreamError::StreamConfigNotSupported);
|
||||||
SampleFormat::F32,
|
}
|
||||||
"emscripten backend currently only supports `f32` data",
|
|
||||||
);
|
let buffer_size_frames = match config.buffer_size {
|
||||||
|
BufferSize::Fixed(v) => {
|
||||||
|
if v == 0 {
|
||||||
|
return Err(BuildStreamError::StreamConfigNotSupported);
|
||||||
|
} else {
|
||||||
|
v as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BufferSize::Default => DEFAULT_BUFFER_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
// Create the stream.
|
// Create the stream.
|
||||||
let audio_ctxt_ref = js!(return new AudioContext()).into_reference().unwrap();
|
let audio_ctxt_ref = js!(return new AudioContext()).into_reference().unwrap();
|
||||||
|
@ -199,7 +220,14 @@ impl DeviceTrait for Device {
|
||||||
// See also: The call to `set_timeout` at the end of the `audio_callback_fn` which creates
|
// See also: The call to `set_timeout` at the end of the `audio_callback_fn` which creates
|
||||||
// the loop.
|
// the loop.
|
||||||
set_timeout(
|
set_timeout(
|
||||||
|| audio_callback_fn::<D, E>(user_data_ptr as *mut c_void),
|
|| {
|
||||||
|
audio_callback_fn::<D, E>(
|
||||||
|
user_data_ptr as *mut c_void,
|
||||||
|
config,
|
||||||
|
sample_format,
|
||||||
|
buffer_size_frames,
|
||||||
|
)
|
||||||
|
},
|
||||||
10,
|
10,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -223,12 +251,18 @@ impl StreamTrait for Stream {
|
||||||
|
|
||||||
// The first argument of the callback function (a `void*`) is a casted pointer to `self`
|
// The first argument of the callback function (a `void*`) is a casted pointer to `self`
|
||||||
// and to the `callback` parameter that was passed to `run`.
|
// and to the `callback` parameter that was passed to `run`.
|
||||||
fn audio_callback_fn<D, E>(user_data_ptr: *mut c_void)
|
fn audio_callback_fn<D, E>(
|
||||||
where
|
user_data_ptr: *mut c_void,
|
||||||
|
config: &StreamConfig,
|
||||||
|
sample_format: SampleFormat,
|
||||||
|
buffer_size_frames: usize,
|
||||||
|
) where
|
||||||
D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
|
D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
|
||||||
E: FnMut(StreamError) + Send + 'static,
|
E: FnMut(StreamError) + Send + 'static,
|
||||||
{
|
{
|
||||||
const SAMPLE_RATE: usize = 44100;
|
let num_channels = config.channels as usize;
|
||||||
|
let sample_rate = config.sample_rate.0;
|
||||||
|
let buffer_size_samples = buffer_size_frames * num_channels;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let user_data_ptr2 = user_data_ptr as *mut (&Stream, D, E);
|
let user_data_ptr2 = user_data_ptr as *mut (&Stream, D, E);
|
||||||
|
@ -237,12 +271,11 @@ where
|
||||||
let audio_ctxt = &stream.audio_ctxt_ref;
|
let audio_ctxt = &stream.audio_ctxt_ref;
|
||||||
|
|
||||||
// TODO: We should be re-using a buffer.
|
// TODO: We should be re-using a buffer.
|
||||||
let mut temporary_buffer = vec![0.0; SAMPLE_RATE * 2 / 3];
|
let mut temporary_buffer = vec![0f32; buffer_size_samples];
|
||||||
|
|
||||||
{
|
{
|
||||||
let len = temporary_buffer.len();
|
let len = temporary_buffer.len();
|
||||||
let data = temporary_buffer.as_mut_ptr() as *mut ();
|
let data = temporary_buffer.as_mut_ptr() as *mut ();
|
||||||
let sample_format = SampleFormat::F32;
|
|
||||||
let mut data = Data::from_parts(data, len, sample_format);
|
let mut data = Data::from_parts(data, len, sample_format);
|
||||||
|
|
||||||
let now_secs: f64 = js!(@{audio_ctxt}.getOutputTimestamp().currentTime)
|
let now_secs: f64 = js!(@{audio_ctxt}.getOutputTimestamp().currentTime)
|
||||||
|
@ -253,7 +286,7 @@ where
|
||||||
// we estimate based on buffer size instead. Probably should use this, but it's only
|
// we estimate based on buffer size instead. Probably should use this, but it's only
|
||||||
// supported by firefox (2020-04-28).
|
// supported by firefox (2020-04-28).
|
||||||
// let latency_secs: f64 = js!(@{audio_ctxt}.outputLatency).try_into().unwrap();
|
// let latency_secs: f64 = js!(@{audio_ctxt}.outputLatency).try_into().unwrap();
|
||||||
let buffer_duration = frames_to_duration(len, SAMPLE_RATE);
|
let buffer_duration = frames_to_duration(len, sample_rate as usize);
|
||||||
let playback = callback
|
let playback = callback
|
||||||
.add(buffer_duration)
|
.add(buffer_duration)
|
||||||
.expect("`playback` occurs beyond representation supported by `StreamInstant`");
|
.expect("`playback` occurs beyond representation supported by `StreamInstant`");
|
||||||
|
@ -273,19 +306,19 @@ where
|
||||||
typed_array
|
typed_array
|
||||||
};
|
};
|
||||||
|
|
||||||
let num_channels = 2u32; // TODO: correct value
|
|
||||||
debug_assert_eq!(temporary_buffer.len() % num_channels as usize, 0);
|
debug_assert_eq!(temporary_buffer.len() % num_channels as usize, 0);
|
||||||
|
|
||||||
js!(
|
js!(
|
||||||
var src_buffer = new Float32Array(@{typed_array}.buffer);
|
var src_buffer = new Float32Array(@{typed_array}.buffer);
|
||||||
var context = @{audio_ctxt};
|
var context = @{audio_ctxt};
|
||||||
var buf_len = @{temporary_buffer.len() as u32};
|
var buffer_size_frames = @{buffer_size_frames as u32};
|
||||||
var num_channels = @{num_channels};
|
var num_channels = @{num_channels as u32};
|
||||||
|
var sample_rate = sample_rate;
|
||||||
|
|
||||||
var buffer = context.createBuffer(num_channels, buf_len / num_channels, 44100);
|
var buffer = context.createBuffer(num_channels, buffer_size_frames, sample_rate);
|
||||||
for (var channel = 0; channel < num_channels; ++channel) {
|
for (var channel = 0; channel < num_channels; ++channel) {
|
||||||
var buffer_content = buffer.getChannelData(channel);
|
var buffer_content = buffer.getChannelData(channel);
|
||||||
for (var i = 0; i < buf_len / num_channels; ++i) {
|
for (var i = 0; i < buffer_size_frames; ++i) {
|
||||||
buffer_content[i] = src_buffer[i * num_channels + channel];
|
buffer_content[i] = src_buffer[i * num_channels + channel];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,7 +332,10 @@ where
|
||||||
// TODO: handle latency better ; right now we just use setInterval with the amount of sound
|
// TODO: handle latency better ; right now we just use setInterval with the amount of sound
|
||||||
// data that is in each buffer ; this is obviously bad, and also the schedule is too tight
|
// data that is in each buffer ; this is obviously bad, and also the schedule is too tight
|
||||||
// and there may be underflows
|
// and there may be underflows
|
||||||
set_timeout(|| audio_callback_fn::<D, E>(user_data_ptr), 330);
|
set_timeout(
|
||||||
|
|| audio_callback_fn::<D, E>(user_data_ptr, config, sample_format, buffer_size_frames),
|
||||||
|
330,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -348,6 +384,15 @@ fn is_webaudio_available() -> bool {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether or not the given stream configuration is valid for building a stream.
|
||||||
|
fn valid_config(conf: &StreamConfig, sample_format: SampleFormat) -> bool {
|
||||||
|
conf.channels <= MAX_CHANNELS
|
||||||
|
&& conf.channels >= MIN_CHANNELS
|
||||||
|
&& conf.sample_rate <= MAX_SAMPLE_RATE
|
||||||
|
&& conf.sample_rate >= MIN_SAMPLE_RATE
|
||||||
|
&& sample_format == SUPPORTED_SAMPLE_FORMAT
|
||||||
|
}
|
||||||
|
|
||||||
// Convert the given duration in frames at the given sample rate to a `std::time::Duration`.
|
// Convert the given duration in frames at the given sample rate to a `std::time::Duration`.
|
||||||
fn frames_to_duration(frames: usize, rate: usize) -> std::time::Duration {
|
fn frames_to_duration(frames: usize, rate: usize) -> std::time::Duration {
|
||||||
let secsf = frames as f64 / rate as f64;
|
let secsf = frames as f64 / rate as f64;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
BackendSpecificError, BufferSize, Data, DefaultStreamConfigError, DeviceNameError,
|
BackendSpecificError, BufferSize, Data, DefaultStreamConfigError, DeviceNameError,
|
||||||
DevicesError, InputCallbackInfo, OutputCallbackInfo, SampleFormat, SampleRate,
|
DevicesError, InputCallbackInfo, OutputCallbackInfo, SampleFormat, SampleRate, StreamConfig,
|
||||||
StreamConfig, SupportedBufferSize, SupportedStreamConfig, SupportedStreamConfigRange,
|
SupportedBufferSize, SupportedStreamConfig, SupportedStreamConfigRange,
|
||||||
SupportedStreamConfigsError, COMMON_SAMPLE_RATES,
|
SupportedStreamConfigsError, COMMON_SAMPLE_RATES,
|
||||||
};
|
};
|
||||||
use std;
|
use std;
|
||||||
|
@ -652,8 +652,8 @@ impl Device {
|
||||||
// TO DO: We need IAudioClient3 to get buffersize ranges first
|
// TO DO: We need IAudioClient3 to get buffersize ranges first
|
||||||
// Otherwise the supported ranges are unknown. In the mean time
|
// Otherwise the supported ranges are unknown. In the mean time
|
||||||
// the smallest buffersize is selected and used.
|
// the smallest buffersize is selected and used.
|
||||||
return Err(BuildStreamError::StreamConfigNotSupported)
|
return Err(BuildStreamError::StreamConfigNotSupported);
|
||||||
},
|
}
|
||||||
BufferSize::Default => (),
|
BufferSize::Default => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -814,8 +814,8 @@ impl Device {
|
||||||
// TO DO: We need IAudioClient3 to get buffersize ranges first
|
// TO DO: We need IAudioClient3 to get buffersize ranges first
|
||||||
// Otherwise the supported ranges are unknown. In the mean time
|
// Otherwise the supported ranges are unknown. In the mean time
|
||||||
// the smallest buffersize is selected and used.
|
// the smallest buffersize is selected and used.
|
||||||
return Err(BuildStreamError::StreamConfigNotSupported)
|
return Err(BuildStreamError::StreamConfigNotSupported);
|
||||||
},
|
}
|
||||||
BufferSize::Default => (),
|
BufferSize::Default => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,10 @@ use self::wasm_bindgen::prelude::*;
|
||||||
use self::wasm_bindgen::JsCast;
|
use self::wasm_bindgen::JsCast;
|
||||||
use self::web_sys::{AudioContext, AudioContextOptions};
|
use self::web_sys::{AudioContext, AudioContextOptions};
|
||||||
use crate::{
|
use crate::{
|
||||||
BackendSpecificError, BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError,
|
BackendSpecificError, BufferSize, BuildStreamError, Data, DefaultStreamConfigError,
|
||||||
DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError, PlayStreamError,
|
DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo, PauseStreamError,
|
||||||
SampleFormat, SampleRate, StreamConfig, StreamError, SupportedStreamConfig,
|
PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError, SupportedBufferSize,
|
||||||
SupportedStreamConfigRange, SupportedStreamConfigsError,
|
SupportedStreamConfig, SupportedStreamConfigRange, SupportedStreamConfigsError,
|
||||||
};
|
};
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
@ -39,6 +39,9 @@ const MAX_CHANNELS: u16 = 32;
|
||||||
const MIN_SAMPLE_RATE: SampleRate = SampleRate(8_000);
|
const MIN_SAMPLE_RATE: SampleRate = SampleRate(8_000);
|
||||||
const MAX_SAMPLE_RATE: SampleRate = SampleRate(96_000);
|
const MAX_SAMPLE_RATE: SampleRate = SampleRate(96_000);
|
||||||
const DEFAULT_SAMPLE_RATE: SampleRate = SampleRate(44_100);
|
const DEFAULT_SAMPLE_RATE: SampleRate = SampleRate(44_100);
|
||||||
|
const MIN_BUFFER_SIZE: u32 = 1;
|
||||||
|
const MAX_BUFFER_SIZE: u32 = std::u32::MAX;
|
||||||
|
const DEFAULT_BUFFER_SIZE: usize = 2048;
|
||||||
const SUPPORTED_SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
|
const SUPPORTED_SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
|
||||||
|
|
||||||
impl Host {
|
impl Host {
|
||||||
|
@ -93,11 +96,16 @@ impl Device {
|
||||||
fn supported_output_configs(
|
fn supported_output_configs(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
|
) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
|
||||||
|
let buffer_size = SupportedBufferSize::Range {
|
||||||
|
min: MIN_BUFFER_SIZE,
|
||||||
|
max: MAX_BUFFER_SIZE,
|
||||||
|
};
|
||||||
let configs: Vec<_> = (MIN_CHANNELS..=MAX_CHANNELS)
|
let configs: Vec<_> = (MIN_CHANNELS..=MAX_CHANNELS)
|
||||||
.map(|channels| SupportedStreamConfigRange {
|
.map(|channels| SupportedStreamConfigRange {
|
||||||
channels,
|
channels,
|
||||||
min_sample_rate: MIN_SAMPLE_RATE,
|
min_sample_rate: MIN_SAMPLE_RATE,
|
||||||
max_sample_rate: MAX_SAMPLE_RATE,
|
max_sample_rate: MAX_SAMPLE_RATE,
|
||||||
|
buffer_size: buffer_size.clone(),
|
||||||
sample_format: SUPPORTED_SAMPLE_FORMAT,
|
sample_format: SUPPORTED_SAMPLE_FORMAT,
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
@ -190,11 +198,20 @@ impl DeviceTrait for Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
let n_channels = config.channels as usize;
|
let n_channels = config.channels as usize;
|
||||||
// Use a buffer period of 1/3s for this early proof of concept.
|
|
||||||
// TODO: Change this to the requested buffer size when updating for the buffer size API.
|
let buffer_size_frames = match config.buffer_size {
|
||||||
let buffer_size_frames = (config.sample_rate.0 as f64 / 3.0).round() as usize;
|
BufferSize::Fixed(v) => {
|
||||||
|
if v == 0 {
|
||||||
|
return Err(BuildStreamError::StreamConfigNotSupported);
|
||||||
|
} else {
|
||||||
|
v as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BufferSize::Default => DEFAULT_BUFFER_SIZE,
|
||||||
|
};
|
||||||
let buffer_size_samples = buffer_size_frames * n_channels;
|
let buffer_size_samples = buffer_size_frames * n_channels;
|
||||||
let buffer_time_step_secs = buffer_time_step_secs(buffer_size_frames, config.sample_rate);
|
let buffer_time_step_secs = buffer_time_step_secs(buffer_size_frames, config.sample_rate);
|
||||||
|
|
||||||
let data_callback = Arc::new(Mutex::new(Box::new(data_callback)));
|
let data_callback = Arc::new(Mutex::new(Box::new(data_callback)));
|
||||||
|
|
||||||
// Create the WebAudio stream.
|
// Create the WebAudio stream.
|
||||||
|
|
|
@ -200,13 +200,11 @@ pub struct StreamConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes the minimum and maximum supported buffer size for the device
|
/// Describes the minimum and maximum supported buffer size for the device
|
||||||
/// and if requested buffersize must be a power of 2 value.
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum SupportedBufferSize {
|
pub enum SupportedBufferSize {
|
||||||
Range {
|
Range {
|
||||||
min: FrameCount,
|
min: FrameCount,
|
||||||
max: FrameCount,
|
max: FrameCount,
|
||||||
requires_power_of_two: bool,
|
|
||||||
},
|
},
|
||||||
/// In the case that the platform provides no way of getting the default
|
/// In the case that the platform provides no way of getting the default
|
||||||
/// buffersize before starting a stream.
|
/// buffersize before starting a stream.
|
||||||
|
|
Loading…
Reference in New Issue