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