1use gbp::CodecError;
4use gbp_core::PayloadCodec;
5use serde::{Deserialize, Serialize};
6use serde_bytes::ByteBuf;
7
8#[derive(Clone, Debug, Serialize, Deserialize)]
10pub struct GapPayload {
11 #[serde(rename = "msid")]
13 pub media_source_id: u32,
14 #[serde(rename = "seq")]
16 pub rtp_sequence: u32,
17 #[serde(rename = "ts")]
19 pub rtp_timestamp: u64,
20 #[serde(rename = "kp")]
22 pub key_phase: u32,
23 #[serde(rename = "opus")]
25 pub opus_frame: ByteBuf,
26}
27
28impl GapPayload {
29 pub fn opus_20ms(
31 media_source_id: u32,
32 rtp_sequence: u16,
33 key_phase: u32,
34 opus: Vec<u8>,
35 ) -> Self {
36 Self {
37 media_source_id,
38 rtp_sequence: rtp_sequence as u32,
39 rtp_timestamp: 960,
40 key_phase,
41 opus_frame: ByteBuf::from(opus),
42 }
43 }
44
45 pub fn with_timestamp(
48 media_source_id: u32,
49 rtp_sequence: u16,
50 rtp_timestamp: u64,
51 key_phase: u32,
52 opus: Vec<u8>,
53 ) -> Self {
54 Self {
55 media_source_id,
56 rtp_sequence: rtp_sequence as u32,
57 rtp_timestamp,
58 key_phase,
59 opus_frame: ByteBuf::from(opus),
60 }
61 }
62
63 pub fn to_cbor(&self) -> Vec<u8> {
65 let mut buf = Vec::new();
66 ciborium::into_writer(self, &mut buf).expect("cbor encode");
67 buf
68 }
69
70 pub fn from_cbor(data: &[u8]) -> Result<Self, CodecError> {
72 ciborium::from_reader(data).map_err(|e| CodecError::Decode(e.to_string()))
73 }
74
75 pub fn to_bytes(&self, codec: PayloadCodec) -> Vec<u8> {
77 match codec {
78 PayloadCodec::Cbor => self.to_cbor(),
79 PayloadCodec::Protobuf => {
80 use prost::Message as _;
81 gbp_proto::gap::GapPayload::from(self).encode_to_vec()
82 }
83 PayloadCodec::FlatBuffers => {
84 let mut b = gbp_flat::planus::Builder::new();
85 b.finish(gbp_flat::gap::GapPayload::from(self), None).to_vec()
86 }
87 }
88 }
89
90 pub fn from_bytes(data: &[u8], codec: PayloadCodec) -> Result<Self, CodecError> {
92 match codec {
93 PayloadCodec::Cbor => Self::from_cbor(data),
94 PayloadCodec::Protobuf => {
95 use prost::Message as _;
96 let p = gbp_proto::gap::GapPayload::decode(data)
97 .map_err(|e| CodecError::Decode(e.to_string()))?;
98 Ok(Self::from(p))
99 }
100 PayloadCodec::FlatBuffers => {
101 use gbp_flat::planus::ReadAsRoot as _;
102 let r = gbp_flat::gap::GapPayloadRef::read_as_root(data)
103 .map_err(|e| CodecError::Decode(e.to_string()))?;
104 Self::try_from(r).map_err(|_| CodecError::Decode("flatbuffers field error".into()))
105 }
106 }
107 }
108}
109
110impl From<&GapPayload> for gbp_proto::gap::GapPayload {
113 fn from(p: &GapPayload) -> Self {
114 Self {
115 media_source_id: p.media_source_id,
116 rtp_sequence: p.rtp_sequence,
117 rtp_timestamp: p.rtp_timestamp,
118 key_phase: p.key_phase,
119 opus_frame: p.opus_frame.to_vec(),
120 }
121 }
122}
123
124impl From<gbp_proto::gap::GapPayload> for GapPayload {
125 fn from(p: gbp_proto::gap::GapPayload) -> Self {
126 Self {
127 media_source_id: p.media_source_id,
128 rtp_sequence: p.rtp_sequence,
129 rtp_timestamp: p.rtp_timestamp,
130 key_phase: p.key_phase,
131 opus_frame: ByteBuf::from(p.opus_frame),
132 }
133 }
134}
135
136impl From<&GapPayload> for gbp_flat::gap::GapPayload {
139 fn from(p: &GapPayload) -> Self {
140 Self {
141 media_source_id: p.media_source_id,
142 rtp_sequence: p.rtp_sequence,
143 rtp_timestamp: p.rtp_timestamp,
144 key_phase: p.key_phase,
145 opus_frame: Some(p.opus_frame.to_vec()),
146 }
147 }
148}
149
150impl<'a> TryFrom<gbp_flat::gap::GapPayloadRef<'a>> for GapPayload {
151 type Error = ();
152 fn try_from(r: gbp_flat::gap::GapPayloadRef<'a>) -> Result<Self, ()> {
153 let opus_frame = r.opus_frame().map_err(|_| ())?.unwrap_or(&[]).to_vec();
154 Ok(Self {
155 media_source_id: r.media_source_id().map_err(|_| ())?,
156 rtp_sequence: r.rtp_sequence().map_err(|_| ())?,
157 rtp_timestamp: r.rtp_timestamp().map_err(|_| ())?,
158 key_phase: r.key_phase().map_err(|_| ())?,
159 opus_frame: ByteBuf::from(opus_frame),
160 })
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 fn sample() -> GapPayload {
169 GapPayload::opus_20ms(1, 42, 7, vec![0xAB, 0xCD, 0xEF])
170 }
171
172 #[test]
173 fn cbor_roundtrip() {
174 let orig = sample();
175 let bytes = orig.to_bytes(PayloadCodec::Cbor);
176 let decoded = GapPayload::from_bytes(&bytes, PayloadCodec::Cbor).unwrap();
177 assert_eq!(decoded.media_source_id, orig.media_source_id);
178 assert_eq!(decoded.rtp_sequence, orig.rtp_sequence);
179 assert_eq!(decoded.key_phase, orig.key_phase);
180 assert_eq!(decoded.opus_frame.as_ref(), orig.opus_frame.as_ref());
181 }
182
183 #[test]
184 fn protobuf_roundtrip() {
185 let orig = sample();
186 let bytes = orig.to_bytes(PayloadCodec::Protobuf);
187 let decoded = GapPayload::from_bytes(&bytes, PayloadCodec::Protobuf).unwrap();
188 assert_eq!(decoded.media_source_id, orig.media_source_id);
189 assert_eq!(decoded.rtp_sequence, orig.rtp_sequence);
190 assert_eq!(decoded.opus_frame.as_ref(), orig.opus_frame.as_ref());
191 }
192
193 #[test]
194 fn flatbuffers_roundtrip() {
195 let orig = sample();
196 let bytes = orig.to_bytes(PayloadCodec::FlatBuffers);
197 let decoded = GapPayload::from_bytes(&bytes, PayloadCodec::FlatBuffers).unwrap();
198 assert_eq!(decoded.media_source_id, orig.media_source_id);
199 assert_eq!(decoded.rtp_sequence, orig.rtp_sequence);
200 assert_eq!(decoded.opus_frame.as_ref(), orig.opus_frame.as_ref());
201 }
202
203 #[test]
204 fn codec_bytes_differ() {
205 let p = sample();
206 let cbor = p.to_bytes(PayloadCodec::Cbor);
207 let proto = p.to_bytes(PayloadCodec::Protobuf);
208 let flat = p.to_bytes(PayloadCodec::FlatBuffers);
209 assert_ne!(cbor, proto);
210 assert_ne!(cbor, flat);
211 assert_ne!(proto, flat);
212 }
213}