The resample_factor_reciprocal also happens to be our
anti-alias cutoff. In this case it represents the minimum
output bandwidth needed to fully represent the input.
Cap the output bandwidth to 92%.
Even at 48kHz it still translates to 100% source bandwidth.
This just provides a little bit of anti-alias filtering.
There is more then likely nothing there to filter,
but it doesn't hurt or cost us anything to make sure.
Since we are including the pipeline latency in the position we need to seek to the correct position when going from paused to play.
We can also drop the ALSA and PulseAudio buffers instead of draining them since their latency's are factored in.
Time impl's from f64 (as secs) so there's no need to manually calculate it beyond converting ms to sec.
If we grab the TimeBase in new we don't need to continually call decoder.codec_params().time_base everytime we want to convert ts to ms.
Collect is probably fine but for code that's this hot it's worth the couple extra lines to make certain there's only ever one allocation when it comes to the returned Vec.
It would be so much easier to use elapsed but elapsed could potentially panic is rare cases.
See: https://doc.rust-lang.org/std/time/struct.Instant.html#monotonicity
Otherwise this is pretty straight forward.
If anything fails getting expected_position_ms it will return 0 which will trigger a notify if either stream_position_ms or decoder_position_ms is > 1000.
If all goes well it's simply a matter of calculating the max delta of expected_position_ms and stream_position_ms and expected_position_ms and decoder_position_ms.
So if the decoder or the sample pipeline are off by more than 1 sec we notify.
- Use variables directly in format strings.
As reported by clippy, variables can be used directly in the
`format!` string.
- Use rewind() instead of seeking to 0.
- Remove superfluous & and ref.
Signed-off-by: Petr Tesarik <petr@tesarici.cz>
- Improve responsiveness by downloading the smallest possible chunk
size when seeking or first loading.
- Improve download time and decrease CPU usage by downloading the
largest possible chunk size as throughput allows, still allowing
for reasonable seek responsiveness (~1 second).
- As a result, take refactoring opportunities: simplify prefetching
logic, download threading, command sending, and some ergonomics.
- Fix disappearing controls in the Spotify mobile UI while loading.
- Fix handling of seek, pause, and play commands while loading.
- Fix download rate calculation (don't use the Mercury rate).
- Fix ping time calculation under lock contention.
Special thanks to @eladyn for all of their help and suggestions.
* Add all player events to `player_event_handler.rs`
* Move event handler code to `player_event_handler.rs`
* Add session events
* Clean up and de-noise events and event firing
* Added metadata support via a TrackChanged event
* Add `event_handler_example.py`
* Handle invalid track start positions by just starting the track from the beginning
* Add repeat support to `spirc.rs`
* Add `disconnect`, `set_position_ms` and `set_volume` to `spirc.rs`
* Set `PlayStatus` to the correct value when Player is loading to avoid blanking out the controls when `self.play_status` is `LoadingPlay` or `LoadingPause` in `spirc.rs`
* Handle attempts to play local files better by basically ignoring attempts to load them in `handle_remote_update` in `spirc.rs`
* Add an event worker thread that runs async to the main thread(s) but sync to itself to prevent potential data races for event consumers.
* Get rid of (probably harmless) `.unwrap()` in `main.rs`
* Ensure that events are emited in a logical order and at logical times
* Handle invalid and disappearing devices better
* Ignore SpircCommands unless we're active with the exception of ShutDown