Пример #1
0
AudioObjectID	CAHALAudioSystemObject::GetAudioDeviceAtIndex(UInt32 inIndex) const
{
	AudioObjectID theAnswer = kAudioObjectUnknown;
	UInt32 theNumberDevices = GetNumberAudioDevices();
	if((theNumberDevices > 0) && (inIndex < theNumberDevices))
	{
		CAAutoArrayDelete<AudioObjectID> theDeviceList(theNumberDevices);
		GetAudioDevices(theNumberDevices, theDeviceList);
		if((theNumberDevices > 0) && (inIndex < theNumberDevices))
		{
			theAnswer = theDeviceList[inIndex];
		}
	}
	return theAnswer;
}
Пример #2
0
void OBS::Stop()
{
    if(!bRunning) return;

    OSEnterMutex(hStartupShutdownMutex);

    //we only want the capture thread to stop first, so we can ensure all packets are flushed
    bShutdownEncodeThread = true;
    ShowWindow(hwndProjector, SW_HIDE);

    if(hEncodeThread)
    {
        OSTerminateThread(hEncodeThread, 30000);
        hEncodeThread = NULL;
    }

    bShutdownVideoThread = true;
    SetEvent(hVideoEvent);

    if(hVideoThread)
    {
        OSTerminateThread(hVideoThread, 30000);
        hVideoThread = NULL;
    }

    bRunning = false;

    ReportStopStreamTrigger();

    for(UINT i=0; i<globalSources.Num(); i++)
        globalSources[i].source->EndScene();

    if(scene)
        scene->EndScene();

    //-------------------------------------------------------------

    if(hSoundThread)
    {
        //ReleaseSemaphore(hRequestAudioEvent, 1, NULL);
        OSTerminateThread(hSoundThread, 20000);
    }

    //if(hRequestAudioEvent)
    //    CloseHandle(hRequestAudioEvent);
    if(hSoundDataMutex)
        OSCloseMutex(hSoundDataMutex);

    hSoundThread = NULL;
    //hRequestAudioEvent = NULL;
    hSoundDataMutex = NULL;

    //-------------------------------------------------------------

    StopBlankSoundPlayback();

    //-------------------------------------------------------------

    delete network;
    network = NULL;
    
    delete fileStream;
    fileStream = NULL;

    delete micAudio;
    micAudio = NULL;

    delete desktopAudio;
    desktopAudio = NULL;

    delete audioEncoder;
    audioEncoder = NULL;

    delete videoEncoder;
    videoEncoder = NULL;

    //-------------------------------------------------------------

    for(UINT i=0; i<pendingAudioFrames.Num(); i++)
        pendingAudioFrames[i].audioData.Clear();
    pendingAudioFrames.Clear();

    //-------------------------------------------------------------

    if(GS)
        GS->UnloadAllData();

    //-------------------------------------------------------------

    delete scene;
    scene = NULL;

    for(UINT i=0; i<globalSources.Num(); i++)
        globalSources[i].FreeData();
    globalSources.Clear();

    //-------------------------------------------------------------

    for(UINT i=0; i<auxAudioSources.Num(); i++)
        delete auxAudioSources[i];
    auxAudioSources.Clear();

    //-------------------------------------------------------------

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        delete mainRenderTextures[i];
        delete yuvRenderTextures[i];

        mainRenderTextures[i] = NULL;
        yuvRenderTextures[i] = NULL;
    }

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        SafeRelease(copyTextures[i]);
    }

    delete transitionTexture;
    transitionTexture = NULL;

    //-------------------------------------------------------------

    delete mainVertexShader;
    delete mainPixelShader;
    delete yuvScalePixelShader;

    delete solidVertexShader;
    delete solidPixelShader;

    mainVertexShader = NULL;
    mainPixelShader = NULL;
    yuvScalePixelShader = NULL;

    solidVertexShader = NULL;
    solidPixelShader = NULL;

    //-------------------------------------------------------------

    delete GS;
    GS = NULL;

    //-------------------------------------------------------------

    ResizeRenderFrame(false);
    RedrawWindow(hwndRenderFrame, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);

    //-------------------------------------------------------------

    AudioDeviceList audioDevices;
    GetAudioDevices(audioDevices, ADT_RECORDING);

    String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL);
    if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice))
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable"));
        strDevice = TEXT("Disable");
    }

    audioDevices.FreeData();
    EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), !strDevice.CompareI(TEXT("Disable")));

    //-------------------------------------------------------------

    ClearStreamInfo();

    DumpProfileData();
    FreeProfileData();
    Log(TEXT("=====Stream End: %s================================================="), CurrentDateTimeString().Array());

    //update notification icon to reflect current status
    UpdateNotificationAreaIcon();

    
    SetWindowText(GetDlgItem(hwndMain, ID_TESTSTREAM), Str("MainWindow.TestStream"));
    EnableWindow(GetDlgItem(hwndMain, ID_STARTSTOP), TRUE);
    SetWindowText(GetDlgItem(hwndMain, ID_STARTSTOP), Str("MainWindow.StartStream"));
    EnableWindow(GetDlgItem(hwndMain, ID_TESTSTREAM), TRUE);


    bEditMode = false;
    SendMessage(GetDlgItem(hwndMain, ID_SCENEEDITOR), BM_SETCHECK, BST_UNCHECKED, 0);
    EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), FALSE);
    ClearStatusBar();

    InvalidateRect(hwndRenderFrame, NULL, TRUE);

    SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, 0, 0);
    SetThreadExecutionState(ES_CONTINUOUS);

    String processPriority = AppConfig->GetString(TEXT("General"), TEXT("Priority"), TEXT("Normal"));
    if (scmp(processPriority, TEXT("Normal")))
        SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);

    bTestStream = false;

    UpdateRenderViewMessage();

    OSLeaveMutex(hStartupShutdownMutex);
}
Пример #3
0
void OBS::Start()
{
    if(bRunning) return;

    OSEnterMutex (hStartupShutdownMutex);

    scenesConfig.Save();

    //-------------------------------------------------------------

    fps = AppConfig->GetInt(TEXT("Video"), TEXT("FPS"), 30);
    frameTime = 1000/fps;

    //-------------------------------------------------------------

    if(!bLoggedSystemStats)
    {
        LogSystemStats();
        bLoggedSystemStats = TRUE;
    }

    OSCheckForBuggyDLLs();

    //-------------------------------------------------------------
retryHookTest:
    bool alreadyWarnedAboutModules = false;
    if (OSIncompatibleModulesLoaded())
    {
        Log(TEXT("Incompatible modules (pre-D3D) detected."));
        int ret = MessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR | MB_ABORTRETRYIGNORE);
        if (ret == IDABORT)
        {
            OSLeaveMutex (hStartupShutdownMutex);
            return;
        }
        else if (ret == IDRETRY)
        {
            goto retryHookTest;
        }

        alreadyWarnedAboutModules = true;
    }

    String strPatchesError;
    if (OSIncompatiblePatchesLoaded(strPatchesError))
    {
        OSLeaveMutex (hStartupShutdownMutex);
        MessageBox(hwndMain, strPatchesError.Array(), NULL, MB_ICONERROR);
        Log(TEXT("Incompatible patches detected."));
        return;
    }

    //-------------------------------------------------------------

    String processPriority = AppConfig->GetString(TEXT("General"), TEXT("Priority"), TEXT("Normal"));
    if (!scmp(processPriority, TEXT("Idle")))
        SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
    else if (!scmp(processPriority, TEXT("Above Normal")))
        SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
    else if (!scmp(processPriority, TEXT("High")))
        SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);

    int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2);
    DWORD delayTime = (DWORD)AppConfig->GetInt(TEXT("Publish"), TEXT("Delay"));

    String strError;

    bFirstConnect = !bReconnecting;

    if(bTestStream)
        network = CreateNullNetwork();
    else
    {
        switch(networkMode)
        {
        case 0: network = (delayTime > 0) ? CreateDelayedPublisher(delayTime) : CreateRTMPPublisher(); break;
        case 1: network = CreateNullNetwork(); break;
        }
    }

    if(!network)
    {
        OSLeaveMutex (hStartupShutdownMutex);

        if(!bReconnecting)
            MessageBox(hwndMain, strError, NULL, MB_ICONERROR);
        else
            DialogBox(hinstMain, MAKEINTRESOURCE(IDD_RECONNECTING), hwndMain, OBS::ReconnectDialogProc);
        return;
    }

    bReconnecting = false;

    //-------------------------------------------------------------

    Log(TEXT("=====Stream Start: %s==============================================="), CurrentDateTimeString().Array());

    //-------------------------------------------------------------

    bEnableProjectorCursor = GlobalConfig->GetInt(L"General", L"EnableProjectorCursor", 1) != 0;
    bPleaseEnableProjector = bPleaseDisableProjector = false;

    int monitorID = AppConfig->GetInt(TEXT("Video"), TEXT("Monitor"));
    if(monitorID >= (int)monitors.Num())
        monitorID = 0;

    RECT &screenRect = monitors[monitorID].rect;
    int defCX = screenRect.right  - screenRect.left;
    int defCY = screenRect.bottom - screenRect.top;

    downscaleType = AppConfig->GetInt(TEXT("Video"), TEXT("Filter"), 0);
    downscale = AppConfig->GetFloat(TEXT("Video"), TEXT("Downscale"), 1.0f);
    baseCX = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"),  defCX);
    baseCY = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"), defCY);

    baseCX = MIN(MAX(baseCX, 128), 4096);
    baseCY = MIN(MAX(baseCY, 128), 4096);

    scaleCX = UINT(double(baseCX) / double(downscale));
    scaleCY = UINT(double(baseCY) / double(downscale));

    //align width to 128bit for fast SSE YUV4:2:0 conversion
    outputCX = scaleCX & 0xFFFFFFFC;
    outputCY = scaleCY & 0xFFFFFFFE;

    bUseMultithreadedOptimizations = AppConfig->GetInt(TEXT("General"), TEXT("UseMultithreadedOptimizations"), TRUE) != 0;
    Log(TEXT("  Multithreaded optimizations: %s"), (CTSTR)(bUseMultithreadedOptimizations ? TEXT("On") : TEXT("Off")));

    encoderSkipThreshold = GlobalConfig->GetInt(TEXT("Video"), TEXT("EncoderSkipThreshold"), fps/4);

    //------------------------------------------------------------------

    Log(TEXT("  Base resolution: %ux%u"), baseCX, baseCY);
    Log(TEXT("  Output resolution: %ux%u"), outputCX, outputCY);
    Log(TEXT("------------------------------------------"));

    //------------------------------------------------------------------

    GS = new D3D10System;
    GS->Init();

    //Thanks to ASUS OSD hooking the goddamn user mode driver framework (!!!!), we have to re-check for dangerous
    //hooks after initializing D3D.
retryHookTestV2:
    if (!alreadyWarnedAboutModules)
    {
        if (OSIncompatibleModulesLoaded())
        {
            Log(TEXT("Incompatible modules (post-D3D) detected."));
            int ret = MessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR | MB_ABORTRETRYIGNORE);
            if (ret == IDABORT)
            {
                //FIXME: really need a better way to abort startup than this...
                delete network;
                delete GS;

                OSLeaveMutex (hStartupShutdownMutex);
                return;
            }
            else if (ret == IDRETRY)
            {
                goto retryHookTestV2;
            }
        }
    }

    //-------------------------------------------------------------

    mainVertexShader    = CreateVertexShaderFromFile(TEXT("shaders/DrawTexture.vShader"));
    mainPixelShader     = CreatePixelShaderFromFile(TEXT("shaders/DrawTexture.pShader"));

    solidVertexShader   = CreateVertexShaderFromFile(TEXT("shaders/DrawSolid.vShader"));
    solidPixelShader    = CreatePixelShaderFromFile(TEXT("shaders/DrawSolid.pShader"));

    if(!mainVertexShader || !mainPixelShader)
        CrashError(TEXT("Unable to load DrawTexture shaders"));

    if(!solidVertexShader || !solidPixelShader)
        CrashError(TEXT("Unable to load DrawSolid shaders"));

    //------------------------------------------------------------------

    CTSTR lpShader;
    if(CloseFloat(downscale, 1.0))
        lpShader = TEXT("shaders/DrawYUVTexture.pShader");
    else if(downscale < 2.01)
    {
        switch(downscaleType)
        {
            case 0: lpShader = TEXT("shaders/DownscaleBilinear1YUV.pShader"); break;
            case 1: lpShader = TEXT("shaders/DownscaleBicubicYUV.pShader"); break;
            case 2: lpShader = TEXT("shaders/DownscaleLanczos6tapYUV.pShader"); break;
        }
    }
    else if(downscale < 3.01)
        lpShader = TEXT("shaders/DownscaleBilinear9YUV.pShader");
    else
        CrashError(TEXT("Invalid downscale value (must be either 1.0, 1.5, 2.0, 2.25, or 3.0)"));

    yuvScalePixelShader = CreatePixelShaderFromFile(lpShader);
    if (!yuvScalePixelShader)
        CrashError(TEXT("Unable to create shader from file %s"), lpShader);

    //-------------------------------------------------------------

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        mainRenderTextures[i] = CreateRenderTarget(baseCX, baseCY, GS_BGRA, FALSE);
        yuvRenderTextures[i]  = CreateRenderTarget(outputCX, outputCY, GS_BGRA, FALSE);
    }

    //-------------------------------------------------------------

    D3D10_TEXTURE2D_DESC td;
    zero(&td, sizeof(td));
    td.Width            = outputCX;
    td.Height           = outputCY;
    td.Format           = DXGI_FORMAT_B8G8R8A8_UNORM;
    td.MipLevels        = 1;
    td.ArraySize        = 1;
    td.SampleDesc.Count = 1;
    td.ArraySize        = 1;
    td.Usage            = D3D10_USAGE_STAGING;
    td.CPUAccessFlags   = D3D10_CPU_ACCESS_READ;

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        HRESULT err = GetD3D()->CreateTexture2D(&td, NULL, &copyTextures[i]);
        if(FAILED(err))
        {
            CrashError(TEXT("Unable to create copy texture"));
            //todo - better error handling
        }
    }

    //------------------------------------------------------------------

    UINT format = AppConfig->GetInt(L"Audio Encoding", L"Format", 1);

    switch (format) {
    case 0: sampleRateHz = 44100; break;
    default:
    case 1: sampleRateHz = 48000; break;
    }

    Log(L"------------------------------------------");
    Log(L"Audio Format: %uhz", sampleRateHz);

    //------------------------------------------------------------------

    AudioDeviceList playbackDevices;
    GetAudioDevices(playbackDevices, ADT_PLAYBACK);

    String strPlaybackDevice = AppConfig->GetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default"));
    if(strPlaybackDevice.IsEmpty() || !playbackDevices.HasID(strPlaybackDevice))
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default"));
        strPlaybackDevice = TEXT("Default");
    }

    Log(TEXT("Playback device %s"), strPlaybackDevice.Array());
    playbackDevices.FreeData();

    desktopAudio = CreateAudioSource(false, strPlaybackDevice);

    if(!desktopAudio) {
        CrashError(TEXT("Cannot initialize desktop audio sound, more info in the log file."));
    }

    AudioDeviceList audioDevices;
    GetAudioDevices(audioDevices, ADT_RECORDING);

    String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL);
    if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice))
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable"));
        strDevice = TEXT("Disable");
    }

    audioDevices.FreeData();

    String strDefaultMic;
    bool bHasDefault = GetDefaultMicID(strDefaultMic);

    if(strDevice.CompareI(TEXT("Disable")))
        EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE);
    else
    {
        bool bUseDefault = strDevice.CompareI(TEXT("Default")) != 0;
        if(!bUseDefault || bHasDefault)
        {
            if(bUseDefault)
                strDevice = strDefaultMic;

            micAudio = CreateAudioSource(true, strDevice);

            if(!micAudio)
                MessageBox(hwndMain, Str("MicrophoneFailure"), NULL, 0);
            else
                micAudio->SetTimeOffset(AppConfig->GetInt(TEXT("Audio"), TEXT("MicTimeOffset"), 0));

            EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), micAudio != NULL);
        }
        else
            EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE);
    }

    //-------------------------------------------------------------

    bool bDisableEncoding = false;

    if (bTestStream)
        bDisableEncoding = GlobalConfig->GetInt(TEXT("General"), TEXT("DisablePreviewEncoding"), false) != 0;

    //-------------------------------------------------------------

    UINT bitRate = (UINT)AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96);
    String strEncoder = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC"));

    if (bDisableEncoding)
        audioEncoder = CreateNullAudioEncoder();
    else
