docs/audio-source-snapshots/codex-rs/voice-host/src/audio_track.rs

Текстовый файл из учебного комплекта, не свидетельство установленного runtime. Вернуться к учебнику · Исходный файл

   1 //! A single Opus RTP track. Muted capture sends generated silence to keep the peer alive;
   2 //! elapsed time still advances its clock without inventing packet loss.
   3 
   4 use std::sync::Arc;
   5 use std::time::Duration;
   6 use std::time::Instant;
   7 
   8 use rtc::media::Sample;
   9 use rtc::rtp_transceiver::rtp_sender::RTCRtpCodec;
  10 use rtc::rtp_transceiver::rtp_sender::RTCRtpCodecParameters;
  11 use rtc::rtp_transceiver::rtp_sender::RTCRtpCodingParameters;
  12 use rtc::rtp_transceiver::rtp_sender::RTCRtpEncodingParameters;
  13 use rtc::rtp_transceiver::rtp_sender::RtpCodecKind;
  14 use webrtc::media_stream::MediaStreamTrack;
  15 use webrtc::media_stream::track_local::static_sample::TrackLocalStaticSample;
  16 use webrtc::peer_connection::MediaEngine;
  17 
  18 pub(crate) const OPUS_PAYLOAD_TYPE: u8 = 111;
  19 pub(crate) const SEND_TIMEOUT: Duration = Duration::from_millis(/*millis*/ 100);
  20 
  21 pub(crate) struct EncodedAudio {
  22     pub(crate) data: Vec<u8>,
  23     pub(crate) at: Instant,
  24 }
  25 
  26 pub(crate) struct AudioTrack {
  27     pub(crate) track: Arc<TrackLocalStaticSample>,
  28     ssrc: u32,
  29     end: Option<Instant>,
  30     silence: Option<Vec<u8>>,
  31 }
  32 
  33 impl AudioTrack {
  34     pub(crate) fn new() -> Result<(MediaEngine, Self), &'static str> {
  35         let ssrc = rand::random();
  36         let codec = RTCRtpCodec {
  37             mime_type: "audio/opus".into(),
  38             clock_rate: 48_000,
  39             channels: 2,
  40             sdp_fmtp_line: "minptime=10;useinbandfec=1".into(),
  41             rtcp_feedback: vec![],
  42         };
  43         let mut media = MediaEngine::default();
  44         media
  45             .register_codec(
  46                 RTCRtpCodecParameters {
  47                     rtp_codec: codec.clone(),
  48                     payload_type: OPUS_PAYLOAD_TYPE,
  49                 },
  50                 RtpCodecKind::Audio,
  51             )
  52             .map_err(|_| "failed to register voice codec")?;
  53         let track = TrackLocalStaticSample::new(MediaStreamTrack::new(
  54             "realtime".into(),
  55             format!("audio-{ssrc}"),
  56             "microphone".into(),
  57             RtpCodecKind::Audio,
  58             vec![RTCRtpEncodingParameters {
  59                 rtp_coding_parameters: RTCRtpCodingParameters {
  60                     ssrc: Some(ssrc),
  61                     ..Default::default()
  62                 },
  63                 codec,
  64                 active: true,
  65                 ..Default::default()
  66             }],
  67         ))
  68         .map_err(|_| "failed to create voice track")?;
  69         Ok((
  70             media,
  71             Self {
  72                 track: Arc::new(track),
  73                 ssrc,
  74                 end: None,
  75                 silence: None,
  76             },
  77         ))
  78     }
  79 
  80     /// Send only synthetic silence while muted, never a device or processing buffer.
  81     /// Reuse the encoded packet and pace it by the same RTP clock as live capture.
  82     #[cfg(any(
  83         target_os = "macos",
  84         all(target_os = "linux", target_env = "gnu"),
  85         all(windows, target_env = "msvc")
  86     ))]
  87     pub(crate) async fn send_muted_silence(&mut self, at: Instant) -> Result<(), &'static str> {
  88         if self.end.is_some_and(|end| at < end) {
  89             return Ok(());
  90         }
  91         if self.silence.is_none() {
  92             let mut encoder = opus::Encoder::new(
  93                 /*sample_rate*/ 48_000,
  94                 opus::Channels::Mono,
  95                 opus::Application::Voip,
  96             )
  97             .map_err(|_| "failed to create voice silence encoder")?;
  98             let mut data = vec![0; 1275];
  99             let len = encoder
 100                 .encode_float(&[0.0; 960], &mut data)
 101                 .map_err(|_| "failed to encode voice silence")?;
 102             data.truncate(len);
 103             self.silence = Some(data);
 104         }
 105         self.send(EncodedAudio {
 106             data: self
 107                 .silence
 108                 .as_ref()
 109                 .ok_or("voice silence unavailable")?
 110                 .clone(),
 111             at,
 112         })
 113         .await
 114     }
 115 
 116     pub(crate) async fn send(&mut self, frame: EncodedAudio) -> Result<(), &'static str> {
 117         tokio::time::timeout(SEND_TIMEOUT, async {
 118             let mut gap = self
 119                 .end
 120                 .map(|end| frame.at.saturating_duration_since(end))
 121                 .unwrap_or_default();
 122             while !gap.is_zero() {
 123                 let duration = gap.min(Duration::from_secs(/*secs*/ 3600));
 124                 self.track
 125                     .write_sample(
 126                         self.ssrc,
 127                         /*payload_type*/ OPUS_PAYLOAD_TYPE,
 128                         &Sample {
 129                             duration,
 130                             ..Default::default()
 131                         },
 132                         &[],
 133                     )
 134                     .await
 135                     .map_err(|_| "failed to advance voice clock")?;
 136                 gap -= duration;
 137             }
 138             let duration = Duration::from_millis(/*millis*/ 20);
 139             self.track
 140                 .write_sample(
 141                     self.ssrc,
 142                     /*payload_type*/ OPUS_PAYLOAD_TYPE,
 143                     &Sample {
 144                         data: frame.data.into(),
 145                         duration,
 146                         ..Default::default()
 147                     },
 148                     &[],
 149                 )
 150                 .await
 151                 .map_err(|_| "failed to send voice audio")?;
 152             self.end = Some(self.end.unwrap_or(frame.at).max(frame.at) + duration);
 153             Ok(())
 154         })
 155         .await
 156         .map_err(|_| "voice audio sender stalled")?
 157     }
 158 }
 159 
 160 #[cfg(test)]
 161 #[path = "audio_track_tests.rs"]
 162 mod tests;