22
22
#include "application.h"
23
23
#include "dvb_si.h"
25
class Lock : public Glib::RecMutex::Lock
28
Lock(Glib::RecMutex& mutex, const Glib::ustring& name) :
29
Glib::RecMutex::Lock(mutex) {}
25
#define READ_TIMEOUT 10 /* In milliseconds */
33
27
FrontendThread::FrontendThread(Dvb::Frontend& f) : Thread("Frontend"), frontend(f)
35
29
g_debug("Creating FrontendThread (%s)", frontend.get_path().c_str());
33
Glib::ustring input_path = frontend.get_adapter().get_dvr_path();
35
g_debug("Opening frontend device '%s' for reading ...", input_path.c_str());
36
if ( (fd = ::open(input_path.c_str(), O_RDONLY | O_NONBLOCK) ) < 0 )
38
throw SystemException("Failed to open frontend device");
40
41
g_debug("FrontendThread created (%s)", frontend.get_path().c_str());
43
44
FrontendThread::~FrontendThread()
45
46
g_debug("Destroying FrontendThread (%s)", frontend.get_path().c_str());
48
g_debug("About to close input channel ...");
53
g_debug("FrontendThread destroyed (%s)", frontend.get_path().c_str());
49
56
void FrontendThread::start()
52
g_debug("Starting frontend thread (%s)", frontend.get_path().c_str());
60
g_debug("Starting frontend thread (%s)", frontend.get_path().c_str());
56
65
void FrontendThread::stop()
58
67
g_debug("Stopping frontend thread (%s)", frontend.get_path().c_str());
62
g_debug("Deleting channel streams");
63
ChannelStreamList::iterator iterator = streams.begin();
64
while (iterator != streams.end())
66
ChannelStream* channel_stream = *iterator;
67
delete channel_stream;
68
iterator = streams.erase(iterator);
72
g_debug("Frontend thread stopped (%s)", frontend.get_path().c_str());
70
g_debug("Frontend thread stopped and joined (%s)", frontend.get_path().c_str());
75
73
void FrontendThread::run()
77
75
g_debug("Frontend thread running (%s)", frontend.get_path().c_str());
77
struct pollfd pfds[1];
79
pfds[0].events = POLLIN;
79
81
guchar buffer[TS_PACKET_SIZE * PACKET_BUFFER_SIZE];
80
82
guchar pat[TS_PACKET_SIZE];
81
83
guchar pmt[TS_PACKET_SIZE];
83
Glib::ustring input_path = frontend.get_adapter().get_dvr_path();
86
if ( (fd = ::open( input_path.c_str(), O_RDONLY | O_NONBLOCK) ) < 0 )
88
throw SystemException("Failed to open frontend");
91
g_debug("Opening frontend device '%s' for reading ...", input_path.c_str());
92
Glib::RefPtr<Glib::IOChannel> input_channel = Glib::IOChannel::create_from_fd(fd);
93
input_channel->set_encoding("");
94
g_debug("Frontend device opened (%s)", frontend.get_path().c_str());
96
85
guint last_insert_time = 0;
99
87
g_debug("Entering FrontendThread loop (%s)", frontend.get_path().c_str());
100
88
while (!is_terminated())
104
g_debug("Frontend is not tuned, waiting (%s)", frontend.get_path().c_str());
113
Lock lock(mutex, __PRETTY_FUNCTION__);
115
if (input_channel->read((gchar*)buffer, TS_PACKET_SIZE * PACKET_BUFFER_SIZE, bytes_read) == Glib::IO_STATUS_NORMAL)
117
// Insert PAT/PMT every second second
118
time_t now = time(NULL);
119
if (now - last_insert_time > 2)
121
g_debug("Writing PAT/PMT header");
123
for (ChannelStreamList::iterator i = streams.begin(); i != streams.end(); i++)
125
ChannelStream& channel_stream = **i;
127
channel_stream.stream.build_pat(pat);
128
channel_stream.stream.build_pmt(pmt);
130
channel_stream.write(pat, TS_PACKET_SIZE);
131
channel_stream.write(pmt, TS_PACKET_SIZE);
133
last_insert_time = now;
136
for (guint offset = 0; offset < bytes_read; offset += TS_PACKET_SIZE)
138
guint pid = ((buffer[offset+1] & 0x1f) << 8) + buffer[offset+2];
140
for (ChannelStreamList::iterator i = streams.begin(); i != streams.end(); i++)
142
ChannelStream& channel_stream = **i;
143
if (channel_stream.stream.contains_pid(pid))
145
channel_stream.write(buffer+offset, TS_PACKET_SIZE);
153
// The show must go on!
98
if (::poll(pfds, 1, READ_TIMEOUT) < 0)
100
throw SystemException("Frontend poll failed");
103
gint bytes_read = ::read(fd, buffer, TS_PACKET_SIZE * PACKET_BUFFER_SIZE);
112
Glib::ustring message = Glib::ustring::compose("Frontend read failed (%1)", frontend.get_path().c_str());
113
throw SystemException(message);
116
// Insert PAT/PMT every second second
117
time_t now = time(NULL);
118
if (now - last_insert_time > 2)
120
g_debug("Writing PAT/PMT header");
122
for (ChannelStreamList::iterator i = streams.begin(); i != streams.end(); i++)
124
ChannelStream& channel_stream = **i;
126
channel_stream.stream.build_pat(pat);
127
channel_stream.stream.build_pmt(pmt);
129
channel_stream.write(pat, TS_PACKET_SIZE);
130
channel_stream.write(pmt, TS_PACKET_SIZE);
132
last_insert_time = now;
135
for (guint offset = 0; offset < (guint)bytes_read; offset += TS_PACKET_SIZE)
137
guint pid = ((buffer[offset+1] & 0x1f) << 8) + buffer[offset+2];
139
for (ChannelStreamList::iterator i = streams.begin(); i != streams.end(); i++)
141
ChannelStream& channel_stream = **i;
142
if (channel_stream.stream.contains_pid(pid))
144
channel_stream.write(buffer+offset, TS_PACKET_SIZE);
151
// The show must go on!
158
155
g_debug("FrontendThread loop exited (%s)", frontend.get_path().c_str());
160
Lock lock(mutex, __PRETTY_FUNCTION__);
162
g_debug("Removing streams ...");
163
ChannelStreamList::iterator iterator = streams.begin();
164
while (iterator != streams.end())
166
(*iterator)->output_channel.reset();
169
iterator = streams.begin();
171
g_debug("Streams removed");
173
g_debug("About to close input channel ...");
174
input_channel->close(true);
175
input_channel.reset();
176
g_debug("Input channel reset (%s)", frontend.get_path().c_str());
179
158
void FrontendThread::setup_dvb(ChannelStream& channel_stream)
181
Lock lock(mutex, __PRETTY_FUNCTION__);
183
160
Glib::ustring demux_path = frontend.get_adapter().get_demux_path();
186
163
const Channel& channel = channel_stream.channel;
188
165
channel_stream.clear_demuxers();
189
if (!is_tuned || channel.transponder != transponder)
166
if (channel.transponder != frontend.get_frontend_parameters())
191
168
stop_epg_thread();
193
169
frontend.tune_to(channel.transponder);
194
transponder = channel_stream.channel.transponder;
195
170
start_epg_thread();