#ifdef USE_AAC
    if(strEncoder.CompareI(TEXT("AAC")))// && OSGetVersion() >= 7)
        audioEncoder = CreateAACEncoder(bitRate);
    else
#endif
        audioEncoder = CreateMP3Encoder(bitRate);

    //-------------------------------------------------------------

    desktopVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f);
    micVol     = AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"),     1.0f);

    //-------------------------------------------------------------

    bRunning = true;

    if(sceneElement)
    {
        scene = CreateScene(sceneElement->GetString(TEXT("class")), sceneElement->GetElement(TEXT("data")));
        XElement *sources = sceneElement->GetElement(TEXT("sources"));
        if(sources)
        {
            UINT numSources = sources->NumElements();
            for(UINT i=0; i<numSources; i++)
            {
                SceneItem *item = scene->AddImageSource(sources->GetElementByID(i));
                if(item)
                {
                    if(ListView_GetItemState(GetDlgItem(hwndMain, ID_SOURCES), i, LVIS_SELECTED) > 0)
                        item->Select(true);
                }
            }
        }

        scene->BeginScene();
    }

    if(scene && scene->HasMissingSources())
        MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0);

    //-------------------------------------------------------------

    int maxBitRate = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000);
    int bufferSize = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("BufferSize"), 1000);
    int quality    = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("Quality"),    8);
    String preset  = AppConfig->GetString(TEXT("Video Encoding"), TEXT("Preset"),     TEXT("veryfast"));
    bUsing444      = false;//AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("Use444"),     0) != 0;
    bUseCFR        = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCFR"), 1) != 0;

    //-------------------------------------------------------------

    bWriteToFile = networkMode == 1 || AppConfig->GetInt(TEXT("Publish"), TEXT("SaveToFile")) != 0;
    String strOutputFile = AppConfig->GetString(TEXT("Publish"), TEXT("SavePath"));

    strOutputFile.FindReplace(TEXT("\\"), TEXT("/"));

    if (bWriteToFile)
    {
        OSFindData ofd;
        HANDLE hFind = NULL;
        bool bUseDateTimeName = true;
        bool bOverwrite = GlobalConfig->GetInt(L"General", L"OverwriteRecordings", false) != 0;

        if(!bOverwrite && (hFind = OSFindFirstFile(strOutputFile, ofd)))
        {
            String strFileExtension = GetPathExtension(strOutputFile);
            String strFileWithoutExtension = GetPathWithoutExtension(strOutputFile);

            if(strFileExtension.IsValid() && !ofd.bDirectory)
            {
                String strNewFilePath;
                UINT curFile = 0;

                do 
                {
                    strNewFilePath.Clear() << strFileWithoutExtension << TEXT(" (") << FormattedString(TEXT("%02u"), ++curFile) << TEXT(").") << strFileExtension;
                } while(OSFileExists(strNewFilePath));

                strOutputFile = strNewFilePath;

                bUseDateTimeName = false;
            }

            if(ofd.bDirectory)
                strOutputFile.AppendChar('/');

            OSFindClose(hFind);
        }

        if(bUseDateTimeName)
        {
            String strFileName = GetPathFileName(strOutputFile);

            if(!strFileName.IsValid() || !IsSafeFilename(strFileName))
            {
                SYSTEMTIME st;
                GetLocalTime(&st);

                String strDirectory = GetPathDirectory(strOutputFile),
                       extension = GetPathExtension(strOutputFile);
                if(extension.IsEmpty())
                    extension = TEXT("mp4");
                strOutputFile = FormattedString(TEXT("%s/%u-%02u-%02u-%02u%02u-%02u.%s"), strDirectory.Array(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, extension.Array());
            }
        }
    }

    //-------------------------------------------------------------

    bufferingTime = GlobalConfig->GetInt(TEXT("General"), TEXT("SceneBufferingTime"), 700);
    Log(TEXT("Scene buffering time set to %u"), bufferingTime);

    //-------------------------------------------------------------

    bForceMicMono = AppConfig->GetInt(TEXT("Audio"), TEXT("ForceMicMono")) != 0;
    bRecievedFirstAudioFrame = false;

    //hRequestAudioEvent = CreateSemaphore(NULL, 0, 0x7FFFFFFFL, NULL);
    hSoundDataMutex = OSCreateMutex();
    hSoundThread = OSCreateThread((XTHREAD)OBS::MainAudioThread, NULL);

    //-------------------------------------------------------------

    StartBlankSoundPlayback(strPlaybackDevice);

    //-------------------------------------------------------------

    colorDesc.fullRange = false;
    colorDesc.primaries = ColorPrimaries_BT709;
    colorDesc.transfer  = ColorTransfer_IEC6196621;
    colorDesc.matrix    = outputCX >= 1280 || outputCY > 576 ? ColorMatrix_BT709 : ColorMatrix_SMPTE170M;

    videoEncoder = nullptr;
    if (bDisableEncoding)
        videoEncoder = CreateNullVideoEncoder();
    else if(AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseQSV")) != 0)
        videoEncoder = CreateQSVEncoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR);

    if(!videoEncoder)
        videoEncoder = CreateX264Encoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR);


    //-------------------------------------------------------------

    // Ensure that the render frame is properly sized
    ResizeRenderFrame(true);

    //-------------------------------------------------------------

    if(!bTestStream && bWriteToFile && strOutputFile.IsValid())
    {
        String strFileExtension = GetPathExtension(strOutputFile);
        if(strFileExtension.CompareI(TEXT("flv")))
            fileStream = CreateFLVFileStream(strOutputFile);
        else if(strFileExtension.CompareI(TEXT("mp4")))
            fileStream = CreateMP4FileStream(strOutputFile);

        if(!fileStream)
        {
            Log(TEXT("Warning - OBSCapture::Start: Unable to create the file stream. Check the file path in Broadcast Settings."));
            MessageBox(hwndMain, Str("Capture.Start.FileStream.Warning"), Str("Capture.Start.FileStream.WarningCaption"), MB_OK | MB_ICONWARNING);        
        }
    }

    //-------------------------------------------------------------

    curFramePic = NULL;
    bShutdownVideoThread = false;
    bShutdownEncodeThread = false;
    //ResetEvent(hVideoThread);
    hEncodeThread = OSCreateThread((XTHREAD)OBS::EncodeThread, NULL);
    hVideoThread = OSCreateThread((XTHREAD)OBS::MainCaptureThread, NULL);

    if(bTestStream)
    {
        EnableWindow(GetDlgItem(hwndMain, ID_STARTSTOP), FALSE);
        SetWindowText(GetDlgItem(hwndMain, ID_TESTSTREAM), Str("MainWindow.StopTest"));
    }
    else
    {
        EnableWindow(GetDlgItem(hwndMain, ID_TESTSTREAM), FALSE);
        SetWindowText(GetDlgItem(hwndMain, ID_STARTSTOP), Str("MainWindow.StopStream"));
    }

    EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), TRUE);

    //-------------------------------------------------------------

    ReportStartStreamTrigger();
    
    SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, 0);
    SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED | ES_DISPLAY_REQUIRED);

    UpdateRenderViewMessage();

    //update notification icon to reflect current status
    UpdateNotificationAreaIcon();

    OSLeaveMutex (hStartupShutdownMutex);
}
Пример #4
0
void SettingsAudio::RefreshDevices()
{
    if (storage) {
        delete storage->recordingDevices;
        delete storage->playbackDevices;
    }
    delete storage;

    HWND hwndTemp = GetDlgItem(hwnd, IDC_MICDEVICES);
    HWND hwndPlayback = GetDlgItem(hwnd, IDC_PLAYBACKDEVICES);

    SendMessage(hwndTemp, CB_RESETCONTENT, 0, 0);
    SendMessage(hwndPlayback, CB_RESETCONTENT, 0, 0);

    storage = new AudioDeviceStorage;

    storage->playbackDevices = new AudioDeviceList;
    GetAudioDevices((*storage->playbackDevices), ADT_PLAYBACK, bDisplayConnectedOnly);

    storage->recordingDevices = new AudioDeviceList;
    GetAudioDevices((*storage->recordingDevices), ADT_RECORDING, bDisplayConnectedOnly);

    for(UINT i=0; i<storage->playbackDevices->devices.Num(); i++)
        SendMessage(hwndPlayback, CB_ADDSTRING, 0, (LPARAM)storage->playbackDevices->devices[i].strName.Array());

    for(UINT i=0; i<storage->recordingDevices->devices.Num(); i++)
        SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)storage->recordingDevices->devices[i].strName.Array());

    String strPlaybackID = AppConfig->GetString(TEXT("Audio"), TEXT("PlaybackDevice"), storage->playbackDevices->devices[0].strID);
    String strDeviceID = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), storage->recordingDevices->devices[0].strID);

    UINT iPlaybackDevice;
    for(iPlaybackDevice=0; iPlaybackDevice<storage->playbackDevices->devices.Num(); iPlaybackDevice++)
    {
        if(storage->playbackDevices->devices[iPlaybackDevice].strID == strPlaybackID)
        {
            SendMessage(hwndPlayback, CB_SETCURSEL, iPlaybackDevice, 0);
            break;
        }
    }

    UINT iDevice;
    for(iDevice=0; iDevice<storage->recordingDevices->devices.Num(); iDevice++)
    {
        if(storage->recordingDevices->devices[iDevice].strID == strDeviceID)
        {
            SendMessage(hwndTemp, CB_SETCURSEL, iDevice, 0);
            break;
        }
    }

    if(iPlaybackDevice == storage->playbackDevices->devices.Num())
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("PlaybackDevice"), storage->playbackDevices->devices[0].strID);
        SendMessage(hwndPlayback, CB_SETCURSEL, 0, 0);
    }

    if(iDevice == storage->recordingDevices->devices.Num())
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("Device"), storage->recordingDevices->devices[0].strID);
        SendMessage(hwndTemp, CB_SETCURSEL, 0, 0);
    }
}
Пример #5
0
void OBS::Stop(bool overrideKeepRecording)
{
    if((!bStreaming && !bRecording && !bRunning) && (!bTestStream)) return;

    //ugly hack to prevent hotkeys from being processed while we're stopping otherwise we end up
    //with callbacks from the ProcessEvents call in DelayedPublisher which causes havoc.
    OSEnterMutex(hHotkeyMutex);

    int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2);

    if(!overrideKeepRecording && bRecording && bKeepRecording && networkMode == 0) {
        NetworkStream *tempStream = NULL;
        
        videoEncoder->RequestKeyframe();
        tempStream = network;
        network = NULL;

        Log(TEXT("=====Stream End (recording continues): %s========================="), CurrentDateTimeString().Array());

        delete tempStream;

        bStreaming = false;
        bSentHeaders = false;

        ReportStopStreamingTrigger();

        ConfigureStreamButtons();

        OSLeaveMutex(hHotkeyMutex);

        return;
    }

    OSEnterMutex(hStartupShutdownMutex);

    //we only want the capture thread to stop first, so we can ensure all packets are flushed
    bShutdownEncodeThread = true;
    ShowWindow(hwndProjector, SW_HIDE);

    if(hEncodeThread)
    {
        OSTerminateThread(hEncodeThread, 30000);
        hEncodeThread = NULL;
    }

    bShutdownVideoThread = true;
    SetEvent(hVideoEvent);

    if(hVideoThread)
    {
        OSTerminateThread(hVideoThread, 30000);
        hVideoThread = NULL;
    }

    bRunning = false;

    ReportStopStreamTrigger();

    for(UINT i=0; i<globalSources.Num(); i++)
        globalSources[i].source->EndScene();

    if(scene)
        scene->EndScene();

    //-------------------------------------------------------------

    if(hSoundThread)
    {
        //ReleaseSemaphore(hRequestAudioEvent, 1, NULL);
        OSTerminateThread(hSoundThread, 20000);
    }

    //if(hRequestAudioEvent)
    //    CloseHandle(hRequestAudioEvent);
    if(hSoundDataMutex)
        OSCloseMutex(hSoundDataMutex);

    hSoundThread = NULL;
    //hRequestAudioEvent = NULL;
    hSoundDataMutex = NULL;

    //-------------------------------------------------------------

    StopBlankSoundPlayback();

    //-------------------------------------------------------------

    delete network;
    network = NULL;
    if (bStreaming) ReportStopStreamingTrigger();
    bStreaming = false;
    
    if(bRecording) StopRecording();

    delete micAudio;
    micAudio = NULL;

    delete desktopAudio;
    desktopAudio = NULL;

    delete audioEncoder;
    audioEncoder = NULL;

    delete videoEncoder;
    videoEncoder = NULL;

    //-------------------------------------------------------------

    for(UINT i=0; i<pendingAudioFrames.Num(); i++)
        pendingAudioFrames[i].audioData.Clear();
    pendingAudioFrames.Clear();

    //-------------------------------------------------------------

    if(GS)
        GS->UnloadAllData();

    //-------------------------------------------------------------

    delete scene;
    scene = NULL;

    for(UINT i=0; i<globalSources.Num(); i++)
        globalSources[i].FreeData();
    globalSources.Clear();

    //-------------------------------------------------------------

    for(UINT i=0; i<auxAudioSources.Num(); i++)
        delete auxAudioSources[i];
    auxAudioSources.Clear();

    //-------------------------------------------------------------

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        delete mainRenderTextures[i];
        delete yuvRenderTextures[i];

        mainRenderTextures[i] = NULL;
        yuvRenderTextures[i] = NULL;
    }

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        SafeRelease(copyTextures[i]);
    }

    delete transitionTexture;
    transitionTexture = NULL;

    //-------------------------------------------------------------

    delete mainVertexShader;
    delete mainPixelShader;
    delete yuvScalePixelShader;

    delete solidVertexShader;
    delete solidPixelShader;

    mainVertexShader = NULL;
    mainPixelShader = NULL;
    yuvScalePixelShader = NULL;

    solidVertexShader = NULL;
    solidPixelShader = NULL;

    //-------------------------------------------------------------

    delete GS;
    GS = NULL;

    //-------------------------------------------------------------

    ResizeRenderFrame(false);
    RedrawWindow(hwndRenderFrame, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);

    //-------------------------------------------------------------

    AudioDeviceList audioDevices;
    GetAudioDevices(audioDevices, ADT_RECORDING, false, true);

    String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL);
    if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice))
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable"));
        strDevice = TEXT("Disable");
    }

    audioDevices.FreeData();
    EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), !strDevice.CompareI(TEXT("Disable")));

    //-------------------------------------------------------------

    ClearStreamInfo();

    DumpProfileData();
    FreeProfileData();
    Log(TEXT("=====Stream End: %s================================================="), CurrentDateTimeString().Array());

    //update notification icon to reflect current status
    UpdateNotificationAreaIcon();

    bEditMode = false;
    SendMessage(GetDlgItem(hwndMain, ID_SCENEEDITOR), BM_SETCHECK, BST_UNCHECKED, 0);
    EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), FALSE);
    ClearStatusBar();

    InvalidateRect(hwndRenderFrame, NULL, TRUE);

    SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 1, 0, 0);
    SetThreadExecutionState(ES_CONTINUOUS);

    String processPriority = AppConfig->GetString(TEXT("General"), TEXT("Priority"), TEXT("Normal"));
    if (scmp(processPriority, TEXT("Normal")))
        SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);

    bTestStream = false;

    ConfigureStreamButtons();

    UpdateRenderViewMessage();

    DisableMenusWhileStreaming(false);

    OSLeaveMutex(hStartupShutdownMutex);

    OSLeaveMutex(hHotkeyMutex);
}
Пример #6
0
void OBS::Start(bool recordingOnly, bool replayBufferOnly)
{
    if(bRunning && !bRecording && !bRecordingReplayBuffer) return;

    int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2);
    DWORD delayTime = (DWORD)AppConfig->GetInt(TEXT("Publish"), TEXT("Delay"));

    if (bRecording && networkMode != 0) return;

    if((bRecording || bRecordingReplayBuffer) && networkMode == 0 && delayTime == 0 && !recordingOnly && !replayBufferOnly) {
        bFirstConnect = !bReconnecting;

        if (network)
        {
            NetworkStream *net = network;
            network = nullptr;
            delete net;
        }
        network = CreateRTMPPublisher();

        Log(TEXT("=====Stream Start (while recording): %s============================="), CurrentDateTimeString().Array());

        bSentHeaders = false;
        bStreaming = true;

        ReportStartStreamingTrigger();
        ConfigureStreamButtons();
        return;
    }

    bStartingUp = true;

    OSEnterMutex(hStartupShutdownMutex);

    DisableMenusWhileStreaming(true);

    scenesConfig.SaveTo(String() << lpAppDataPath << "\\scenes.xconfig");
    scenesConfig.Save();

    //-------------------------------------------------------------

    fps = AppConfig->GetInt(TEXT("Video"), TEXT("FPS"), 30);
    frameTime = 1000/fps;

    //-------------------------------------------------------------

    if(!bLoggedSystemStats)
    {
        LogSystemStats();
        bLoggedSystemStats = TRUE;
    }

    OSCheckForBuggyDLLs();

    //-------------------------------------------------------------
