]> git.sesse.net Git - vlc/blob - modules/access/rtp/input.c
Use var_InheritString for --decklink-video-connection.
[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 Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1
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 #ifdef HAVE_SRTP
39 # include <srtp.h>
40 #endif
41
42 static bool fd_dead (int fd)
43 {
44     struct pollfd ufd = { .fd = fd, };
45     return (poll (&ufd, 1, 0) > 0) && (ufd.revents & POLLHUP);
46 }
47
48 /**
49  * Gets a datagram from the network.
50  * @param fd datagram file descriptor
51  * @return a block or NULL on fatal error (socket dead)
52  */
53 static block_t *rtp_dgram_recv (vlc_object_t *obj, int fd)
54 {
55     block_t *block = block_Alloc (0xffff);
56     ssize_t len;
57
58     block_cleanup_push (block);
59     do
60     {
61         len = net_Read (obj, fd, NULL,
62                         block->p_buffer, block->i_buffer, false);
63
64         if (((len <= 0) && fd_dead (fd)) || !vlc_object_alive (obj))
65         {   /* POLLHUP -> permanent (DCCP) socket error */
66             block_Release (block);
67             block = NULL;
68             break;
69         }
70     }
71     while (len == -1);
72     vlc_cleanup_pop ();
73
74     return block ? block_Realloc (block, 0, len) : NULL;
75 }
76
77
78 /**
79  * Gets a framed RTP packet.
80  * @param fd stream file descriptor
81  * @return a block or NULL in case of fatal error
82  */
83 static block_t *rtp_stream_recv (vlc_object_t *obj, int fd)
84 {
85     ssize_t len = 0;
86     uint8_t hdr[2]; /* frame header */
87
88     /* Receives the RTP frame header */
89     do
90     {
91         ssize_t val = net_Read (obj, fd, NULL, hdr + len, 2 - len, false);
92         if (val <= 0)
93             return NULL;
94         len += val;
95     }
96     while (len < 2);
97
98     block_t *block = block_Alloc (GetWBE (hdr));
99
100     /* Receives the RTP packet */
101     for (ssize_t i = 0; i < len;)
102     {
103         ssize_t val;
104
105         block_cleanup_push (block);
106         val = net_Read (obj, fd, NULL,
107                         block->p_buffer + i, block->i_buffer - i, false);
108         vlc_cleanup_pop ();
109
110         if (val <= 0)
111         {
112             block_Release (block);
113             return NULL;
114         }
115         i += val;
116     }
117
118     return block;
119 }
120
121
122 static block_t *rtp_recv (demux_t *demux)
123 {
124     demux_sys_t *p_sys = demux->p_sys;
125
126     for (block_t *block;; block_Release (block))
127     {
128         block = p_sys->framed_rtp
129                 ? rtp_stream_recv (VLC_OBJECT (demux), p_sys->fd)
130                 : rtp_dgram_recv (VLC_OBJECT (demux), p_sys->fd);
131         if (block == NULL)
132         {
133             msg_Err (demux, "RTP flow stopped");
134             break; /* fatal error */
135         }
136
137         if (block->i_buffer < 2)
138             continue;
139
140         /* FIXME */
141         const uint8_t ptype = rtp_ptype (block);
142         if (ptype >= 72 && ptype <= 76)
143             continue; /* Muxed RTCP, ignore for now */
144 #ifdef HAVE_SRTP
145         if (p_sys->srtp)
146         {
147             size_t len = block->i_buffer;
148             int canc, err;
149
150             canc = vlc_savecancel ();
151             err = srtp_recv (p_sys->srtp, block->p_buffer, &len);
152             vlc_restorecancel (canc);
153             if (err)
154             {
155                 msg_Dbg (demux, "SRTP authentication/decryption failed");
156                 continue;
157             }
158             block->i_buffer = len;
159         }
160 #endif
161         return block; /* success! */
162     }
163     return NULL;
164 }
165
166
167 static void timer_cleanup (void *timer)
168 {
169     vlc_timer_destroy ((vlc_timer_t)timer);
170 }
171
172 static void rtp_process (void *data);
173
174 void *rtp_thread (void *data)
175 {
176     demux_t *demux = data;
177     demux_sys_t *p_sys = demux->p_sys;
178     bool autodetect = true;
179
180     if (vlc_timer_create (&p_sys->timer, rtp_process, data))
181         return NULL;
182     vlc_cleanup_push (timer_cleanup, (void *)p_sys->timer);
183
184     for (;;)
185     {
186         block_t *block = rtp_recv (demux);
187         if (block == NULL)
188             break;
189
190         if (autodetect)
191         {   /* Autodetect payload type, _before_ rtp_queue() */
192             /* No need for lock - the queue is empty. */
193             if (rtp_autodetect (demux, p_sys->session, block))
194             {
195                 block_Release (block);
196                 continue;
197             }
198             autodetect = false;
199         }
200
201         int canc = vlc_savecancel ();
202         vlc_mutex_lock (&p_sys->lock);
203         rtp_queue (demux, p_sys->session, block);
204         vlc_mutex_unlock (&p_sys->lock);
205         vlc_restorecancel (canc);
206
207         rtp_process (demux);
208     }
209     vlc_cleanup_run ();
210     return NULL;
211 }
212
213
214 /**
215  * Process one RTP packet from the de-jitter queue.
216  */
217 static void rtp_process (void *data)
218 {
219     demux_t *demux = data;
220     demux_sys_t *p_sys = demux->p_sys;
221     mtime_t deadline;
222
223     vlc_mutex_lock (&p_sys->lock);
224     if (rtp_dequeue (demux, p_sys->session, &deadline))
225         vlc_timer_schedule (p_sys->timer, true, deadline, 0);
226     vlc_mutex_unlock (&p_sys->lock);
227 }