RTP: notify demux thread when RTP flow is dead
[vlc.git] / 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 /**
41  * Gets a datagram from the network.
42  * @param fd datagram file descriptor
43  * @return a block or NULL on fatal error (socket dead)
44  */
45 static block_t *rtp_dgram_recv (vlc_object_t *obj, int fd)
46 {
47     block_t *block = block_Alloc (0xffff);
48     ssize_t len;
49
50     do
51     {
52         block_cleanup_push (block);
53         len = net_Read (obj, fd, NULL,
54                         block->p_buffer, block->i_buffer, false);
55         vlc_cleanup_pop ();
56
57         if (((len <= 0) && poll (&(struct pollfd){ .fd = fd, }, 1, 0))
58          || !vlc_object_alive (obj))
59         {   /* POLLHUP -> permanent (DCCP) socket error */
60             block_Release (block);
61             return NULL;
62         }
63     }
64     while (len == -1);
65
66     return block_Realloc (block, 0, len);
67 }
68
69
70 /**
71  * Gets a framed RTP packet.
72  * @param fd stream file descriptor
73  * @return a block or NULL in case of fatal error
74  */
75 static block_t *rtp_stream_recv (vlc_object_t *obj, int fd)
76 {
77     ssize_t len = 0;
78     uint8_t hdr[2]; /* frame header */
79
80     /* Receives the RTP frame header */
81     do
82     {
83         ssize_t val = net_Read (obj, fd, NULL, hdr + len, 2 - len, false);
84         if (val <= 0)
85             return NULL;
86         len += val;
87     }
88     while (len < 2);
89
90     block_t *block = block_Alloc (GetWBE (hdr));
91
92     /* Receives the RTP packet */
93     for (ssize_t i = 0; i < len;)
94     {
95         ssize_t val;
96
97         block_cleanup_push (block);
98         val = net_Read (obj, fd, NULL,
99                         block->p_buffer + i, block->i_buffer - i, false);
100         vlc_cleanup_pop ();
101
102         if (val <= 0)
103         {
104             block_Release (block);
105             return NULL;
106         }
107         i += val;
108     }
109
110     return block;
111 }
112
113
114 static block_t *rtp_recv (demux_t *demux)
115 {
116     demux_sys_t *p_sys = demux->p_sys;
117
118     for (block_t *block;; block_Release (block))
119     {
120         block = p_sys->framed_rtp
121                 ? rtp_stream_recv (VLC_OBJECT (demux), p_sys->fd)
122                 : rtp_dgram_recv (VLC_OBJECT (demux), p_sys->fd);
123         if (block == NULL)
124         {
125             msg_Err (demux, "RTP flow stopped");
126             break; /* fatal error */
127         }
128
129         if (block->i_buffer < 2)
130             continue;
131
132         /* FIXME */
133         const uint8_t ptype = rtp_ptype (block);
134         if (ptype >= 72 && ptype <= 76)
135             continue; /* Muxed RTCP, ignore for now */
136
137         if (p_sys->srtp)
138         {
139             size_t len = block->i_buffer;
140             int canc, err;
141
142             canc = vlc_savecancel ();
143             err = srtp_recv (p_sys->srtp, block->p_buffer, &len);
144             vlc_restorecancel (canc);
145             if (err)
146             {
147                 msg_Dbg (demux, "SRTP authentication/decryption failed");
148                 continue;
149             }
150             block->i_buffer = len;
151         }
152         return block; /* success! */
153     }
154     return NULL;
155 }
156
157
158 void *rtp_thread (void *data)
159 {
160     demux_t *demux = data;
161     demux_sys_t *p_sys = demux->p_sys;
162
163     do
164     {
165         block_t *block = rtp_recv (demux);
166
167         vlc_mutex_lock (&p_sys->lock);
168         if (block == NULL)
169             p_sys->dead = true; /* Fatal error: abort */
170         else
171         {
172             if (p_sys->autodetect)
173             {   /* Autodetect payload type, _before_ rtp_queue() */
174                 if (rtp_autodetect (demux, p_sys->session, block))
175                 {
176                     vlc_mutex_unlock (&p_sys->lock);
177                     block_Release (block);
178                     continue;
179                 }
180                 p_sys->autodetect = false;
181             }
182             rtp_queue (demux, p_sys->session, block);
183         }
184         vlc_cond_signal (&p_sys->wait);
185         vlc_mutex_unlock (&p_sys->lock);
186     }
187     while (!p_sys->dead);
188
189     return NULL;
190 }
191
192
193 void rtp_process (demux_t *demux)
194 {
195     demux_sys_t *p_sys = demux->p_sys;
196     mtime_t deadline = INT64_MAX;
197
198     vlc_mutex_lock (&p_sys->lock);
199     if (!rtp_dequeue (demux, p_sys->session, &deadline))
200         deadline = mdate () + CLOCK_FREQ / 5;
201     vlc_cond_timedwait (&p_sys->wait, &p_sys->lock, deadline);
202     vlc_mutex_unlock (&p_sys->lock);
203 }
204