retryHookTest:
    bool alreadyWarnedAboutModules = false;
    if (OSIncompatibleModulesLoaded())
    {
        Log(TEXT("Incompatible modules (pre-D3D) detected."));
        int ret = OBSMessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR | MB_ABORTRETRYIGNORE);
        if (ret == IDABORT)
        {
            DisableMenusWhileStreaming(false);
            OSLeaveMutex (hStartupShutdownMutex);
            bStartingUp = false;
            return;
        }
        else if (ret == IDRETRY)
        {
            goto retryHookTest;
        }

        alreadyWarnedAboutModules = true;
    }

    String strPatchesError;
    if (OSIncompatiblePatchesLoaded(strPatchesError))
    {
        DisableMenusWhileStreaming(false);
        OSLeaveMutex (hStartupShutdownMutex);
        OBSMessageBox(hwndMain, strPatchesError.Array(), NULL, MB_ICONERROR);
        Log(TEXT("Incompatible patches detected."));
        bStartingUp = false;
        return;
    }

    //check the user isn't trying to stream or record with no sources which is typically
    //a configuration error
    if (!bTestStream)
    {
        bool foundSource = false;
        XElement *scenes = App->scenesConfig.GetElement(TEXT("scenes"));
        if (scenes)
        {
            UINT numScenes = scenes->NumElements();

            for (UINT i = 0; i<numScenes; i++)
            {
                XElement *sceneElement = scenes->GetElementByID(i);
                XElement *sources = sceneElement->GetElement(TEXT("sources"));
                if (sources && sources->NumElements())
                {
                    foundSource = true;
                    break;
                }
            }
        }

        if (!foundSource)
        {
            if (OBSMessageBox(hwndMain, Str("NoSourcesFound"), NULL, MB_ICONWARNING|MB_YESNO) == IDNO)
            {
                DisableMenusWhileStreaming(false);
                OSLeaveMutex(hStartupShutdownMutex);
                bStartingUp = false;
                return;
            }
        }
    }

    //-------------------------------------------------------------

    String processPriority = AppConfig->GetString(TEXT("General"), TEXT("Priority"), TEXT("Normal"));
    if (!scmp(processPriority, TEXT("Idle")))
        SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
    else if (!scmp(processPriority, TEXT("Above Normal")))
        SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
    else if (!scmp(processPriority, TEXT("High")))
        SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);

    networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2);
    delayTime = (DWORD)AppConfig->GetInt(TEXT("Publish"), TEXT("Delay"));

    String strError;

    bFirstConnect = !bReconnecting;

    if(bTestStream || recordingOnly || replayBufferOnly)
        network = CreateNullNetwork();
    else
    {
        switch(networkMode)
        {
        case 0: network = (delayTime > 0) ? CreateDelayedPublisher(delayTime) : CreateRTMPPublisher(); break;
        case 1: network = CreateNullNetwork(); break;
        }
    }

    if(!network)
    {
        DisableMenusWhileStreaming(false);
        OSLeaveMutex (hStartupShutdownMutex);

        if(!bReconnecting)
            OBSMessageBox(hwndMain, strError, NULL, MB_ICONERROR);
        else
            OBSDialogBox(hinstMain, MAKEINTRESOURCE(IDD_RECONNECTING), hwndMain, OBS::ReconnectDialogProc);
        bStartingUp = false;
        return;
    }

    bReconnecting = false;

    //-------------------------------------------------------------

    Log(TEXT("=====Stream Start: %s==============================================="), CurrentDateTimeString().Array());

    //-------------------------------------------------------------

    bEnableProjectorCursor = GlobalConfig->GetInt(L"General", L"EnableProjectorCursor", 1) != 0;
    bPleaseEnableProjector = bPleaseDisableProjector = false;

    int monitorID = AppConfig->GetInt(TEXT("Video"), TEXT("Monitor"));
    if(monitorID >= (int)monitors.Num())
        monitorID = 0;

    RECT &screenRect = monitors[monitorID].rect;
    int defCX = screenRect.right  - screenRect.left;
    int defCY = screenRect.bottom - screenRect.top;

    downscaleType = AppConfig->GetInt(TEXT("Video"), TEXT("Filter"), 0);
    downscale = AppConfig->GetFloat(TEXT("Video"), TEXT("Downscale"), 1.0f);
    baseCX = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"),  defCX);
    baseCY = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"), defCY);

    baseCX = MIN(MAX(baseCX, 128), 4096);
    baseCY = MIN(MAX(baseCY, 128), 4096);

    scaleCX = UINT(double(baseCX) / double(downscale));
    scaleCY = UINT(double(baseCY) / double(downscale));

    //align width to 128bit for fast SSE YUV4:2:0 conversion
    outputCX = scaleCX & 0xFFFFFFFC;
    outputCY = scaleCY & 0xFFFFFFFE;

    bUseMultithreadedOptimizations = AppConfig->GetInt(TEXT("General"), TEXT("UseMultithreadedOptimizations"), TRUE) != 0;
    Log(TEXT("  Multithreaded optimizations: %s"), (CTSTR)(bUseMultithreadedOptimizations ? TEXT("On") : TEXT("Off")));

    encoderSkipThreshold = GlobalConfig->GetInt(TEXT("Video"), TEXT("EncoderSkipThreshold"), fps/4);

    //------------------------------------------------------------------

    Log(TEXT("  Base resolution: %ux%u"), baseCX, baseCY);
    Log(TEXT("  Output resolution: %ux%u"), outputCX, outputCY);
    Log(TEXT("------------------------------------------"));

    //------------------------------------------------------------------

    GS = new D3D10System;
    GS->Init();

    //Thanks to ASUS OSD hooking the goddamn user mode driver framework (!!!!), we have to re-check for dangerous
    //hooks after initializing D3D.
