├── binzume
├── http.h
└── socket.h
├── .gitmodules
├── BonDriver_Mirakurun.ini
├── .gitignore
├── README.md
├── IBonDriver2.h
├── IBonDriver.h
├── BonDriver_Mirakurun.vcxproj.filters
├── BonDriver_Mirakurun.sln
├── LICENSE
├── BonDriver_Mirakurun.h
├── BonDriver_Mirakurun.vcxproj
└── BonDriver_Mirakurun.cpp
/binzume/http.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chinachu/BonDriver_Mirakurun/HEAD/binzume/http.h
--------------------------------------------------------------------------------
/binzume/socket.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Chinachu/BonDriver_Mirakurun/HEAD/binzume/socket.h
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "picojson"]
2 | path = picojson
3 | url = https://github.com/kazuho/picojson
4 |
--------------------------------------------------------------------------------
/BonDriver_Mirakurun.ini:
--------------------------------------------------------------------------------
1 | [GLOBAL]
2 | SERVER_HOST="mirakurun.hogehoge.moe"
3 | SERVER_PORT=40772
4 |
5 | ; B25(1=enable)
6 | DECODE_B25=1
7 |
8 | ; Priority(0=Low Priority)
9 | PRIORITY=0
10 |
11 | ; Service Split(1=enable)
12 | SERVICE_SPLIT=0
13 |
14 | ; MagicPacket(1=enable)
15 | MAGICPACKET_ENABLE=0
16 | MAGICPACKET_TARGETMAC="00:00:00:00:00:00"
17 | MAGICPACKET_TARGETIP="192.168.0.255"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 | *.obj
6 |
7 | # Precompiled Headers
8 | *.gch
9 | *.pch
10 |
11 | # Compiled Dynamic libraries
12 | *.so
13 | *.dylib
14 | *.dll
15 |
16 | # Fortran module files
17 | *.mod
18 |
19 | # Compiled Static libraries
20 | *.lai
21 | *.la
22 | *.a
23 | *.lib
24 |
25 | # Executables
26 | *.exe
27 | *.out
28 | *.app
29 |
30 | x64/
31 | Debug/
32 | Release/
33 | .vs/
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BonDriver_Mirakurun
2 |
3 | TVTestから[Mirakurun](https://github.com/kanreisa/Mirakurun)を利用する為のBonDriverです。
4 |
5 | ソースコードのベースはBonDriver_HTTPからです。
6 | Visual Studio Community 2015 でビルド、TVTest 0.9.0-dev(x64) の環境で動作確認しております。
7 |
8 | ## ビルド済みDLL
9 | 不定期に(作者的に)安定版DLLはこちらにアップロードしております
10 | https://github.com/Chinachu/BonDriver_Mirakurun/releases
11 |
12 | ## ランタイム
13 | [Microsoft Visual C++ 2015 Redistrebutable]を必要とします
14 |
15 | Microsoft公式よりラインタイムのダウンロードおよびインストールを行ってください
16 | https://support.microsoft.com/ja-jp/help/2977003/the-latest-supported-visual-c-downloads
17 |
18 | ## License
19 | This software is released under the MIT License, see LICENSE.
20 |
--------------------------------------------------------------------------------
/IBonDriver2.h:
--------------------------------------------------------------------------------
1 | // IBonDriver2.h: IBonDriver2 クラスのインターフェイス
2 | //
3 | //////////////////////////////////////////////////////////////////////
4 |
5 | #if !defined(_IBONDRIVER2_H_)
6 | #define _IBONDRIVER2_H_
7 |
8 | #if _MSC_VER > 1000
9 | #pragma once
10 | #endif // _MSC_VER > 1000
11 |
12 |
13 | #include "IBonDriver.h"
14 |
15 |
16 | // 凡ドライバインタフェース2
17 | class IBonDriver2 : public IBonDriver
18 | {
19 | public:
20 | virtual LPCTSTR GetTunerName(void) = 0;
21 |
22 | virtual const BOOL IsTunerOpening(void) = 0;
23 | virtual LPCTSTR EnumTuningSpace(const DWORD dwSpace) = 0;
24 | virtual LPCTSTR EnumChannelName(const DWORD dwSpace, const DWORD dwChannel) = 0;
25 |
26 | virtual const BOOL SetChannel(const DWORD dwSpace, const DWORD dwChannel) = 0;
27 |
28 | virtual const DWORD GetCurSpace(void) = 0;
29 | virtual const DWORD GetCurChannel(void) = 0;
30 |
31 | // IBonDriver
32 | virtual void Release(void) = 0;
33 | };
34 |
35 | #endif // !defined(_IBONDRIVER2_H_)
36 |
--------------------------------------------------------------------------------
/IBonDriver.h:
--------------------------------------------------------------------------------
1 | // IBonDriver.h: IBonDriver クラスのインターフェイス
2 | //
3 | //////////////////////////////////////////////////////////////////////
4 |
5 | #if !defined(_IBONDRIVER_H_)
6 | #define _IBONDRIVER_H_
7 |
8 | #if _MSC_VER > 1000
9 | #pragma once
10 | #endif // _MSC_VER > 1000
11 |
12 |
13 | // 凡ドライバインタフェース
14 | class IBonDriver
15 | {
16 | public:
17 | virtual const BOOL OpenTuner(void) = 0;
18 | virtual void CloseTuner(void) = 0;
19 |
20 | virtual const BOOL SetChannel(const BYTE bCh) = 0;
21 | virtual const float GetSignalLevel(void) = 0;
22 |
23 | virtual const DWORD WaitTsStream(const DWORD dwTimeOut = 0) = 0;
24 | virtual const DWORD GetReadyCount(void) = 0;
25 |
26 | virtual const BOOL GetTsStream(BYTE *pDst, DWORD *pdwSize, DWORD *pdwRemain) = 0;
27 | virtual const BOOL GetTsStream(BYTE **ppDst, DWORD *pdwSize, DWORD *pdwRemain) = 0;
28 |
29 | virtual void PurgeTsStream(void) = 0;
30 |
31 | virtual void Release(void) = 0;
32 | };
33 |
34 |
35 | #endif // !defined(_IBONDRIVER_H_)
36 |
--------------------------------------------------------------------------------
/BonDriver_Mirakurun.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ソースファイル
6 |
7 |
8 |
9 |
10 | ヘッダファイル
11 |
12 |
13 | ヘッダファイル
14 |
15 |
16 | ヘッダファイル
17 |
18 |
19 | ヘッダファイル
20 |
21 |
22 | ヘッダファイル
23 |
24 |
25 | ヘッダファイル
26 |
27 |
28 |
29 |
30 | {0d9d2765-7e56-4258-b889-67936a02e1ea}
31 |
32 |
33 | {79045bde-3f39-45a8-b2ab-950f964f9197}
34 |
35 |
36 |
--------------------------------------------------------------------------------
/BonDriver_Mirakurun.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BonDriver_Mirakurun", "BonDriver_Mirakurun.vcxproj", "{26C43DF8-9F2B-46BE-B430-71D01F96EEDA}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}.Debug|x64.ActiveCfg = Debug|x64
17 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}.Debug|x64.Build.0 = Debug|x64
18 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}.Debug|x86.ActiveCfg = Debug|Win32
19 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}.Debug|x86.Build.0 = Debug|Win32
20 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}.Release|x64.ActiveCfg = Release|x64
21 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}.Release|x64.Build.0 = Release|x64
22 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}.Release|x86.ActiveCfg = Release|Win32
23 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016-2017 h-mineta@0nyx.net
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | --------------------------------------------------------------------------
23 |
24 | 以下に定める条件に従い、本ソフトウェアおよび関連文書のファイル(以下「ソフトウェア」)の
25 | 複製を取得するすべての人に対し、ソフトウェアを無制限に扱うことを無償で許可します。
26 | これには、ソフトウェアの複製を使用、複写、変更、結合、掲載、頒布、サブライセンス、および/または
27 | 販売する権利、およびソフトウェアを提供する相手に同じことを許可する権利も無制限に含まれます。
28 |
29 | 上記の著作権表示および本許諾表示を、ソフトウェアのすべての複製または重要な部分に記載するものとします。
30 |
31 | ソフトウェアは「現状のまま」で、明示であるか暗黙であるかを問わず、何らの保証もなく提供されます。
32 | ここでいう保証とは、商品性、特定の目的への適合性、および権利非侵害についての保証も含みますが、
33 | それに限定されるものではありません。 作者または著作権者は、契約行為、不法行為、またはそれ以外であろうと、
34 | ソフトウェアに起因または関連し、あるいはソフトウェアの使用またはその他の扱いによって生じる一切の請求、
35 | 損害、その他の義務について何らの責任も負わないものとします。
36 |
--------------------------------------------------------------------------------
/BonDriver_Mirakurun.h:
--------------------------------------------------------------------------------
1 | #define _WINSOCK_DEPRECATED_NO_WARNINGS
2 |
3 | #include
4 | #include
5 | #include
6 | #include "IBonDriver2.h"
7 | #include "binzume\http.h"
8 | #include "picojson\picojson.h"
9 | using namespace std;
10 | using namespace Net;
11 |
12 | #if !defined(_BONTUNER_H_)
13 | #define _BONTUNER_H_
14 |
15 | #if _MSC_VER > 1000
16 | #pragma once
17 | #endif // _MSC_VER > 1000
18 |
19 | #define dllimport dllexport
20 |
21 |
22 | #define TUNER_NAME "BonDriver_Mirakurun"
23 |
24 | // 受信サイズ
25 | #define TSDATASIZE 48128 // TSデータのサイズ 188 * 256
26 |
27 | static wchar_t g_IniFilePath[MAX_PATH] = { '\0' };
28 |
29 | // チューナ空間
30 | #define SPACE_NUM 8
31 | static char *g_pType[SPACE_NUM];
32 | static DWORD g_Max_Type;
33 | static DWORD g_Channel_Base[SPACE_NUM];
34 |
35 | #define MAX_HOST_LEN 256
36 | #define MAX_PORT_LEN 8
37 | static char g_ServerHost[MAX_HOST_LEN];
38 | static char g_ServerPort[MAX_PORT_LEN];
39 | static int g_DecodeB25;
40 | static int g_Priority;
41 | static int g_Service_Split;
42 | picojson::value g_Channel_JSON;
43 | static int g_MagicPacket_Enable;
44 | static char g_MagicPacket_TargetMAC[18];
45 | static char g_MagicPacket_TargetIP[16];
46 | #define MAGICPACKET_WAIT_SECONDS 20
47 |
48 | class CBonTuner : public IBonDriver2
49 | {
50 | public:
51 | CBonTuner();
52 | virtual ~CBonTuner();
53 |
54 | // Initialize channel
55 | void InitChannel(void);
56 |
57 | // IBonDriver
58 | const BOOL OpenTuner(void);
59 | void CloseTuner(void);
60 |
61 | const BOOL SetChannel(const BYTE bCh);
62 | const float GetSignalLevel(void);
63 |
64 | const DWORD WaitTsStream(const DWORD dwTimeOut = 0);
65 | const DWORD GetReadyCount(void);
66 |
67 | const BOOL GetTsStream(BYTE *pDst, DWORD *pdwSize, DWORD *pdwRemain);
68 | const BOOL GetTsStream(BYTE **ppDst, DWORD *pdwSize, DWORD *pdwRemain);
69 |
70 | void PurgeTsStream(void);
71 |
72 | // IBonDriver2(暫定)
73 | LPCTSTR GetTunerName(void);
74 |
75 | const BOOL IsTunerOpening(void);
76 |
77 | LPCTSTR EnumTuningSpace(const DWORD dwSpace);
78 | LPCTSTR EnumChannelName(const DWORD dwSpace, const DWORD dwChannel);
79 |
80 | const BOOL SetChannel(const DWORD dwSpace, const DWORD dwChannel);
81 |
82 | const DWORD GetCurSpace(void);
83 | const DWORD GetCurChannel(void);
84 |
85 | void Release(void);
86 |
87 | static CBonTuner * m_pThis;
88 | static HINSTANCE m_hModule;
89 | static char * m_cList[7];
90 |
91 |
92 | protected:
93 | // I/Oリクエストキューデータ
94 | struct AsyncIoReq
95 | {
96 | WSAOVERLAPPED OverLapped;
97 | DWORD dwState;
98 | DWORD dwRxdSize;
99 | BYTE RxdBuff[TSDATASIZE];
100 | AsyncIoReq *pNext;
101 | };
102 |
103 | AsyncIoReq * AllocIoReqBuff(const DWORD dwBuffNum);
104 | void FreeIoReqBuff(AsyncIoReq *pBuff);
105 |
106 | static DWORD WINAPI PushIoThread(LPVOID pParam);
107 | static DWORD WINAPI PopIoThread(LPVOID pParam);
108 |
109 | const BOOL PushIoRequest(SOCKET sock);
110 | const BOOL PopIoRequest(SOCKET sock);
111 |
112 | bool m_bTunerOpen;
113 |
114 | HANDLE m_hMutex;
115 |
116 | BYTE m_RxdBuff[256];
117 |
118 | AsyncIoReq *m_pIoReqBuff;
119 | AsyncIoReq *m_pIoPushReq;
120 | AsyncIoReq *m_pIoPopReq;
121 | AsyncIoReq *m_pIoGetReq;
122 |
123 | DWORD m_dwBusyReqNum;
124 | DWORD m_dwReadyReqNum;
125 |
126 | HANDLE m_hPushIoThread;
127 | HANDLE m_hPopIoThread;
128 | BOOL m_bLoopIoThread;
129 |
130 | HANDLE m_hOnStreamEvent;
131 |
132 | CRITICAL_SECTION m_CriticalSection;
133 |
134 | DWORD m_dwCurSpace;
135 | DWORD m_dwCurChannel;
136 |
137 | // 追加 byMeru(2008/03/27)
138 | SOCKET m_sock;
139 | float m_fBitRate;
140 |
141 | void CalcBitRate();
142 | void GetApiChannels(picojson::value *json_array, int service_split);
143 | DWORD m_dwRecvBytes;
144 | DWORD m_dwLastCalcTick;
145 | ULONGLONG m_u64RecvBytes;
146 | ULONGLONG m_u64LastCalcByte;
147 | };
148 |
149 | #endif // !defined(_BONTUNER_H_)
150 |
--------------------------------------------------------------------------------
/BonDriver_Mirakurun.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {26C43DF8-9F2B-46BE-B430-71D01F96EEDA}
23 | BonDriver_UDP
24 | Win32Proj
25 |
26 |
27 |
28 | DynamicLibrary
29 | v140
30 | Unicode
31 | true
32 |
33 |
34 | DynamicLibrary
35 | v140
36 | Unicode
37 |
38 |
39 | DynamicLibrary
40 | v140
41 | Unicode
42 | true
43 |
44 |
45 | DynamicLibrary
46 | v140
47 | Unicode
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | <_ProjectFileVersion>14.0.24730.2
67 |
68 |
69 | $(SolutionDir)$(Configuration)\
70 | $(Configuration)\
71 | true
72 |
73 |
74 | $(SolutionDir)$(Configuration)\
75 | $(Configuration)\
76 | false
77 |
78 |
79 | $(SolutionDir)$(Platform)\$(Configuration)\
80 | $(Platform)\$(Configuration)\
81 | true
82 |
83 |
84 | $(SolutionDir)$(Platform)\$(Configuration)\
85 | $(Platform)\$(Configuration)\
86 | false
87 |
88 |
89 |
90 | Disabled
91 | WIN32;_DEBUG;_WINDOWS;_USRDLL;BONDRIVER_UDP_EXPORTS;%(PreprocessorDefinitions)
92 | true
93 | EnableFastChecks
94 | MultiThreadedDebugDLL
95 |
96 | Level3
97 | EditAndContinue
98 |
99 |
100 | false
101 | true
102 | Windows
103 |
104 | MachineX86
105 |
106 |
107 |
108 |
109 | AnySuitable
110 | true
111 | Speed
112 | WIN32;NDEBUG;_WINDOWS;_USRDLL;BONDRIVER_UDP_EXPORTS;%(PreprocessorDefinitions)
113 | true
114 | MultiThreadedDLL
115 | false
116 |
117 | Level3
118 | ProgramDatabase
119 | Full
120 | true
121 | Fast
122 |
123 |
124 | false
125 | false
126 | Windows
127 | true
128 | true
129 |
130 | MachineX86
131 |
132 |
133 |
134 |
135 | X64
136 |
137 |
138 | Disabled
139 | WIN32;_DEBUG;_WINDOWS;_USRDLL;BONDRIVER_UDP_EXPORTS;%(PreprocessorDefinitions)
140 | true
141 | EnableFastChecks
142 | MultiThreadedDebugDLL
143 |
144 | Level3
145 | ProgramDatabase
146 |
147 |
148 | false
149 | true
150 | Windows
151 |
152 | MachineX64
153 |
154 |
155 |
156 |
157 | X64
158 |
159 |
160 | AnySuitable
161 | true
162 | Speed
163 | WIN32;NDEBUG;_WINDOWS;_USRDLL;BONDRIVER_UDP_EXPORTS;%(PreprocessorDefinitions)
164 | true
165 | MultiThreadedDLL
166 | false
167 |
168 | Level3
169 | ProgramDatabase
170 | Full
171 | true
172 | Fast
173 |
174 |
175 | false
176 | false
177 | Windows
178 | true
179 | true
180 |
181 | MachineX64
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
--------------------------------------------------------------------------------
/BonDriver_Mirakurun.cpp:
--------------------------------------------------------------------------------
1 | #include "BonDriver_Mirakurun.h"
2 |
3 | #pragma comment(lib, "ws2_32.lib")
4 |
5 | #define BITRATE_CALC_TIME 500 //ms
6 |
7 | //////////////////////////////////////////////////////////////////////
8 | // 定数定義
9 | //////////////////////////////////////////////////////////////////////
10 |
11 | // ミューテックス名
12 | #define MUTEX_NAME TEXT(TUNER_NAME)
13 |
14 | // FIFOバッファ設定
15 | #define ASYNCBUFFTIME 2 // バッファ長 = 2秒
16 | #define ASYNCBUFFSIZE ( 0x200000 / TSDATASIZE * ASYNCBUFFTIME ) // 平均16Mbpsとする
17 |
18 | #define REQRESERVNUM 8 // 非同期リクエスト予約数 //before 16
19 | #define REQPOLLINGWAIT 20 // 非同期リクエストポーリング間隔(ms) //before 10
20 |
21 | // 非同期リクエスト状態
22 | #define IORS_IDLE 0x00 // リクエスト空
23 | #define IORS_BUSY 0x01 // リクエスト受信中
24 | #define IORS_RECV 0x02 // 受信完了、ストア待ち
25 |
26 | static int Init(HMODULE hModule)
27 | {
28 | GetModuleFileName(hModule, g_IniFilePath, MAX_PATH);
29 |
30 | wchar_t drive[_MAX_DRIVE];
31 | wchar_t dir[_MAX_DIR];
32 | wchar_t fname[_MAX_FNAME];
33 | _wsplitpath_s(g_IniFilePath, drive, sizeof(drive), dir, sizeof(dir), fname, sizeof(fname), NULL, NULL);
34 | wsprintf(g_IniFilePath, L"%s%s%s.ini\0", drive, dir, fname);
35 |
36 | HANDLE hFile = CreateFile(g_IniFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
37 | if (hFile == INVALID_HANDLE_VALUE) {
38 | return -2;
39 | }
40 | CloseHandle(hFile);
41 | size_t ret;
42 |
43 | wchar_t tmpServerHost[MAX_HOST_LEN];
44 | GetPrivateProfileString(L"GLOBAL", L"SERVER_HOST", L"localhost", tmpServerHost, sizeof(tmpServerHost), g_IniFilePath);
45 | wcstombs_s(&ret, g_ServerHost, tmpServerHost, sizeof(g_ServerHost));
46 |
47 | wchar_t tmpServerPort[MAX_PORT_LEN];
48 | GetPrivateProfileString(L"GLOBAL", L"SERVER_PORT", L"8888", tmpServerPort, sizeof(tmpServerPort), g_IniFilePath);
49 | wcstombs_s(&ret, g_ServerPort, tmpServerPort, sizeof(g_ServerPort));
50 |
51 | g_DecodeB25 = GetPrivateProfileInt(L"GLOBAL", L"DECODE_B25", 0, g_IniFilePath);
52 | g_Priority = GetPrivateProfileInt(L"GLOBAL", L"PRIORITY", 0, g_IniFilePath);
53 | g_Service_Split = GetPrivateProfileInt(L"GLOBAL", L"SERVICE_SPLIT", 0, g_IniFilePath);
54 |
55 | setlocale(LC_ALL, "japanese");
56 |
57 | g_MagicPacket_Enable = GetPrivateProfileInt(L"GLOBAL", L"MAGICPACKET_ENABLE", 0, g_IniFilePath);
58 |
59 | if (g_MagicPacket_Enable) {
60 | wchar_t tmpMagicPacket_TargetMAC[18];
61 | GetPrivateProfileString(L"GLOBAL", L"MAGICPACKET_TARGETMAC", L"00:00:00:00:00:00", tmpMagicPacket_TargetMAC, sizeof(tmpMagicPacket_TargetMAC), g_IniFilePath);
62 | wcstombs_s(&ret, g_MagicPacket_TargetMAC, tmpMagicPacket_TargetMAC, sizeof(g_MagicPacket_TargetMAC));
63 |
64 |
65 | for (int i = 0; i < 6; i++) {
66 | BYTE b = 0;
67 | char *p = &g_MagicPacket_TargetMAC[i * 3];
68 | for (int j = 0; j < 2; j++) {
69 | if (*p >= '0' && *p <= '9') {
70 | b = b * 0x10 + (*p - '0');
71 | } else if (*p >= 'a' && *p <= 'f') {
72 | b = b * 0x10 + (10 + *p - 'a');
73 | } else if (*p >= 'A' && *p <= 'F') {
74 | b = b * 0x10 + (10 + *p - 'A');
75 | }
76 | p++;
77 | }
78 | g_MagicPacket_TargetMAC[i] = b;
79 | }
80 | wchar_t tmpMagicPacket_TargetIP[16];
81 | GetPrivateProfileString(L"GLOBAL", L"MAGICPACKET_TARGETIP", L"0.0.0.0", tmpMagicPacket_TargetIP, sizeof(tmpMagicPacket_TargetIP), g_IniFilePath);
82 | wcstombs_s(&ret, g_MagicPacket_TargetIP, tmpMagicPacket_TargetIP, sizeof(g_MagicPacket_TargetIP));
83 |
84 | }
85 |
86 | return 0;
87 | }
88 |
89 | BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD fdwReason, LPVOID lpReserved)
90 | {
91 | switch (fdwReason) {
92 | case DLL_PROCESS_ATTACH:
93 | if (Init(hModule) != 0) {
94 | return FALSE;
95 | }
96 | // モジュールハンドル保存
97 | CBonTuner::m_hModule = hModule;
98 | break;
99 |
100 | case DLL_PROCESS_DETACH:
101 | // 未開放の場合はインスタンス開放
102 | if (CBonTuner::m_pThis) {
103 | CBonTuner::m_pThis->Release();
104 | }
105 | break;
106 | }
107 |
108 | return TRUE;
109 | }
110 |
111 | inline DWORD DiffTime(DWORD BeginTime,DWORD EndTime)
112 | {
113 | if (BeginTime <= EndTime)
114 | return EndTime-BeginTime;
115 | return (0xFFFFFFFFUL-BeginTime)+EndTime+1UL;
116 | }
117 |
118 |
119 | //////////////////////////////////////////////////////////////////////
120 | // インスタンス生成メソッド
121 | //////////////////////////////////////////////////////////////////////
122 |
123 | extern "C" __declspec(dllexport) IBonDriver * CreateBonDriver()
124 | {
125 | // スタンス生成(既存の場合はインスタンスのポインタを返す)
126 | return (CBonTuner::m_pThis)? CBonTuner::m_pThis : ((IBonDriver *) new CBonTuner);
127 | }
128 |
129 |
130 | //////////////////////////////////////////////////////////////////////
131 | // 構築/消滅
132 | //////////////////////////////////////////////////////////////////////
133 |
134 | // 静的メンバ初期化
135 | CBonTuner * CBonTuner::m_pThis = NULL;
136 | HINSTANCE CBonTuner::m_hModule = NULL;
137 |
138 | CBonTuner::CBonTuner()
139 | : m_bTunerOpen(FALSE)
140 | , m_hMutex(NULL)
141 | , m_pIoReqBuff(NULL)
142 | , m_pIoPushReq(NULL)
143 | , m_pIoPopReq(NULL)
144 | , m_pIoGetReq(NULL)
145 | , m_dwBusyReqNum(0UL)
146 | , m_dwReadyReqNum(0UL)
147 | , m_hPushIoThread(NULL)
148 | , m_hPopIoThread(NULL)
149 | , m_hOnStreamEvent(NULL)
150 | , m_dwCurSpace(0UL)
151 | , m_dwCurChannel(0xFFFFFFFFUL)
152 | , m_sock(INVALID_SOCKET)
153 | , m_fBitRate(0.0f)
154 | , m_dwRecvBytes(0UL)
155 | , m_dwLastCalcTick(0UL)
156 | {
157 | m_pThis = this;
158 |
159 | // グローバル変数初期化
160 | for (int i = 0; i < SPACE_NUM; i++) {
161 | g_pType[i] = NULL;
162 | }
163 |
164 | // クリティカルセクション初期化
165 | ::InitializeCriticalSection(&m_CriticalSection);
166 |
167 | //Initialize channel
168 | InitChannel();
169 | }
170 |
171 | CBonTuner::~CBonTuner()
172 | {
173 | // 開かれてる場合は閉じる
174 | CloseTuner();
175 |
176 | // メモリ解放
177 | for (int i = 0; i < SPACE_NUM; i++) {
178 | if (g_pType[i]) {
179 | free(g_pType[i]);
180 | }
181 | else {
182 | break;
183 | }
184 | }
185 |
186 | // クリティカルセクション削除
187 | ::DeleteCriticalSection(&m_CriticalSection);
188 |
189 | // Winsock終了
190 | if (m_bTunerOpen) {
191 | WSACleanup();
192 | }
193 |
194 | m_pThis = NULL;
195 | }
196 |
197 | void CBonTuner::InitChannel()
198 | {
199 | // Mirakurun APIよりchannel取得
200 | GetApiChannels(&g_Channel_JSON, g_Service_Split);
201 | if (g_Channel_JSON.is()) {
202 | return;
203 | }
204 | if (!g_Channel_JSON.contains(0)) {
205 | return;
206 | }
207 |
208 | // チューナ空間取得
209 | int i = 0;
210 | int j = 0;
211 | while (j < SPACE_NUM - 1) {
212 | if (!g_Channel_JSON.contains(i)) {
213 | break;
214 | }
215 | picojson::object& channel_obj = g_Channel_JSON.get(i).get();
216 | const char *type;
217 | if (g_Service_Split == 1) {
218 | picojson::object& channel_detail = channel_obj["channel"].get();
219 | type = channel_detail["type"].get().c_str();
220 | }
221 | else {
222 | type = channel_obj["type"].get().c_str();
223 | }
224 | if (!g_pType[0]) {
225 | int len = (int)strlen(type) + 1;
226 | g_pType[0] = (char *)malloc(len);
227 | if (!g_pType[0]) {
228 | break;
229 | }
230 | strcpy_s(g_pType[0], len, type);
231 | }
232 | else if (strcmp(g_pType[j], type)) {
233 | int len = (int)strlen(type) + 1;
234 | g_pType[++j] = (char *)malloc(len);
235 | if (!g_pType[j]) {
236 | j--;
237 | break;
238 | }
239 | strcpy_s(g_pType[j], len, type);
240 | g_Channel_Base[j] = i;
241 | }
242 | i++;
243 | }
244 | g_Max_Type = j;
245 | }
246 |
247 | const BOOL CBonTuner::OpenTuner()
248 | {
249 | if (g_Channel_JSON.is()) {
250 | return FALSE;
251 | }
252 |
253 | if (!m_bTunerOpen) {
254 | // Winsock初期化
255 | WSADATA stWsa;
256 | if (WSAStartup(MAKEWORD(2,2), &stWsa) != 0) {
257 | return FALSE;
258 | }
259 | if (g_MagicPacket_Enable) {
260 | char magicpacket[102];
261 | memset(&magicpacket, 0xff, 6);
262 | for (int i = 0; i < 16; i++) {
263 | memcpy(&magicpacket[i * 6 + 6], g_MagicPacket_TargetMAC, 6);
264 | }
265 | SOCKET s = socket(PF_INET, SOCK_DGRAM, 0);
266 | if (s == SOCKET_ERROR) {
267 | return FALSE;
268 | }
269 | SOCKADDR_IN addr;
270 | addr.sin_family = AF_INET;
271 | addr.sin_port = htons(9);
272 | addr.sin_addr.S_un.S_addr = inet_addr(g_MagicPacket_TargetIP);
273 |
274 | sendto(s, magicpacket, sizeof(magicpacket), 0, (LPSOCKADDR)&addr, sizeof(addr));
275 |
276 | DWORD dwLastTime = ::GetTickCount();
277 | int countdown = 0;
278 | for (countdown = 0; countdown < MAGICPACKET_WAIT_SECONDS; countdown++) {
279 | try {
280 | struct addrinfo hints;
281 | struct addrinfo* res = NULL;
282 | struct addrinfo* ai;
283 |
284 | memset(&hints, 0, sizeof(hints));
285 | hints.ai_family = AF_INET6; //IPv6優先
286 | hints.ai_socktype = SOCK_STREAM;
287 | hints.ai_protocol = IPPROTO_TCP;
288 | hints.ai_flags = AI_NUMERICSERV;
289 | if (getaddrinfo(g_ServerHost, g_ServerPort, &hints, &res) != 0) {
290 | //printf("getaddrinfo(): %s\n", gai_strerror(err));
291 | hints.ai_family = AF_INET; //IPv4限定
292 | if (getaddrinfo(g_ServerHost, g_ServerPort, &hints, &res) != 0) {
293 | throw 1UL;
294 | }
295 | }
296 |
297 | for (ai = res; ai; ai = ai->ai_next) {
298 | m_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
299 | if (m_sock == INVALID_SOCKET) {
300 | continue;
301 | }
302 |
303 | if (connect(m_sock, ai->ai_addr, (int)ai->ai_addrlen) >= 0) {
304 | // OK
305 | break;
306 | }
307 | closesocket(m_sock);
308 | m_sock = INVALID_SOCKET;
309 | }
310 | freeaddrinfo(res);
311 |
312 | if (m_sock == INVALID_SOCKET) {
313 | TCHAR szDebugOut[128];
314 | ::wsprintf(szDebugOut, TEXT("%s: CBonTuner::OpenTuner() connection error %d\n"), TUNER_NAME, WSAGetLastError());
315 | ::OutputDebugString(szDebugOut);
316 | throw 1UL;
317 | }
318 |
319 | const char serverRequest[] = "GET / HTTP/1.0\r\n\r\n";
320 | if (send(m_sock, serverRequest, (int)strlen(serverRequest), 0) < 0) {
321 | TCHAR szDebugOut[128];
322 | ::wsprintf(szDebugOut, TEXT("%s: CBonTuner::OpenTuner() send error %d\n"), TUNER_NAME, WSAGetLastError());
323 | ::OutputDebugString(szDebugOut);
324 | throw 1UL;
325 | }
326 |
327 | // Success
328 | break;
329 | }
330 | catch (const DWORD dwErrorStep) {
331 | if (::GetTickCount() - dwLastTime > (MAGICPACKET_WAIT_SECONDS * 1000)) {
332 | TCHAR szDebugOut[1024];
333 | ::wsprintf(szDebugOut, TEXT("TimeOut\n"));
334 | ::OutputDebugString(szDebugOut);
335 | return FALSE;
336 | }
337 | // エラー発生
338 | TCHAR szDebugOut[1024];
339 | ::wsprintf(szDebugOut, TEXT("%s: CBonTuner::OpenTuner() dwErrorStep = %lu\n"), TUNER_NAME, dwErrorStep);
340 | ::OutputDebugString(szDebugOut);
341 | Sleep(1000);
342 | }
343 | }
344 |
345 | if (countdown >= MAGICPACKET_WAIT_SECONDS) {
346 | // Failed
347 | return FALSE;
348 | }
349 | }
350 |
351 | m_bTunerOpen = TRUE;
352 | }
353 |
354 | //return SetChannel(0UL,0UL);
355 |
356 | return TRUE;
357 | }
358 |
359 | void CBonTuner::CloseTuner()
360 | {
361 | // スレッド終了要求セット
362 | m_bLoopIoThread = FALSE;
363 |
364 | // イベント開放
365 | if (m_hOnStreamEvent) {
366 | ::CloseHandle(m_hOnStreamEvent);
367 | m_hOnStreamEvent = NULL;
368 | }
369 |
370 | // スレッド終了
371 | if (m_hPushIoThread) {
372 | if (::WaitForSingleObject(m_hPushIoThread, 1000) != WAIT_OBJECT_0) {
373 | // スレッド強制終了
374 | ::TerminateThread(m_hPushIoThread, 0);
375 |
376 | TCHAR szDebugOut[128];
377 | ::wsprintf(szDebugOut, TEXT("%s: CBonTuner::CloseTuner() ::TerminateThread(m_hPushIoThread)\n"), TUNER_NAME);
378 | ::OutputDebugString(szDebugOut);
379 | }
380 |
381 | ::CloseHandle(m_hPushIoThread);
382 | m_hPushIoThread = NULL;
383 | }
384 |
385 | if (m_hPopIoThread) {
386 | if (::WaitForSingleObject(m_hPopIoThread, 1000) != WAIT_OBJECT_0) {
387 | // スレッド強制終了
388 | ::TerminateThread(m_hPopIoThread, 0);
389 |
390 | TCHAR szDebugOut[128];
391 | ::wsprintf(szDebugOut, TEXT("%s: CBonTuner::CloseTuner() ::TerminateThread(m_hPopIoThread)\n"), TUNER_NAME);
392 | ::OutputDebugString(szDebugOut);
393 | }
394 |
395 | ::CloseHandle(m_hPopIoThread);
396 | m_hPopIoThread = NULL;
397 | }
398 |
399 |
400 | // バッファ開放
401 | FreeIoReqBuff(m_pIoReqBuff);
402 | m_pIoReqBuff = NULL;
403 | m_pIoPushReq = NULL;
404 | m_pIoPopReq = NULL;
405 | m_pIoGetReq = NULL;
406 |
407 | m_dwBusyReqNum = 0UL;
408 | m_dwReadyReqNum = 0UL;
409 |
410 | // ソケットクローズ
411 | if (m_sock != INVALID_SOCKET) {
412 | closesocket(m_sock);
413 | m_sock = INVALID_SOCKET;
414 | }
415 |
416 | // チャンネル初期化
417 | m_dwCurSpace = 0UL;
418 | m_dwCurChannel = 0xFFFFFFFFUL;
419 |
420 | // ミューテックス開放
421 | if (m_hMutex) {
422 | ::ReleaseMutex(m_hMutex);
423 | ::CloseHandle(m_hMutex);
424 | m_hMutex = NULL;
425 | }
426 |
427 | m_fBitRate = 0.0f;
428 | m_dwRecvBytes = 0UL;
429 | }
430 |
431 | const DWORD CBonTuner::WaitTsStream(const DWORD dwTimeOut)
432 | {
433 | // 終了チェック
434 | if (!m_hOnStreamEvent || !m_bLoopIoThread) {
435 | return WAIT_ABANDONED;
436 | }
437 |
438 | // イベントがシグナル状態になるのを待つ
439 | const DWORD dwRet = ::WaitForSingleObject(m_hOnStreamEvent, (dwTimeOut)? dwTimeOut : INFINITE);
440 |
441 | switch (dwRet) {
442 | case WAIT_ABANDONED :
443 | // チューナが閉じられた
444 | return WAIT_ABANDONED;
445 |
446 | case WAIT_OBJECT_0 :
447 | case WAIT_TIMEOUT :
448 | // ストリーム取得可能 or チューナが閉じられた
449 | return (m_bLoopIoThread)? dwRet : WAIT_ABANDONED;
450 |
451 | case WAIT_FAILED :
452 | default:
453 | // 例外
454 | return WAIT_FAILED;
455 | }
456 | }
457 |
458 | const DWORD CBonTuner::GetReadyCount()
459 | {
460 | // 取り出し可能TSデータ数を取得する
461 | return m_dwReadyReqNum;
462 | }
463 |
464 | const BOOL CBonTuner::GetTsStream(BYTE *pDst, DWORD *pdwSize, DWORD *pdwRemain)
465 | {
466 | BYTE *pSrc = NULL;
467 |
468 | // TSデータをバッファから取り出す
469 | if (GetTsStream(&pSrc, pdwSize, pdwRemain)) {
470 | if (*pdwSize) {
471 | ::CopyMemory(pDst, pSrc, *pdwSize);
472 | }
473 |
474 | return TRUE;
475 | }
476 |
477 | return FALSE;
478 | }
479 |
480 | const BOOL CBonTuner::GetTsStream(BYTE **ppDst, DWORD *pdwSize, DWORD *pdwRemain)
481 | {
482 | if (!m_pIoGetReq) {
483 | return FALSE;
484 | }
485 |
486 | // TSデータをバッファから取り出す
487 | if (m_dwReadyReqNum) {
488 | if (m_pIoGetReq->dwState == IORS_RECV) {
489 |
490 | // データコピー
491 | *pdwSize = m_pIoGetReq->dwRxdSize;
492 | *ppDst = m_pIoGetReq->RxdBuff;
493 |
494 | // バッファ位置を進める
495 | ::EnterCriticalSection(&m_CriticalSection);
496 | m_pIoGetReq = m_pIoGetReq->pNext;
497 | m_dwReadyReqNum--;
498 | *pdwRemain = m_dwReadyReqNum;
499 | ::LeaveCriticalSection(&m_CriticalSection);
500 |
501 | return TRUE;
502 | }
503 |
504 | // 例外
505 | return FALSE;
506 | }
507 |
508 | // 取り出し可能なデータがない
509 | *pdwSize = 0;
510 | *pdwRemain = 0;
511 |
512 | return TRUE;
513 | }
514 |
515 | void CBonTuner::PurgeTsStream()
516 | {
517 | // バッファから取り出し可能データをパージする
518 | ::EnterCriticalSection(&m_CriticalSection);
519 | m_pIoGetReq = m_pIoPopReq;
520 | m_dwReadyReqNum = 0;
521 | ::LeaveCriticalSection(&m_CriticalSection);
522 | }
523 |
524 | void CBonTuner::Release()
525 | {
526 | // インスタンス開放
527 | delete this;
528 | }
529 |
530 | LPCTSTR CBonTuner::GetTunerName(void)
531 | {
532 | // チューナ名を返す
533 | return TEXT(TUNER_NAME);
534 | }
535 |
536 | const BOOL CBonTuner::IsTunerOpening(void)
537 | {
538 | // チューナの使用中の有無を返す(全プロセスを通して)
539 | HANDLE hMutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, MUTEX_NAME);
540 |
541 | if (hMutex) {
542 | // 既にチューナは開かれている
543 | ::CloseHandle(hMutex);
544 | return TRUE;
545 | }
546 |
547 | // チューナは開かれていない
548 | return FALSE;
549 | }
550 |
551 | LPCTSTR CBonTuner::EnumTuningSpace(const DWORD dwSpace)
552 | {
553 | if (dwSpace > g_Max_Type) {
554 | return NULL;
555 | }
556 |
557 | // 使用可能なチューニング空間を返す
558 | static TCHAR buf[128];
559 | ::MultiByteToWideChar(CP_UTF8, 0, g_pType[dwSpace], -1, buf, sizeof(buf));
560 | return buf;
561 | }
562 |
563 | LPCTSTR CBonTuner::EnumChannelName(const DWORD dwSpace, const DWORD dwChannel)
564 | {
565 | if (dwSpace > g_Max_Type) {
566 | return NULL;
567 | }
568 | if (dwSpace < g_Max_Type) {
569 | if (dwChannel >= g_Channel_Base[dwSpace + 1] - g_Channel_Base[dwSpace]) {
570 | return NULL;
571 | }
572 | }
573 |
574 | DWORD Bon_Channel = dwChannel + g_Channel_Base[dwSpace];
575 | if (!g_Channel_JSON.contains(Bon_Channel)) {
576 | return NULL;
577 | }
578 |
579 | picojson::object& channel_obj = g_Channel_JSON.get(Bon_Channel).get();
580 | const char *channel_name = channel_obj["name"].get().c_str();
581 |
582 | static TCHAR buf[128];
583 | ::MultiByteToWideChar(CP_UTF8, 0, channel_name, -1, buf, sizeof(buf));
584 |
585 | return buf;
586 | }
587 |
588 | const DWORD CBonTuner::GetCurSpace(void)
589 | {
590 | // 現在のチューニング空間を返す
591 | return m_dwCurSpace;
592 | }
593 |
594 | const DWORD CBonTuner::GetCurChannel(void)
595 | {
596 | // 現在のチャンネルを返す
597 | return m_dwCurChannel;
598 | }
599 |
600 | CBonTuner::AsyncIoReq * CBonTuner::AllocIoReqBuff(const DWORD dwBuffNum)
601 | {
602 | if (dwBuffNum < 2) {
603 | return NULL;
604 | }
605 |
606 | // メモリを確保する
607 | AsyncIoReq *pNewBuff = new AsyncIoReq [dwBuffNum];
608 | if (!pNewBuff) {
609 | return NULL;
610 | }
611 |
612 | // ゼロクリア
613 | ::ZeroMemory(pNewBuff, sizeof(AsyncIoReq) * dwBuffNum);
614 |
615 | // リンクを構築する
616 | DWORD dwIndex;
617 | for(dwIndex = 0 ; dwIndex < ( dwBuffNum - 1 ) ; dwIndex++) {
618 | pNewBuff[dwIndex].pNext= &pNewBuff[dwIndex + 1];
619 | }
620 |
621 | pNewBuff[dwIndex].pNext = &pNewBuff[0];
622 |
623 | return pNewBuff;
624 | }
625 |
626 | void CBonTuner::FreeIoReqBuff(CBonTuner::AsyncIoReq *pBuff)
627 | {
628 | if (!pBuff) {
629 | return;
630 | }
631 |
632 | // バッファを開放する
633 | delete [] pBuff;
634 | }
635 |
636 | DWORD WINAPI CBonTuner::PushIoThread(LPVOID pParam)
637 | {
638 | CBonTuner *pThis = (CBonTuner *)pParam;
639 |
640 | DWORD dwLastTime = ::GetTickCount();
641 |
642 | // ::OutputDebugString("CBonTuner::PushIoThread() Start!\n");
643 |
644 | // ドライバにTSデータリクエストを発行する
645 | while (pThis->m_bLoopIoThread) {
646 |
647 | // リクエスト処理待ちが規定未満なら追加する
648 | if (pThis->m_dwBusyReqNum < REQRESERVNUM) {
649 |
650 | // ドライバにTSデータリクエストを発行する(HTTPなので受信要求のみ)
651 | if (!pThis->PushIoRequest(pThis->m_sock)) {
652 | // エラー発生
653 | break;
654 | }
655 |
656 | } else {
657 | // リクエスト処理待ちがフルの場合はウェイト
658 | ::Sleep(REQPOLLINGWAIT);
659 | }
660 | }
661 |
662 | // ::OutputDebugString("CBonTuner::PushIoThread() End!\n");
663 | return 0;
664 | }
665 |
666 | DWORD WINAPI CBonTuner::PopIoThread(LPVOID pParam)
667 | {
668 | CBonTuner *pThis = (CBonTuner *)pParam;
669 |
670 | // 処理済リクエストをポーリングしてリクエストを完了させる
671 | while (pThis->m_bLoopIoThread) {
672 |
673 | // 処理済データがあればリクエストを完了する
674 | if (pThis->m_dwBusyReqNum) {
675 |
676 | // リクエストを完了する
677 | if (!pThis->PopIoRequest(pThis->m_sock)) {
678 | // エラー発生
679 | break;
680 | }
681 | }
682 | }
683 |
684 | return 0;
685 | }
686 |
687 | const BOOL CBonTuner::PushIoRequest(SOCKET sock)
688 | {
689 | // ドライバに非同期リクエストを発行する
690 |
691 | // オープンチェック
692 | if (sock == INVALID_SOCKET)return FALSE;
693 |
694 | // リクエストセット
695 | m_pIoPushReq->dwRxdSize = 0;
696 |
697 | // イベント設定
698 | ::ZeroMemory(&m_pIoPushReq->OverLapped, sizeof(WSAOVERLAPPED));
699 | if (!(m_pIoPushReq->OverLapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL)))return FALSE;
700 |
701 | // HTTP受信を要求スルニダ!
702 | DWORD Flags = 0;
703 | WSABUF wsaBuf;
704 | wsaBuf.buf = (char *)m_pIoPushReq->RxdBuff;
705 | wsaBuf.len = sizeof(m_pIoPushReq->RxdBuff);
706 | if (SOCKET_ERROR == WSARecv(sock, &wsaBuf, 1, &m_pIoPushReq->dwRxdSize, &Flags, &m_pIoPushReq->OverLapped, NULL)) {
707 | int sock_err = WSAGetLastError();
708 | if (sock_err != ERROR_IO_PENDING) {
709 | return FALSE;
710 | }
711 | }
712 |
713 | m_pIoPushReq->dwState = IORS_BUSY;
714 |
715 | // バッファ状態更新
716 | ::EnterCriticalSection(&m_CriticalSection);
717 | m_pIoPushReq = m_pIoPushReq->pNext;
718 | m_dwBusyReqNum++;
719 | ::LeaveCriticalSection(&m_CriticalSection);
720 |
721 | return TRUE;
722 | }
723 |
724 | const BOOL CBonTuner::PopIoRequest(SOCKET sock)
725 | {
726 | // 非同期リクエストを完了する
727 |
728 | // オープンチェック
729 | if (sock == INVALID_SOCKET) {
730 | return FALSE;
731 | }
732 |
733 | // 状態チェック
734 | if (m_pIoPopReq->dwState != IORS_BUSY) {
735 | // 例外
736 | return TRUE;
737 | }
738 |
739 | // リクエスト取得
740 | DWORD Flags=0;
741 | const BOOL bRet = ::WSAGetOverlappedResult(sock, &m_pIoPopReq->OverLapped, &m_pIoPopReq->dwRxdSize, FALSE, &Flags);
742 |
743 | // エラーチェック
744 | if (!bRet) {
745 | int sock_err = WSAGetLastError();
746 | if (sock_err == ERROR_IO_INCOMPLETE) {
747 | // 処理未完了
748 | ::Sleep(REQPOLLINGWAIT);
749 | return TRUE;
750 | }
751 | }
752 |
753 | // 総受信サイズ加算
754 | m_dwRecvBytes += m_pIoPopReq->dwRxdSize;
755 |
756 | // ビットレート計算
757 | if (DiffTime(m_dwLastCalcTick,::GetTickCount()) >= BITRATE_CALC_TIME) {
758 | CalcBitRate();
759 | }
760 |
761 | // イベント削除
762 | ::CloseHandle(m_pIoPopReq->OverLapped.hEvent);
763 |
764 | if (!bRet) {
765 | // エラー発生
766 | return FALSE;
767 | }
768 |
769 | m_pIoPopReq->dwState = IORS_RECV;
770 |
771 | // バッファ状態更新
772 | ::EnterCriticalSection(&m_CriticalSection);
773 | m_pIoPopReq = m_pIoPopReq->pNext;
774 | m_dwBusyReqNum--;
775 | m_dwReadyReqNum++;
776 | ::LeaveCriticalSection(&m_CriticalSection);
777 |
778 | // イベントセット
779 | ::SetEvent(m_hOnStreamEvent);
780 |
781 | return TRUE;
782 | }
783 |
784 |
785 | // チャンネル設定
786 | const BOOL CBonTuner::SetChannel(const BYTE bCh)
787 | {
788 | return SetChannel((DWORD)0,(DWORD)bCh - 13);
789 | }
790 |
791 | // チャンネル設定
792 | const BOOL CBonTuner::SetChannel(const DWORD dwSpace, const DWORD dwChannel)
793 | {
794 | if (dwSpace > g_Max_Type) {
795 | return NULL;
796 | }
797 |
798 | DWORD Bon_Channel = dwChannel + g_Channel_Base[dwSpace];
799 | if (!g_Channel_JSON.contains(Bon_Channel)) {
800 | return NULL;
801 | }
802 |
803 | picojson::object& channel_obj = g_Channel_JSON.get(Bon_Channel).get();
804 |
805 | const char *type;
806 | const char *channel;
807 | char serviceId[6];
808 | if (g_Service_Split == 1) {
809 | picojson::object& channel_detail = channel_obj["channel"].get();
810 | type = channel_detail["type"].get().c_str();
811 | channel = channel_detail["channel"].get().c_str();
812 | sprintf_s(serviceId, "%u", (DWORD)channel_obj["serviceId"].get());
813 | }
814 | else {
815 | type = channel_obj["type"].get().c_str();
816 | channel = channel_obj["channel"].get().c_str();
817 | }
818 |
819 | // 一旦クローズ
820 | CloseTuner();
821 |
822 | // バッファ確保
823 | if (!(m_pIoReqBuff = AllocIoReqBuff(ASYNCBUFFSIZE))) {
824 | return FALSE;
825 | }
826 |
827 | // バッファ位置同期
828 | m_pIoPushReq = m_pIoReqBuff;
829 | m_pIoPopReq = m_pIoReqBuff;
830 | m_pIoGetReq = m_pIoReqBuff;
831 | m_dwBusyReqNum = 0;
832 | m_dwReadyReqNum = 0;
833 |
834 | try{
835 | char url[128];
836 | char serverRequest[256];
837 |
838 | // URL生成
839 | if (g_Service_Split == 1) {
840 | sprintf_s(url, "/api/channels/%s/%s/services/%s/stream?decode=%d", type, channel, serviceId, g_DecodeB25);
841 | }
842 | else {
843 | sprintf_s(url, "/api/channels/%s/%s/stream?decode=%d", type, channel, g_DecodeB25);
844 | }
845 | sprintf_s(serverRequest, "GET %s HTTP/1.0\r\nX-Mirakurun-Priority: %d\r\n\r\n", url, g_Priority);
846 |
847 | struct addrinfo hints;
848 | struct addrinfo* res = NULL;
849 | struct addrinfo* ai;
850 |
851 | memset(&hints, 0, sizeof(hints));
852 | hints.ai_family = AF_INET6; //IPv6優先
853 | hints.ai_socktype = SOCK_STREAM;
854 | hints.ai_protocol = IPPROTO_TCP;
855 | hints.ai_flags = AI_NUMERICSERV;
856 | if (getaddrinfo(g_ServerHost, g_ServerPort, &hints, &res) != 0) {
857 | //printf("getaddrinfo(): %s\n", gai_strerror(err));
858 | hints.ai_family = AF_INET; //IPv4限定
859 | if (getaddrinfo(g_ServerHost, g_ServerPort, &hints, &res) != 0) {
860 | throw 1UL;
861 | }
862 | }
863 |
864 | for (ai = res; ai; ai = ai->ai_next) {
865 | m_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
866 | if (m_sock == INVALID_SOCKET) {
867 | continue;
868 | }
869 |
870 | if (connect(m_sock, ai->ai_addr, (int)ai->ai_addrlen) >= 0) {
871 | // OK
872 | break;
873 | }
874 | closesocket(m_sock);
875 | m_sock = INVALID_SOCKET;
876 | }
877 | freeaddrinfo(res);
878 |
879 | if (m_sock == INVALID_SOCKET) {
880 | TCHAR szDebugOut[128];
881 | ::wsprintf(szDebugOut, TEXT("%s: CBonTuner::OpenTuner() connection error %d\n"), TUNER_NAME, WSAGetLastError());
882 | ::OutputDebugString(szDebugOut);
883 | throw 1UL;
884 | }
885 |
886 | if (send(m_sock, serverRequest, (int)strlen(serverRequest), 0) < 0) {
887 | TCHAR szDebugOut[128];
888 | ::wsprintf(szDebugOut, TEXT("%s: CBonTuner::OpenTuner() send error %d\n"), TUNER_NAME, WSAGetLastError());
889 | ::OutputDebugString(szDebugOut);
890 | throw 1UL;
891 | }
892 |
893 | // イベント作成
894 | if (!(m_hOnStreamEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL))) {
895 | throw 2UL;
896 | }
897 |
898 | // スレッド起動
899 | DWORD dwPushIoThreadID = 0UL, dwPopIoThreadID = 0UL;
900 | m_hPushIoThread = ::CreateThread(NULL, 0UL, CBonTuner::PushIoThread, this, CREATE_SUSPENDED, &dwPopIoThreadID);
901 | m_hPopIoThread = ::CreateThread(NULL, 0UL, CBonTuner::PopIoThread, this, CREATE_SUSPENDED, &dwPushIoThreadID);
902 |
903 | if (!m_hPushIoThread || !m_hPopIoThread) {
904 | if (m_hPushIoThread) {
905 | ::TerminateThread(m_hPushIoThread, 0UL);
906 | ::CloseHandle(m_hPushIoThread);
907 | m_hPushIoThread = NULL;
908 | }
909 |
910 | if (m_hPopIoThread) {
911 | ::TerminateThread(m_hPopIoThread, 0UL);
912 | ::CloseHandle(m_hPopIoThread);
913 | m_hPopIoThread = NULL;
914 | }
915 |
916 | throw 3UL;
917 | }
918 |
919 | // スレッド開始
920 | m_bLoopIoThread = TRUE;
921 | if (::ResumeThread(m_hPushIoThread) == 0xFFFFFFFFUL || ::ResumeThread(m_hPopIoThread) == 0xFFFFFFFFUL) {
922 | throw 4UL;
923 | }
924 |
925 | // ミューテックス作成
926 | if (!(m_hMutex = ::CreateMutex(NULL, TRUE, MUTEX_NAME))) {
927 | throw 5UL;
928 | }
929 |
930 | } catch (const DWORD dwErrorStep) {
931 | // エラー発生
932 | TCHAR szDebugOut[1024];
933 | ::wsprintf(szDebugOut, TEXT("%s: CBonTuner::OpenTuner() dwErrorStep = %lu\n"), TUNER_NAME, dwErrorStep);
934 | ::OutputDebugString(szDebugOut);
935 |
936 | CloseTuner();
937 | return FALSE;
938 | }
939 |
940 | // チャンネル情報更新
941 | m_dwCurSpace = dwSpace;
942 | m_dwCurChannel = dwChannel;
943 |
944 | // TSデータパージ
945 | PurgeTsStream();
946 |
947 | return TRUE;
948 | }
949 |
950 | // 信号レベル(ビットレート)取得
951 | const float CBonTuner::GetSignalLevel(void)
952 | {
953 | CalcBitRate();
954 | return m_fBitRate;
955 | }
956 |
957 | void CBonTuner::CalcBitRate()
958 | {
959 | DWORD dwCurrentTick = GetTickCount();
960 | DWORD Span = DiffTime(m_dwLastCalcTick,dwCurrentTick);
961 |
962 | if (Span >= BITRATE_CALC_TIME) {
963 | m_fBitRate = (float)(((double)m_dwRecvBytes*(8*1000))/((double)Span*(1024*1024)));
964 | m_dwRecvBytes = 0;
965 | m_dwLastCalcTick = dwCurrentTick;
966 | }
967 | return;
968 | }
969 |
970 | void CBonTuner::GetApiChannels(picojson::value* channel_json, int service_split)
971 | {
972 | HttpClient client;
973 | char url[512];
974 | sprintf_s(url, "http://%s:%s/api/", g_ServerHost, g_ServerPort);
975 | if (service_split == 1) {
976 | strcat_s(url, "services");
977 | }
978 | else {
979 | strcat_s(url, "channels");
980 | }
981 | HttpResponse response = client.get(url);
982 |
983 | picojson::value v;
984 | std::string err = picojson::parse(v, response.content);
985 | if (err.empty()) {
986 | *channel_json = v;
987 |
988 | /*
989 | // DEBUG
990 | picojson::array channel_array = v.get();
991 | for (picojson::array::iterator it = channel_array.begin(); it != channel_array.end(); it++) {
992 | picojson::object& channel = it->get();
993 | std::string channel_name = channel["name"].get();
994 | picojson::array& services = channel["services"].get();
995 |
996 | std::string tmp_debug("channel name : ");
997 | tmp_debug.append(channel_name);
998 | wchar_t debug[128];
999 | mbstowcs(debug, tmp_debug.c_str(), sizeof(debug));
1000 | OutputDebugString(debug);
1001 | }
1002 | */
1003 | }
1004 | }
1005 |
--------------------------------------------------------------------------------