reqwesthttpsrc: Add support for parsing the Content-Type header

In iradio-mode we would put it as an additional field to the caps,
otherwise if it's audio/L16 we would create audio/x-unaligned-raw caps
accordingly.
This commit is contained in:
Sebastian Dröge 2019-10-14 21:59:49 +03:00
parent 12058a4c9a
commit bc34fbd2eb
2 changed files with 96 additions and 3 deletions

View file

@ -347,8 +347,8 @@ impl ReqwestHttpSrc {
) -> Result<State, Option<gst::ErrorMessage>> {
use hyperx::header::{
qitem, AcceptEncoding, AcceptRanges, ByteRangeSpec, Connection, ContentLength,
ContentRange, ContentRangeSpec, Cookie, Encoding, Headers, Range, RangeUnit, RawLike,
UserAgent,
ContentRange, ContentRangeSpec, ContentType, Cookie, Encoding, Headers, Range,
RangeUnit, RawLike, UserAgent,
};
gst_debug!(self.cat, obj: src, "Creating new request for {}", uri);
@ -557,7 +557,7 @@ impl ReqwestHttpSrc {
)));
}
let caps = headers
let mut caps = headers
.get_raw("icy-metaint")
.and_then(|h| h.one())
.and_then(|s| std::str::from_utf8(s).ok())
@ -568,6 +568,33 @@ impl ReqwestHttpSrc {
.build()
});
if let Some(ContentType(ref content_type)) = headers.get() {
gst_debug!(self.cat, obj: src, "Got content type {}", content_type);
if let Some(ref mut caps) = caps {
let caps = caps.get_mut().unwrap();
let s = caps.get_mut_structure(0).unwrap();
s.set("content-type", &content_type.as_ref());
} else if content_type.type_() == "audio" && content_type.subtype() == "L16" {
let channels = content_type
.get_param("channels")
.and_then(|s| s.as_ref().parse::<i32>().ok())
.unwrap_or(2);
let rate = content_type
.get_param("rate")
.and_then(|s| s.as_ref().parse::<i32>().ok())
.unwrap_or(44_100);
caps = Some(
gst::Caps::builder("audio/x-unaligned-raw")
.field("format", &"S16BE")
.field("layout", &"interleaved")
.field("channels", &channels)
.field("rate", &rate)
.build(),
);
}
}
let mut tags = gst::TagList::new();
{
let tags = tags.get_mut().unwrap();

View file

@ -590,6 +590,7 @@ fn test_iradio_mode() {
.header("icy-name", "Name")
.header("icy-genre", "Genre")
.header("icy-url", "http://www.example.com")
.header("Content-Type", "audio/mpeg; rate=44100")
.body(Body::from("Hello World"))
.unwrap()
},
@ -634,6 +635,7 @@ fn test_iradio_mode() {
caps,
gst::Caps::builder("application/x-icy")
.field("metadata-interval", &8192i32)
.field("content-type", &"audio/mpeg; rate=44100")
.build()
);
@ -657,6 +659,70 @@ fn test_iradio_mode() {
}
}
#[test]
fn test_audio_l16() {
use std::io::{Cursor, Read};
init();
// Set up a harness that returns "Hello World" for any HTTP request and check if the
// audio/L16 content type is parsed correctly and put into the caps
let mut h = Harness::new(
|_req| {
use hyper::{Body, Response};
Response::builder()
.header("Content-Type", "audio/L16; rate=48000; channels=2")
.body(Body::from("Hello World"))
.unwrap()
},
|_src| {
// No additional setup needed here
},
);
// Set the HTTP source to Playing so that everything can start
h.run(|src| {
src.set_state(gst::State::Playing).unwrap();
});
// And now check if the data we receive is exactly what we expect it to be
let expected_output = "Hello World";
let mut cursor = Cursor::new(expected_output);
while let Some(buffer) = h.wait_buffer_or_eos() {
// On the first buffer also check if the duration reported by the HTTP source is what we
// would expect it to be
if cursor.position() == 0 {
assert_eq!(
h.src.query_duration::<gst::format::Bytes>(),
Some(gst::format::Bytes::from(expected_output.len() as u64))
);
}
// Map the buffer readable and check if it contains exactly the data we would expect at
// this point after reading everything else we read in previous runs
let map = buffer.map_readable().unwrap();
let mut read_buf = vec![0; map.get_size()];
assert_eq!(cursor.read(&mut read_buf).unwrap(), map.get_size());
assert_eq!(&*map, &*read_buf);
}
// Check if everything was read
assert_eq!(cursor.position(), 11);
let srcpad = h.src.get_static_pad("src").unwrap();
let caps = srcpad.get_current_caps().unwrap();
assert_eq!(
caps,
gst::Caps::builder("audio/x-unaligned-raw")
.field("format", &"S16BE")
.field("layout", &"interleaved")
.field("channels", &2i32)
.field("rate", &48_000i32)
.build()
);
}
#[test]
fn test_authorization() {
use std::io::{Cursor, Read};