retryHookTestV2:
    if (!alreadyWarnedAboutModules)
    {
        if (OSIncompatibleModulesLoaded())
        {
            Log(TEXT("Incompatible modules (post-D3D) detected."));
            int ret = OBSMessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR | MB_ABORTRETRYIGNORE);
            if (ret == IDABORT)
            {
                //FIXME: really need a better way to abort startup than this...
                delete network;
                delete GS;

                DisableMenusWhileStreaming(false);
                OSLeaveMutex (hStartupShutdownMutex);
                bStartingUp = false;
                return;
            }
            else if (ret == IDRETRY)
            {
                goto retryHookTestV2;
            }
        }
    }

    //-------------------------------------------------------------

    mainVertexShader    = CreateVertexShaderFromFile(TEXT("shaders/DrawTexture.vShader"));
    mainPixelShader     = CreatePixelShaderFromFile(TEXT("shaders/DrawTexture.pShader"));

    solidVertexShader   = CreateVertexShaderFromFile(TEXT("shaders/DrawSolid.vShader"));
    solidPixelShader    = CreatePixelShaderFromFile(TEXT("shaders/DrawSolid.pShader"));

    if(!mainVertexShader || !mainPixelShader)
        CrashError(TEXT("Unable to load DrawTexture shaders"));

    if(!solidVertexShader || !solidPixelShader)
        CrashError(TEXT("Unable to load DrawSolid shaders"));

    //------------------------------------------------------------------

    CTSTR lpShader;
    if(CloseFloat(downscale, 1.0))
        lpShader = TEXT("shaders/DrawYUVTexture.pShader");
    else if(downscale < 2.01)
    {
        switch(downscaleType)
        {
            case 0: lpShader = TEXT("shaders/DownscaleBilinear1YUV.pShader"); break;
            case 1: lpShader = TEXT("shaders/DownscaleBicubicYUV.pShader"); break;
            case 2: lpShader = TEXT("shaders/DownscaleLanczos6tapYUV.pShader"); break;
        }
    }
    else if(downscale < 3.01)
        lpShader = TEXT("shaders/DownscaleBilinear9YUV.pShader");
    else
        CrashError(TEXT("Invalid downscale value (must be either 1.0, 1.5, 2.0, 2.25, or 3.0)"));

    yuvScalePixelShader = CreatePixelShaderFromFile(lpShader);
    if (!yuvScalePixelShader)
        CrashError(TEXT("Unable to create shader from file %s"), lpShader);

    //-------------------------------------------------------------

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        mainRenderTextures[i] = CreateRenderTarget(baseCX, baseCY, GS_BGRA, FALSE);
        yuvRenderTextures[i]  = CreateRenderTarget(outputCX, outputCY, GS_BGRA, FALSE);
    }

    //-------------------------------------------------------------

    D3D10_TEXTURE2D_DESC td;
    zero(&td, sizeof(td));
    td.Width            = outputCX;
    td.Height           = outputCY;
    td.Format           = DXGI_FORMAT_B8G8R8A8_UNORM;
    td.MipLevels        = 1;
    td.ArraySize        = 1;
    td.SampleDesc.Count = 1;
    td.ArraySize        = 1;
    td.Usage            = D3D10_USAGE_STAGING;
    td.CPUAccessFlags   = D3D10_CPU_ACCESS_READ;

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        HRESULT err = GetD3D()->CreateTexture2D(&td, NULL, &copyTextures[i]);
        if(FAILED(err))
        {
            CrashError(TEXT("Unable to create copy texture"));
            //todo - better error handling
        }
    }

    //------------------------------------------------------------------

    String strEncoder = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC"));
    BOOL isAAC = strEncoder.CompareI(TEXT("AAC"));

    UINT format = AppConfig->GetInt(L"Audio Encoding", L"Format", 1);

    if (!isAAC)
        format = 0;

    switch (format) {
    case 0: sampleRateHz = 44100; break;
    default:
    case 1: sampleRateHz = 48000; break;
    }

    Log(L"------------------------------------------");
    Log(L"Audio Format: %u Hz", sampleRateHz);

    //------------------------------------------------------------------

    BOOL isStereo = AppConfig->GetInt(L"Audio Encoding", L"isStereo", 1);

    switch (isStereo) {
    case 0: audioChannels = 1; break;
    default:
    case 1: audioChannels = 2; break;
    }

    Log(L"------------------------------------------");
    Log(L"Audio Channels: %u Ch", audioChannels);

    //------------------------------------------------------------------

    AudioDeviceList playbackDevices;
    bool useInputDevices = AppConfig->GetInt(L"Audio", L"InputDevicesForDesktopSound", false) != 0;
    GetAudioDevices(playbackDevices, useInputDevices ? ADT_RECORDING : ADT_PLAYBACK);

    String strPlaybackDevice = AppConfig->GetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default"));
    if(strPlaybackDevice.IsEmpty() || !playbackDevices.HasID(strPlaybackDevice))
    {
        //AppConfig->SetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default"));
        strPlaybackDevice = TEXT("Default");
    }

    Log(TEXT("Playback device %s"), strPlaybackDevice.Array());
    playbackDevices.FreeData();

    desktopAudio = CreateAudioSource(false, strPlaybackDevice);

    if(!desktopAudio) {
        CrashError(TEXT("Cannot initialize desktop audio sound, more info in the log file."));
    }

    if (useInputDevices)
        Log(L"Use Input Devices enabled, not recording standard desktop audio");

    AudioDeviceList audioDevices;
    GetAudioDevices(audioDevices, ADT_RECORDING, false, true);

    String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL);
    if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice))
    {
        //AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable"));
        strDevice = TEXT("Disable");
    }

    audioDevices.FreeData();

    String strDefaultMic;
    bool bHasDefault = GetDefaultMicID(strDefaultMic);

    if(strDevice.CompareI(TEXT("Disable")))
        EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE);
    else
    {
        bool bUseDefault = strDevice.CompareI(TEXT("Default")) != 0;
        if(!bUseDefault || bHasDefault)
        {
            if(bUseDefault)
                strDevice = strDefaultMic;

            micAudio = CreateAudioSource(true, strDevice);

            if(!micAudio)
                OBSMessageBox(hwndMain, Str("MicrophoneFailure"), NULL, 0);
            else
            {
                int offset = AppConfig->GetInt(TEXT("Audio"), TEXT("MicTimeOffset"), 0);
                Log(L"Mic time offset: %d", offset);
                micAudio->SetTimeOffset(offset);
            }

            EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), micAudio != NULL);
        }
        else
            EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE);
    }

    //-------------------------------------------------------------

    bool bDisableEncoding = false;

    if (bTestStream)
        bDisableEncoding = GlobalConfig->GetInt(TEXT("General"), TEXT("DisablePreviewEncoding"), false) != 0;

    //-------------------------------------------------------------

    UINT bitRate = (UINT)AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96);

    if (bDisableEncoding)
        audioEncoder = CreateNullAudioEncoder();
    else
#ifdef USE_AAC
    if(isAAC) // && OSGetVersion() >= 7)
        audioEncoder = CreateAACEncoder(bitRate);
    else
