-
Notifications
You must be signed in to change notification settings - Fork 223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Volume, play/pause, and fix sink dropping #83
Conversation
pending_sounds: Mutex<Vec<HandleHandle>>, | ||
} | ||
|
||
// Handle to a handle I guess. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same two remarks as #84
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, there is no such thing as an AtomicF32 though so I assume the volume level should still be a Mutex
The other two have been merged into this request and the requested changes have been made. |
@tomaka Ready for review. |
Hmmm, unfortunately I'm not a fan of the fact that we lock the volume's mutex for each sample. |
Please load the volume in a temporary variable outside of the iterator (for example between lines 126 and 127) so that we only lock the mutex once from time to time. That should be okay-ish I think. |
/// The value `1.0` is the "normal" volume (unfiltered input). Any value other than 1.0 will | ||
/// multiply each sample by this value. | ||
#[inline] | ||
pub fn get_volume(&self) -> f32 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename this to just volume()
.
@@ -206,18 +250,42 @@ impl Handle { | |||
self.next_sounds.lock().unwrap().push((source, Some(tx))); | |||
} | |||
|
|||
/// Gets the volume of the sound played by this sink. | |||
#[inline] | |||
pub fn get_volume(&self) -> f32 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
Sorry, I didn't review your volume PR carefully. This time it should be good after these changes. |
Ok, so I agree it is not desirable for the sampling thread to block, locking can lead to blocking. However I do want the volume to be fetched for every sample as that makes the set_volume function feel the most responsive. It's not possible to make the f32 atomic. So the approach I'm currently thinking of would use a channel, we'd store the Sender in the Handle and the Receiver in the HandleHandle, then whenever the Handle wishes to change the volume level it will send an f32 through the channel, HandleHandle would store an f32 called volume and in the sample iterator (lines 128-133) we would call try_recv to fetch any new volume level sent by Handle, and store it in HandleHandle. This will not be contained in a while loop, it will only attempt to receive one volume level per sample, which prevents the sampling thread from being DDOSed by a large influx of volume change requests. I'll create and push an implementation of this on my lunch break, let me know if you find any fault in it. |
I don't think it's better to use a channel. The iterator that builds the samples is a code that is very easy to optimize for the compiler. The fact that we're using the If you're introducing a channel read or a mutex in there, you're not only paying the price of the channel or mutex read, but by introducing a memory fence in the loop you're also totally killing any potential for a compiler optimisation on this code. In fact I have already doubts about the fact that EDIT: When it comes to being responsive, I don't think you'd notice a 5 milliseconds lag for example (since AFAIK that's more or less the best possible value for real-time audio processing right now), and by fetching the volume only every 5 milliseconds for example you'd avoid between 2200 and 4400 mutex locks. |
I have a difficult time imagining how the engine could have the features in this request in a more optimized manner, unless we were to make changes to cpal. That being said, currently on line 126 of engine.rs I am dropping the sound if it was declared dead, and that seems to be responsive enough in my own testing, so on second thought I'm not opposed to loading temporary volume variables here. |
You could put the |
Ok, that makes sense. I'd like to see if I can accomplish that, should "from time to time" just be approximately every 5ms? |
Some context: I'm using rodio in a game engine project and I want to give users of my engine more control over the playback of their sounds, those features that I need to do that are in this PR. I don't have anywhere near the same level of experience manipulating audio devices as you do but I gave it my best attempt. I'm trying to avoid having an audio engine that is just "good enough for now" I'd like it to be at this ideal performance level you describe. So I'm willing to tackle the idea of finding a good place and way to do more infrequent fetching of the variables into a local copy. |
Alternatively if you want to do a rewrite of the engine I could just add my temporary variable after line 126 as you originally suggested and just be done with it. |
I'd like to rewrite some parts of the engine but I don't know if it's going to happen in the next month or in the next year. Basically the ideal solution would be to add a filter (similar to the ones in Then the engine could wrap all sound sources passed to it around that filter. |
Ok, do you also feel we should be storing local copies for the AtomicBools in this filter or is the current implementation sufficient for those? |
@Xaeroxe23 Yeah I think that would be better. |
Resolved in another PR, closing. |
Fixed the set_volume function of a Sink and adds a get_volume function.