/src/rtpproxy/src/rtpp_server.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org> |
3 | | * Copyright (c) 2006-2016 Sippy Software, Inc., http://www.sippysoft.com |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * 1. Redistributions of source code must retain the above copyright |
10 | | * notice, this list of conditions and the following disclaimer. |
11 | | * 2. Redistributions in binary form must reproduce the above copyright |
12 | | * notice, this list of conditions and the following disclaimer in the |
13 | | * documentation and/or other materials provided with the distribution. |
14 | | * |
15 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
16 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
19 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
20 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
21 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
22 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
23 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
24 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | | * SUCH DAMAGE. |
26 | | * |
27 | | */ |
28 | | |
29 | | #include <sys/types.h> |
30 | | #include <netinet/in.h> |
31 | | #include <fcntl.h> |
32 | | #include <limits.h> |
33 | | #include <stddef.h> |
34 | | #include <stdio.h> |
35 | | #include <stdlib.h> |
36 | | #include <string.h> |
37 | | #include <unistd.h> |
38 | | |
39 | | #include "rtpp_types.h" |
40 | | #include "rtp.h" |
41 | | #include "rtpp_time.h" |
42 | | #include "rtp_packet.h" |
43 | | #include "rtpp_mallocs.h" |
44 | | #include "rtpp_codeptr.h" |
45 | | #include "rtpp_refcnt.h" |
46 | | #include "rtpp_server.h" |
47 | | #include "rtpp_server_fin.h" |
48 | | #include "rtpp_genuid.h" |
49 | | #include "rtpp_debug.h" |
50 | | |
51 | | /* |
52 | | * Minimum length of each RTP packet in ms. |
53 | | * Actual length may differ due to codec's framing constrains. |
54 | | */ |
55 | 0 | #define RTPS_TICKS_MIN 10 |
56 | | |
57 | | #define RTPS_SRATE 8000 |
58 | | |
59 | | struct rtpp_server_priv { |
60 | | struct rtpp_server pub; |
61 | | double btime; |
62 | | unsigned char buf[1024]; |
63 | | rtp_hdr_t *rtp; |
64 | | unsigned char *pload; |
65 | | int fd; |
66 | | int loop; |
67 | | uint64_t dts; |
68 | | int ptime; |
69 | | int started; |
70 | | }; |
71 | | |
72 | | static void rtpp_server_dtor(struct rtpp_server_priv *); |
73 | | static struct rtp_packet *rtpp_server_get(struct rtpp_server *, double, int *); |
74 | | static uint32_t rtpp_server_get_ssrc(struct rtpp_server *); |
75 | | static void rtpp_server_set_ssrc(struct rtpp_server *, uint32_t); |
76 | | static uint16_t rtpp_server_get_seq(struct rtpp_server *); |
77 | | static void rtpp_server_set_seq(struct rtpp_server *, uint16_t); |
78 | | static void rtpp_server_start(struct rtpp_server *, double); |
79 | | |
80 | | DEFINE_SMETHODS(rtpp_server, |
81 | | .get = &rtpp_server_get, |
82 | | .get_ssrc = &rtpp_server_get_ssrc, |
83 | | .set_ssrc = &rtpp_server_set_ssrc, |
84 | | .get_seq = &rtpp_server_get_seq, |
85 | | .set_seq = &rtpp_server_set_seq, |
86 | | .start = &rtpp_server_start |
87 | | ); |
88 | | |
89 | | struct rtpp_server * |
90 | | rtpp_server_ctor(struct rtpp_server_ctor_args *ap) |
91 | 0 | { |
92 | 0 | struct rtpp_server_priv *rp; |
93 | 0 | int fd; |
94 | 0 | char path[PATH_MAX + 1]; |
95 | 0 | size_t len; |
96 | |
|
97 | 0 | len = snprintf(path, sizeof(path), "%s.%d", ap->name, ap->codec); |
98 | 0 | if (len >= sizeof(path)) { |
99 | 0 | ap->result = RTPP_SERV_BADARG; |
100 | 0 | goto e0; |
101 | 0 | } |
102 | 0 | fd = open(path, O_RDONLY); |
103 | 0 | if (fd == -1) { |
104 | 0 | ap->result = RTPP_SERV_NOENT; |
105 | 0 | goto e0; |
106 | 0 | } |
107 | | |
108 | 0 | rp = rtpp_rzmalloc(sizeof(struct rtpp_server_priv), PVT_RCOFFS(rp)); |
109 | 0 | if (rp == NULL) { |
110 | 0 | ap->result = RTPP_SERV_NOMEM; |
111 | 0 | goto e1; |
112 | 0 | } |
113 | | |
114 | 0 | rp->dts = 0; |
115 | 0 | rp->fd = fd; |
116 | 0 | rp->loop = (ap->loop > 0) ? ap->loop - 1 : ap->loop; |
117 | 0 | rp->ptime = (ap->ptime > 0) ? ap->ptime : RTPS_TICKS_MIN; |
118 | |
|
119 | 0 | rp->rtp = (rtp_hdr_t *)rp->buf; |
120 | 0 | rp->rtp->version = 2; |
121 | 0 | rp->rtp->p = 0; |
122 | 0 | rp->rtp->x = 0; |
123 | 0 | rp->rtp->cc = 0; |
124 | 0 | rp->rtp->mbt = 1; |
125 | 0 | rp->rtp->pt = ap->codec; |
126 | 0 | rp->rtp->ts = random() & 0xfffffffe; |
127 | 0 | rp->rtp->seq = random() & 0xffff; |
128 | 0 | rp->rtp->ssrc = random(); |
129 | 0 | rp->pload = rp->buf + RTP_HDR_LEN(rp->rtp); |
130 | |
|
131 | 0 | rp->pub.sruid = CALL_SMETHOD(ap->guid, gen); |
132 | |
|
133 | 0 | PUBINST_FININIT(&rp->pub, rp, rtpp_server_dtor); |
134 | 0 | ap->result = RTPP_SERV_OK; |
135 | 0 | return (&rp->pub); |
136 | 0 | e1: |
137 | 0 | close(fd); |
138 | 0 | e0: |
139 | 0 | return (NULL); |
140 | 0 | } |
141 | | |
142 | | static void |
143 | | rtpp_server_dtor(struct rtpp_server_priv *rp) |
144 | 0 | { |
145 | |
|
146 | 0 | rtpp_server_fin(&rp->pub); |
147 | 0 | close(rp->fd); |
148 | 0 | } |
149 | | |
150 | | static struct rtp_packet * |
151 | | rtpp_server_get(struct rtpp_server *self, double dtime, int *rval) |
152 | 0 | { |
153 | 0 | struct rtp_packet *pkt; |
154 | 0 | uint32_t ts; |
155 | 0 | int rlen, rticks, bytes_per_frame, ticks_per_frame, number_of_frames; |
156 | 0 | int hlen; |
157 | 0 | struct rtpp_server_priv *rp; |
158 | |
|
159 | 0 | PUB2PVT(self, rp); |
160 | |
|
161 | 0 | if (rp->started == 0 || (rp->btime + ((double)rp->dts / 1000.0) > dtime)) { |
162 | 0 | *rval = RTPS_LATER; |
163 | 0 | return (NULL); |
164 | 0 | } |
165 | | |
166 | 0 | switch (rp->rtp->pt) { |
167 | 0 | case RTP_PCMU: |
168 | 0 | case RTP_PCMA: |
169 | 0 | bytes_per_frame = 8; |
170 | 0 | ticks_per_frame = 1; |
171 | 0 | break; |
172 | | |
173 | 0 | case RTP_G729: |
174 | | /* 10 ms per 8 kbps G.729 frame */ |
175 | 0 | bytes_per_frame = 10; |
176 | 0 | ticks_per_frame = 10; |
177 | 0 | break; |
178 | | |
179 | 0 | case RTP_G723: |
180 | | /* 30 ms per 6.3 kbps G.723 frame */ |
181 | 0 | bytes_per_frame = 24; |
182 | 0 | ticks_per_frame = 30; |
183 | 0 | break; |
184 | | |
185 | 0 | case RTP_GSM: |
186 | | /* 20 ms per 13 kbps GSM frame */ |
187 | 0 | bytes_per_frame = 33; |
188 | 0 | ticks_per_frame = 20; |
189 | 0 | break; |
190 | | |
191 | 0 | case RTP_G722: |
192 | 0 | bytes_per_frame = 8; |
193 | 0 | ticks_per_frame = 1; |
194 | 0 | break; |
195 | | |
196 | 0 | default: |
197 | 0 | *rval = RTPS_ERROR; |
198 | 0 | return (NULL); |
199 | 0 | } |
200 | | |
201 | 0 | number_of_frames = rp->ptime / ticks_per_frame; |
202 | 0 | if (rp->ptime % ticks_per_frame != 0) |
203 | 0 | number_of_frames++; |
204 | |
|
205 | 0 | rlen = bytes_per_frame * number_of_frames; |
206 | 0 | rticks = ticks_per_frame * number_of_frames; |
207 | 0 | rp->dts += rticks; |
208 | |
|
209 | 0 | pkt = rtp_packet_alloc(); |
210 | 0 | if (pkt == NULL) { |
211 | 0 | *rval = RTPS_ENOMEM; |
212 | 0 | return (NULL); |
213 | 0 | } |
214 | 0 | hlen = RTP_HDR_LEN(rp->rtp); |
215 | |
|
216 | 0 | if (read(rp->fd, pkt->data.buf + hlen, rlen) != rlen) { |
217 | 0 | if (rp->loop == 0 || lseek(rp->fd, 0, SEEK_SET) == -1 || |
218 | 0 | read(rp->fd, pkt->data.buf + hlen, rlen) != rlen) { |
219 | 0 | *rval = RTPS_EOF; |
220 | 0 | RTPP_OBJ_DECREF(pkt); |
221 | 0 | return (NULL); |
222 | 0 | } |
223 | 0 | if (rp->loop != -1) |
224 | 0 | rp->loop -= 1; |
225 | 0 | } |
226 | | |
227 | 0 | memcpy(&pkt->data.header, rp->rtp, hlen); |
228 | |
|
229 | 0 | if (rp->rtp->mbt != 0) { |
230 | 0 | rp->rtp->mbt = 0; |
231 | 0 | } |
232 | |
|
233 | 0 | ts = ntohl(rp->rtp->ts); |
234 | 0 | rp->rtp->ts = htonl(ts + (RTPS_SRATE * rticks / 1000)); |
235 | 0 | rp->rtp->seq = htons(ntohs(rp->rtp->seq) + 1); |
236 | |
|
237 | 0 | pkt->size = hlen + rlen; |
238 | 0 | return (pkt); |
239 | 0 | } |
240 | | |
241 | | static uint32_t |
242 | | rtpp_server_get_ssrc(struct rtpp_server *self) |
243 | 0 | { |
244 | 0 | struct rtpp_server_priv *rp; |
245 | |
|
246 | 0 | PUB2PVT(self, rp); |
247 | 0 | return (ntohl(rp->rtp->ssrc)); |
248 | 0 | } |
249 | | |
250 | | static void |
251 | | rtpp_server_set_ssrc(struct rtpp_server *self, uint32_t ssrc) |
252 | 0 | { |
253 | 0 | struct rtpp_server_priv *rp; |
254 | |
|
255 | 0 | PUB2PVT(self, rp); |
256 | 0 | rp->rtp->ssrc = htonl(ssrc); |
257 | 0 | } |
258 | | |
259 | | static uint16_t |
260 | | rtpp_server_get_seq(struct rtpp_server *self) |
261 | 0 | { |
262 | 0 | struct rtpp_server_priv *rp; |
263 | |
|
264 | 0 | PUB2PVT(self, rp); |
265 | 0 | return (ntohs(rp->rtp->seq)); |
266 | 0 | } |
267 | | |
268 | | static void |
269 | | rtpp_server_set_seq(struct rtpp_server *self, uint16_t seq) |
270 | 0 | { |
271 | 0 | struct rtpp_server_priv *rp; |
272 | |
|
273 | 0 | PUB2PVT(self, rp); |
274 | 0 | rp->rtp->seq = htons(seq); |
275 | 0 | } |
276 | | |
277 | | static void |
278 | | rtpp_server_start(struct rtpp_server *self, double dtime) |
279 | 0 | { |
280 | 0 | struct rtpp_server_priv *rp; |
281 | |
|
282 | | PUB2PVT(self, rp); |
283 | 0 | RTPP_DBG_ASSERT(rp->started == 0); |
284 | 0 | rp->btime = dtime; |
285 | 0 | rp->started = 1; |
286 | 0 | } |