]> git.sesse.net Git - vlc/blob - modules/access/rtp/input.c
963fe3d837f99da1559adecef3aea7419fc168b8
[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 void *rtp_thread (void *data)
164 {
165     demux_t *demux = data;
166     demux_sys_t *p_sys = demux->p_sys;
167
168     do
169     {
170         block_t *block = rtp_recv (demux);
171
172         vlc_mutex_lock (&p_sys->lock);
173         if (block == NULL)
174             p_sys->dead = true; /* Fatal error: abort */
175         else
176         {
177             if (p_sys->autodetect)
178             {   /* Autodetect payload type, _before_ rtp_queue() */
179                 if (rtp_autodetect (demux, p_sys->session, block))
180                 {
181                     vlc_mutex_unlock (&p_sys->lock);
182                     block_Release (block);
183                     continue;
184                 }
185                 p_sys->autodetect = false;
186             }
187             rtp_queue (demux, p_sys->session, block);
188         }
189         vlc_cond_signal (&p_sys->wait);
190         vlc_mutex_unlock (&p_sys->lock);
191     }
192     while (!p_sys->dead);
193
194     return NULL;
195 }
196
197
198 /**
199  * Process one RTP packet from the de-jitter queue.
200  * @return 0 on success, -1 on EOF
201  */
202 int rtp_process (demux_t *demux)
203 {
204     demux_sys_t *p_sys = demux->p_sys;
205     mtime_t deadline = INT64_MAX;
206     int ret;
207
208     vlc_mutex_lock (&p_sys->lock);
209     if (rtp_dequeue (demux, p_sys->session, &deadline))
210         /* Pace the demux thread */
211         vlc_cond_timedwait (&p_sys->wait, &p_sys->lock, deadline);
212     else
213         vlc_cond_wait (&p_sys->wait, &p_sys->lock);
214     ret = p_sys->dead ? -1 : 0;
215     vlc_mutex_unlock (&p_sys->lock);
216
217     return ret;
218 }