a943bab95081cfc9a016bbae02aaf56bee5e7760
[vuplus_transtreamproxy] / src / Demuxer.cpp
1 /*
2  * Demux.h
3  *
4  *  Created on: 2014. 6. 11.
5  *      Author: oskwon
6  */
7
8 #include <poll.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <string.h>
12 #include <sys/ioctl.h>
13 #include <arpa/inet.h>
14 #include <netinet/ip.h>
15 #include <linux/dvb/dmx.h>
16 #include <linux/dvb/version.h>
17
18 #include "Utils.h"
19 #include "Logger.h"
20 #include "Demuxer.h"
21
22 using namespace std;
23 //-------------------------------------------------------------------------------
24
25 std::string Demuxer::webif_reauest(std::string service, std::string auth) throw(trap)
26 {
27         if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
28                 throw(trap("webif create socket fail."));
29
30         struct sockaddr_in sock_addr;
31         sock_addr.sin_family = AF_INET;
32         sock_addr.sin_port = htons(80);
33         sock_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
34         if (connect(sock, (struct sockaddr*)&sock_addr, sizeof(struct sockaddr_in)))
35                 throw(trap("webif connect fail."));
36
37         std::string request = string("GET /web/stream?StreamService=") + service + " HTTP/1.0\r\n";
38         if (auth != "")
39                 request += "Authorization: " + auth + "\r\n";
40         request += "\r\n";
41
42         if (write(sock, request.c_str(), request.length()) != request.length())
43                 throw(trap("webif send(request) fail."));
44         DEBUG("webif request :\n", request.c_str());
45
46         std::string response = "";
47         struct pollfd pollevt[2];
48         pollevt[0].fd      = sock;
49         pollevt[0].events  = POLLIN;
50         for (;;) {
51                 char buffer[1024] = {0};
52
53                 pollevt[0].revents = 0;
54                 int poll_state = poll(pollevt, 1, 1000);
55                 if (poll_state == 0)
56                         break;
57                 else if (poll_state < 0) {
58                         ERROR("webif receive poll error : %s (%d)", strerror(errno), errno);
59                         throw(trap("webif receive response error."));
60                 }
61                 if (pollevt[0].revents & POLLIN) {
62                         if (read(sock, buffer, 1024) <= 0) {
63                                 break;
64                         }
65                         response += buffer;
66                 }
67         }
68         return response;
69 }
70 //-------------------------------------------------------------------------------
71
72 bool Demuxer::already_exist(std::vector<unsigned long> &pidlist, int pid)
73 {
74         for(int i = 0; i < pidlist.size(); ++i) {
75                 if(pidlist[i] == pid)
76                         return true;
77         }
78         return false;
79 }
80 //-------------------------------------------------------------------------------
81
82 void Demuxer::set_filter(std::vector<unsigned long> &new_pids) throw(trap)
83 {
84         struct dmx_pes_filter_params filter;
85         ioctl(fd, DMX_SET_BUFFER_SIZE, 1024*1024);
86
87         filter.pid = new_pids[0];
88         filter.input = DMX_IN_FRONTEND;
89 #if DVB_API_VERSION > 3
90         filter.output = DMX_OUT_TSDEMUX_TAP;
91         filter.pes_type = DMX_PES_OTHER;
92 #else
93         filter.output = DMX_OUT_TAP;
94         filter.pes_type = DMX_TAP_TS;
95 #endif
96         filter.flags = DMX_IMMEDIATE_START;
97
98         if (::ioctl(fd, DMX_SET_PES_FILTER, &filter) < 0)
99                 throw(trap("demux filter setting failed."));
100         DEBUG("demux filter setting ok.");
101
102         for(int i = 0; i < new_pids.size(); ++i) {
103                 uint16_t pid = new_pids[i];
104
105                 if(already_exist(pids, pid))
106                         continue;
107                 LOG("demux add pid (%x).", pid);
108
109 #if DVB_API_VERSION > 3
110                 if (::ioctl(fd, DMX_ADD_PID, &pid) < 0)
111                         throw(trap("demux add pid failed."));
112 #else
113                 if (::ioctl(fd, DMX_ADD_PID, pid) < 0)
114                         throw(trap("demux add pid failed."));
115 #endif
116         }
117
118         for(int i = 0; i < pids.size(); ++i) {
119                 uint16_t pid = pids[i];
120                 if(already_exist(new_pids, pid))
121                         continue;
122                 if(i == 4) break;
123
124                 LOG("demux remove pid (%x).", pid);
125 #if DVB_API_VERSION > 3
126                 ::ioctl(fd, DMX_REMOVE_PID, &pid);
127 #else
128                 ::ioctl(fd, DMX_REMOVE_PID, pid);
129 #endif
130         }
131         DEBUG("demux setting PID ok.");
132         pids = new_pids;
133 }
134 //-------------------------------------------------------------------------------
135
136 bool Demuxer::parse_webif_response(std::string& response, std::vector<unsigned long> &new_pids)
137 {
138         int start_idx, end_idx;
139         if ((start_idx = response.rfind('+')) == string::npos)
140                 return false;
141         if ((end_idx = response.find('\n', start_idx)) == string::npos)
142                 return false;
143
144         std::string line = response.substr(start_idx, end_idx - start_idx);
145         if (line.length() < 3 || line.at(0) != '+')
146                 return false;
147
148         /*+0:0:pat,17d4:pmt,17de:video,17e8:audio,17e9:audio,17eb:audio,17ea:audio,17f3:subtitle,17de:pcr,17f2:text*/
149         demux_id = atoi(line.substr(1,1).c_str());
150
151         std::vector<std::string> pidtokens;
152         if (split(line.c_str() + 3, ',', pidtokens)) {
153                 for (int i = 0; i < pidtokens.size(); ++i) {
154                         std::string pidstr, pidtype;
155                         std::string toekn = pidtokens[i];
156                         if (!split_key_value(toekn, ":", pidstr, pidtype))
157                                 continue;
158
159                         unsigned long pid = strtoul(pidstr.c_str(), 0, 0x10);
160                         if (pid == -1) continue;
161
162                         if (!video_pid || !audio_pid || !pmt_pid) {
163                                 if (pidtype == "pat") {
164                                         pat_pid = pid;
165                                 }
166                                 else if (pidtype == "pmt") {
167                                         pmt_pid = pid;
168                                 }
169                                 else if (pidtype == "video") {
170                                         video_pid = pid;
171                                 }
172                                 else if (pidtype == "audio") {
173                                         audio_pid = pid;
174                                 }
175                         }
176                         if (!already_exist(new_pids, pid)) {
177                                 new_pids.push_back(pid);
178                         }
179                         DEBUG("find pid : %s - %04X", toekn.c_str(), pid);
180                 }
181         }
182         return true;
183 }
184 //-------------------------------------------------------------------------------
185
186 Demuxer::Demuxer(RequestHeader *header) throw(trap)
187 {
188         demux_id = pat_pid = fd = sock = -1;
189         pmt_pid = audio_pid = video_pid = 0;
190
191         std::string auth = header->params["WWW-Authenticate"];
192         std::string service = header->path.substr(1);
193         std::string webif_response = webif_reauest(service, auth);
194         DEBUG("webif response :\n%s", webif_response.c_str());
195
196         std::vector<unsigned long> new_pids;
197         if (!parse_webif_response(webif_response, new_pids))
198                 throw(trap("webif response parsing fail."));
199
200         std::string demuxpath = "/dev/dvb/adapter0/demux" + ultostr(demux_id);
201         if ((fd = open(demuxpath.c_str(), O_RDWR | O_NONBLOCK)) < 0) {
202                 throw(trap(std::string("demux open fail : ") + demuxpath));
203         }
204         INFO("demux open success : %s", demuxpath.c_str());
205
206         set_filter(new_pids);
207 }
208 //-------------------------------------------------------------------------------
209
210 Demuxer::~Demuxer() throw()
211 {
212         if (fd != -1) close(fd);
213         if (sock != -1) close(sock);
214
215         fd = sock = -1;
216 }
217 //-------------------------------------------------------------------------------
218
219 int Demuxer::get_fd() const throw()
220 {
221         return fd;
222 }
223 //-------------------------------------------------------------------------------