Skip to content
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

Merge dev into tokio_migration and fix warnings #683

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
matrix:
os: [ubuntu-latest]
toolchain:
- 1.42.0 # MSRV (Minimum supported rust version)
- 1.41.1 # MSRV (Minimum supported rust version)
- stable
- beta
experimental: [false]
Expand Down
2 changes: 1 addition & 1 deletion COMPILING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ curl https://sh.rustup.rs -sSf | sh

Follow any prompts it gives you to install Rust. Once that’s done, Rust's standard tools should be setup and ready to use.

*Note: The current minimum required Rust version at the time of writing is 1.40.0, you can find the current minimum version specified in the `.github/workflow/test.yml` file.*
*Note: The current minimum required Rust version at the time of writing is 1.41, you can find the current minimum version specified in the `.github/workflow/test.yml` file.*

#### Additional Rust tools - `rustfmt`
To ensure a consistent codebase, we utilise [`rustfmt`](https://github.com/rust-lang/rustfmt), which is installed by default with `rustup` these days, else it can be installed manually with:
Expand Down
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

171 changes: 92 additions & 79 deletions audio/src/passthrough_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,75 +5,32 @@ use std::fmt;
use std::io::{Read, Seek};
use std::time::{SystemTime, UNIX_EPOCH};

fn write_headers<T: Read + Seek>(
rdr: &mut PacketReader<T>,
wtr: &mut PacketWriter<Vec<u8>>,
) -> Result<u32, PassthroughError> {
let mut stream_serial: u32 = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as u32;

// search for ident, comment, setup
get_header(1, rdr, wtr, &mut stream_serial, PacketWriteEndInfo::EndPage)?;
get_header(
3,
rdr,
wtr,
&mut stream_serial,
PacketWriteEndInfo::NormalPacket,
)?;
get_header(5, rdr, wtr, &mut stream_serial, PacketWriteEndInfo::EndPage)?;

// remove un-needed packets
rdr.delete_unread_packets();
Ok(stream_serial)
}

fn get_header<T>(
code: u8,
rdr: &mut PacketReader<T>,
wtr: &mut PacketWriter<Vec<u8>>,
stream_serial: &mut u32,
info: PacketWriteEndInfo,
) -> Result<u32, PassthroughError>
fn get_header<T>(code: u8, rdr: &mut PacketReader<T>) -> Result<Box<[u8]>, PassthroughError>
where
T: Read + Seek,
{
let pck: Packet = rdr.read_packet_expected()?;

// set a unique serial number
if pck.stream_serial() != 0 {
*stream_serial = pck.stream_serial();
}

let pkt_type = pck.data[0];
debug!("Vorbis header type{}", &pkt_type);

// all headers are mandatory
if pkt_type != code {
return Err(PassthroughError(OggReadError::InvalidData));
}

// headers keep original granule number
let absgp_page = pck.absgp_page();
wtr.write_packet(
pck.data.into_boxed_slice(),
*stream_serial,
info,
absgp_page,
)
.unwrap();

Ok(*stream_serial)
Ok(pck.data.into_boxed_slice())
}

pub struct PassthroughDecoder<R: Read + Seek> {
rdr: PacketReader<R>,
wtr: PacketWriter<Vec<u8>>,
lastgp_page: Option<u64>,
absgp_page: u64,
eos: bool,
bos: bool,
ofsgp_page: u64,
stream_serial: u32,
ident: Box<[u8]>,
comment: Box<[u8]>,
setup: Box<[u8]>,
}

pub struct PassthroughError(ogg::OggReadError);
Expand All @@ -82,70 +39,126 @@ impl<R: Read + Seek> PassthroughDecoder<R> {
/// Constructs a new Decoder from a given implementation of `Read + Seek`.
pub fn new(rdr: R) -> Result<Self, PassthroughError> {
let mut rdr = PacketReader::new(rdr);
let mut wtr = PacketWriter::new(Vec::new());
let stream_serial = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_millis() as u32;

let stream_serial = write_headers(&mut rdr, &mut wtr)?;
info!("Starting passthrough track with serial {}", stream_serial);

// search for ident, comment, setup
let ident = get_header(1, &mut rdr)?;
let comment = get_header(3, &mut rdr)?;
let setup = get_header(5, &mut rdr)?;

// remove un-needed packets
rdr.delete_unread_packets();

Ok(PassthroughDecoder {
rdr,
wtr,
lastgp_page: Some(0),
absgp_page: 0,
wtr: PacketWriter::new(Vec::new()),
ofsgp_page: 0,
stream_serial,
ident,
comment,
setup,
eos: false,
bos: false,
})
}
}

impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
fn seek(&mut self, ms: i64) -> Result<(), AudioError> {
info!("Seeking to {}", ms);
self.lastgp_page = match ms {
0 => Some(0),
_ => None,
};

// add an eos to previous stream if missing
if self.bos && !self.eos {
match self.rdr.read_packet() {
Ok(Some(pck)) => {
let absgp_page = pck.absgp_page() - self.ofsgp_page;
self.wtr
.write_packet(
pck.data.into_boxed_slice(),
self.stream_serial,
PacketWriteEndInfo::EndStream,
absgp_page,
)
.unwrap();
}
_ => warn! {"Cannot write EoS after seeking"},
};
}

self.eos = false;
self.bos = false;
self.ofsgp_page = 0;
self.stream_serial += 1;

// hard-coded to 44.1 kHz
match self.rdr.seek_absgp(None, (ms * 44100 / 1000) as u64) {
Ok(_) => Ok(()),
Ok(_) => {
// need to set some offset for next_page()
let pck = self.rdr.read_packet().unwrap().unwrap();
self.ofsgp_page = pck.absgp_page();
debug!("Seek to offset page {}", self.ofsgp_page);
Ok(())
}
Err(err) => Err(AudioError::PassthroughError(err.into())),
}
}

fn next_packet(&mut self) -> Result<Option<AudioPacket>, AudioError> {
let mut skip = self.lastgp_page.is_none();
// write headers if we are (re)starting
if !self.bos {
self.wtr
.write_packet(
self.ident.clone(),
self.stream_serial,
PacketWriteEndInfo::EndPage,
0,
)
.unwrap();
self.wtr
.write_packet(
self.comment.clone(),
self.stream_serial,
PacketWriteEndInfo::NormalPacket,
0,
)
.unwrap();
self.wtr
.write_packet(
self.setup.clone(),
self.stream_serial,
PacketWriteEndInfo::EndPage,
0,
)
.unwrap();
self.bos = true;
debug!("Wrote Ogg headers");
}

loop {
let pck = match self.rdr.read_packet() {
Ok(Some(pck)) => pck,

Ok(None) | Err(OggReadError::NoCapturePatternFound) => {
info!("end of streaming");
return Ok(None);
}

Err(err) => return Err(AudioError::PassthroughError(err.into())),
};

let pckgp_page = pck.absgp_page();
let lastgp_page = self.lastgp_page.get_or_insert(pckgp_page);

// consume packets till next page to get a granule reference
if skip {
if *lastgp_page == pckgp_page {
debug!("skipping packet");
continue;
}
skip = false;
info!("skipped at {}", pckgp_page);
// skip till we have audio and a calculable granule position
if pckgp_page == 0 || pckgp_page == self.ofsgp_page {
continue;
}

// now we can calculate absolute granule
self.absgp_page += pckgp_page - *lastgp_page;
self.lastgp_page = Some(pckgp_page);

// set packet type
let inf = if pck.last_in_stream() {
self.lastgp_page = Some(0);
self.eos = true;
PacketWriteEndInfo::EndStream
} else if pck.last_in_page() {
PacketWriteEndInfo::EndPage
Expand All @@ -158,7 +171,7 @@ impl<R: Read + Seek> AudioDecoder for PassthroughDecoder<R> {
pck.data.into_boxed_slice(),
self.stream_serial,
inf,
self.absgp_page,
pckgp_page - self.ofsgp_page,
)
.unwrap();

Expand Down
2 changes: 1 addition & 1 deletion connect/src/spirc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ fn initial_state() -> State {
fn initial_device_state(config: ConnectConfig) -> DeviceState {
{
let mut msg = DeviceState::new();
msg.set_sw_version(version::version_string());
msg.set_sw_version(version::VERSION_STRING.to_string());
msg.set_is_active(false);
msg.set_can_play(true);
msg.set_volume(0);
Expand Down
3 changes: 2 additions & 1 deletion core/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ fn main() {
.take(8)
.map(char::from)
.collect();
println!("cargo:rustc-env=VERGEN_BUILD_ID={}", build_id);

println!("cargo:rustc-env=LIBRESPOT_BUILD_ID={}", build_id);
}
4 changes: 2 additions & 2 deletions core/src/apresolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use super::AP_FALLBACK;
const APRESOLVE_ENDPOINT: &str = "http://apresolve.spotify.com:80";

#[derive(Clone, Debug, Deserialize)]
struct APResolveData {
struct ApResolveData {
ap_list: Vec<String>,
}

Expand Down Expand Up @@ -41,7 +41,7 @@ async fn try_apresolve(
};

let body = hyper::body::to_bytes(response.into_body()).await?;
let data: APResolveData = serde_json::from_slice(body.as_ref())?;
let data: ApResolveData = serde_json::from_slice(body.as_ref())?;

let ap = if ap_port.is_some() || proxy.is_some() {
data.ap_list.into_iter().find_map(|ap| {
Expand Down
7 changes: 2 additions & 5 deletions core/src/authentication.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,10 @@ impl Credentials {
/// ### Example
/// ```rust
/// use librespot_core::authentication::Credentials;
///
///
/// let creds = Credentials::with_password("my account", "my password");
/// ```
pub fn with_password(
username: impl Into<String>,
password: impl Into<String>,
) -> Credentials {
pub fn with_password(username: impl Into<String>, password: impl Into<String>) -> Credentials {
Credentials {
username: username.into(),
auth_type: AuthenticationType::AUTHENTICATION_USER_PASS,
Expand Down
20 changes: 10 additions & 10 deletions core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl Default for SessionConfig {
fn default() -> SessionConfig {
let device_id = uuid::Uuid::new_v4().to_hyphenated().to_string();
SessionConfig {
user_agent: crate::version::version_string(),
user_agent: crate::version::VERSION_STRING.to_string(),
device_id,
proxy: None,
ap_port: None,
Expand All @@ -29,9 +29,9 @@ pub enum DeviceType {
Tablet = 2,
Smartphone = 3,
Speaker = 4,
TV = 5,
AVR = 6,
STB = 7,
Tv = 5,
Avr = 6,
Stb = 7,
AudioDongle = 8,
GameConsole = 9,
CastAudio = 10,
Expand All @@ -54,9 +54,9 @@ impl FromStr for DeviceType {
"tablet" => Ok(Tablet),
"smartphone" => Ok(Smartphone),
"speaker" => Ok(Speaker),
"tv" => Ok(TV),
"avr" => Ok(AVR),
"stb" => Ok(STB),
"tv" => Ok(Tv),
"avr" => Ok(Avr),
"stb" => Ok(Stb),
"audiodongle" => Ok(AudioDongle),
"gameconsole" => Ok(GameConsole),
"castaudio" => Ok(CastAudio),
Expand All @@ -80,9 +80,9 @@ impl fmt::Display for DeviceType {
Tablet => f.write_str("Tablet"),
Smartphone => f.write_str("Smartphone"),
Speaker => f.write_str("Speaker"),
TV => f.write_str("TV"),
AVR => f.write_str("AVR"),
STB => f.write_str("STB"),
Tv => f.write_str("TV"),
Avr => f.write_str("AVR"),
Stb => f.write_str("STB"),
AudioDongle => f.write_str("AudioDongle"),
GameConsole => f.write_str("GameConsole"),
CastAudio => f.write_str("CastAudio"),
Expand Down
Loading