]> git.vomp.tv Git - vompserver.git/blob - transceiver.c
New logging system, bug fixed where client could gazump recordings or
[vompserver.git] / transceiver.c
1 /*
2      Edited for VOMP by Chris Tallon
3      Edits Copyright 2004-2005 Chris Tallon
4 */
5
6 /*
7  *   MediaMVP Server
8  *
9  *   (C) 2003 Dominic Morris
10  *
11  *   $Id$
12  *   $Date$
13  *
14  *   Transceiver stuff - blatantly stolen from streamdev then changed
15  *   a bit..
16  */
17
18
19
20
21
22 #include "transceiver.h"
23 #include "ts2ps.h"
24 #include "ts2es.h"
25 //#include "setup.h"
26
27 #include <vdr/ringbuffer.h>
28
29 #include <sys/types.h>
30 #include <unistd.h>
31
32
33 #define VIDEOBUFSIZE MEGABYTE(1)
34
35 /* Disable logging if BUFCOUNT buffer overflows occur within BUFOVERTIME
36    milliseconds. Enable logging again if there is no error within BUFOVERTIME
37    milliseconds. */
38 #define BUFOVERTIME  5000
39 #define BUFOVERCOUNT 100
40
41 #if VDRVERSNUM < 10300
42 cMediamvpTransceiver::cMediamvpTransceiver(const cChannel *Channel, int Priority, int Socket, cDevice *Device) :
43                 cReceiver(Channel->Ca(), Priority, 7, Channel->Vpid(), Channel->Ppid(),
44                                 Channel->Apid1(), Channel->Apid2(), Channel->Dpid1(), Channel->Dpid2(),
45                                 Channel->Tpid()) {
46 #else
47 cMediamvpTransceiver::cMediamvpTransceiver(const cChannel *Channel, int Priority, int Socket, cDevice *Device) :
48                 cReceiver(Channel->Ca(), Priority, Channel->Vpid(),
49                                 Channel->Apids(), Channel->Dpids(), Channel->Spids()) {
50 #endif
51   m_Active = false;
52         m_Socket = Socket;
53         m_Remux = NULL;
54         m_Device = Device;
55
56 //cjt
57   log = Log::getInstance();
58
59         m_RingBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 2, true);
60 //        m_RingBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 20, true);
61
62     /* Select the correct Muxing depending on whether it's video or not */
63 #if VDRVERSNUM < 10300
64     if ( Channel->Vpid() == 0 || Channel->Vpid() == 1 || Channel->Vpid() == 0x1FFF ) {
65         m_Remux = new cTS2ESRemux(Channel->Apid1());
66     } else {
67                 m_Remux = new cTS2PSRemux(Channel->Vpid(), Channel->Apid1(), 0, 0, 0, 0);
68     }
69 #else
70     if ( Channel->Vpid() == 0 || Channel->Vpid() == 1 || Channel->Vpid() == 0x1FFF ) {
71         m_Remux = new cTS2ESRemux(Channel->Apid(0));
72     } else {
73                 m_Remux = new cTS2PSRemux(Channel->Vpid(), Channel->Apid(0), 0, 0, 0, 0);
74     }
75 #endif
76     log->log("Transciever", Log::DEBUG, "Created transceiver at %p, remux @%p ringbuffer %p",this,m_Remux,m_RingBuffer);
77
78     /* Suggested by Peter Wagner to assist single DVB card systems */
79 #ifdef SINGLE_DEVICE
80         m_Device->SwitchChannel(Channel, true);
81 #else
82         m_Device->SwitchChannel(Channel, false);
83 #endif
84         Attach();
85
86
87         // CJT
88         rb.init(1000000);
89         pthread_mutex_init(&ringLock, NULL);
90
91 }
92
93 cMediamvpTransceiver::~cMediamvpTransceiver(void)
94 {
95     log->log("Transciever", Log::DEBUG, "Deleting transceiver at %p, remux @%p ringbuffer %p",this,m_Remux,m_RingBuffer);
96
97         Detach();
98         if (m_Remux)
99         delete m_Remux;
100     m_Remux = NULL;
101     if ( m_RingBuffer)
102         delete m_RingBuffer;
103     m_RingBuffer = NULL;
104 }
105
106 void cMediamvpTransceiver::Activate(bool On)
107 {
108         if (On)
109                 Start();
110         else if (m_Active)
111                 Stop();
112 }
113
114 void cMediamvpTransceiver::Stop(void)
115 {
116         if (m_Active) {
117                 m_Active = false;
118                 usleep(50000);
119                 Cancel(0);
120         }
121 }
122
123 void cMediamvpTransceiver::Receive(uchar *Data, int Length)
124 {
125         static time_t firsterr = 0;
126         static int errcnt = 0;
127         static bool showerr = true;
128
129         if (m_Active) {
130                 int p = m_RingBuffer->Put(Data, Length);
131                 if (p != Length) {
132                         ++errcnt;
133 #if VDRVERSNUM < 10300
134       if (showerr) {
135                                 if (firsterr == 0)
136                                         firsterr = time_ms();
137                                 else if (firsterr + BUFOVERTIME > time_ms() && errcnt > BUFOVERCOUNT) {
138                                         esyslog("ERROR: too many buffer overflows, logging stopped");
139                                         showerr = false;
140                                         firsterr = time_ms();
141                                 }
142                         } else if (firsterr + BUFOVERTIME < time_ms()) {
143                                 showerr = true;
144                                 firsterr = 0;
145                                 errcnt = 0;
146                         }
147
148                         if (showerr)
149                                 esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
150                         else
151                                 firsterr = time_ms();
152 #else
153       if (showerr) {
154                                 if (firsterr == 0) {
155                                         firsterr = 1;
156           lastTime.Set();
157         }
158                                 else if (lastTime.Elapsed() > BUFOVERTIME && errcnt > BUFOVERCOUNT) {
159                                         esyslog("ERROR: too many buffer overflows, logging stopped");
160                                         showerr = false;
161                                 }
162                         } else if (lastTime.Elapsed() < BUFOVERTIME) {
163                                 showerr = true;
164                                 firsterr = 0;
165                                 errcnt = 0;
166                         }
167
168                         if (showerr)
169                                 esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
170                         else
171                                 firsterr = 1;
172 #endif
173                 }
174         }
175 }
176
177 void cMediamvpTransceiver::Action(void)
178 {
179         int max = 0;
180
181
182     log->log("Transciever", Log::DEBUG, "Mediamvp: Transceiver thread started (pid=%d)", getpid());
183
184
185         m_Active = true;
186
187         while (m_Active) {
188                 int recvd;
189                 const uchar *block = m_RingBuffer->Get(recvd);
190
191                 if (block && recvd > 0) {
192                         const uchar *sendBlock;
193                         int bytes = 0;
194                         int taken = recvd;
195
196             sendBlock = m_Remux->Process(block, taken, bytes);
197
198                         m_RingBuffer->Del(taken);
199
200                         if (bytes > max)
201                                 max = bytes;
202       // CJT
203
204        //     write(m_Socket,sendBlock,bytes);
205       //      printf("Written %i bytes\n", bytes);
206
207
208       pthread_mutex_lock(&ringLock);
209       rb.put((unsigned char*)sendBlock, bytes);
210       pthread_mutex_unlock(&ringLock);
211 //printf("Put %i into buffer\n", bytes);
212
213
214                 } else
215                         usleep(1);
216         }
217
218
219     log->log("Transciever", Log::DEBUG, "Mediamvp: Transceiver thread ended");
220 }
221
222 unsigned long cMediamvpTransceiver::getBlock(unsigned char* buffer, unsigned long amount)
223 {
224   pthread_mutex_lock(&ringLock);
225
226   while ((unsigned long)rb.getContent() < amount)
227   {
228     pthread_mutex_unlock(&ringLock);
229     usleep(500000);
230     pthread_mutex_lock(&ringLock);
231   }
232
233   unsigned long amountReceived = rb.get(buffer, amount);
234   pthread_mutex_unlock(&ringLock);
235   return amountReceived;
236 }