#endif
        audioEncoder = CreateMP3Encoder(bitRate);

    //-------------------------------------------------------------

    desktopVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f);
    micVol     = AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"),     1.0f);

    //-------------------------------------------------------------

    bRunning = true;

    if(sceneElement)
    {
        scene = CreateScene(sceneElement->GetString(TEXT("class")), sceneElement->GetElement(TEXT("data")));
        XElement *sources = sceneElement->GetElement(TEXT("sources"));
        if(sources)
        {
            UINT numSources = sources->NumElements();
            for(UINT i=0; i<numSources; i++)
            {
                SceneItem *item = scene->AddImageSource(sources->GetElementByID(i));
                if(item)
                {
                    if(ListView_GetItemState(GetDlgItem(hwndMain, ID_SOURCES), i, LVIS_SELECTED) > 0)
                        item->Select(true);
                }
            }
        }

        scene->BeginScene();
        unsigned int 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(scene && scene->HasMissingSources())
        OBSMessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0);

    //-------------------------------------------------------------

    int maxBitRate = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000);
    int bufferSize = maxBitRate;
    if (AppConfig->GetInt(L"Video Encoding", L"UseBufferSize", 0) != 0)
        bufferSize = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("BufferSize"), 1000);
    int quality    = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("Quality"),    8);
    String preset  = AppConfig->GetString(TEXT("Video Encoding"), TEXT("Preset"),     TEXT("veryfast"));
    bUsing444      = false;//AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("Use444"),     0) != 0;
    bUseCFR        = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCFR"), 1) != 0;

    //-------------------------------------------------------------

    bufferingTime = GlobalConfig->GetInt(TEXT("General"), TEXT("SceneBufferingTime"), 700);
    Log(TEXT("Scene buffering time set to %u"), bufferingTime);

    //-------------------------------------------------------------

    bForceMicMono = AppConfig->GetInt(TEXT("Audio"), TEXT("ForceMicMono")) != 0;
    bRecievedFirstAudioFrame = false;

    //hRequestAudioEvent = CreateSemaphore(NULL, 0, 0x7FFFFFFFL, NULL);
    hSoundDataMutex = OSCreateMutex();
    hSoundThread = OSCreateThread((XTHREAD)OBS::MainAudioThread, NULL);

    //-------------------------------------------------------------

    //if (!useInputDevices)
    //    StartBlankSoundPlayback(strPlaybackDevice);

    //-------------------------------------------------------------

    colorDesc.fullRange = false;
    colorDesc.primaries = ColorPrimaries_BT709;
    colorDesc.transfer  = ColorTransfer_IEC6196621;
    colorDesc.matrix    = outputCX >= 1280 || outputCY > 576 ? ColorMatrix_BT709 : ColorMatrix_SMPTE170M;

    videoEncoder = nullptr;
    String videoEncoderErrors;
    String vencoder = AppConfig->GetString(L"Video Encoding", L"Encoder");
    if (bDisableEncoding)
        videoEncoder = CreateNullVideoEncoder();
    else if(vencoder == L"QSV")
        videoEncoder = CreateQSVEncoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR, videoEncoderErrors);
    else if(vencoder == L"NVENC")
        videoEncoder = CreateNVENCEncoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR, videoEncoderErrors);
    else
        videoEncoder = CreateX264Encoder(fps, outputCX, outputCY, quality, preset, bUsing444, colorDesc, maxBitRate, bufferSize, bUseCFR);

    if (!videoEncoder)
    {
        Log(L"Couldn't initialize encoder");
        Stop(true);

        if (videoEncoderErrors.IsEmpty())
            videoEncoderErrors = Str("Encoder.InitFailed");
        else
            videoEncoderErrors = String(Str("Encoder.InitFailedWithReason")) + videoEncoderErrors;

        OBSMessageBox(hwndMain, videoEncoderErrors.Array(), nullptr, MB_OK | MB_ICONERROR); //might want to defer localization until here to automatically
                                                                                         //output english localization to logfile
        return;
    }

    if ((bStreaming = (!recordingOnly && !replayBufferOnly) && networkMode == 0)) ReportStartStreamingTrigger();
    //-------------------------------------------------------------

    // Ensure that the render frame is properly sized
    ResizeRenderFrame(true);

    //-------------------------------------------------------------

    if ((!replayBufferOnly && !StartRecording(recordingOnly)) && !bStreaming)
    {
        Stop(true);
        return;
    }

    //-------------------------------------------------------------

    curFramePic = NULL;
    bShutdownVideoThread = false;
    bShutdownEncodeThread = false;
    //ResetEvent(hVideoThread);
    hEncodeThread = OSCreateThread((XTHREAD)OBS::EncodeThread, NULL);
    hVideoThread = OSCreateThread((XTHREAD)OBS::MainCaptureThread, NULL);

    EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), TRUE);

    //-------------------------------------------------------------

    ReportStartStreamTrigger();
    
    SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, 0);
    SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED | ES_DISPLAY_REQUIRED);

    UpdateRenderViewMessage();

    //update notification icon to reflect current status
    UpdateNotificationAreaIcon();

    OSLeaveMutex (hStartupShutdownMutex);

    bStartingUp = false;

    ConfigureStreamButtons();
}
Пример #7
0
int main(int argc, char *argv[]) {
	int exit_code = 0;
	slimproto_t slimproto;
	slimaudio_t slimaudio;

	PaDeviceIndex output_device_id = PA_DEFAULT_DEVICE;
	char *output_device_name = NULL;
	char *hostapi_name = NULL;

	unsigned int output_predelay = 0;
	unsigned int output_predelay_amplitude = 0;
#ifdef EMPEG
	bool power_bypass = false, power_last = false;
	bool geteq = false;
	long key, ir;
#endif
#ifdef EMPEG
	slimaudio_volume_t volume_control = VOLUME_DRIVER;
#else
	slimaudio_volume_t volume_control = VOLUME_SOFTWARE;
#endif
	unsigned int retry_interval = RETRY_DEFAULT;

	char macaddress[6] = { 0, 0, 0, 0, 0, 1 };

	int keepalive_interval = -1;

	bool listdevs = false;
	bool listservers = false;
	bool discover_server = false;
	unsigned int json_port;

#ifdef SLIMPROTO_ZONES
	bool default_macaddress = true;
	unsigned int zone = 0;
	unsigned int num_zones = 1;
#endif
#ifdef DAEMONIZE
	bool should_daemonize = false;
	char *logfile = NULL;
#endif
#ifdef PORTAUDIO_DEV
	/* User suggested latency */
	bool modify_latency = false;
	unsigned int user_latency = 0L;
#endif
	char slimserver_address[INET_FQDNSTRLEN] = "127.0.0.1";

	char getopt_options[OPTLEN] = "a:FId:Y:e:f:hk:Lm:n:o:P:p:Rr:TO:Vv:";

	static struct option long_options[] = {
		{"predelay_amplitude", required_argument, 0, 'a'},
		{"discover",           no_argument,       0, 'F'},
		{"debug",              required_argument, 0, 'd'},
		{"debuglog",           required_argument, 0, 'Y'},
		{"help",               no_argument,       0, 'h'},
		{"keepalive",          required_argument, 0, 'k'},
		{"list",               no_argument,       0, 'L'},
		{"findservers",        no_argument,       0, 'I'},
		{"mac",	               required_argument, 0, 'm'},
		{"name",               required_argument, 0, 'n'},
		{"output",             required_argument, 0, 'o'},
		{"playerid",           required_argument, 0, 'e'},
		{"firmware",           required_argument, 0, 'f'},
		{"port",               required_argument, 0, 'P'},
		{"predelay",           required_argument, 0, 'p'},
		{"threshold_override", no_argument,       0, 'T'},
		{"output_threshold",   required_argument, 0, 'O'},
#ifdef EMPEG
		{"puteq",              no_argument,       0, 'Q'},
		{"geteq",              no_argument,       0, 'q'},
#endif
		{"retry",              no_argument,       0, 'R'},
		{"intretry",           required_argument, 0, 'r'},
		{"version",            no_argument,       0, 'V'},
		{"volume",             required_argument, 0, 'v'},
		{"zone",               required_argument, 0, 'z'},
#ifdef PORTAUDIO_DEV
		{"latency",            required_argument, 0, 'y'},
		{"audiotype",          required_argument, 0, 't'},
#else
		{"paframes",           required_argument, 0, 'g'},
		{"pabuffers",          required_argument, 0, 'j'},
#endif
#ifdef DAEMONIZE
		{"daemonize",          required_argument, 0, 'M'},
#endif
#ifdef __WIN32__
		{"highpriority",       no_argument,       0, 'H'},
#ifdef PADEV_WASAPI
		{"shared",             no_argument,       0, 'S'},
#endif
#endif
#ifdef INTERACTIVE
		{"lircrc",             required_argument, 0, 'c'},
		{"lirc",               no_argument,       0, 'i'},
		{"lcd",                no_argument,       0, 'l'},
		{"lcdc",               no_argument,       0, 'C'},
		{"display",            no_argument,       0, 'D'},
		{"width",              required_argument, 0, 'w'},
#endif
#ifdef SLIMPROTO_RENICE
		{"renice",             no_argument,       0, 'N'},
#endif
#ifdef SLIMPROTO_ZONES
		{"zone",               required_argument, 0, 'z'},
#endif
		{0, 0, 0, 0}
	};

#ifdef INTERACTIVE
        fd_set read_fds;
        fd_set write_fds;
        int key = 0;
        unsigned long ir = 0;
	int maxfd = 0;
	char *home;
	struct timeval timeout;
	timeout.tv_usec = 0;

#ifdef __WIN32__
	int WSAerrno;
	int ptw32_processInitialize (void);
	ptw32_processInitialize();
#endif /* __WIN32__ */
        /* default lircrc file ($HOME/.lircrc) */
	home = getenv("HOME");
	if (home == NULL) home = "";
	lircrc = (char *)malloc((strlen(home) + strlen("/.lircrc") + 1) * sizeof(char));
	strcpy(lircrc,home);
	strcat(lircrc,"/.lircrc");
#endif /* INTERACTIVE */

#ifdef EMPEG
	strcat (getopt_options, "Qq");
#endif
#ifdef PORTAUDIO_DEV
	strcat (getopt_options, "y:t:");
#else
	strcat (getopt_options, "g:j:");
#endif	
#ifdef DAEMONIZE	
	strcat (getopt_options, "M:");
#endif
#ifdef INTERACTIVE
	strcat (getopt_options, "c:CDilw:");
#endif
#ifdef __WIN32__
	strcat (getopt_options, "H");
#ifdef PADEV_WASAPI
	strcat (getopt_options, "S");
#endif
#endif
#ifdef SLIMPROTO_RENICE
	strcat (getopt_options, "N");
#endif
#ifdef SLIMPROTO_ZONES
	strcat (getopt_options, "z:");
#endif
#ifdef EMPEG
	empeg_getmac(macaddress);
#endif

	while (true) {
		const char shortopt =
			getopt_long_only(argc, argv, getopt_options, long_options, NULL);

		if (shortopt == (char) -1) {
			break;
		}

		switch (shortopt) {
		case 'a':
			output_predelay_amplitude = strtoul(optarg, NULL, 0);
			break;
		case 'F':
			discover_server = true;
			break;
		case 'd':
#ifdef SLIMPROTO_DEBUG
			if (strcmp(optarg, "all") == 0)
			{
				slimproto_debug = true;
				slimaudio_debug = true;
				slimaudio_buffer_debug = true;
				slimaudio_buffer_debug_v = true;
				slimaudio_decoder_debug = true;
				slimaudio_decoder_debug_r = true;
				slimaudio_decoder_debug_v = true;
				slimaudio_http_debug = true;
				slimaudio_http_debug_v = true;
				slimaudio_output_debug = true;
				slimaudio_output_debug_v = true;
			}
			else if (strcmp(optarg, "slimproto") == 0)
				slimproto_debug = true;
			else if (strcmp(optarg, "slimaudio") == 0)
				slimaudio_debug = true;
			else if (strcmp(optarg, "slimaudio_buffer") == 0)
				slimaudio_buffer_debug = true;
			else if (strcmp(optarg, "slimaudio_buffer_v") == 0)
				slimaudio_buffer_debug_v = true;
			else if (strcmp(optarg, "slimaudio_decoder") == 0)
				slimaudio_decoder_debug = true;
			else if (strcmp(optarg, "slimaudio_decoder_r") == 0)
				slimaudio_decoder_debug_r = true;
			else if (strcmp(optarg, "slimaudio_decoder_v") == 0)
				slimaudio_decoder_debug_v = true;
			else if (strcmp(optarg, "slimaudio_http") == 0)
				slimaudio_http_debug = true;
			else if (strcmp(optarg, "slimaudio_http_v") == 0)
				slimaudio_http_debug_v = true;
			else if (strcmp(optarg, "slimaudio_output") == 0)
				slimaudio_output_debug = true;
			else if (strcmp(optarg, "slimaudio_output_v") == 0)
				slimaudio_output_debug_v = true;
			else
				fprintf(stderr, "%s: Unknown debug option %s\n", argv[0], optarg);
#else
				fprintf(stderr, "%s: Recompile with -DSLIMPROTO_DEBUG to enable debugging.\n", argv[0]);
#endif
			break;
		case 'Y':
#ifdef SLIMPROTO_DEBUG
                        if ( optarg == NULL )
                        {
                                fprintf(stderr, "%s: Cannot parse debug log filename %s\n", argv[0], optarg);
                                exit(-1);
                        } else
                        {
				debuglog = freopen( optarg, "a", stderr);
				if ( debuglog )
					debug_logfile = true;
				else
					fprintf(stderr, "%s: Redirection of stderr to %s failed.\n", argv[0], optarg);
                        }
#endif
			break;

/* From server/Slim/Networking/Slimproto.pm from 7.5r28596
** squeezebox(2)
** softsqueeze(3)
** squeezebox2(4)
** transporter(5)
** softsqueeze3(6)
** receiver(7)
** squeezeslave(8)
** controller(9)
** boom(10)
** softboom(11)
** squeezeplay(12)
** radio(13)
** touch(14)
*/
		case 'e':
			player_type = strtoul(optarg, NULL, 0);
			if ( (player_type < 2) || (player_type > 14) )
			{
				player_type = PLAYER_TYPE;
				fprintf(stderr, "%s: Unknown player type, using (%d)\n", argv[0], player_type);
			}
			break;
		case 'f':
			firmware = strtoul(optarg, NULL, 0);
			if ( (firmware < 0) || (firmware > 254) )
			{
				firmware = FIRMWARE_VERSION;
				fprintf(stderr, "%s: Invalid firmware value, using (%d)\n", argv[0], firmware);
			}
			break;
		case 'h':
			print_help();
			exit(0);	
		case 'k':
			keepalive_interval = strtoul(optarg, NULL, 0);
			break;
		case 'T':
			threshold_override = true;
			break;
		case 'O':
			output_threshold = strtoul(optarg, NULL, 0);
			if ( (output_threshold < 0) || (output_threshold > 1000000) )
			{
				output_threshold = OUTPUT_THRESHOLD;
				fprintf(stderr, "%s: Invalid output threshold, using (%d)\n",
					argv[0], output_threshold);
			}
			break;
		case 'm':
			if (parse_macaddress(macaddress, optarg) != 0) {
				fprintf(stderr, "%s: Cannot parse mac address %s\n", argv[0], optarg);
				exit(-1);	
			}
#ifdef SLIMPROTO_ZONES
			default_macaddress = false;
#endif
			break;
#ifdef DAEMONIZE
		case 'M':
			if ( optarg == NULL )
			{
				fprintf(stderr, "%s: Cannot parse log filename %s\n", argv[0], optarg);
				exit(-1);	
			} else
			{
				logfile = optarg;
			}
			should_daemonize = true;
			break;
#endif

#ifdef __WIN32__
		case 'H':
			/* Change Window process priority class to HIGH */
			if ( !SetPriorityClass ( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) )
			{
				int dwError = GetLastError();
				fprintf(stderr, "%s: Failed to set priority (%d), using default.\n", argv[0],
					dwError);
			} 
			break;
#ifdef PADEV_WASAPI
		case 'S':
			wasapi_exclusive = false;
			break;
#endif
#endif
#ifdef SLIMPROTO_RENICE
		case 'N':
			renice = true;
			break;
#endif
		case 'n':
			output_device_name = optarg;
			output_change = true;
			break;
		case 'o':
			output_device_id = strtoul(optarg, NULL, 0);
			output_change = true;
			break;
		case 'p':
			output_predelay = strtoul(optarg, NULL, 0);
			break;
		case 'P':
			port = strtoul(optarg, NULL, 0);
			if ( (port < 0) || (port > 65535) )
			{
				port = SLIMPROTOCOL_PORT;
				fprintf(stderr, "%s: Invalid port number, using %d.\n", argv[0], port);
			}
			break;
			break;
#ifdef EMPEG
		case 'Q':
			empeg_puteq_tofile();
			exit(0);
			break;
		case 'q':
			geteq = true;
			break;
#endif
		case 'R':
			retry_connection = true;
			break;
		case 'r':
			retry_connection = true;
			retry_interval = strtoul(optarg, NULL, 0);
			if ( ( retry_interval < 1 ) || ( retry_interval > 120 ) )
			{
				retry_interval = RETRY_DEFAULT;
				fprintf (stderr, "Invalid retry interval, using %d seconds.\n", retry_interval );
			}
			break;
#ifdef INTERACTIVE
		case 'c':
		        free(lircrc);
			lircrc = optarg;
			break;
#ifndef __WIN32__
		case 'i':
			using_lirc = true;
			break;
		case 'l':
			use_lcdd_menu = true;
			break;
		case 'C':
			use_lcdd_menu = true;
			lcdd_compat = true;
			break;
#endif
		case 'D':
			using_curses = 1;
			break;
		case 'w':
			linelen = strtoul(optarg, NULL, 0);
			break;
#endif
		case 'L':
			listdevs = true;
			break;
		case 'I':
			listservers = true;
			break;
		case 'V':
			print_version();
			exit(0);
			break;
		case 'v':
		 	if (strcmp(optarg, "sw") == 0) {
				volume_control = VOLUME_SOFTWARE;
			}
#ifndef PORTAUDIO_DEV
			else if (strcmp(optarg, "on") == 0 ) {
				volume_control = VOLUME_DRIVER;
			}
#endif
			else if (strcmp(optarg, "off") == 0 ) {
				volume_control = VOLUME_NONE;
			}
			break;
#ifdef PORTAUDIO_DEV
		case 'y':
			modify_latency = true;
			user_latency = strtoul(optarg, NULL, 0);

			if ( user_latency > 1000 )
			{
				fprintf (stderr, "Suggested latency invalid, using device default.\n");
				modify_latency = false;
			}
			break;
		case 't':
			hostapi_name = optarg;
			break;
#else
		case 'g':
			pa_framesPerBuffer = strtoul(optarg, NULL, 0);

			if ( (pa_framesPerBuffer > 65536) || (pa_framesPerBuffer < 64) )
			{
				fprintf (stderr,
					"Portaudio frames per buffer invalid, using default (%d).\n",
					PA_FRAMES_PER_BUFFER);
				pa_framesPerBuffer = PA_FRAMES_PER_BUFFER ;
			}
			break;
		case 'j':
			pa_numberOfBuffers = strtoul(optarg, NULL, 0);

			if ( (pa_numberOfBuffers > 64) || (pa_numberOfBuffers < 0) )
			{
				fprintf (stderr,
					"Number of Portaudio buffers invalid, using default (%d).\n",
					PA_NUM_BUFFERS);
				pa_numberOfBuffers = PA_NUM_BUFFERS;
			}
			break;
#endif
#ifdef SLIMPROTO_ZONES
		case 'z':
			if (sscanf(optarg, "%u/%u", &zone, &num_zones) != 2)
			{
				fprintf (stderr, "Invalid zone specification, using default.\n");
			}
			if (num_zones > MAX_ZONES)
			{
				fprintf(stderr, "Number of zones > %d not supported\n", MAX_ZONES);
				zone=0;
				num_zones=1;
			}
			if (num_zones <= zone)
			{
				fprintf (stderr, "Invalid zone specification, using default.\n");
				zone = 0;
				num_zones = 1;
			}
			break;
#endif
		default:
			break;
		}
	}

	if (listdevs) {
		GetAudioDevices(output_device_id, output_device_name, hostapi_name, output_change, true);
		exit(0);
	}

	if (listservers) {
		slimproto_discover(slimserver_address, sizeof(slimserver_address), port, &json_port, true);
		exit(0);
	}

	if (optind < argc)
		strncpy(slimserver_address, argv[optind], sizeof(slimserver_address));

#ifdef DAEMONIZE
	if ( should_daemonize ) {
#ifdef INTERACTIVE
		if ( using_curses || use_lcdd_menu )
		{
			fprintf(stderr, "Daemonize not supported with display modes.\n");
			exit(-1);
		}
		else
#endif
			init_daemonize();
	}
#endif
	signal(SIGTERM, &exit_handler);
	signal(SIGINT, &exit_handler);
	install_restart_handler();

#ifdef INTERACTIVE
	install_toggle_handler();  /*SIGUSR2 to toggle IR/LCD on and off */
#endif
	if (slimproto_init(&slimproto) < 0) {
		fprintf(stderr, "Failed to initialize slimproto\n");
		exit(-1);	
	}

#ifdef SLIMPROTO_ZONES
	if (slimaudio_init(&slimaudio, &slimproto, output_device_id, output_device_name,
		hostapi_name, output_change, zone, num_zones) < 0)
#else
	if (slimaudio_init(&slimaudio, &slimproto, output_device_id, output_device_name,
		hostapi_name, output_change) < 0)
#endif
	{
		fprintf(stderr, "Failed to initialize slimaudio\n");
		exit(-1);
	}
#ifdef SLIMPROTO_ZONES
	if (default_macaddress)
		macaddress[5] += zone;
#endif
#ifdef PORTAUDIO_DEV
	if( modify_latency ) {
		slimaudio_set_latency( &slimaudio, user_latency );
	}
#endif	
	slimaudio_set_renice( &slimaudio, renice );
	slimproto_add_connect_callback(&slimproto, connect_callback, macaddress);

#ifdef INTERACTIVE
	/* Process VFD (display) commands */
	if ( using_curses || using_lirc || use_lcdd_menu )
		slimproto_add_command_callback(&slimproto, "vfdc", vfd_callback, macaddress);
#endif
#ifdef EMPEG
	slimproto_add_command_callback(&slimproto, "grfe", empeg_vfd_callback, macaddress);
	slimproto_add_command_callback(&slimproto, "grfb", empeg_vfdbrt_callback, macaddress);
	slimproto_add_command_callback(&slimproto, "aude", empeg_aude_callback, macaddress);
#endif

	slimaudio_set_volume_control(&slimaudio, volume_control);
	slimaudio_set_output_predelay(&slimaudio, output_predelay, output_predelay_amplitude);

	if (keepalive_interval >= 0) {
		slimaudio_set_keepalive_interval(&slimaudio, keepalive_interval);
	}

#ifdef INTERACTIVE
	init_lcd();
#endif
#ifdef EMPEG
	empeg_init();
	if (geteq)
	   empeg_geteq_fromfile();
	power_last = empeg_state.power_on;
	empeg_state.power_on = false;
#endif

	if (slimaudio_open(&slimaudio) < 0) {
		fprintf(stderr, "Failed to open slimaudio\n");
		exit_code = -1;
		goto exit;
	}

#ifdef SLIMPROTO_DEBUG
	if (slimaudio_debug)
		fprintf ( stderr, "Using audio device index: %d\n", slimaudio.output_device_id );
#endif

#ifdef INTERACTIVE
        init_lirc();

	setlocale(LC_ALL, "");
	initcurses();
#endif
#ifdef DAEMONIZE
	if ( should_daemonize ) {
		daemonize(logfile);
	}
#endif
	/* When retry_connection is true, retry connecting to Squeezebox Server 
	** until we succeed, unless the signal handler tells us to give up.
	*/
	do {
		if (signal_restart_flag) { 
#ifdef INTERACTIVE
			exitcurses();
#endif
			fprintf(stderr,"Retry in %d seconds.\n", retry_interval);
			Pa_Sleep(1000 * retry_interval);
#ifdef INTERACTIVE
	   	        initcurses();
#endif
		}
#ifdef EMPEG
		if (discover_server && empeg_state.last_server[0] != '\0')
		{
			strcpy(slimserver_address, (char *)empeg_state.last_server);
			empeg_state.last_server[0] = '\0';
		}
		else
#endif
		if (discover_server && slimproto_discover(slimserver_address,
			sizeof(slimserver_address), port, &json_port, false) < 0)
		{
			fprintf(stderr,"Discover failed.\n");
			if (!retry_connection) {
				exit_code = -1;
				goto exit;
			}
			signal_restart_flag = true;
			continue;
		}

		if (slimproto_connect(
			&slimproto, slimserver_address, port) < 0) {
			fprintf(stderr, "Connection to Squeezebox Server %s failed.\n", slimserver_address);
			if (!retry_connection) {
				exit_code = -1;
				goto exit;
			}
			signal_restart_flag = true;
			continue;
		}
		signal_restart_flag = false;
		discover_server = false;
#ifdef EMPEG
		strcpy((char *)empeg_state.last_server, slimserver_address);
		if (power_last)
			while (!empeg_state.power_on)
			{
				Pa_Sleep(100);
				slimproto_ir(&slimproto, 1, 1, 0x76898F70);
			}
#endif
                while (!signal_exit_flag && !signal_restart_flag) {
#ifdef EMPEG
		   int rc = empeg_idle();
		   if (power_bypass)
		   {
		      if (rc == 0 || !empeg_state.power_on)
		      {
		         power_last = false;
		         power_bypass = false;
		      }
		   }
		   else if (rc == -1)
		   {
		      fprintf(stderr, "Power loss detected.\n");
		      power_last = empeg_state.power_on;
                      slimproto_ir(&slimproto, 1, 1, 0x76898778);
		      while (empeg_state.power_on)
		         Pa_Sleep(250);
		   }
		   else if (rc == -2 && empeg_state.power_on)
		   {
		      fprintf(stderr, "Manual override, aborting power down.\n");
		      power_bypass = true;
		   }
		   else if (rc == -3)
		   {
		      fprintf(stderr, "Power restored.\n");
		      if (power_last)
                         slimproto_ir(&slimproto, 1, 1, 0x76898F70);
		   }
		   else if (rc == -4)
		   {
		      fprintf(stderr, "Powering down.\n");
		      slimproto_goodbye(&slimproto, 0x00);
		      Pa_Sleep(400);
		      slimproto_close(&slimproto);
		      empeg_state.power_on = power_last;
		      empeg_poweroff();
		      signal_restart_flag = true;
		   }
#endif
#ifdef INTERACTIVE
                   if (using_curses == 1 || use_lcdd_menu || using_lirc) {
                      FD_ZERO(&read_fds);
                      FD_ZERO(&write_fds);
		      if (using_curses == 1)
     	                 FD_SET(0, &read_fds); /* watch stdin */
   	              if  (use_lcdd_menu) {
		         FD_SET(lcd_fd, &read_fds); 
		         maxfd = lcd_fd;
		      }
   	              if (using_lirc) {
		         FD_SET(lirc_fd, &read_fds); 
                         if (lirc_fd > maxfd) 
		            maxfd = lirc_fd;
                      }
		      timeout.tv_sec = 5;
                      if(select(maxfd + 1, &read_fds, NULL, NULL, &timeout) == -1) {
#ifndef __WIN32__
    	                 if (errno != EINTR)
			 {
		           fprintf(stderr,"Select Error:%d\n", errno);
#else
			 WSAerrno = WSAGetLastError();
			 if ( (WSAerrno != WSAEINTR) && (WSAerrno != WSAENOTSOCK) )
			 {	
		           fprintf(stderr,"Select Error:%d\n", WSAerrno);
#endif
   	                   abort();
	                 }
#ifdef __WIN32__
			 else
				 WaitForSingleObject( GetStdHandle(STD_INPUT_HANDLE), 5000 );
#endif
                      }
		      if (FD_ISSET(0, &read_fds)) {
                         while ((key = getch()) != ERR) {
                            ir = getircode(key);
	                    if (ir == (unsigned long) 0x01) {
  		               signal_exit_flag = 1;
                            }else{
			       if (ir != 0) slimproto_ir(&slimproto, 1, 1, ir);
			    }
		         }
		      } 
		      if (using_lirc && FD_ISSET(lirc_fd, &read_fds)) {
                         while((key = read_lirc()) != 0 ) { 
                            ir = getircode(key);
	                    if (ir == 0x01) { 
  		               signal_exit_flag = 1;
                            } else {
			       if (ir != 0) slimproto_ir(&slimproto, 1, 1, ir);
			    }
		         }
		      } 
		      if (use_lcdd_menu && FD_ISSET(lcd_fd, &read_fds)) {
                         while(read_lcd()); 
		      }
		   } else {
                      wait_for_restart_signal();
		   }
#else
#ifdef EMPEG
                   while ((key = empeg_getkey()) != -1)
                   {
                      ir = empeg_getircode(key);
                      if (ir != 0)
                         slimproto_ir(&slimproto, 1, 1, ir);
                   }
#else
                   wait_for_restart_signal();
#endif
#endif
		}
#ifdef INTERACTIVE
                FD_ZERO(&read_fds);
                FD_ZERO(&write_fds);
#endif
        } while (signal_restart_flag && !signal_exit_flag);

exit:
	slimaudio_close(&slimaudio);

	slimproto_goodbye(&slimproto, 0x00);

	/* Wait 200ms for BYE! message send to complete */
	Pa_Sleep(200);

	slimproto_close(&slimproto);

#ifdef INTERACTIVE
	exitcurses();
	close_lirc();
#endif

#if defined(EMPEG) || defined(INTERACTIVE)
	close_lcd();
#endif

#ifdef SLIMPROTO_DEBUG
	if (debug_logfile)
	{
		fclose (debuglog);
	}
#endif

	slimproto_destroy(&slimproto);
	slimaudio_destroy(&slimaudio);

	return exit_code;
} 
Пример #8
0
int main(int argc, char *argv[]) {
	slimproto_t slimproto;
	slimaudio_t slimaudio;

	PaDeviceIndex output_device_id = PA_DEFAULT_DEVICE;

	unsigned int output_predelay = 0;
	unsigned int output_predelay_amplitude = 0;

	slimaudio_volume_t volume_control = VOLUME_SOFTWARE;

	unsigned int retry_interval = RETRY_DEFAULT;

	char macaddress[6] = { 0, 0, 0, 0, 0, 1 };

	int keepalive_interval = -1;

	bool listdevs = false;

#ifdef DAEMONIZE
	bool should_daemonize = false;
	char *logfile = NULL;
#endif


#ifdef INTERACTIVE
        fd_set read_fds;
        fd_set write_fds;
        int key = 0;
        unsigned long ir = 0;
	int maxfd = 0;
	char *home;
	struct timeval timeout;
	timeout.tv_usec = 0;

#ifdef __WIN32__
	int WSAerrno;
	int ptw32_processInitialize (void);
	ptw32_processInitialize();
#endif
        // default lircrc file ($HOME/.lircrc)
	home = getenv("HOME");
	if (home == NULL) home = "";
	lircrc = (char *)malloc((strlen(home) + strlen("/.lircrc") + 1) * sizeof(char));
	strcpy(lircrc,home);
	strcat(lircrc,"/.lircrc");
#endif

	char getopt_options[OPTLEN] = "a:d:Y:e:f:hk:Lm:o:P:p:Rr:Vv:";
	static struct option long_options[] = {
		{"predelay_amplitude", required_argument, 0, 'a'},
		{"debug",              required_argument, 0, 'd'},
		{"debuglog",           required_argument, 0, 'Y'},
		{"help",               no_argument,       0, 'h'},
		{"keepalive",          required_argument, 0, 'k'},
		{"list",               no_argument,       0, 'L'},
		{"mac",	               required_argument, 0, 'm'},
		{"output",             required_argument, 0, 'o'},
		{"playerid",           required_argument, 0, 'e'},
		{"firmware",           required_argument, 0, 'f'},
		{"port",               required_argument, 0, 'P'},
		{"predelay",           required_argument, 0, 'p'},
		{"retry",              no_argument,       0, 'R'},
		{"intretry",           required_argument, 0, 'r'},
		{"version",            no_argument,       0, 'V'},
		{"volume",             required_argument, 0, 'v'},
#ifdef PORTAUDIO_DEV
		{"latency",            required_argument, 0, 'y'},
#endif
#ifdef DAEMONIZE
		{"daemonize",          required_argument, 0, 'M'},
#endif
#ifdef __WIN32__
		{"highpriority",       no_argument,       0, 'H'},
#ifdef PA_WASAPI
		{"shared",             no_argument,       0, 'S'},
#endif
#endif
#ifdef INTERACTIVE
		{"lircrc",             required_argument, 0, 'c'},
		{"lirc",               no_argument,       0, 'i'},
		{"lcd",                no_argument,       0, 'l'},
		{"display",            no_argument,       0, 'D'},
		{"width",              required_argument, 0, 'w'},
#endif
		{0, 0, 0, 0}
	};
#ifdef PORTAUDIO_DEV
	strcat (getopt_options, "y:");
#endif	
#ifdef DAEMONIZE	
	strcat (getopt_options, "M:");
#endif
#ifdef INTERACTIVE
	strcat (getopt_options, "c:Dilw:");
#endif
#ifdef __WIN32__
	strcat (getopt_options, "H");
#ifdef PA_WASAPI
	strcat (getopt_options, "S");
#endif
#endif
	while (true) {
		const char shortopt =
			getopt_long_only(argc, argv, getopt_options, long_options, NULL);

		if (shortopt == (char) -1) {
			break;
		}

		switch (shortopt) {
		case 'a':
			output_predelay_amplitude = strtoul(optarg, NULL, 0);
			break;
		case 'd':
#ifdef SLIMPROTO_DEBUG
			if (strcmp(optarg, "all") == 0)
			{
				slimproto_debug = true;
				slimaudio_debug = true;
				slimaudio_buffer_debug = true;
				slimaudio_buffer_debug_v = true;
				slimaudio_decoder_debug = true;
				slimaudio_decoder_debug_r = true;
				slimaudio_decoder_debug_v = true;
				slimaudio_http_debug = true;
				slimaudio_http_debug_v = true;
				slimaudio_output_debug = true;
				slimaudio_output_debug_v = true;
			}
			else if (strcmp(optarg, "slimproto") == 0)
				slimproto_debug = true;
			else if (strcmp(optarg, "slimaudio") == 0)
				slimaudio_debug = true;
			else if (strcmp(optarg, "slimaudio_buffer") == 0)
				slimaudio_buffer_debug = true;
			else if (strcmp(optarg, "slimaudio_buffer_v") == 0)
				slimaudio_buffer_debug_v = true;
			else if (strcmp(optarg, "slimaudio_decoder") == 0)
				slimaudio_decoder_debug = true;
			else if (strcmp(optarg, "slimaudio_decoder_r") == 0)
				slimaudio_decoder_debug_r = true;
			else if (strcmp(optarg, "slimaudio_decoder_v") == 0)
				slimaudio_decoder_debug_v = true;
			else if (strcmp(optarg, "slimaudio_http") == 0)
				slimaudio_http_debug = true;
			else if (strcmp(optarg, "slimaudio_http_v") == 0)
				slimaudio_http_debug_v = true;
			else if (strcmp(optarg, "slimaudio_output") == 0)
				slimaudio_output_debug = true;
			else if (strcmp(optarg, "slimaudio_output_v") == 0)
				slimaudio_output_debug_v = true;
			else
				fprintf(stderr, "%s: Unknown debug option %s\n", argv[0], optarg);
#else
				fprintf(stderr, "%s: Recompile with -DSLIMPROTO_DEBUG to enable debugging.\n", argv[0]);
#endif
			break;
		case 'Y':
#ifdef SLIMPROTO_DEBUG
                        if ( optarg == NULL )
                        {
                                fprintf(stderr, "%s: Cannot parse debug log filename %s\n", argv[0], optarg);
                                exit(-1);
                        } else
                        {
				debuglog = freopen( optarg, "a", stderr);
				if ( debuglog )
					debug_logfile = true;
				else
					fprintf(stderr, "%s: Redirection of stderr to %s failed.\n", argv[0], optarg);
                        }
#endif
			break;

// From server/Slim/Networking/Slimproto.pm from 7.5r28596
// squeezebox(2)
// softsqueeze(3)
// squeezebox2(4)
// transporter(5)
// softsqueeze3(6)
// receiver(7)
// squeezeslave(8)
// controller(9)
// boom(10)
// softboom(11)
// squeezeplay(12)
// radio(13)
// touch(14)

		case 'e':
			player_type = strtoul(optarg, NULL, 0);
			if ( (player_type < 2) || (player_type > 14) )
			{
				player_type = PLAYER_TYPE;
				fprintf(stderr, "%s: Unknown player type, using (%d)\n", argv[0], player_type);
			}
			break;
		case 'f':
			firmware = strtoul(optarg, NULL, 0);
			if ( (firmware < 0) || (firmware > 254) )
			{
				firmware = FIRMWARE_VERSION;
				fprintf(stderr, "%s: Invalid firmware value, using (%d)\n", argv[0], firmware);
			}
			break;
		case 'h':
			print_help();
			exit(0);	
		case 'k':
			keepalive_interval = strtoul(optarg, NULL, 0);
			break;
		case 'm':
			if (parse_macaddress(macaddress, optarg) != 0) {
				fprintf(stderr, "%s: Cannot parse mac address %s\n", argv[0], optarg);
				exit(-1);	
			}
			break;
#ifdef DAEMONIZE
		case 'M':
			if ( optarg == NULL )
			{
				fprintf(stderr, "%s: Cannot parse log filename %s\n", argv[0], optarg);
				exit(-1);	
			} else
			{
				logfile = optarg;
			}
			should_daemonize = true;
			break;
#endif

#ifdef __WIN32__
		case 'H':
			/* Change Window process priority class to HIGH */
			if ( !SetPriorityClass ( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) )
			{
				int dwError = GetLastError();
				fprintf(stderr, "%s: Failed to set priority (%d), using default.\n", argv[0],
					dwError);
			} 
			break;
#ifdef PA_WASAPI
		case 'S':
			wasapi_exclusive = false;
			break;
#endif
#endif
		case 'o':
			output_device_id = strtoul(optarg, NULL, 0);
			output_change = true;
			break;
		case 'p':
			output_predelay = strtoul(optarg, NULL, 0);
			break;
		case 'P':
			port = strtoul(optarg, NULL, 0);
			if ( (port < 0) || (port > 65535) )
			{
				port = SLIMPROTOCOL_PORT;
				fprintf(stderr, "%s: Invalid port value, using (%d)\n", argv[0], port);
			}
			break;
			break;
		case 'R':
			retry_connection = true;
			break;
		case 'r':
			retry_connection = true;
			retry_interval = strtoul(optarg, NULL, 0);
			if ( retry_interval < 1 )
			{
				fprintf (stderr, "Retry option requires value in seconds.\n");
				exit(-1);
			}
			break;
#ifdef INTERACTIVE
		case 'c':
		        free(lircrc);
			lircrc = optarg;
			break;
#ifndef __WIN32__
		case 'i':
			using_lirc = true;
			break;
		case 'l':
			use_lcdd_menu = true;
			break;
#endif
		case 'D':
			using_curses = 1;
			break;
		case 'w':
			linelen = strtoul(optarg, NULL, 0);
			break;
#endif
		case 'L':
			listdevs = true;
			break;
		case 'V':
			print_version();
			exit(0);
			break;
		case 'v':
		 	if (strcmp(optarg, "sw") == 0) {
				volume_control = VOLUME_SOFTWARE;
			}
#ifndef PORTAUDIO_DEV
			else if (strcmp(optarg, "on") == 0 ) {
				volume_control = VOLUME_DRIVER;
			}
#endif
			else if (strcmp(optarg, "off") == 0 ) {
				volume_control = VOLUME_NONE;
			}
			break;
#ifdef PORTAUDIO_DEV
		case 'y':
			modify_latency = true;
			user_latency = strtoul(optarg, NULL, 0);

			if ( user_latency > 1000 )
			{
				fprintf (stderr, "Suggested latency invalid, using device default.\n");
				modify_latency = false;
			}
			break;
#endif
		default:
			break;
		}
	}

	if (listdevs) {
		GetAudioDevices(output_device_id, output_change, true);
		exit(0);
	}

#ifdef DAEMONIZE
	if ( should_daemonize ) {
#ifdef INTERACTIVE
		if ( using_curses || using_lirc || use_lcdd_menu )
		{
			fprintf(stderr, "Daemonize not supported with lirc or display modes.\n");
			exit(-1);
		}
		else
#endif
			init_daemonize();
	}
#endif

	char *slimserver_address = "127.0.0.1";
	if (optind < argc)
		slimserver_address = argv[optind];

	signal(SIGTERM, &exit_handler);
	install_restart_handler();

#ifdef INTERACTIVE
	install_toggle_handler();  //SIGUSR2 to toggle IR/LCD on and off
#endif
	if (slimproto_init(&slimproto) < 0) {
		fprintf(stderr, "Failed to initialize slimproto\n");
		exit(-1);	
	}

	if (slimaudio_init(&slimaudio, &slimproto, output_device_id, output_change) < 0) {
		fprintf(stderr, "Failed to initialize slimaudio\n");
		exit(-1);
	}

	slimproto_add_connect_callback(&slimproto, connect_callback, macaddress);

#ifdef INTERACTIVE
	// Process VFD (display) commands
	if ( using_curses || using_lirc || use_lcdd_menu )
		slimproto_add_command_callback(&slimproto, "vfdc", vfd_callback, macaddress);
#endif

	slimaudio_set_volume_control(&slimaudio, volume_control);
	slimaudio_set_output_predelay(&slimaudio, output_predelay, output_predelay_amplitude);

	if (keepalive_interval >= 0) {
		slimaudio_set_keepalive_interval(&slimaudio, keepalive_interval);
	}

#ifdef INTERACTIVE
	init_lcd();
#endif

	if (slimaudio_open(&slimaudio) < 0) {
		fprintf(stderr, "Failed to open slimaudio\n");
#ifdef INTERACTIVE
		close (lcd_fd);
#endif
		exit(-1);
	}

#ifdef SLIMPROTO_DEBUG
	if (slimaudio_debug)
		fprintf ( stderr, "Using audio device index: %d\n", slimaudio.output_device_id );
#endif

#ifdef INTERACTIVE
        init_lirc();

	setlocale(LC_ALL, "");
	initcurses();
#endif
#ifdef DAEMONIZE
	if ( should_daemonize ) {
		daemonize(logfile);
	}
#endif
	// When retry_connection is true, retry connecting to Squeezebox Server 
	// until we succeed, unless the signal handler tells us to give up.
	do {
		while (slimproto_connect(
			&slimproto, slimserver_address, port) < 0) {
			if (!retry_connection || signal_exit_flag) {
				if (signal_exit_flag) {
					// No message when the exit is triggered
					// by the user.
#ifdef INTERACTIVE
					exitcurses();
					close_lirc();
					close_lcd();
#endif
					exit(0);
				}
#ifdef INTERACTIVE
				exitcurses();
				close_lirc();
				close_lcd();
#endif
				fprintf(stderr, "Connection to Squeezebox Server %s failed.\n", slimserver_address);
				exit(-1);
			}
#ifdef INTERACTIVE
			exitcurses();
#endif
			fprintf(stderr,"Retry in %d seconds.\n", retry_interval);
			Pa_Sleep(1000 * retry_interval);
#ifdef INTERACTIVE
	   	        initcurses();
#endif
		}
                signal_restart_flag = false;
                while (!signal_exit_flag && !signal_restart_flag) {
#ifdef INTERACTIVE
                   if (using_curses == 1 || use_lcdd_menu) {
                      FD_ZERO(&read_fds);
                      FD_ZERO(&write_fds);
		      if (using_curses == 1)
     	                 FD_SET(0, &read_fds); /* watch stdin */
   	              if (use_lcdd_menu) {
		         FD_SET(lcd_fd, &read_fds); 
		         maxfd = lcd_fd;
		      }
   	              if (using_lirc) {
		         FD_SET(lirc_fd, &read_fds); 
                         if (lirc_fd > maxfd) 
		            maxfd = lirc_fd;
                      }
		      timeout.tv_sec = 5;
                      if(select(maxfd + 1, &read_fds, NULL, NULL, &timeout) == -1) {
#ifndef __WIN32__
    	                 if (errno != EINTR)
			 {
		           fprintf(stderr,"Select Error:%d\n", errno);
#else
			 WSAerrno = WSAGetLastError();
			 if ( (WSAerrno != WSAEINTR) && (WSAerrno != WSAENOTSOCK) )
			 {	
		           fprintf(stderr,"Select Error:%d\n", WSAerrno);
#endif
   	                   abort();
	                 }
#ifdef __WIN32__
			 else
				 WaitForSingleObject( GetStdHandle(STD_INPUT_HANDLE), 5000 );
#endif
                      }
		      if (FD_ISSET(0, &read_fds)) {
                         while ((key = getch()) != ERR) {
                            ir = getircode(key);
	                    if (ir == (unsigned long) 0x01) {
  		               signal_exit_flag = 1;
                            }else{
			       if (ir != 0) slimproto_ir(&slimproto, 1, 1, ir);
			    }
		         }
		      } 
		      if (using_lirc && FD_ISSET(lirc_fd, &read_fds)) {
                         while((key = read_lirc()) != 0 ) { 
                            ir = getircode(key);
	                    if (ir == 0x01) { 
  		               signal_exit_flag = 1;
                            } else {
			       if (ir != 0) slimproto_ir(&slimproto, 1, 1, ir);
			    }
		         }
		      } 
		      if (use_lcdd_menu && FD_ISSET(lcd_fd, &read_fds)) {
                         while(read_lcd()); 
		      }
		   } else {
                      wait_for_restart_signal();
		   }
#else
                   wait_for_restart_signal();
#endif
		}
#ifdef INTERACTIVE
                FD_ZERO(&read_fds);
                FD_ZERO(&write_fds);
#endif
		if (signal_restart_flag) { 
#ifdef INTERACTIVE
			exitcurses();
#endif
			fprintf(stderr,"Retry in %d seconds.\n", retry_interval);
			Pa_Sleep(1000 * retry_interval);
#ifdef INTERACTIVE
	   	        initcurses();
#endif
		}
        } while (signal_restart_flag && !signal_exit_flag);

#ifdef INTERACTIVE
	close_lirc();
#endif
	slimaudio_close(&slimaudio);
	slimproto_close(&slimproto);

#ifdef INTERACTIVE
        exitcurses();
        close_lcd();
#endif
#ifdef SLIMPROTO_DEBUG
	if (debug_logfile)
	{
		fclose (debuglog);
	}
#endif
	slimaudio_destroy(&slimaudio);
	slimproto_destroy(&slimproto);
	return 0;
} 
Пример #9
0
void OBS::Start()
{
    if(bRunning) return;

    OSEnterMutex (hStartupShutdownMutex);

    scenesConfig.Save();

    //-------------------------------------------------------------

    fps = AppConfig->GetInt(TEXT("Video"), TEXT("FPS"), 30);
    frameTime = 1000/fps;

    //-------------------------------------------------------------

    if(!bLoggedSystemStats)
    {
        LogSystemStats();
        bLoggedSystemStats = TRUE;
    }

    //-------------------------------------------------------------

    if (OSIncompatibleModulesLoaded())
    {
        OSLeaveMutex (hStartupShutdownMutex);
        MessageBox(hwndMain, Str("IncompatibleModules"), NULL, MB_ICONERROR);
        Log(TEXT("Incompatible modules detected."));
        return;
    }

    String strPatchesError;
    if (OSIncompatiblePatchesLoaded(strPatchesError))
    {
        OSLeaveMutex (hStartupShutdownMutex);
        MessageBox(hwndMain, strPatchesError.Array(), NULL, MB_ICONERROR);
        Log(TEXT("Incompatible patches detected."));
        return;
    }

    //-------------------------------------------------------------

    int networkMode = AppConfig->GetInt(TEXT("Publish"), TEXT("Mode"), 2);
    DWORD delayTime = (DWORD)AppConfig->GetInt(TEXT("Publish"), TEXT("Delay"));

    String strError;

    if(bTestStream)
        network = CreateNullNetwork();
    else
    {
        switch(networkMode)
        {
        case 0: network = (delayTime > 0) ? CreateDelayedPublisher(delayTime) : CreateRTMPPublisher(); break;
        case 1: network = CreateNullNetwork(); break;
        }
    }

    if(!network)
    {
        OSLeaveMutex (hStartupShutdownMutex);

        if(!bReconnecting)
            MessageBox(hwndMain, strError, NULL, MB_ICONERROR);
        else
            DialogBox(hinstMain, MAKEINTRESOURCE(IDD_RECONNECTING), hwndMain, OBS::ReconnectDialogProc);
        return;
    }

    bReconnecting = false;

    //-------------------------------------------------------------

    Log(TEXT("=====Stream Start: %s==============================================="), CurrentDateTime().Array());

    //-------------------------------------------------------------

    int monitorID = AppConfig->GetInt(TEXT("Video"), TEXT("Monitor"));
    if(monitorID >= (int)monitors.Num())
        monitorID = 0;

    RECT &screenRect = monitors[monitorID].rect;
    int defCX = screenRect.right  - screenRect.left;
    int defCY = screenRect.bottom - screenRect.top;

    downscaleType = AppConfig->GetInt(TEXT("Video"), TEXT("Filter"), 0);
    downscale = AppConfig->GetFloat(TEXT("Video"), TEXT("Downscale"), 1.0f);
    baseCX = AppConfig->GetInt(TEXT("Video"), TEXT("BaseWidth"),  defCX);
    baseCY = AppConfig->GetInt(TEXT("Video"), TEXT("BaseHeight"), defCY);

    baseCX = MIN(MAX(baseCX, 128), 4096);
    baseCY = MIN(MAX(baseCY, 128), 4096);

    scaleCX = UINT(double(baseCX) / double(downscale));
    scaleCY = UINT(double(baseCY) / double(downscale));

    //align width to 128bit for fast SSE YUV4:2:0 conversion
    outputCX = scaleCX & 0xFFFFFFFC;
    outputCY = scaleCY & 0xFFFFFFFE;

    bUseMultithreadedOptimizations = AppConfig->GetInt(TEXT("General"), TEXT("UseMultithreadedOptimizations"), TRUE) != 0;
    Log(TEXT("  Multithreaded optimizations: %s"), (CTSTR)(bUseMultithreadedOptimizations ? TEXT("On") : TEXT("Off")));

    GlobalConfig->SetInt(TEXT("Audio"), TEXT("GlobalAudioTimeAdjust"), 0);

    //------------------------------------------------------------------

    Log(TEXT("  Base resolution: %ux%u"), baseCX, baseCY);
    Log(TEXT("  Output resolution: %ux%u"), outputCX, outputCY);
    Log(TEXT("------------------------------------------"));

    //------------------------------------------------------------------

    GS = new D3D10System;
    GS->Init();

    //-------------------------------------------------------------

    mainVertexShader    = CreateVertexShaderFromFile(TEXT("shaders/DrawTexture.vShader"));
    mainPixelShader     = CreatePixelShaderFromFile(TEXT("shaders/DrawTexture.pShader"));

    solidVertexShader   = CreateVertexShaderFromFile(TEXT("shaders/DrawSolid.vShader"));
    solidPixelShader    = CreatePixelShaderFromFile(TEXT("shaders/DrawSolid.pShader"));

    //------------------------------------------------------------------

    CTSTR lpShader;
    if(CloseFloat(downscale, 1.0))
        lpShader = TEXT("shaders/DrawYUVTexture.pShader");
    else if(downscale < 2.01)
    {
        switch(downscaleType)
        {
            case 0: lpShader = TEXT("shaders/DownscaleBilinear1YUV.pShader"); break;
            case 1: lpShader = TEXT("shaders/DownscaleBicubicYUV.pShader"); break;
            case 2: lpShader = TEXT("shaders/DownscaleLanczos6tapYUV.pShader"); break;
        }
    }
    else if(downscale < 3.01)
        lpShader = TEXT("shaders/DownscaleBilinear9YUV.pShader");
    else
        CrashError(TEXT("Invalid downscale value (must be either 1.0, 1.5, 2.0, 2.25, or 3.0)"));

    yuvScalePixelShader = CreatePixelShaderFromFile(lpShader);
    if (!yuvScalePixelShader)
        CrashError(TEXT("Unable to create shader from file %s"), lpShader);

    //-------------------------------------------------------------

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        mainRenderTextures[i] = CreateRenderTarget(baseCX, baseCY, GS_BGRA, FALSE);
        yuvRenderTextures[i]  = CreateRenderTarget(outputCX, outputCY, GS_BGRA, FALSE);
    }

    //-------------------------------------------------------------

    D3D10_TEXTURE2D_DESC td;
    zero(&td, sizeof(td));
    td.Width            = outputCX;
    td.Height           = outputCY;
    td.Format           = DXGI_FORMAT_B8G8R8A8_UNORM;
    td.MipLevels        = 1;
    td.ArraySize        = 1;
    td.SampleDesc.Count = 1;
    td.ArraySize        = 1;
    td.Usage            = D3D10_USAGE_STAGING;
    td.CPUAccessFlags   = D3D10_CPU_ACCESS_READ;

    for(UINT i=0; i<NUM_RENDER_BUFFERS; i++)
    {
        HRESULT err = GetD3D()->CreateTexture2D(&td, NULL, &copyTextures[i]);
        if(FAILED(err))
        {
            CrashError(TEXT("Unable to create copy texture"));
            //todo - better error handling
        }
    }

    //-------------------------------------------------------------

    AudioDeviceList playbackDevices;
    GetAudioDevices(playbackDevices, ADT_PLAYBACK);

    String strPlaybackDevice = AppConfig->GetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default"));
    if(strPlaybackDevice.IsEmpty() || !playbackDevices.HasID(strPlaybackDevice))
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("PlaybackDevice"), TEXT("Default"));
        strPlaybackDevice = TEXT("Default");
    }

    Log(TEXT("Playback device %s"), strPlaybackDevice.Array());
    playbackDevices.FreeData();

    desktopAudio = CreateAudioSource(false, strPlaybackDevice);

    if(!desktopAudio) {
        CrashError(TEXT("Cannot initialize desktop audio sound, more info in the log file."));
    }

    AudioDeviceList audioDevices;
    GetAudioDevices(audioDevices, ADT_RECORDING);

    String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL);
    if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice))
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable"));
        strDevice = TEXT("Disable");
    }

    audioDevices.FreeData();

    String strDefaultMic;
    bool bHasDefault = GetDefaultMicID(strDefaultMic);

    if(strDevice.CompareI(TEXT("Disable")))
        EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE);
    else
    {
        bool bUseDefault = strDevice.CompareI(TEXT("Default")) != 0;
        if(!bUseDefault || bHasDefault)
        {
            if(bUseDefault)
                strDevice = strDefaultMic;

            micAudio = CreateAudioSource(true, strDevice);

            if(!micAudio)
                MessageBox(hwndMain, Str("MicrophoneFailure"), NULL, 0);
            else
                micAudio->SetTimeOffset(AppConfig->GetInt(TEXT("Audio"), TEXT("MicTimeOffset"), 0));

            EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), micAudio != NULL);
        }
        else
            EnableWindow(GetDlgItem(hwndMain, ID_MICVOLUME), FALSE);
    }

    //-------------------------------------------------------------

    UINT bitRate = (UINT)AppConfig->GetInt(TEXT("Audio Encoding"), TEXT("Bitrate"), 96);
    String strEncoder = AppConfig->GetString(TEXT("Audio Encoding"), TEXT("Codec"), TEXT("AAC"));

