void OBS::CheckSources() { XElement *curSceneElement = App->sceneElement; XElement *sources = curSceneElement->GetElement(TEXT("sources")); if(!sources) return; HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); UINT numSources = ListView_GetItemCount(hwndSources); for(UINT i = 0; i < numSources; i++) { bool checked = ListView_GetCheckState(hwndSources, i) > 0; XElement *source =sources->GetElementByID(i); bool curRender = source->GetInt(TEXT("render"), 0) > 0; if(curRender != checked) { source->SetInt(TEXT("render"), (checked)?1:0); if(scene && i < scene->NumSceneItems()) { SceneItem *sceneItem = scene->GetSceneItem(i); sceneItem->bRender = checked; sceneItem->SetRender(checked); } ReportSourceChanged(source->GetName(), source); } } }
json_t* OBSAPIMessageHandler::HandleGetSceneList(OBSAPIMessageHandler* handler, json_t* message) { OBSEnterSceneMutex(); json_t* ret = GetOkResponse(); XElement* xscenes = OBSGetSceneListElement(); XElement* currentScene = OBSGetSceneElement(); json_object_set_new(ret, "current-scene", json_string_wchar(currentScene->GetName())); json_t* scenes = json_array(); if(scenes != NULL) { int numScenes = xscenes->NumElements(); for(int i = 0; i < numScenes; i++) { XElement* scene = xscenes->GetElementByID(i); json_array_append_new(scenes, getSceneJson(scene)); } } json_object_set_new(ret,"scenes", scenes); OBSLeaveSceneMutex(); return ret; }
void OBS::GetGlobalSourceNames(List<CTSTR> &globalSourceNames) { globalSourceNames.Clear(); XElement *globals = scenesConfig.GetElement(TEXT("global sources")); if(globals) { UINT numSources = globals->NumElements(); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = globals->GetElementByID(i); globalSourceNames << sourceElement->GetName(); } } }
WebRequest* WProcessEngine::ParseRequest(XDocument* pxDoc, const char* mapName) { XElement *pxRoot = pxDoc->GetRootNode(); const char* request = pxRoot->GetName(); WebHandler* handler = GetHandler(request); if(handler == NULL) { char msg[AUGE_MSG_MAX]; g_sprintf(msg, "%s doesn't support request [%s]", GetType(), request); GLogger* pLogger = augeGetLoggerInstance(); pLogger->Error(msg, __FILE__, __LINE__); GError* pError = augeGetErrorInstance(); pError->SetError(msg); return NULL; } return handler->ParseRequest(pxDoc, mapName); }
void STDCALL SceneHotkey(DWORD hotkey, UPARAM param, bool bDown) { if(!bDown) return; XElement *scenes = API->GetSceneListElement(); if(scenes) { UINT numScenes = scenes->NumElements(); for(UINT i=0; i<numScenes; i++) { XElement *scene = scenes->GetElementByID(i); DWORD sceneHotkey = (DWORD)scene->GetInt(TEXT("hotkey")); if(sceneHotkey == hotkey) { App->SetScene(scene->GetName()); return; } } } }
void WebSocketOBSTriggerHandler::SourceOrderChanged() { json_t* update = json_object(); json_object_set_new(update, "update-type", json_string("SourceOrderChanged")); XElement* xsources = OBSGetSceneElement()->GetElement(TEXT("sources")); json_t* sources = json_array(); for(UINT i = 0; i < xsources->NumElements(); i++) { XElement* source = xsources->GetElementByID(i); json_array_append_new(sources, json_string_wchar(source->GetName())); } json_object_set_new(update, "sources", sources); OSEnterMutex(this->updateQueueMutex); this->updates.Add(update); OSLeaveMutex(this->updateQueueMutex); }
void OBS::SetSourceRender(CTSTR sourceName, bool render) { XElement *curSceneElement = App->sceneElement; XElement *sources = curSceneElement->GetElement(TEXT("sources")); if(!sources) return; HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); UINT numSources = ListView_GetItemCount(hwndSources); for(UINT i = 0; i < numSources; i++) { bool checked = ListView_GetCheckState(hwndSources, i) > 0; XElement *source =sources->GetElementByID(i); if(scmp(source->GetName(), sourceName) == 0 && checked != render) { if(scene && i < scene->NumSceneItems()) { SceneItem *sceneItem = scene->GetSceneItem(i); sceneItem->SetRender(render); } else { source->SetInt(TEXT("render"), (render)?1:0); } App->bChangingSources = true; ListView_SetCheckState(hwndSources, i, render); App->bChangingSources = false; ReportSourceChanged(sourceName, source); break; } } }
json_t* OBSAPIMessageHandler::HandleGetCurrentScene(OBSAPIMessageHandler* handler, json_t* message) { OBSEnterSceneMutex(); json_t* ret = GetOkResponse(); XElement* scene = OBSGetSceneElement(); json_object_set_new(ret, "name", json_string_wchar(scene->GetName())); XElement* sources = scene->GetElement(TEXT("sources")); json_t* scene_items = json_array(); if(sources != NULL) { for(UINT i = 0; i < sources->NumElements(); i++) { XElement* source = sources->GetElementByID(i); json_array_append_new(scene_items, getSourceJson(source)); } } json_object_set_new(ret, "sources", scene_items); OBSLeaveSceneMutex(); return ret; }
bool OBS::SetScene(CTSTR lpScene) { if(bDisableSceneSwitching) return false; HWND hwndScenes = GetDlgItem(hwndMain, ID_SCENES); UINT curSel = (UINT)SendMessage(hwndScenes, LB_GETCURSEL, 0, 0); //------------------------- if(curSel != LB_ERR) { UINT textLen = (UINT)SendMessage(hwndScenes, LB_GETTEXTLEN, curSel, 0); String strLBName; strLBName.SetLength(textLen); SendMessage(hwndScenes, LB_GETTEXT, curSel, (LPARAM)strLBName.Array()); if(!strLBName.CompareI(lpScene)) { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } } else { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } //------------------------- XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *newSceneElement = scenes->GetElement(lpScene); if(!newSceneElement) return false; if(sceneElement == newSceneElement) return true; sceneElement = newSceneElement; CTSTR lpClass = sceneElement->GetString(TEXT("class")); if(!lpClass) { AppWarning(TEXT("OBS::SetScene: no class found for scene '%s'"), newSceneElement->GetName()); return false; } DWORD sceneChangeStartTime; if(bRunning) { Log(TEXT("++++++++++++++++++++++++++++++++++++++++++++++++++++++")); Log(TEXT(" New Scene")); sceneChangeStartTime = OSGetTime(); } XElement *sceneData = newSceneElement->GetElement(TEXT("data")); //------------------------- Scene *newScene = NULL; if(bRunning) newScene = CreateScene(lpClass, sceneData); //------------------------- HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)FALSE, (LPARAM) 0); bChangingSources = true; ListView_DeleteAllItems(hwndSources); XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); ListView_SetItemCount(hwndSources, numSources); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); bool render = sourceElement->GetInt(TEXT("render"), 1) > 0; InsertSourceItem(i, (LPWSTR)sourceElement->GetName(), render); if(bRunning && newScene) newScene->AddImageSource(sourceElement); } } bChangingSources = false; SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)TRUE, (LPARAM) 0); RedrawWindow(hwndSources, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); if(scene && newScene && newScene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); if(bRunning) { //todo: cache scenes maybe? undecided. not really as necessary with global sources OSEnterMutex(hSceneMutex); UINT numSources; if (scene) { //shutdown previous scene, if any numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceLeaveScene(); } } } scene->EndScene(); } Scene *previousScene = scene; scene = newScene; scene->BeginScene(); numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceEnterScene(); } } } if(!bTransitioning) { bTransitioning = true; transitionAlpha = 0.0f; } OSLeaveMutex(hSceneMutex); delete previousScene; DWORD sceneChangeTime = OSGetTime() - sceneChangeStartTime; if (sceneChangeTime >= 500) Log(TEXT("PERFORMANCE WARNING: Scene change took %u ms, maybe some sources should be global sources?"), sceneChangeTime); } if(API != NULL) ReportSwitchScenes(lpScene); return true; }
INT_PTR SettingsPublish::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam) { HWND hwndTemp; switch(message) { case WM_INITDIALOG: { LocalizeWindow(hwnd); RECT serviceRect, saveToFileRect; GetWindowRect(GetDlgItem(hwnd, IDC_SERVICE), &serviceRect); GetWindowRect(GetDlgItem(hwnd, IDC_SAVEPATH), &saveToFileRect); data.fileControlOffset = saveToFileRect.top-serviceRect.top; //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_MODE); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)Str("Settings.Publish.Mode.LiveStream")); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)Str("Settings.Publish.Mode.FileOnly")); int mode = LoadSettingComboInt(hwndTemp, TEXT("Publish"), TEXT("Mode"), 0, 2); data.mode = mode; //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_SERVICE); int itemId = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("Custom")); SendMessage(hwndTemp, CB_SETITEMDATA, itemId, 0); UINT numServices = 0; XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *service = services->GetElementByID(i); itemId = (int)SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)service->GetName()); SendMessage(hwndTemp, CB_SETITEMDATA, itemId, service->GetInt(TEXT("id"))); } } } int serviceID = AppConfig->GetInt(TEXT("Publish"), TEXT("Service"), 0); if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_PLAYPATH); LoadSettingEditString(hwndTemp, TEXT("Publish"), TEXT("PlayPath"), NULL); if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); if(serviceID == 0) //custom { ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), SW_HIDE); hwndTemp = GetDlgItem(hwnd, IDC_URL); LoadSettingEditString(hwndTemp, TEXT("Publish"), TEXT("URL"), NULL); SendDlgItemMessage(hwnd, IDC_SERVICE, CB_SETCURSEL, 0, 0); } else { ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_HIDE); hwndTemp = GetDlgItem(hwnd, IDC_SERVERLIST); XElement *services = serverData.GetElement(TEXT("services")); if(services) { XElement *service = NULL; numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *curService = services->GetElementByID(i); if(curService->GetInt(TEXT("id")) == serviceID) { SendDlgItemMessage(hwnd, IDC_SERVICE, CB_SETCURSEL, i+1, 0); service = curService; break; } } if(service) { XElement *servers = service->GetElement(TEXT("servers")); if(servers) { UINT numServers = servers->NumDataItems(); for(UINT i=0; i<numServers; i++) { XDataItem *server = servers->GetDataItemByID(i); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName()); } } } } LoadSettingComboString(hwndTemp, TEXT("Publish"), TEXT("URL"), NULL); } if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_LOWLATENCYMODE); BOOL bLowLatencyMode = AppConfig->GetInt(TEXT("Publish"), TEXT("LowLatencyMode"), 0); SendMessage(hwndTemp, BM_SETCHECK, bLowLatencyMode ? BST_CHECKED : BST_UNCHECKED, 0); //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_AUTORECONNECT); BOOL bAutoReconnect = AppConfig->GetInt(TEXT("Publish"), TEXT("AutoReconnect"), 1); SendMessage(hwndTemp, BM_SETCHECK, bAutoReconnect ? BST_CHECKED : BST_UNCHECKED, 0); if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); hwndTemp = GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT); EnableWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_EDIT), bAutoReconnect); EnableWindow(hwndTemp, bAutoReconnect); int retryTime = AppConfig->GetInt(TEXT("Publish"), TEXT("AutoReconnectTimeout"), 10); if(retryTime > 60) retryTime = 60; else if(retryTime < 0) retryTime = 0; SendMessage(hwndTemp, UDM_SETRANGE32, 0, 60); SendMessage(hwndTemp, UDM_SETPOS32, 0, retryTime); if(mode != 0) ShowWindow(hwndTemp, SW_HIDE); //-------------------------------------------- hwndTemp = GetDlgItem(hwnd, IDC_DELAY); int delayTime = AppConfig->GetInt(TEXT("Publish"), TEXT("Delay"), 0); SendMessage(hwndTemp, UDM_SETRANGE32, 0, 900); SendMessage(hwndTemp, UDM_SETPOS32, 0, delayTime); //-------------------------------------------- if(mode != 0) { ShowWindow(GetDlgItem(hwnd, IDC_SERVICE_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_PLAYPATH_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_URL_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_SERVER_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_LOWLATENCYMODE), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_EDIT), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_DELAY_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_DELAY_EDIT), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_DELAY), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_KEEPRECORDING), SW_HIDE); //ShowWindow(GetDlgItem(hwnd, IDC_DASHBOARDLINK), SW_HIDE); //ShowWindow(GetDlgItem(hwnd, IDC_DASHBOARDLINK_STATIC), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_SAVETOFILE), SW_HIDE); AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_BROWSE), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTSTREAM), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTRECORDING), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STOPRECORDING), 0, -data.fileControlOffset); } //-------------------------------------------- DWORD startHotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StartStreamHotkey")); SendMessage(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), HKM_SETHOTKEY, startHotkey, 0); //-------------------------------------------- DWORD stopHotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StopStreamHotkey")); SendMessage(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), HKM_SETHOTKEY, stopHotkey, 0); //-------------------------------------------- startHotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StartRecordingHotkey")); SendMessage(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), HKM_SETHOTKEY, startHotkey, 0); //-------------------------------------------- stopHotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StopRecordingHotkey")); SendMessage(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), HKM_SETHOTKEY, stopHotkey, 0); //-------------------------------------------- BOOL bKeepRecording = AppConfig->GetInt(TEXT("Publish"), TEXT("KeepRecording")); SendMessage(GetDlgItem(hwnd, IDC_KEEPRECORDING), BM_SETCHECK, bKeepRecording ? BST_CHECKED : BST_UNCHECKED, 0); BOOL bSaveToFile = AppConfig->GetInt(TEXT("Publish"), TEXT("SaveToFile")); SendMessage(GetDlgItem(hwnd, IDC_SAVETOFILE), BM_SETCHECK, bSaveToFile ? BST_CHECKED : BST_UNCHECKED, 0); String path = OSGetDefaultVideoSavePath(L"\\.flv"); CTSTR lpSavePath = AppConfig->GetStringPtr(TEXT("Publish"), TEXT("SavePath"), path.IsValid() ? path.Array() : nullptr); SetWindowText(GetDlgItem(hwnd, IDC_SAVEPATH), lpSavePath); EnableWindow(GetDlgItem(hwnd, IDC_KEEPRECORDING), true); EnableWindow(GetDlgItem(hwnd, IDC_SAVEPATH), true); EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), true); //-------------------------------------------- //SetWindowText(GetDlgItem(hwnd, IDC_DASHBOARDLINK), App->strDashboard); //-------------------------------------------- SetWarningInfo(); ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_HIDE); SetChangedSettings(false); return TRUE; } case WM_CTLCOLORSTATIC: { switch (GetDlgCtrlID((HWND)lParam)) { case IDC_WARNINGS: SetTextColor((HDC)wParam, RGB(255, 0, 0)); SetBkColor((HDC)wParam, COLORREF(GetSysColor(COLOR_3DFACE))); return (INT_PTR)GetSysColorBrush(COLOR_BTNFACE); } } break; case WM_DESTROY: { } break; case WM_NOTIFY: { NMHDR *nmHdr = (NMHDR*)lParam; if(nmHdr->idFrom == IDC_AUTORECONNECT_TIMEOUT) { if(nmHdr->code == UDN_DELTAPOS) SetChangedSettings(true); } break; } case WM_COMMAND: { bool bDataChanged = false; switch(LOWORD(wParam)) { case IDC_MODE: { if(HIWORD(wParam) != CBN_SELCHANGE) break; int mode = (int)SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0); int swShowControls = (mode == 0) ? SW_SHOW : SW_HIDE; ShowWindow(GetDlgItem(hwnd, IDC_SERVICE), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_PLAYPATH), swShowControls); int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0); if(serviceID == 0) { ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_URL), swShowControls); } else { ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_HIDE); } if(mode == 0 && data.mode == 1) { AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_BROWSE), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTSTREAM), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY_STATIC), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTRECORDING), 0, data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STOPRECORDING), 0, data.fileControlOffset); } else if(mode == 1 && data.mode == 0) { AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_SAVEPATH), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_BROWSE), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTSTREAM), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY_STATIC), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STARTRECORDING), 0, -data.fileControlOffset); AdjustWindowPos(GetDlgItem(hwnd, IDC_CLEARHOTKEY_STOPRECORDING), 0, -data.fileControlOffset); } data.mode = mode; ShowWindow(GetDlgItem(hwnd, IDC_SERVICE_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_PLAYPATH_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_URL_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_SERVER_STATIC), swShowControls); //ShowWindow(GetDlgItem(hwnd, IDC_DASHBOARDLINK), swShowControls); //ShowWindow(GetDlgItem(hwnd, IDC_DASHBOARDLINK_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_LOWLATENCYMODE), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_EDIT), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_DELAY_STATIC), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_DELAY_EDIT), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_DELAY), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_SAVETOFILE), swShowControls); ShowWindow(GetDlgItem(hwnd, IDC_KEEPRECORDING), swShowControls); SetWarningInfo(); bDataChanged = true; break; } case IDC_SERVICE: if(HIWORD(wParam) == CBN_SELCHANGE) { int serviceID = (int)SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0); if(serviceID == 0) { ShowWindow(GetDlgItem(hwnd, IDC_SERVERLIST), SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_SHOW); SetWindowText(GetDlgItem(hwnd, IDC_URL), NULL); //SetWindowText(GetDlgItem(hwnd, IDC_DASHBOARDLINK), NULL); } else { ShowWindow(GetDlgItem(hwnd, IDC_URL), SW_HIDE); hwndTemp = GetDlgItem(hwnd, IDC_SERVERLIST); ShowWindow(hwndTemp, SW_SHOW); SendMessage(hwndTemp, CB_RESETCONTENT, 0, 0); XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { XElement *service = services->GetElementByID(serviceID-1); if(service) { XElement *servers = service->GetElement(TEXT("servers")); if(servers) { UINT numServers = servers->NumDataItems(); for(UINT i=0; i<numServers; i++) { XDataItem *server = servers->GetDataItemByID(i); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)server->GetName()); } } } } } SendMessage(hwndTemp, CB_SETCURSEL, 0, 0); } SetWindowText(GetDlgItem(hwnd, IDC_PLAYPATH), NULL); bDataChanged = true; } SetWarningInfo(); break; case IDC_AUTORECONNECT: if(HIWORD(wParam) == BN_CLICKED) { BOOL bAutoReconnect = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED; EnableWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT), bAutoReconnect); EnableWindow(GetDlgItem(hwnd, IDC_AUTORECONNECT_TIMEOUT_EDIT), bAutoReconnect); SetChangedSettings(true); } break; case IDC_AUTORECONNECT_TIMEOUT_EDIT: if(HIWORD(wParam) == EN_CHANGE) SetChangedSettings(true); break; case IDC_DELAY_EDIT: if(HIWORD(wParam) == EN_CHANGE) bDataChanged = true; break; case IDC_KEEPRECORDING: if(HIWORD(wParam) == BN_CLICKED) { BOOL bKeepRecording = SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED; App->bKeepRecording = bKeepRecording != 0; bDataChanged = true; } break; case IDC_BROWSE: { TCHAR lpFile[512]; OPENFILENAME ofn; zero(&ofn, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.lpstrFile = lpFile; ofn.nMaxFile = 511; ofn.lpstrFile[0] = 0; ofn.lpstrFilter = TEXT("MP4 File (*.mp4)\0*.mp4\0Flash Video File (*.flv)\0*.flv\0"); ofn.lpstrFileTitle = NULL; ofn.nMaxFileTitle = 0; ofn.nFilterIndex = 1; String path = OSGetDefaultVideoSavePath(); ofn.lpstrInitialDir = AppConfig->GetStringPtr(TEXT("Publish"), TEXT("LastSaveDir"), path.IsValid() ? path.Array() : nullptr); ofn.Flags = OFN_PATHMUSTEXIST; TCHAR curDirectory[512]; GetCurrentDirectory(511, curDirectory); BOOL bChoseFile = GetSaveFileName(&ofn); SetCurrentDirectory(curDirectory); if(*lpFile && bChoseFile) { String strFile = lpFile; strFile.FindReplace(TEXT("\\"), TEXT("/")); String strExtension = GetPathExtension(strFile); if(strExtension.IsEmpty() || (!strExtension.CompareI(TEXT("flv")) && /*!strExtension.CompareI(TEXT("avi")) &&*/ !strExtension.CompareI(TEXT("mp4")))) { switch(ofn.nFilterIndex) { case 1: strFile << TEXT(".mp4"); break; case 2: strFile << TEXT(".flv"); break; /*case 3: strFile << TEXT(".avi"); break;*/ } } String strFilePath = GetPathDirectory(strFile).FindReplace(TEXT("/"), TEXT("\\")) << TEXT("\\"); AppConfig->SetString(TEXT("Publish"), TEXT("LastSaveDir"), strFilePath); strFile.FindReplace(TEXT("/"), TEXT("\\")); SetWindowText(GetDlgItem(hwnd, IDC_SAVEPATH), strFile); bDataChanged = true; } break; } case IDC_LOWLATENCYMODE: case IDC_SAVETOFILE: if(HIWORD(wParam) == BN_CLICKED) bDataChanged = true; break; case IDC_STARTSTREAMHOTKEY: case IDC_STOPSTREAMHOTKEY: //case IDC_DASHBOARDLINK: case IDC_STARTRECORDINGHOTKEY: case IDC_STOPRECORDINGHOTKEY: if(HIWORD(wParam) == EN_CHANGE) SetChangedSettings(true); break; case IDC_PLAYPATH: case IDC_URL: case IDC_SAVEPATH: if(HIWORD(wParam) == EN_CHANGE) bDataChanged = true; break; case IDC_CLEARHOTKEY_STARTSTREAM: if(HIWORD(wParam) == BN_CLICKED) { if(SendMessage(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), HKM_GETHOTKEY, 0, 0)) { SendMessage(GetDlgItem(hwnd, IDC_STARTSTREAMHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(true); } } break; case IDC_CLEARHOTKEY: if(HIWORD(wParam) == BN_CLICKED) { if(SendMessage(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), HKM_GETHOTKEY, 0, 0)) { SendMessage(GetDlgItem(hwnd, IDC_STOPSTREAMHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(true); } } break; case IDC_CLEARHOTKEY_STARTRECORDING: if (HIWORD(wParam) == BN_CLICKED) { if (SendMessage(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), HKM_GETHOTKEY, 0, 0)) { SendMessage(GetDlgItem(hwnd, IDC_STARTRECORDINGHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(true); } } break; case IDC_CLEARHOTKEY_STOPRECORDING: if (HIWORD(wParam) == BN_CLICKED) { if (SendMessage(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), HKM_GETHOTKEY, 0, 0)) { SendMessage(GetDlgItem(hwnd, IDC_STOPRECORDINGHOTKEY), HKM_SETHOTKEY, 0, 0); SetChangedSettings(true); } } break; case IDC_SERVERLIST: if(HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam) == CBN_SELCHANGE) bDataChanged = true; break; } if(bDataChanged) { ShowWindow(GetDlgItem(hwnd, IDC_INFO), SW_SHOW); SetChangedSettings(true); } break; } } return FALSE; }
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 OBS::SetScene(CTSTR lpScene) { if(bDisableSceneSwitching) return false; HWND hwndScenes = GetDlgItem(hwndMain, ID_SCENES); UINT curSel = (UINT)SendMessage(hwndScenes, LB_GETCURSEL, 0, 0); //------------------------- if(curSel != LB_ERR) { UINT textLen = (UINT)SendMessage(hwndScenes, LB_GETTEXTLEN, curSel, 0); String strLBName; strLBName.SetLength(textLen); SendMessage(hwndScenes, LB_GETTEXT, curSel, (LPARAM)strLBName.Array()); if(!strLBName.CompareI(lpScene)) { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } } else { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } //------------------------- XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *newSceneElement = scenes->GetElement(lpScene); if(!newSceneElement) return false; if(sceneElement == newSceneElement) return true; sceneElement = newSceneElement; CTSTR lpClass = sceneElement->GetString(TEXT("class")); if(!lpClass) { AppWarning(TEXT("OBS::SetScene: no class found for scene '%s'"), newSceneElement->GetName()); return false; } if(bRunning) { Log(TEXT("++++++++++++++++++++++++++++++++++++++++++++++++++++++")); Log(TEXT(" New Scene")); } XElement *sceneData = newSceneElement->GetElement(TEXT("data")); //------------------------- Scene *newScene = NULL; if(bRunning) newScene = CreateScene(lpClass, sceneData); //------------------------- HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)FALSE, (LPARAM) 0); bChangingSources = true; ListView_DeleteAllItems(hwndSources); XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); ListView_SetItemCount(hwndSources, numSources); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); bool render = sourceElement->GetInt(TEXT("render"), 1) > 0; AddSourceItem((LPWSTR)sourceElement->GetName(), render, i); if(bRunning && newScene) newScene->AddImageSource(sourceElement); } } bChangingSources = false; SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)TRUE, (LPARAM) 0); RedrawWindow(hwndSources, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); if(scene && newScene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); if(bRunning) { //todo: cache scenes maybe? undecided. not really as necessary with global sources OSEnterMutex(hSceneMutex); if(scene) scene->EndScene(); Scene *previousScene = scene; scene = newScene; scene->BeginScene(); if(!bTransitioning) { bTransitioning = true; transitionAlpha = 0.0f; } OSLeaveMutex(hSceneMutex); delete previousScene; } return true; }
void SettingsPublish::SetWarningInfo() { int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0); bool bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR"), 1) != 0; int maxBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int keyframeInt = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("KeyframeInterval"), 0); int audioBitRate = AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96); String currentx264Profile = AppConfig->GetString(TEXT("Video Encoding"), TEXT("X264Profile"), L"high"); String currentAudioCodec = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC")); float currentAspect = AppConfig->GetInt(L"Video", L"BaseWidth") / (float)max(1, AppConfig->GetInt(L"Video", L"BaseHeight")); //ignore for non-livestreams if (data.mode != 0) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } bool hasErrors = false; bool canOptimize = false; String strWarnings; XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { UINT numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *service = services->GetElementByID(i); if (service->GetInt(TEXT("id")) == serviceID) { strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName()); //check to see if the service we're using has recommendations if (!service->HasItem(TEXT("recommended"))) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } XElement *r = service->GetElement(TEXT("recommended")); if (r->HasItem(TEXT("ratecontrol"))) { CTSTR rc = r->GetString(TEXT("ratecontrol")); if (!scmp (rc, TEXT("cbr")) && !bUseCBR) { hasErrors = true; canOptimize = true; strWarnings << Str("Settings.Publish.Warning.UseCBR"); } } if (r->HasItem(TEXT("max bitrate"))) { int max_bitrate = r->GetInt(TEXT("max bitrate")); if (maxBitRate > max_bitrate) { hasErrors = true; canOptimize = true; strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate); } } if (r->HasItem(L"supported audio codec")) { StringList codecs; r->GetStringList(L"supported audio codec", codecs); if (codecs.FindValueIndex(currentAudioCodec) == INVALID) { String msg = Str("Settings.Publish.Warning.UnsupportedAudioCodec"); //good thing OBS only supports MP3 (and AAC), otherwise I'd have to come up with a better translation solution msg.FindReplace(L"$1", codecs[0].Array()); msg.FindReplace(L"$2", currentAudioCodec.Array()); hasErrors = true; canOptimize = true; strWarnings << msg; } } if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC")))) { int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac")); if (audioBitRate > maxaudioaac) { hasErrors = true; canOptimize = true; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac); } } if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3")))) { int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3")); if (audioBitRate > maxaudiomp3) { hasErrors = true; canOptimize = true; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3); } } if (r->HasItem(L"video aspect ratio")) { String aspectRatio = r->GetString(L"video aspect ratio"); StringList numbers; aspectRatio.GetTokenList(numbers, ':'); if (numbers.Num() == 2) { float aspect = numbers[0].ToInt() / max(1.f, numbers[1].ToFloat()); if (!CloseFloat(aspect, currentAspect)) { String aspectLocalized = Str("Settings.Video.AspectRatioFormat"); aspectLocalized.FindReplace(L"$1", UIntString(numbers[0].ToInt())); aspectLocalized.FindReplace(L"$2", UIntString(numbers[1].ToInt())); String msg = Str("Settings.Publish.Warning.VideoAspectRatio"); msg.FindReplace(L"$1", aspectLocalized); strWarnings << msg; hasErrors = true; } } } if (r->HasItem(TEXT("profile"))) { String expectedProfile = r->GetString(TEXT("profile")); if (!expectedProfile.CompareI(currentx264Profile)) { hasErrors = true; canOptimize = true; strWarnings << Str("Settings.Publish.Warning.RecommendMainProfile"); } } if (r->HasItem(TEXT("keyint"))) { int keyint = r->GetInt(TEXT("keyint")); if (!keyframeInt || keyframeInt * 1000 > keyint) { hasErrors = true; canOptimize = true; strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000); } } break; } } } } if (hasErrors) { if (canOptimize) strWarnings << Str("Settings.Publish.Warning.CanOptimize"); SetDlgItemText(hwnd, IDC_WARNINGS, strWarnings.Array()); } else SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); SetCanOptimizeSettings(canOptimize); }
void SettingsPublish::SetWarningInfo() { int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0); bool bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR"), 1) != 0; int maxBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int keyframeInt = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("KeyframeInterval"), 0); int audioBitRate = AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96); String currentx264Profile = AppConfig->GetString(TEXT("Video Encoding"), TEXT("X264Profile"), L"high"); String currentAudioCodec = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC")); //ignore for non-livestreams if (data->mode != 0) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } int errors = 0; String strWarnings; XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { UINT numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *service = services->GetElementByID(i); if (service->GetInt(TEXT("id")) == serviceID) { strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName()); //check to see if the service we're using has recommendations if (!service->HasItem(TEXT("recommended"))) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } XElement *r = service->GetElement(TEXT("recommended")); if (r->HasItem(TEXT("ratecontrol"))) { CTSTR rc = r->GetString(TEXT("ratecontrol")); if (!scmp (rc, TEXT("cbr")) && !bUseCBR) { errors++; strWarnings << Str("Settings.Publish.Warning.UseCBR"); } } if (r->HasItem(TEXT("max bitrate"))) { int max_bitrate = r->GetInt(TEXT("max bitrate")); if (maxBitRate > max_bitrate) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate); } } if (r->HasItem(TEXT("profile"))) { String expectedProfile = r->GetString(TEXT("profile")); if (!expectedProfile.CompareI(currentx264Profile)) { errors++; strWarnings << Str("Settings.Publish.Warning.RecommendMainProfile"); } } if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC")))) { int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac")); if (audioBitRate > maxaudioaac) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac); } } if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3")))) { int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3")); if (audioBitRate > maxaudiomp3) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3); } } if (r->HasItem(TEXT("keyint"))) { int keyint = r->GetInt(TEXT("keyint")); if (!keyframeInt || keyframeInt * 1000 > keyint) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000); } } if (r->HasItem(L"supported audio codec")) { StringList codecs; r->GetStringList(L"supported audio codec", codecs); if (codecs.FindValueIndex(currentAudioCodec) == INVALID) { String msg = Str("Settings.Publish.Warning.UnsupportedAudioCodec"); //good thing OBS only supports MP3 (and AAC), otherwise I'd have to come up with a better translation solution msg.FindReplace(L"$1", codecs[0].Array()); msg.FindReplace(L"$2", currentAudioCodec.Array()); errors += 1; strWarnings << msg; } } break; } } } } if (errors) SetDlgItemText(hwnd, IDC_WARNINGS, strWarnings.Array()); else SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); }
bool OBS::SetScene(CTSTR lpScene) { if(bDisableSceneSwitching) return false; HWND hwndScenes = GetDlgItem(hwndMain, ID_SCENES); UINT curSel = (UINT)SendMessage(hwndScenes, LB_GETCURSEL, 0, 0); //------------------------- if(curSel != LB_ERR) { UINT textLen = (UINT)SendMessage(hwndScenes, LB_GETTEXTLEN, curSel, 0); String strLBName; strLBName.SetLength(textLen); SendMessage(hwndScenes, LB_GETTEXT, curSel, (LPARAM)strLBName.Array()); if(!strLBName.CompareI(lpScene)) { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } } else { UINT id = (UINT)SendMessage(hwndScenes, LB_FINDSTRINGEXACT, -1, (LPARAM)lpScene); if(id == LB_ERR) return false; SendMessage(hwndScenes, LB_SETCURSEL, id, 0); } //------------------------- XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); XElement *newSceneElement = scenes->GetElement(lpScene); if(!newSceneElement) return false; if(sceneElement == newSceneElement) return true; sceneElement = newSceneElement; CTSTR lpClass = sceneElement->GetString(TEXT("class")); if(!lpClass) { AppWarning(TEXT("OBS::SetScene: no class found for scene '%s'"), newSceneElement->GetName()); return false; } DWORD sceneChangeStartTime; if(bRunning) { Log(TEXT("++++++++++++++++++++++++++++++++++++++++++++++++++++++")); Log(TEXT(" New Scene")); sceneChangeStartTime = OSGetTime(); } XElement *sceneData = newSceneElement->GetElement(TEXT("data")); //------------------------- Scene *newScene = NULL; if(bRunning) newScene = CreateScene(lpClass, sceneData); //------------------------- HWND hwndSources = GetDlgItem(hwndMain, ID_SOURCES); SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)FALSE, (LPARAM) 0); App->scaleItem = NULL; bChangingSources = true; ListView_DeleteAllItems(hwndSources); bool bSkipTransition = false; XElement *sources = sceneElement->GetElement(TEXT("sources")); if(sources) { UINT numSources = sources->NumElements(); ListView_SetItemCount(hwndSources, numSources); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); String className = sourceElement->GetString(TEXT("class")); if(className == "DeviceCapture") { // There's a capture device in the next scene that isn't a global source, // so let's skip the transition since it won't work anyway. bSkipTransition = true; } } for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); bool render = sourceElement->GetInt(TEXT("render"), 1) > 0; InsertSourceItem(i, (LPWSTR)sourceElement->GetName(), render); // Do not add image sources yet in case we're skipping the transition. // This fixes the issue where capture devices sources that used the // same device as one in the previous scene would just go blank // after switching. if(bRunning && newScene && !bSkipTransition) newScene->AddImageSource(sourceElement); } } bChangingSources = false; SendMessage(hwndSources, WM_SETREDRAW, (WPARAM)TRUE, (LPARAM) 0); RedrawWindow(hwndSources, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); if(scene && newScene && newScene->HasMissingSources()) MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0); if(bRunning) { //todo: cache scenes maybe? undecided. not really as necessary with global sources OSEnterMutex(hSceneMutex); UINT numSources; if (scene) { //shutdown previous scene, if any numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceLeaveScene(); } } } scene->EndScene(); } Scene *previousScene = scene; scene = newScene; if(newScene && bSkipTransition) { // If we're skipping the transition because of a non-global // DirectShow device, delete the scene here and add the // ImageSources at this point instead. delete previousScene; if(sources) { UINT numSources = sources->NumElements(); for(UINT i=0; i<numSources; i++) { XElement *sourceElement = sources->GetElementByID(i); if(newScene) newScene->AddImageSource(sourceElement); } } } scene->BeginScene(); numSources = scene->sceneItems.Num(); for(UINT i=0; i<numSources; i++) { XElement *source = scene->sceneItems[i]->GetElement(); String className = source->GetString(TEXT("class")); if(scene->sceneItems[i]->bRender && className == "GlobalSource") { XElement *globalSourceData = source->GetElement(TEXT("data")); String globalSourceName = globalSourceData->GetString(TEXT("name")); if(App->GetGlobalSource(globalSourceName) != NULL) { App->GetGlobalSource(globalSourceName)->GlobalSourceEnterScene(); } } } if(!bTransitioning && !bSkipTransition) { bTransitioning = true; transitionAlpha = 0.0f; } OSLeaveMutex(hSceneMutex); if(!bSkipTransition) { // Do not delete the previous scene here, since it has already // been deleted. delete previousScene; } DWORD sceneChangeTime = OSGetTime() - sceneChangeStartTime; if (sceneChangeTime >= 500) Log(TEXT("PERFORMANCE WARNING: Scene change took %u ms, maybe some sources should be global sources?"), sceneChangeTime); } if(API != NULL) ReportSwitchScenes(lpScene); return true; }
void SettingsPublish::SetWarningInfo() { int serviceID = (int)SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETITEMDATA, SendMessage(GetDlgItem(hwnd, IDC_SERVICE), CB_GETCURSEL, 0, 0), 0); bool bUseCBR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCBR"), 1) != 0; int maxBitRate = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000); int keyframeInt = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("KeyframeInterval"), 0); int audioBitRate = AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96); String currentAudioCodec = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC")); //ignore for non-livestreams if (data->mode != 0) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } int errors = 0; String strWarnings; XConfig serverData; if(serverData.Open(TEXT("services.xconfig"))) { XElement *services = serverData.GetElement(TEXT("services")); if(services) { UINT numServices = services->NumElements(); for(UINT i=0; i<numServices; i++) { XElement *service = services->GetElementByID(i); if (service->GetInt(TEXT("id")) == serviceID) { strWarnings = FormattedString(Str("Settings.Publish.Warning.BadSettings"), service->GetName()); //check to see if the service we're using has recommendations if (!service->HasItem(TEXT("recommended"))) { SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); return; } XElement *r = service->GetElement(TEXT("recommended")); if (r->HasItem(TEXT("ratecontrol"))) { CTSTR rc = r->GetString(TEXT("ratecontrol")); if (!scmp (rc, TEXT("cbr")) && !bUseCBR) { errors++; strWarnings << Str("Settings.Publish.Warning.UseCBR"); } } if (r->HasItem(TEXT("max bitrate"))) { int max_bitrate = r->GetInt(TEXT("max bitrate")); if (maxBitRate > max_bitrate) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.Maxbitrate"), max_bitrate); } } if (r->HasItem(TEXT("max audio bitrate aac")) && (!scmp(currentAudioCodec, TEXT("AAC")))) { int maxaudioaac = r->GetInt(TEXT("max audio bitrate aac")); if (audioBitRate > maxaudioaac) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudioaac); } } if (r->HasItem(TEXT("max audio bitrate mp3")) && (!scmp(currentAudioCodec, TEXT("MP3")))) { int maxaudiomp3 = r->GetInt(TEXT("max audio bitrate mp3")); if (audioBitRate > maxaudiomp3) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.MaxAudiobitrate"), maxaudiomp3); } } if (r->HasItem(TEXT("keyint"))) { int keyint = r->GetInt(TEXT("keyint")); if (!keyframeInt || keyframeInt * 1000 > keyint) { errors++; strWarnings << FormattedString(Str("Settings.Publish.Warning.Keyint"), keyint / 1000); } } break; } } } } if (errors) SetDlgItemText(hwnd, IDC_WARNINGS, strWarnings.Array()); else SetDlgItemText(hwnd, IDC_WARNINGS, TEXT("")); }
OBS::OBS() { App = this; __cpuid(cpuInfo, 1); bSSE2Available = (cpuInfo[3] & (1<<26)) != 0; hSceneMutex = OSCreateMutex(); hAuxAudioMutex = OSCreateMutex(); monitors.Clear(); EnumDisplayMonitors(NULL, NULL, (MONITORENUMPROC)MonitorInfoEnumProc, (LPARAM)&monitors); INITCOMMONCONTROLSEX ecce; ecce.dwSize = sizeof(ecce); ecce.dwICC = ICC_STANDARD_CLASSES; if(!InitCommonControlsEx(&ecce)) CrashError(TEXT("Could not initalize common shell controls")); InitHotkeyExControl(hinstMain); InitColorControl(hinstMain); InitVolumeControl(); InitVolumeMeter(); //----------------------------------------------------- // load locale if(!locale->LoadStringFile(TEXT("locale/en.txt"))) AppWarning(TEXT("Could not open locale string file '%s'"), TEXT("locale/en.txt")); strLanguage = GlobalConfig->GetString(TEXT("General"), TEXT("Language"), TEXT("en")); if(!strLanguage.CompareI(TEXT("en"))) { String langFile; langFile << TEXT("locale/") << strLanguage << TEXT(".txt"); if(!locale->LoadStringFile(langFile)) AppWarning(TEXT("Could not open locale string file '%s'"), langFile.Array()); } //----------------------------------------------------- // load classes RegisterSceneClass(TEXT("Scene"), Str("Scene"), (OBSCREATEPROC)CreateNormalScene, NULL); RegisterImageSourceClass(TEXT("DesktopImageSource"), Str("Sources.SoftwareCaptureSource"), (OBSCREATEPROC)CreateDesktopSource, (OBSCONFIGPROC)ConfigureDesktopSource); RegisterImageSourceClass(TEXT("BitmapImageSource"), Str("Sources.BitmapSource"), (OBSCREATEPROC)CreateBitmapSource, (OBSCONFIGPROC)ConfigureBitmapSource); RegisterImageSourceClass(TEXT("BitmapTransitionSource"), Str("Sources.TransitionSource"), (OBSCREATEPROC)CreateBitmapTransitionSource, (OBSCONFIGPROC)ConfigureBitmapTransitionSource); RegisterImageSourceClass(TEXT("GlobalSource"), Str("Sources.GlobalSource"), (OBSCREATEPROC)CreateGlobalSource, (OBSCONFIGPROC)OBS::ConfigGlobalSource); RegisterImageSourceClass(TEXT("TextSource"), Str("Sources.TextSource"), (OBSCREATEPROC)CreateTextSource, (OBSCONFIGPROC)ConfigureTextSource); //----------------------------------------------------- // render frame class WNDCLASS wc; zero(&wc, sizeof(wc)); wc.hInstance = hinstMain; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.lpszClassName = OBS_RENDERFRAME_CLASS; wc.lpfnWndProc = (WNDPROC)OBS::RenderFrameProc; wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); if(!RegisterClass(&wc)) CrashError(TEXT("Could not register render frame class")); //----------------------------------------------------- // main window class wc.lpszClassName = OBS_WINDOW_CLASS; wc.lpfnWndProc = (WNDPROC)OBSProc; wc.hIcon = LoadIcon(hinstMain, MAKEINTRESOURCE(IDI_ICON1)); wc.hbrBackground = (HBRUSH)COLOR_WINDOW; wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU); if(!RegisterClass(&wc)) CrashError(TEXT("Could not register main window class")); //----------------------------------------------------- // create main window int fullscreenX = GetSystemMetrics(SM_CXFULLSCREEN); int fullscreenY = GetSystemMetrics(SM_CYFULLSCREEN); borderXSize = borderYSize = 0; borderXSize += GetSystemMetrics(SM_CXSIZEFRAME)*2; borderYSize += GetSystemMetrics(SM_CYSIZEFRAME)*2; borderYSize += GetSystemMetrics(SM_CYMENU); borderYSize += GetSystemMetrics(SM_CYCAPTION); clientWidth = GlobalConfig->GetInt(TEXT("General"), TEXT("Width"), 700); clientHeight = GlobalConfig->GetInt(TEXT("General"), TEXT("Height"), 553); if(clientWidth < minClientWidth) clientWidth = minClientWidth; if(clientHeight < minClientHeight) clientHeight = minClientHeight; int maxCX = fullscreenX-borderXSize; int maxCY = fullscreenY-borderYSize; if(clientWidth > maxCX) clientWidth = maxCX; if(clientHeight > maxCY) clientHeight = maxCY; int cx = clientWidth + borderXSize; int cy = clientHeight + borderYSize; int x = (fullscreenX/2)-(cx/2); int y = (fullscreenY/2)-(cy/2); int posX = GlobalConfig->GetInt(TEXT("General"), TEXT("PosX")); int posY = GlobalConfig->GetInt(TEXT("General"), TEXT("PosY")); bool bInsideMonitors = false; if(posX || posY) { for(UINT i=0; i<monitors.Num(); i++) { if( posX >= monitors[i].rect.left && posX < monitors[i].rect.right && posY >= monitors[i].rect.top && posY < monitors[i].rect.bottom ) { bInsideMonitors = true; break; } } } if(bInsideMonitors) { x = posX; y = posY; } hwndMain = CreateWindowEx(WS_EX_CONTROLPARENT|WS_EX_WINDOWEDGE, OBS_WINDOW_CLASS, OBS_VERSION_STRING, WS_OVERLAPPED | WS_THICKFRAME | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU | WS_CLIPCHILDREN, x, y, cx, cy, NULL, NULL, hinstMain, NULL); if(!hwndMain) CrashError(TEXT("Could not create main window")); HMENU hMenu = GetMenu(hwndMain); LocalizeMenu(hMenu); //----------------------------------------------------- // render frame hwndRenderFrame = CreateWindow(OBS_RENDERFRAME_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE, 0, 0, 0, 0, hwndMain, NULL, hinstMain, NULL); if(!hwndRenderFrame) CrashError(TEXT("Could not create render frame")); //----------------------------------------------------- // scenes listbox HWND hwndTemp; hwndTemp = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("LISTBOX"), NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|LBS_HASSTRINGS|WS_VSCROLL|LBS_NOTIFY|LBS_NOINTEGRALHEIGHT|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SCENES, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); listboxProc = (WNDPROC)GetWindowLongPtr(hwndTemp, GWLP_WNDPROC); SetWindowLongPtr(hwndTemp, GWLP_WNDPROC, (LONG_PTR)OBS::ListboxHook); //----------------------------------------------------- // elements listview hwndTemp = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|WS_VSCROLL|WS_CLIPSIBLINGS|LVS_REPORT|LVS_NOCOLUMNHEADER| LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOLABELWRAP, 0, 0, 0, 0, hwndMain, (HMENU)ID_SOURCES, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); ListView_SetExtendedListViewStyle(hwndTemp, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER); //add single column needed for report style LVCOLUMN column; column.mask = LVCF_TEXT; column.fmt = LVCFMT_FIXED_WIDTH; column.cx = 0; column.pszText = TEXT(""); ListView_InsertColumn(hwndTemp, 0, &column); ListView_InsertColumn(hwndTemp, 1, &column); listviewProc = (WNDPROC)GetWindowLongPtr(hwndTemp, GWLP_WNDPROC); SetWindowLongPtr(hwndTemp, GWLP_WNDPROC, (LONG_PTR)OBS::ListboxHook); HWND hwndSources = hwndTemp; //----------------------------------------------------- // status control hwndTemp = CreateWindowEx(0, STATUSCLASSNAME, NULL, WS_CHILD|WS_VISIBLE|SBARS_SIZEGRIP|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_STATUS, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // mic volume control hwndTemp = CreateWindow(VOLUME_CONTROL_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_MICVOLUME, 0, 0); SetVolumeControlIcons(hwndTemp, GetIcon(hinstMain, IDI_SOUND_MIC), GetIcon(hinstMain, IDI_SOUND_MIC_MUTED)); //----------------------------------------------------- // mic volume meter hwndTemp = CreateWindow(VOLUME_METER_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_MICVOLUMEMETER, 0, 0); //----------------------------------------------------- // desktop volume meter hwndTemp = CreateWindow(VOLUME_METER_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_DESKTOPVOLUMEMETER, 0, 0); //----------------------------------------------------- // desktop volume control hwndTemp = CreateWindow(VOLUME_CONTROL_CLASS, NULL, WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_DESKTOPVOLUME, 0, 0); SetVolumeControlIcons(hwndTemp, GetIcon(hinstMain, IDI_SOUND_DESKTOP), GetIcon(hinstMain, IDI_SOUND_DESKTOP_MUTED)); //----------------------------------------------------- // settings button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("Settings"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SETTINGS, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // start/stop stream button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.StartStream"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_STARTSTOP, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // edit scene button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.SceneEditor"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_AUTOCHECKBOX|BS_PUSHLIKE|WS_DISABLED|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SCENEEDITOR, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // global sources button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("GlobalSources"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_GLOBALSOURCES, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // test stream button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.TestStream"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_TESTSTREAM, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // plugins button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.Plugins"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_PLUGINS, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // dashboard button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.Dashboard"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_DASHBOARD, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // exit button hwndTemp = CreateWindow(TEXT("BUTTON"), Str("MainWindow.Exit"), WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP|BS_TEXT|BS_PUSHBUTTON|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_EXIT, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // scenes text hwndTemp = CreateWindow(TEXT("STATIC"), Str("MainWindow.Scenes"), WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SCENES_TEXT, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // scenes text hwndTemp = CreateWindow(TEXT("STATIC"), Str("MainWindow.Sources"), WS_CHILDWINDOW|WS_VISIBLE|WS_CLIPSIBLINGS, 0, 0, 0, 0, hwndMain, (HMENU)ID_SOURCES_TEXT, 0, 0); SendMessage(hwndTemp, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), TRUE); //----------------------------------------------------- // populate scenes hwndTemp = GetDlgItem(hwndMain, ID_SCENES); String strScenesConfig; strScenesConfig << lpAppDataPath << TEXT("\\scenes.xconfig"); if(!scenesConfig.Open(strScenesConfig)) CrashError(TEXT("Could not open '%s'"), strScenesConfig); XElement *scenes = scenesConfig.GetElement(TEXT("scenes")); if(!scenes) scenes = scenesConfig.CreateElement(TEXT("scenes")); UINT numScenes = scenes->NumElements(); if(!numScenes) { XElement *scene = scenes->CreateElement(Str("Scene")); scene->SetString(TEXT("class"), TEXT("Scene")); numScenes++; } for(UINT i=0; i<numScenes; i++) { XElement *scene = scenes->GetElementByID(i); scene->SetString(TEXT("class"), TEXT("Scene")); SendMessage(hwndTemp, LB_ADDSTRING, 0, (LPARAM)scene->GetName()); } //----------------------------------------------------- // populate sources if(numScenes) { String strScene = AppConfig->GetString(TEXT("General"), TEXT("CurrentScene")); int id = (int)SendMessage(hwndTemp, LB_FINDSTRINGEXACT, -1, 0); if(id == LB_ERR) id = 0; SendMessage(hwndTemp, LB_SETCURSEL, (WPARAM)id, 0); SendMessage(hwndMain, WM_COMMAND, MAKEWPARAM(ID_SCENES, LBN_SELCHANGE), (LPARAM)GetDlgItem(hwndMain, ID_SCENES)); } //----------------------------------------------------- hHotkeyMutex = OSCreateMutex(); hInfoMutex = OSCreateMutex(); hStartupShutdownMutex = OSCreateMutex(); //----------------------------------------------------- API = CreateOBSApiInterface(); ResizeWindow(false); ShowWindow(hwndMain, SW_SHOW); // make sure sources listview column widths are as expected after obs window is shown ListView_SetColumnWidth(hwndSources,0,LVSCW_AUTOSIZE_USEHEADER); ListView_SetColumnWidth(hwndSources,1,LVSCW_AUTOSIZE_USEHEADER); //----------------------------------------------------- for(UINT i=0; i<numScenes; i++) { XElement *scene = scenes->GetElementByID(i); DWORD hotkey = scene->GetInt(TEXT("hotkey")); if(hotkey) { SceneHotkeyInfo hotkeyInfo; hotkeyInfo.hotkey = hotkey; hotkeyInfo.scene = scene; hotkeyInfo.hotkeyID = API->CreateHotkey(hotkey, SceneHotkey, 0); if(hotkeyInfo.hotkeyID) sceneHotkeys << hotkeyInfo; } } //----------------------------------------------------- // load plugins OSFindData ofd; HANDLE hFind = OSFindFirstFile(TEXT("plugins/*.dll"), ofd); if(hFind) { do { if(!ofd.bDirectory) //why would someone give a directory a .dll extension in the first place? pranksters. { String strLocation; strLocation << TEXT("plugins/") << ofd.fileName; HMODULE hPlugin = LoadLibrary(strLocation); if(hPlugin) { LOADPLUGINPROC loadPlugin = (LOADPLUGINPROC)GetProcAddress(hPlugin, "LoadPlugin"); if(loadPlugin && loadPlugin()) { PluginInfo *pluginInfo = plugins.CreateNew(); pluginInfo->hModule = hPlugin; pluginInfo->strFile = ofd.fileName; GETPLUGINNAMEPROC getName = (GETPLUGINNAMEPROC)GetProcAddress(hPlugin, "GetPluginName"); CTSTR lpName; if(getName) lpName = getName(); else lpName = TEXT("<unknown>"); //FIXME: log this somewhere else, it comes before the OBS version info and looks weird. //Log(TEXT("Loaded plugin '%s', %s"), lpName, strLocation); } else { Log(TEXT("Failed to initialize plugin %s"), strLocation); FreeLibrary(hPlugin); } } else { Log(TEXT("Failed to load plugin %s, %d"), strLocation, GetLastError()); } } } while (OSFindNextFile(hFind, ofd)); OSFindClose(hFind); } //----------------------------------------------------- ReloadIniSettings(); ResetProfileMenu(); //----------------------------------------------------- bAutoReconnect = AppConfig->GetInt(TEXT("Publish"), TEXT("AutoReconnect"), 1) != 0; reconnectTimeout = AppConfig->GetInt(TEXT("Publish"), TEXT("AutoReconnectTimeout"), 10); if(reconnectTimeout < 5) reconnectTimeout = 5; hHotkeyThread = OSCreateThread((XTHREAD)HotkeyThread, NULL); #ifndef OBS_DISABLE_AUTOUPDATE ULARGE_INTEGER lastUpdateTime; ULARGE_INTEGER currentTime; FILETIME systemTime; lastUpdateTime.QuadPart = GlobalConfig->GetInt(TEXT("General"), TEXT("LastUpdateCheck"), 0); GetSystemTimeAsFileTime(&systemTime); currentTime.LowPart = systemTime.dwLowDateTime; currentTime.HighPart = systemTime.dwHighDateTime; //OBS doesn't support 64 bit ints in the config file, so we have to normalize it to a 32 bit int currentTime.QuadPart /= 10000000; currentTime.QuadPart -= 13000000000; if (currentTime.QuadPart - lastUpdateTime.QuadPart >= 3600) { GlobalConfig->SetInt(TEXT("General"), TEXT("LastUpdateCheck"), (int)currentTime.QuadPart); OSCloseThread(OSCreateThread((XTHREAD)CheckUpdateThread, NULL)); } #endif bRenderViewEnabled = true; if(GlobalConfig->GetInt(TEXT("General"), TEXT("ShowWebrootWarning"), TRUE) && IsWebrootLoaded()) MessageBox(hwndMain, TEXT("Webroot Secureanywhere appears to be active. This product will cause problems with OBS as the security features block OBS from accessing Windows GDI functions. It is highly recommended that you disable Secureanywhere and restart OBS.\r\n\r\nOf course you can always just ignore this message if you want, but it may prevent you from being able to stream certain things. Please do not report any bugs you may encounter if you leave Secureanywhere enabled."), TEXT("Just a slight issue you might want to be aware of"), MB_OK); }
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; }