├── 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 | --------------------------------------------------------------------------------