Skip to content

Commit

Permalink
Merge pull request #232 from orottier/feature/set-sink-id
Browse files Browse the repository at this point in the history
Change output device for running AudioContext
  • Loading branch information
orottier committed Nov 6, 2022
2 parents 59a396e + 63c75c7 commit f3d8f2c
Show file tree
Hide file tree
Showing 13 changed files with 388 additions and 394 deletions.
7 changes: 6 additions & 1 deletion examples/sink_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,10 @@ fn main() {
osc.connect(&context.destination());
osc.start();

std::thread::sleep(std::time::Duration::from_secs(4));
loop {
println!("Choose output device, enter the 'device_id' and press <Enter>:");
let sink_id = std::io::stdin().lines().next().unwrap().unwrap();
context.set_sink_id_sync(sink_id).unwrap();
println!("Playing beep for sink {:?}", context.sink_id());
}
}
2 changes: 1 addition & 1 deletion examples/toy_webrtc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fn run_server() -> std::io::Result<()> {
};
*/

socket.send_to(buf, &src)?;
socket.send_to(buf, src)?;
}
}

Expand Down
37 changes: 24 additions & 13 deletions src/context/concrete_base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ use crate::spatial::AudioListenerParams;

use crate::AudioListener;

use crossbeam_channel::Sender;
use crossbeam_channel::{SendError, Sender};
use std::sync::atomic::{AtomicU64, AtomicU8, Ordering};
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, RwLock, RwLockWriteGuard};

/// The struct that corresponds to the Javascript `BaseAudioContext` object.
///
Expand Down Expand Up @@ -51,7 +51,7 @@ struct ConcreteBaseAudioContextInner {
/// destination node's current channel count
destination_channel_config: ChannelConfig,
/// message channel from control to render thread
render_channel: Sender<ControlMessage>,
render_channel: RwLock<Sender<ControlMessage>>,
/// control messages that cannot be sent immediately
queued_messages: Mutex<Vec<ControlMessage>>,
/// number of frames played
Expand Down Expand Up @@ -104,7 +104,7 @@ impl BaseAudioContext for ConcreteBaseAudioContext {
self.inner.queued_audio_listener_msgs.lock().unwrap();
queued_audio_listener_msgs.push(message);
} else {
self.inner.render_channel.send(message).unwrap();
self.send_control_msg(message).unwrap();
self.resolve_queued_control_msgs(id);
}

Expand All @@ -124,7 +124,7 @@ impl ConcreteBaseAudioContext {
let base_inner = ConcreteBaseAudioContextInner {
sample_rate,
max_channel_count,
render_channel,
render_channel: RwLock::new(render_channel),
queued_messages: Mutex::new(Vec::new()),
node_id_inc: AtomicU64::new(0),
destination_channel_config: ChannelConfigOptions::default().into(),
Expand Down Expand Up @@ -188,6 +188,17 @@ impl ConcreteBaseAudioContext {
base
}

pub(crate) fn send_control_msg(
&self,
msg: ControlMessage,
) -> Result<(), SendError<ControlMessage>> {
self.inner.render_channel.read().unwrap().send(msg)
}

pub(crate) fn lock_control_msg_sender(&self) -> RwLockWriteGuard<Sender<ControlMessage>> {
self.inner.render_channel.write().unwrap()
}

/// Inform render thread that the control thread `AudioNode` no langer has any handles
pub(super) fn mark_node_dropped(&self, id: u64) {
// do not drop magic nodes
Expand All @@ -199,7 +210,7 @@ impl ConcreteBaseAudioContext {

// Sending the message will fail when the render thread has already shut down.
// This is fine
let _r = self.inner.render_channel.send(message);
let _r = self.send_control_msg(message);
}
}

Expand All @@ -211,7 +222,7 @@ impl ConcreteBaseAudioContext {

// Sending the message will fail when the render thread has already shut down.
// This is fine
let _r = self.inner.render_channel.send(message);
let _r = self.send_control_msg(message);
}

/// `ChannelConfig` of the `AudioDestinationNode`
Expand Down Expand Up @@ -283,7 +294,7 @@ impl ConcreteBaseAudioContext {
while i < queued.len() {
if matches!(&queued[i], ControlMessage::ConnectNode {to, ..} if *to == id) {
let m = queued.remove(i);
self.inner.render_channel.send(m).unwrap();
self.send_control_msg(m).unwrap();
} else {
i += 1;
}
Expand All @@ -304,7 +315,7 @@ impl ConcreteBaseAudioContext {
output,
input,
};
self.inner.render_channel.send(message).unwrap();
self.send_control_msg(message).unwrap();
}

/// Schedule a connection of an `AudioParam` to the `AudioNode` it belongs to
Expand All @@ -326,13 +337,13 @@ impl ConcreteBaseAudioContext {
from: from.0,
to: to.0,
};
self.inner.render_channel.send(message).unwrap();
self.send_control_msg(message).unwrap();
}

/// Disconnects all outgoing connections from the audio node.
pub(crate) fn disconnect(&self, from: &AudioNodeId) {
let message = ControlMessage::DisconnectAll { from: from.0 };
self.inner.render_channel.send(message).unwrap();
self.send_control_msg(message).unwrap();
}

/// Pass an `AudioParam::AudioParamEvent` to the render thread
Expand All @@ -348,7 +359,7 @@ impl ConcreteBaseAudioContext {
to: to.clone(),
event,
};
self.inner.render_channel.send(message).unwrap();
self.send_control_msg(message).unwrap();
}

/// Attach the 9 `AudioListener` coordinates to a `PannerNode`
Expand All @@ -370,7 +381,7 @@ impl ConcreteBaseAudioContext {
let mut released = false;
while let Some(message) = queued_audio_listener_msgs.pop() {
// add the AudioListenerRenderer to the graph
self.inner.render_channel.send(message).unwrap();
self.send_control_msg(message).unwrap();
released = true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl From<&AudioParamId> for NodeIndex {
}

/// Describes the current state of the `AudioContext`
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AudioContextState {
/// This context is currently suspended (context time is not proceeding,
/// audio hardware may be powered down/released).
Expand Down
5 changes: 5 additions & 0 deletions src/context/offline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,17 @@ impl OfflineAudioContext {
/// * `length` - length of the rendering audio buffer
/// * `sample_rate` - output sample rate
#[must_use]
#[allow(clippy::missing_panics_doc)]
pub fn new(number_of_channels: usize, length: usize, sample_rate: f32) -> Self {
assert_valid_sample_rate(sample_rate);

// communication channel to the render thread
let (sender, receiver) = crossbeam_channel::unbounded();

let graph = crate::render::graph::Graph::new();
let message = crate::message::ControlMessage::Startup { graph };
sender.send(message).unwrap();

// track number of frames - synced from render thread to control thread
let frames_played = Arc::new(AtomicU64::new(0));
let frames_played_clone = frames_played.clone();
Expand Down
Loading

0 comments on commit f3d8f2c

Please sign in to comment.