DWORD WINAPI RTMPPublisher::CreateConnectionThread(RTMPPublisher *publisher) { //------------------------------------------------------ // set up URL bool bRetry = false; bool bSuccess = false; bool bCanRetry = false; String failReason; String strBindIP; int serviceID = AppConfig->GetInt (TEXT("Publish"), TEXT("Service")); String strURL = AppConfig->GetString(TEXT("Publish"), TEXT("URL")); String strPlayPath = AppConfig->GetString(TEXT("Publish"), TEXT("PlayPath")); strURL.KillSpaces(); strPlayPath.KillSpaces(); LPSTR lpAnsiURL = NULL, lpAnsiPlaypath = NULL; RTMP *rtmp = NULL; //-------------------------------- // unbelievably disgusting hack for elgato devices String strOldDirectory; UINT dirSize = GetCurrentDirectory(0, 0); strOldDirectory.SetLength(dirSize); GetCurrentDirectory(dirSize, strOldDirectory.Array()); OSSetCurrentDirectory(API->GetAppPath()); //-------------------------------- if(!strURL.IsValid()) { failReason = TEXT("No server specified to connect to"); goto end; } if(serviceID != 0) { XConfig serverData; if(!serverData.Open(TEXT("services.xconfig"))) { failReason = TEXT("Could not open services.xconfig"); goto end; } XElement *services = serverData.GetElement(TEXT("services")); if(!services) { failReason = TEXT("Could not find any services in services.xconfig"); goto end; } XElement *service = NULL; DWORD numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *curService = services->GetElementByID(i); if(curService->GetInt(TEXT("id")) == serviceID) { service = curService; break; } } if(!service) { failReason = TEXT("Could not find the service specified in services.xconfig"); goto end; } XElement *servers = service->GetElement(TEXT("servers")); if(!servers) { failReason = TEXT("Could not find any servers for the service specified in services.xconfig"); goto end; } XDataItem *item = servers->GetDataItem(strURL); if(!item) item = servers->GetDataItemByID(0); strURL = item->GetData(); Log(TEXT("Using RTMP service: %s"), service->GetName()); Log(TEXT(" Server selection: %s"), strURL.Array()); } //------------------------------------------------------ // now back to the elgato directory if it needs the directory changed still to function *sigh* OSSetCurrentDirectory(strOldDirectory); //------------------------------------------------------ rtmp = RTMP_Alloc(); RTMP_Init(rtmp); RTMP_LogSetCallback(librtmpErrorCallback); //RTMP_LogSetLevel(RTMP_LOGERROR); lpAnsiURL = strURL.CreateUTF8String(); lpAnsiPlaypath = strPlayPath.CreateUTF8String(); if(!RTMP_SetupURL2(rtmp, lpAnsiURL, lpAnsiPlaypath)) { failReason = Str("Connection.CouldNotParseURL"); goto end; } char *rtmpUser = AppConfig->GetString(TEXT("Publish"), TEXT("Username")).CreateUTF8String(); char *rtmpPass = AppConfig->GetString(TEXT("Publish"), TEXT("Password")).CreateUTF8String(); if (rtmpUser) { rtmp->Link.pubUser.av_val = rtmpUser; rtmp->Link.pubUser.av_len = (int)strlen(rtmpUser); } if (rtmpPass) { rtmp->Link.pubPasswd.av_val = rtmpPass; rtmp->Link.pubPasswd.av_len = (int)strlen(rtmpPass); } RTMP_EnableWrite(rtmp); //set it to publish rtmp->Link.swfUrl.av_len = rtmp->Link.tcUrl.av_len; rtmp->Link.swfUrl.av_val = rtmp->Link.tcUrl.av_val; /*rtmp->Link.pageUrl.av_len = rtmp->Link.tcUrl.av_len; rtmp->Link.pageUrl.av_val = rtmp->Link.tcUrl.av_val;*/ rtmp->Link.flashVer.av_val = "FMLE/3.0 (compatible; FMSc/1.0)"; rtmp->Link.flashVer.av_len = (int)strlen(rtmp->Link.flashVer.av_val); //----------------------------------------- UINT tcpBufferSize = AppConfig->GetInt(TEXT("Publish"), TEXT("TCPBufferSize"), 64*1024); if(tcpBufferSize < 8192) tcpBufferSize = 8192; else if(tcpBufferSize > 1024*1024) tcpBufferSize = 1024*1024; rtmp->m_outChunkSize = 4096;//RTMP_DEFAULT_CHUNKSIZE;// rtmp->m_bSendChunkSizeInfo = TRUE; rtmp->m_bUseNagle = TRUE; strBindIP = AppConfig->GetString(TEXT("Publish"), TEXT("BindToIP"), TEXT("Default")); if (scmp(strBindIP, TEXT("Default"))) { rtmp->m_bindIP.addr.sin_family = AF_INET; rtmp->m_bindIP.addrLen = sizeof(rtmp->m_bindIP.addr); if (WSAStringToAddress(strBindIP.Array(), AF_INET, NULL, (LPSOCKADDR)&rtmp->m_bindIP.addr, &rtmp->m_bindIP.addrLen) == SOCKET_ERROR) { // no localization since this should rarely/never happen failReason = TEXT("WSAStringToAddress: Could not parse address"); goto end; } } LogInterfaceType(rtmp); //----------------------------------------- if(!RTMP_Connect(rtmp, NULL)) { failReason = Str("Connection.CouldNotConnect"); failReason << TEXT("\r\n\r\n") << RTMPPublisher::GetRTMPErrors(); bCanRetry = true; goto end; } if(!RTMP_ConnectStream(rtmp, 0)) { failReason = Str("Connection.InvalidStream"); failReason << TEXT("\r\n\r\n") << RTMPPublisher::GetRTMPErrors(); bCanRetry = true; goto end; } //----------------------------------------- OSDebugOut(TEXT("Connected: %u\r\n"), OSGetTime()); publisher->RequestKeyframe(1000); //----------------------------------------- bSuccess = true; end: if (lpAnsiURL) Free(lpAnsiURL); if (lpAnsiPlaypath) Free(lpAnsiPlaypath); if(!bSuccess) { if(rtmp) { RTMP_Close(rtmp); RTMP_Free(rtmp); } if(failReason.IsValid()) App->SetStreamReport(failReason); if(!publisher->bStopping) PostMessage(hwndMain, OBS_REQUESTSTOP, bCanRetry ? 0 : 1, 0); Log(TEXT("Connection to %s failed: %s"), strURL.Array(), failReason.Array()); publisher->bStopping = true; } else { publisher->Init(rtmp, tcpBufferSize); publisher->bConnected = true; publisher->bConnecting = false; } return 0; }
BOOL ParseUpdateManifest (TCHAR *path, BOOL *updatesAvailable, String &description) { XConfig manifest; XElement *root; if (!manifest.Open(path)) return FALSE; root = manifest.GetRootElement(); DWORD numPackages = root->NumElements(); DWORD totalUpdatableFiles = 0; int priority, bestPriority = 999; for (DWORD i = 0; i < numPackages; i++) { XElement *package; package = root->GetElementByID(i); CTSTR packageName = package->GetName(); //find out if this package is relevant to us String platform = package->GetString(TEXT("platform")); if (!platform) continue; if (scmp(platform, TEXT("all"))) { #ifndef _WIN64 if (scmp(platform, TEXT("Win32"))) continue; #else if (scmp(platform, TEXT("Win64"))) continue; #endif } //what is it? String name = package->GetString(TEXT("name")); String version = package->GetString(TEXT("version")); //figure out where the files belong XDataItem *pathElement = package->GetDataItem(TEXT("path")); if (!pathElement) continue; CTSTR path = pathElement->GetData(); if (path == NULL) path = TEXT(""); if (!IsSafePath(path)) continue; priority = package->GetInt(TEXT("priority"), 999); //get the file list for this package XElement *files = package->GetElement(TEXT("files")); if (!files) continue; DWORD numFiles = files->NumElements(); DWORD numUpdatableFiles = 0; for (DWORD j = 0; j < numFiles; j++) { XElement *file = files->GetElementByID(j); String hash = file->GetString(TEXT("hash")); if (!hash || hash.Length() != 40) continue; String fileName = file->GetName(); if (!fileName) continue; if (!IsSafeFilename(fileName)) continue; String filePath; filePath << path; filePath << fileName; BYTE fileHash[20]; TCHAR fileHashString[41]; if (OSFileExists(filePath)) { if (!CalculateFileHash(filePath, fileHash)) continue; HashToString(fileHash, fileHashString); if (!scmp(fileHashString, hash)) continue; } numUpdatableFiles++; } if (numUpdatableFiles) { if (version.Length()) description << name << TEXT(" (") << version << TEXT(")\r\n"); else description << name << TEXT("\r\n"); if (priority < bestPriority) bestPriority = priority; } totalUpdatableFiles += numUpdatableFiles; numUpdatableFiles = 0; } manifest.Close(); if (totalUpdatableFiles) { if (!FetchUpdaterModule()) return FALSE; } if (bestPriority <= 5) *updatesAvailable = TRUE; else *updatesAvailable = FALSE; return TRUE; }