Add request type(/m3u) for Vu+PlayerHD (IOS).
[vuplus_transtreamproxy] / src / Encoder.cpp
1 /*
2  * Encoder.cpp
3  *
4  *  Created on: 2014. 6. 12.
5  *      Author: oskwon
6  */
7
8 #include <stdio.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <dirent.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16
17 #include "Util.h"
18 #include "Logger.h"
19 #include "Encoder.h"
20
21 using namespace std;
22 //----------------------------------------------------------------------
23
24 Encoder::Encoder() throw(trap)
25 {
26         encoder_id = fd = -1;
27         max_encodr_count = state = ENCODER_STAT_INIT;
28
29         DIR* d = opendir("/dev");
30         if (d != 0) {
31                 struct dirent* de;
32                 while ((de = readdir(d)) != 0) {
33                         if (strncmp("bcm_enc", de->d_name, 7) == 0) {
34                                 max_encodr_count++;
35                         }
36                 }
37                 closedir(d);
38         }
39
40         mSemId = 0;
41         mShmFd = 0;
42         mShmData = 0;
43
44         mSemName = "/tsp_session_sem";
45         mShmName = "/tsp_session_shm";
46         mShmSize = sizeof(Session) * max_encodr_count;
47
48         if (Open() == false)
49                 throw(trap("session ctrl init fail."));
50         DEBUG("shm-info : fd [%d], name [%s], size [%d], data [%p]", mShmFd, mShmName.c_str(), mShmSize, mShmData);
51         DEBUG("sem-info : id [%p], name [%s]", mSemId, mSemName.c_str());
52
53         std::vector<int> pidlist = Util::find_process_by_name("transtreamproxy", 0);
54
55         session_dump("before init.");
56
57         Wait();
58         for (int i = 0; i < max_encodr_count; i++) {
59                 if (mShmData[i].pid != 0) {
60                         int pid = mShmData[i].pid;
61                         if(session_terminated(pidlist, pid)) {
62                                 session_erase(pid);
63                         }
64                 }
65         }
66         Post();
67
68         int mypid = getpid();
69         std::string ipaddr = Util::host_addr();
70         if (session_already_exist(ipaddr) > 0) {
71                 encoder_id = session_update(ipaddr, mypid);
72         }
73         else {
74                 encoder_id = session_register(ipaddr, mypid);
75         }
76         DEBUG("encoder_device_id : %d", encoder_id);
77 }
78 //----------------------------------------------------------------------
79
80 Encoder::~Encoder()
81 {
82         if (fd != -1) {
83                 if (state == ENCODER_STAT_STARTED) {
84                         DEBUG("stop transcoding..");
85                         ioctl(IOCTL_STOP_TRANSCODING, 0);
86                 }
87                 close(fd);
88                 fd = -1;
89         }
90 }
91 //----------------------------------------------------------------------
92
93 bool Encoder::encoder_open()
94 {
95         std::string path = "/dev/bcm_enc" + Util::ultostr(encoder_id);
96         fd = ::open(path.c_str(), O_RDWR, 0);
97         if (fd >= 0) {
98                 state = ENCODER_STAT_OPENED;
99         }
100         DEBUG("open encoder : %s, fd : %d", path.c_str(), fd);
101         return (state == ENCODER_STAT_OPENED) ? true : false;
102 }
103 //----------------------------------------------------------------------
104
105 bool Encoder::retry_open(int retry_count, int sleep_time)
106 {
107         for (int i = 0; i < retry_count; ++i) {
108                 if (encoder_open()) {
109                         DEBUG("encoder-%d open success..", encoder_id);
110                         return true;
111                 }
112                 WARNING("encoder%d open fail, retry count : %d/%d", encoder_id, i, retry_count);
113                 sleep(sleep_time);
114         }
115         ERROR("encoder open fail : %s (%d)", strerror(errno), errno);
116         return false;
117 }
118 //----------------------------------------------------------------------
119
120 bool Encoder::ioctl(int cmd, int value)
121 {
122         int result = ::ioctl(fd, cmd, value);
123         DEBUG("ioctl command : %d -> %x, result : %d", cmd, value, result);
124
125         if (result == 0) {
126                 switch (cmd) {
127                 case IOCTL_START_TRANSCODING: state = ENCODER_STAT_STARTED; break;
128                 case IOCTL_STOP_TRANSCODING:  state = ENCODER_STAT_STOPED;  break;
129                 }
130         }
131
132         return (result == 0) ? true : false;
133 }
134 //----------------------------------------------------------------------
135
136 int Encoder::get_fd()
137 {
138         return fd;
139 }
140 //----------------------------------------------------------------------
141
142 void Encoder::session_dump(const char* aMessage)
143 {
144         if (Logger::instance()->get_level() >= Logger::INFO) {
145                 DUMMY(" >> %s", aMessage);
146                 DUMMY("-------- [ DUMP HOST INFO ] ---------");
147                 for (int i = 0; i < max_encodr_count; i++) {
148                         DUMMY("%d : ip [%s], pid [%d]", i,  mShmData[i].ip, mShmData[i].pid);
149                 }
150                 DUMMY("-------------------------------------");
151         }
152 }
153 //----------------------------------------------------------------------
154
155 bool Encoder::session_terminated(std::vector<int>& aList, int aPid)
156 {
157         for (int i = 0; i < aList.size(); ++i) {
158                 if (aList[i] == aPid) {
159                         return false;
160                 }
161         }
162         return true;
163 }
164 //----------------------------------------------------------------------
165
166 int Encoder::session_register(std::string aIpAddr, int aPid)
167 {
168         int i = 0;
169         bool result = false;
170
171         Wait();
172         for (; i < max_encodr_count; i++) {
173                 if (mShmData[i].pid == 0) {
174                         result = true;
175                         mShmData[i].pid = aPid;
176                         strcpy(mShmData[i].ip, aIpAddr.c_str());
177                         break;
178                 }
179         }
180         Post();
181         session_dump("after register.");
182
183         return result ? i : -1;
184 }
185 //----------------------------------------------------------------------
186
187 void Encoder::session_unregister(std::string aIpAddr)
188 {
189         Wait();
190         for (int i = 0; i < max_encodr_count; i++) {
191                 if (strcmp(mShmData[i].ip, aIpAddr.c_str()) == 0) {
192                         memset(mShmData[i].ip, 0, 16);
193                         mShmData[i].pid = 0;
194                         break;
195                 }
196         }
197         Post();
198         session_dump("after unregister.");
199 }
200 //----------------------------------------------------------------------
201
202 void Encoder::session_erase(int aPid)
203 {
204         for (int i = 0; i < max_encodr_count; i++) {
205                 if (mShmData[i].pid == aPid) {
206                         DEBUG("erase.. %s : %d", mShmData[i].ip, mShmData[i].pid);
207                         memset(mShmData[i].ip, 0, 16);
208                         mShmData[i].pid = 0;
209                         break;
210                 }
211         }
212 }
213 //----------------------------------------------------------------------
214
215 int Encoder::session_update(std::string aIpAddr, int aPid)
216 {
217         int i = 0;
218         bool result = false;
219
220         session_dump("before update.");
221         Wait();
222         for (; i < max_encodr_count; i++) {
223                 if (strcmp(mShmData[i].ip, aIpAddr.c_str()) == 0) {
224                         result = true;
225                         Util::kill_process(mShmData[i].pid);
226                         memset(mShmData[i].ip, 0, 16);
227                         mShmData[i].pid = 0;
228                         break;
229                 }
230         }
231         Post();
232         session_register(aIpAddr, aPid);
233         return result ? i : -1;
234 }
235 //----------------------------------------------------------------------
236
237 int Encoder::session_already_exist(std::string aIpAddr)
238 {
239         int existCount = 0;
240         Wait();
241         for (int i = 0; i < max_encodr_count; i++) {
242                 if (strcmp(mShmData[i].ip, aIpAddr.c_str()) == 0) {
243                         existCount++;
244                 }
245         }
246         Post();
247         return existCount;
248 }
249 //----------------------------------------------------------------------