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