#ifdef USE_AAC
    if(strEncoder.CompareI(TEXT("AAC")) && OSGetVersion() >= 7)
        audioEncoder = CreateAACEncoder(bitRate);
    else
#endif
        audioEncoder = CreateMP3Encoder(bitRate);

    //-------------------------------------------------------------

    desktopVol = AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f);
    micVol     = AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"),     1.0f);

    //-------------------------------------------------------------

    bRunning = true;

    if(sceneElement)
    {
        scene = CreateScene(sceneElement->GetString(TEXT("class")), sceneElement->GetElement(TEXT("data")));
        XElement *sources = sceneElement->GetElement(TEXT("sources"));
        if(sources)
        {
            UINT numSources = sources->NumElements();
            for(UINT i=0; i<numSources; i++)
            {
                SceneItem *item = scene->AddImageSource(sources->GetElementByID(i));
                if(item)
                {
                    if(ListView_GetItemState(GetDlgItem(hwndMain, ID_SOURCES), i, LVIS_SELECTED) > 0)
                        item->Select(true);
                }
            }
        }

        scene->BeginScene();
    }

    if(scene && scene->HasMissingSources())
        MessageBox(hwndMain, Str("Scene.MissingSources"), NULL, 0);

    //-------------------------------------------------------------

    int maxBitRate = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("MaxBitrate"), 1000);
    int bufferSize = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("BufferSize"), 1000);
    int quality    = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("Quality"),    8);
    String preset  = AppConfig->GetString(TEXT("Video Encoding"), TEXT("Preset"),     TEXT("veryfast"));
    bUsing444      = AppConfig->GetInt   (TEXT("Video Encoding"), TEXT("Use444"),     0) != 0;

    bDupeFrames = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("DupeFrames"), 1) != 0;

    if(bUsing444)
        bDupeFrames = bUseCFR = false;
    else
    {
        bUseCFR = AppConfig->GetInt(TEXT("Video Encoding"), TEXT("UseCFR"), 0) != 0;
        if(bUseCFR) bDupeFrames = true;
    }

    //-------------------------------------------------------------

    bWriteToFile = networkMode == 1 || AppConfig->GetInt(TEXT("Publish"), TEXT("SaveToFile")) != 0;
    String strOutputFile = AppConfig->GetString(TEXT("Publish"), TEXT("SavePath"));

    strOutputFile.FindReplace(TEXT("\\"), TEXT("/"));

    if (bWriteToFile)
    {
        OSFindData ofd;
        HANDLE hFind = NULL;
        bool bUseDateTimeName = true;

        if(hFind = OSFindFirstFile(strOutputFile, ofd))
        {
            String strFileExtension = GetPathExtension(strOutputFile);
            String strFileWithoutExtension = GetPathWithoutExtension(strOutputFile);

            if(strFileExtension.IsValid() && !ofd.bDirectory)
            {
                String strNewFilePath;
                UINT curFile = 0;

                do 
                {
                    strNewFilePath.Clear() << strFileWithoutExtension << TEXT(" (") << FormattedString(TEXT("%02u"), ++curFile) << TEXT(").") << strFileExtension;
                } while(OSFileExists(strNewFilePath));

                strOutputFile = strNewFilePath;

                bUseDateTimeName = false;
            }

            if(ofd.bDirectory)
                strOutputFile.AppendChar('/');

            OSFindClose(hFind);
        }

        if(bUseDateTimeName)
        {
            String strFileName = GetPathFileName(strOutputFile);

            if(!strFileName.IsValid() || !IsSafeFilename(strFileName))
            {
                SYSTEMTIME st;
                GetLocalTime(&st);

                String strDirectory = GetPathDirectory(strOutputFile);
                strOutputFile = FormattedString(TEXT("%s/%u-%02u-%02u-%02u%02u-%02u.mp4"), strDirectory.Array(), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
            }
        }
    }

    //-------------------------------------------------------------

    bufferingTime = GlobalConfig->GetInt(TEXT("General"), TEXT("SceneBufferingTime"), 400);

    //-------------------------------------------------------------

    bForceMicMono = AppConfig->GetInt(TEXT("Audio"), TEXT("ForceMicMono")) != 0;
    bRecievedFirstAudioFrame = false;

    //hRequestAudioEvent = CreateSemaphore(NULL, 0, 0x7FFFFFFFL, NULL);
    hSoundDataMutex = OSCreateMutex();
    hSoundThread = OSCreateThread((XTHREAD)OBS::MainAudioThread, NULL);

    //-------------------------------------------------------------

    StartBlankSoundPlayback(strPlaybackDevice);

    //-------------------------------------------------------------

    ctsOffset = 0;
    videoEncoder = CreateX264Encoder(fps, outputCX, outputCY, quality, preset, bUsing444, maxBitRate, bufferSize, bUseCFR, bDupeFrames);

    //-------------------------------------------------------------

    // Ensure that the render frame is properly sized
    ResizeRenderFrame(true);

    //-------------------------------------------------------------

    if(!bTestStream && bWriteToFile && strOutputFile.IsValid())
    {
        String strFileExtension = GetPathExtension(strOutputFile);
        if(strFileExtension.CompareI(TEXT("flv")))
            fileStream = CreateFLVFileStream(strOutputFile);
        else if(strFileExtension.CompareI(TEXT("mp4")))
            fileStream = CreateMP4FileStream(strOutputFile);
    }

    //-------------------------------------------------------------

    hMainThread = OSCreateThread((XTHREAD)OBS::MainCaptureThread, NULL);

    if(bTestStream)
    {
        EnableWindow(GetDlgItem(hwndMain, ID_STARTSTOP), FALSE);
        SetWindowText(GetDlgItem(hwndMain, ID_TESTSTREAM), Str("MainWindow.StopTest"));
    }
    else
    {
        EnableWindow(GetDlgItem(hwndMain, ID_TESTSTREAM), FALSE);
        SetWindowText(GetDlgItem(hwndMain, ID_STARTSTOP), Str("MainWindow.StopStream"));
    }

    EnableWindow(GetDlgItem(hwndMain, ID_SCENEEDITOR), TRUE);

    //-------------------------------------------------------------

    ReportStartStreamTrigger();
    
    SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, 0, 0, 0);
    SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED | ES_DISPLAY_REQUIRED);

    UpdateRenderViewMessage();

    //update notification icon to reflect current status
    UpdateNotificationAreaIcon();

    OSLeaveMutex (hStartupShutdownMutex);
}
Пример #10
0
void OBS::ReloadIniSettings()
{
    HWND hwndTemp;

    //-------------------------------------------
    // mic volume data
    hwndTemp = GetDlgItem(hwndMain, ID_MICVOLUME);

    if(!AppConfig->HasKey(TEXT("Audio"), TEXT("MicVolume")))
        AppConfig->SetFloat(TEXT("Audio"), TEXT("MicVolume"), 0.0f);
    SetVolumeControlValue(hwndTemp, AppConfig->GetFloat(TEXT("Audio"), TEXT("MicVolume"), 0.0f));

    AudioDeviceList audioDevices;
    GetAudioDevices(audioDevices, ADT_RECORDING);

    String strDevice = AppConfig->GetString(TEXT("Audio"), TEXT("Device"), NULL);
    if(strDevice.IsEmpty() || !audioDevices.HasID(strDevice))
    {
        AppConfig->SetString(TEXT("Audio"), TEXT("Device"), TEXT("Disable"));
        strDevice = TEXT("Disable");
    }

    audioDevices.FreeData();

    EnableWindow(hwndTemp, !strDevice.CompareI(TEXT("Disable")));

    //-------------------------------------------
    // desktop volume
    hwndTemp = GetDlgItem(hwndMain, ID_DESKTOPVOLUME);

    if(!AppConfig->HasKey(TEXT("Audio"), TEXT("DesktopVolume")))
        AppConfig->SetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 1.0f);
    SetVolumeControlValue(hwndTemp, AppConfig->GetFloat(TEXT("Audio"), TEXT("DesktopVolume"), 0.0f));

    //-------------------------------------------
    // mic boost
    DWORD micBoostPercentage = AppConfig->GetInt(TEXT("Audio"), TEXT("MicBoostMultiple"), 1);
    if(micBoostPercentage < 1)
        micBoostPercentage = 1;
    else if(micBoostPercentage > 20)
        micBoostPercentage = 20;
    micBoost = float(micBoostPercentage);

    //-------------------------------------------
    // dashboard
    strDashboard = AppConfig->GetString(TEXT("Publish"), TEXT("Dashboard"));
    strDashboard.KillSpaces();

    //-------------------------------------------
    // hotkeys
    QuickClearHotkey(pushToTalkHotkeyID);
    QuickClearHotkey(muteMicHotkeyID);
    QuickClearHotkey(muteDesktopHotkeyID);
    QuickClearHotkey(stopStreamHotkeyID);
    QuickClearHotkey(startStreamHotkeyID);

    bUsingPushToTalk = AppConfig->GetInt(TEXT("Audio"), TEXT("UsePushToTalk")) != 0;
    DWORD hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("PushToTalkHotkey"));
    pushToTalkDelay = AppConfig->GetInt(TEXT("Audio"), TEXT("PushToTalkDelay"), 200);

    if(bUsingPushToTalk && hotkey)
        pushToTalkHotkeyID = API->CreateHotkey(hotkey, OBS::PushToTalkHotkey, NULL);

    hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("MuteMicHotkey"));
    if(hotkey)
        muteMicHotkeyID = API->CreateHotkey(hotkey, OBS::MuteMicHotkey, NULL);

    hotkey = AppConfig->GetInt(TEXT("Audio"), TEXT("MuteDesktopHotkey"));
    if(hotkey)
        muteDesktopHotkeyID = API->CreateHotkey(hotkey, OBS::MuteDesktopHotkey, NULL);

    hotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StopStreamHotkey"));
    if(hotkey)
        stopStreamHotkeyID = API->CreateHotkey(hotkey, OBS::StopStreamHotkey, NULL);

    hotkey = AppConfig->GetInt(TEXT("Publish"), TEXT("StartStreamHotkey"));
    if(hotkey)
        startStreamHotkeyID = API->CreateHotkey(hotkey, OBS::StartStreamHotkey, NULL);
}