]> git.sesse.net Git - vlc/blob - modules/access/rtp/input.c
RTP: avoid pf_demux. Fix input thread latency
[vlc] / modules / access / rtp / input.c
1 /**
2  * @file input.c
3  * @brief RTP packet input
4  */
5 /*****************************************************************************
6  * Copyright © 2008 Rémi Denis-Courmont
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2.0
11  * of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  ****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_demux.h>
29 #include <vlc_block.h>
30 #include <vlc_network.h>
31
32 #include <unistd.h>
33 #ifdef HAVE_POLL
34 # include <poll.h>
35 #endif
36
37 #include "rtp.h"
38 #include <srtp.h>
39
40 static bool fd_dead (int fd)
41 {
42     struct pollfd ufd = { .fd = fd, };
43     return (poll (&ufd, 1, 0) > 0) && (ufd.revents & POLLHUP);
44 }
45
46 /**
47  * Gets a datagram from the network.
48  * @param fd datagram file descriptor
49  * @return a block or NULL on fatal error (socket dead)
50  */
51 static block_t *rtp_dgram_recv (vlc_object_t *obj, int fd)
52 {
53     block_t *block = block_Alloc (0xffff);
54     ssize_t len;
55
56     do
57     {
58         block_cleanup_push (block);
59         len = net_Read (obj, fd, NULL,
60                         block->p_buffer, block->i_buffer, false);
61         vlc_cleanup_pop ();
62
63         if (((len <= 0) && fd_dead (fd)) || !vlc_object_alive (obj))
64         {   /* POLLHUP -> permanent (DCCP) socket error */
65             block_Release (block);
66             return NULL;
67         }
68     }
69     while (len == -1);
70
71     return block_Realloc (block, 0, len);
72 }
73
74
75 /**
76  * Gets a framed RTP packet.
77  * @param fd stream file descriptor
78  * @return a block or NULL in case of fatal error
79  */
80 static block_t *rtp_stream_recv (vlc_object_t *obj, int fd)
81 {
82     ssize_t len = 0;
83     uint8_t hdr[2]; /* frame header */
84
85     /* Receives the RTP frame header */
86     do
87     {
88         ssize_t val = net_Read (obj, fd, NULL, hdr + len, 2 - len, false);
89         if (val <= 0)
90             return NULL;
91         len += val;
92     }
93     while (len < 2);
94
95     block_t *block = block_Alloc (GetWBE (hdr));
96
97     /* Receives the RTP packet */
98     for (ssize_t i = 0; i < len;)
99     {
100         ssize_t val;
101
102         block_cleanup_push (block);
103         val = net_Read (obj, fd, NULL,
104                         block->p_buffer + i, block->i_buffer - i, false);
105         vlc_cleanup_pop ();
106
107         if (val <= 0)
108         {
109             block_Release (block);
110             return NULL;
111         }
112         i += val;
113     }
114
115     return block;
116 }
117
118
119 static block_t *rtp_recv (demux_t *demux)
120 {
121     demux_sys_t *p_sys = demux->p_sys;
122
123     for (block_t *block;; block_Release (block))
124     {
125         block = p_sys->framed_rtp
126                 ? rtp_stream_recv (VLC_OBJECT (demux), p_sys->fd)
127                 : rtp_dgram_recv (VLC_OBJECT (demux), p_sys->fd);
128         if (block == NULL)
129         {
130             msg_Err (demux, "RTP flow stopped");
131             break; /* fatal error */
132         }
133
134         if (block->i_buffer < 2)
135             continue;
136
137         /* FIXME */
138         const uint8_t ptype = rtp_ptype (block);
139         if (ptype >= 72 && ptype <= 76)
140             continue; /* Muxed RTCP, ignore for now */
141
142         if (p_sys->srtp)
143         {
144             size_t len = block->i_buffer;
145             int canc, err;
146
147             canc = vlc_savecancel ();
148             err = srtp_recv (p_sys->srtp, block->p_buffer, &len);
149             vlc_restorecancel (canc);
150             if (err)
151             {
152                 msg_Dbg (demux, "SRTP authentication/decryption failed");
153                 continue;
154             }
155             block->i_buffer = len;
156         }
157         return block; /* success! */
158     }
159     return NULL;
160 }
161
162
163 static void timer_cleanup (void *timer)
164 {
165     vlc_timer_destroy (timer);
166 }
167
168 static void rtp_process (void *data);
169
170 void *rtp_thread (void *data)
171 {
172     demux_t *demux = data;
173     demux_sys_t *p_sys = demux->p_sys;
174     bool autodetect = true, reorder = false;
175
176     if (vlc_timer_create (&p_sys->timer, rtp_process, data))
177         return NULL;
178     vlc_cleanup_push (timer_cleanup, &p_sys->timer);
179
180     for (;;)
181     {
182         block_t *block = rtp_recv (demux);
183         if (block == NULL)
184             break;
185
186         if (autodetect)
187         {   /* Autodetect payload type, _before_ rtp_queue() */
188             /* No need for lock - the queue is empty. */
189             if (rtp_autodetect (demux, p_sys->session, block))
190             {
191                 block_Release (block);
192                 continue;
193             }
194             autodetect = false;
195         }
196
197         vlc_mutex_lock (&p_sys->lock);
198         rtp_queue (demux, p_sys->session, block);
199         vlc_mutex_unlock (&p_sys->lock);
200
201         rtp_process (demux);
202     }
203     vlc_cleanup_run ();
204     return NULL;
205 }
206
207
208 /**
209  * Process one RTP packet from the de-jitter queue.
210  */
211 static void rtp_process (void *data)
212 {
213     demux_t *demux = data;
214     demux_sys_t *p_sys = demux->p_sys;
215     mtime_t deadline;
216
217     vlc_mutex_lock (&p_sys->lock);
218     if (rtp_dequeue (demux, p_sys->session, &deadline))
219         vlc_timer_schedule (&p_sys->timer, true, deadline, 0);
220     vlc_mutex_unlock (&p_sys->lock);
221 }