diff options
Diffstat (limited to 'stream/src')
-rw-r--r-- | stream/src/hls.rs | 64 | ||||
-rw-r--r-- | stream/src/lib.rs | 10 | ||||
-rw-r--r-- | stream/src/segment.rs | 2 |
3 files changed, 71 insertions, 5 deletions
diff --git a/stream/src/hls.rs b/stream/src/hls.rs index 6ddc2a4..81d0c8c 100644 --- a/stream/src/hls.rs +++ b/stream/src/hls.rs @@ -3,3 +3,67 @@ which is licensed under the GNU Affero General Public License (version 3); see /COPYING. Copyright (C) 2023 metamuffin <metamuffin.org> */ + +use anyhow::{anyhow, Result}; +use jellybase::CONF; +use jellycommon::{ + stream::{StreamFormat, StreamSpec}, + LocalTrack, Node, +}; +use std::{fmt::Write, ops::Range}; +use tokio::io::{AsyncWriteExt, DuplexStream}; + +pub async fn hls_master_stream( + _node: Node, + _track_sources: Vec<LocalTrack>, + spec: StreamSpec, + mut b: DuplexStream, +) -> Result<()> { + let mut out = String::new(); + writeln!(out, "#EXTM3U")?; + writeln!(out, "#EXT-X-VERSION:4")?; + writeln!(out, "#EXT-X-INDEPENDENT-SEGMENTS")?; + for t in spec.tracks { + let uri = format!( + "stream?{}", + StreamSpec { + tracks: vec![t], + format: StreamFormat::HlsVariant, + ..Default::default() + } + .to_query() + ); + // writeln!(out,"#EXT-X-MEDIA:NAME=\"track {t}\", TYPE=AUDIO, GROUP-ID=\"track{t}\", DEFAULT=YES, AUTOSELECT=YES, URI=\"{uri}\"")?; + writeln!(out, "{uri}")?; + } + tokio::spawn(async move { b.write_all(out.as_bytes()).await }); + Ok(()) +} + +pub async fn hls_variant_stream( + node: Node, + track_sources: Vec<LocalTrack>, + mut spec: StreamSpec, + mut b: DuplexStream, +) -> Result<()> { + let track = *spec.tracks.get(0).ok_or(anyhow!("no track"))?; + let snips = jellyremuxer::snippet::snippet_index( + CONF.library_path.clone(), + node.public.clone(), + &track_sources, + track, + )?; + let mut out = String::new(); + writeln!(out, "#EXTM3U")?; + writeln!(out, "#EXT-X-VERSION:4")?; + + spec.format = StreamFormat::Segment; + for (i, Range { start, end }) in snips.iter().enumerate() { + writeln!(out, "#EXTINF:{},", end - start)?; + spec.index = Some(i); + writeln!(out, "stream?{}", spec.to_query())?; + } + + tokio::spawn(async move { b.write_all(out.as_bytes()).await }); + Ok(()) +} diff --git a/stream/src/lib.rs b/stream/src/lib.rs index 726f1e8..be1ff32 100644 --- a/stream/src/lib.rs +++ b/stream/src/lib.rs @@ -7,12 +7,13 @@ pub mod hls; pub mod segment; use anyhow::{anyhow, bail, Context, Result}; +use hls::{hls_master_stream, hls_variant_stream}; use jellybase::CONF; use jellycommon::{ stream::{StreamFormat, StreamSpec}, LocalTrack, MediaSource, Node, }; -use segment::stream_segment; +use segment::segment_stream; use std::{io::SeekFrom, ops::Range}; use tokio::{ fs::File, @@ -31,7 +32,7 @@ pub fn stream_head(spec: &StreamSpec) -> StreamHead { match spec.format { StreamFormat::Original => StreamHead { content_type: "video/x-matroska", range_supported: true }, StreamFormat::Matroska => StreamHead { content_type: webm_or_mkv, range_supported: true }, - StreamFormat::Hls => StreamHead { content_type: "application/vnd.apple.mpegurl", range_supported: false }, + StreamFormat::HlsMaster | StreamFormat::HlsVariant => StreamHead { content_type: "application/vnd.apple.mpegurl", range_supported: false }, StreamFormat::Jhls => StreamHead { content_type: "application/jellything-jhls+json", range_supported: false }, StreamFormat::Segment => StreamHead { content_type: webm_or_mkv, range_supported: false }, } @@ -53,9 +54,10 @@ pub async fn stream(node: Node, spec: StreamSpec, range: Range<usize>) -> Result match spec.format { StreamFormat::Original => original_stream(track_sources, spec, range, b).await?, StreamFormat::Matroska => remux_stream(node, track_sources, spec, range, b).await?, - StreamFormat::Hls => bail!("unsupported"), + StreamFormat::HlsMaster => hls_master_stream(node, track_sources, spec, b).await?, + StreamFormat::HlsVariant => hls_variant_stream(node, track_sources, spec, b).await?, StreamFormat::Jhls => bail!("unsupported"), - StreamFormat::Segment => stream_segment(node, track_sources, spec, b).await?, + StreamFormat::Segment => segment_stream(node, track_sources, spec, b).await?, } Ok(a) diff --git a/stream/src/segment.rs b/stream/src/segment.rs index d09d357..77f1238 100644 --- a/stream/src/segment.rs +++ b/stream/src/segment.rs @@ -10,7 +10,7 @@ use log::warn; use tokio::io::DuplexStream; use tokio_util::io::SyncIoBridge; -pub async fn stream_segment( +pub async fn segment_stream( node: Node, track_sources: Vec<LocalTrack>, spec: StreamSpec, |