<commit_before>//
// Copyright (c) 2020, Marc Deslauriers
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "CRallyXBaseGame.h"
#include "CZ80ACpu.h"
#include <DFR_Key.h>

//
// Probe Head GND:
//   Z80 GND Pin 29
//
// Watchdog Disable:
//   TBD - Probably doesn't need to be disabled
//
// Board Designations:
//   c - CPU board
//   v - Video board
//
// Z80 Compatibility Notes
//   VBLANK interrupt is only activated with a write to INT ON at 0x0a181

//
// RAM region is the same for all games on this board set.
//
static const RAM_REGION s_ramRegion[] PROGMEM = { //                                            "012", "012345"
                                                  {NO_BANK_SWITCH, 0x008000, 0x0083FF, 1, 0x0F, " 6C", "RadRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008000, 0x0083FF, 1, 0xF0, " 6A", "RadRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008400, 0x0087FF, 1, 0x0F, " 6D", "TilRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008400, 0x0087FF, 1, 0xF0, " 6B", "TilRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008800, 0x008BFF, 1, 0x0F, " 6K", "RadRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008800, 0x008BFF, 1, 0xF0, " 6J", "RadRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008C00, 0x008FFF, 1, 0x0F, " 6L", "TilRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008C00, 0x008FFF, 1, 0xF0, " 6H", "TilRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x009800, 0x009BFF, 1, 0x0F, " 6M", "WorRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x009800, 0x009BFF, 1, 0xF0, " 6F", "WorRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x009C00, 0x009FFF, 1, 0x0F, " 6N", "WorRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x009C00, 0x009FFF, 1, 0xF0, " 6E", "WorRam"}, // 2114
                                                  {0}
                                                }; // end of list

//
// RAM region is the same for all games on this board set.
//
static const RAM_REGION s_ramRegionByteOnly[] PROGMEM = { //                                            "012", "012345"
                                                          {NO_BANK_SWITCH, 0x008000, 0x0083FF, 1, 0xFF, "6AC", "RadRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x008400, 0x0087FF, 1, 0xFF, "6BD", "TilRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x008800, 0x008BFF, 1, 0xFF, "6JK", "RadRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x008C00, 0x008FFF, 1, 0xFF, "6HL", "TilRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x009800, 0x009BFF, 1, 0xFF, "6FM", "WorRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x009C00, 0x009FFF, 1, 0xFF, "6EN", "WorRam"}, // 2114
                                                          {0}
                                                        }; // end of list

//
// RAM region is the same for all games on this board set.
//
static const RAM_REGION s_ramRegionWriteOnly[] PROGMEM = { // "012", "012345"
                                                           {0}
                                                         }; // end of list

//
// Input region is the same for all games on this board set.
//
static const INPUT_REGION s_inputRegion[] PROGMEM = { //                             "012", "012345"
                                                      {NO_BANK_SWITCH, 0xa000, 0xFF, "   ", "P1    "},
                                                      {NO_BANK_SWITCH, 0xa080, 0xFF, "   ", "P2    "},
                                                      {NO_BANK_SWITCH, 0xa100, 0xFF, "   ", "DSW   "},
                                                      {0}
                                                    }; // end of list

//
// Output region is the same for all versions on this board set.
//
static const OUTPUT_REGION s_outputRegion[] PROGMEM = { //                                    "012", "012345"
                                                        {NO_BANK_SWITCH, 0x0a080, 0x01, 0x00, "12P", "WatchD"}, //
                                                        {NO_BANK_SWITCH, 0x0a130, 0x01, 0x00, "   ", "ScrolX"}, //
                                                        {NO_BANK_SWITCH, 0x0a140, 0x01, 0x00, "   ", "ScrolY"}, //
                                                        {NO_BANK_SWITCH, 0x0a180, 0x01, 0x00, "12M", "Bang  "}, //
                                                        {NO_BANK_SWITCH, 0x0a181, 0x01, 0x00, "12M", "Int On"}, //
                                                        {NO_BANK_SWITCH, 0x0a182, 0x01, 0x00, "12M", "Snd On"}, //
                                                        {NO_BANK_SWITCH, 0x0a183, 0x01, 0x00, "12M", "FlipSc"}, //
                                                        {NO_BANK_SWITCH, 0x0a184, 0x01, 0x00, "12M", "Led 0 "}, //
                                                        {NO_BANK_SWITCH, 0x0a185, 0x01, 0x00, "12M", "Led 1 "}, //
                                                        {NO_BANK_SWITCH, 0x0a186, 0x01, 0x00, "12M", "CoinLo"}, //
                                                        {NO_BANK_SWITCH, 0x0a187, 0x01, 0x00, "12M", "CoinCo"}, //
                                                        {0}
                                                      }; // end of list

//
// Custom functions implemented for this game.
//
static const CUSTOM_FUNCTION s_customFunction[] PROGMEM = {{NO_CUSTOM_FUNCTION}}; // end of list

CRallyXBaseGame::CRallyXBaseGame(
    const ROM_DATA2N *romData2n,
    const ROM_REGION *romRegion
) : CGame( romData2n,
           romRegion,
           s_ramRegion,
           s_ramRegionByteOnly,
           s_ramRegionWriteOnly,
           s_inputRegion,
           s_outputRegion,
           s_customFunction )
{
    m_cpu = new CZ80ACpu();
    m_cpu = new CZ80ACpu(0,
                         NO_ADDRESS_REMAP,
                         NULL,
                         NO_DATA_REMAP,
                         NULL,
                         CZ80ACpu::CYCLE_TYPE_LADYBUG);
    m_cpu->idle();
}

CRallyXBaseGame::~CRallyXBaseGame(
)
{
    delete m_cpu;
    m_cpu = (ICpu *) NULL;
}

//
// TODO: test interrupt
//
PERROR
CRallyXBaseGame::interruptCheck(
)
{
    return errorNotImplemented;
}

<commit_msg>Added more details on the wait configuration used by Rally-X<commit_after>//
// Copyright (c) 2020, Marc Deslauriers
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "CRallyXBaseGame.h"
#include "CZ80ACpu.h"
#include <DFR_Key.h>

//
// Probe Head GND:
//   Z80 GND Pin 29
//
// Watchdog Disable:
//   TBD - Probably doesn't need to be disabled
//
// Board Designations:
//   c - CPU board
//   v - Video board
//
// Z80 Compatibility Notes
//   * VBLANK interrupt is only activated with a write to INT ON at 0x0a181
//   * While this board has a Sync Bus Controller, it doesn't work with the
//     Puckman wait configuration. It does work with the Ladybug wait
//     configuration though, so that is what is used here.

//
// RAM region is the same for all games on this board set.
//
static const RAM_REGION s_ramRegion[] PROGMEM = { //                                            "012", "012345"
                                                  {NO_BANK_SWITCH, 0x008000, 0x0083FF, 1, 0x0F, " 6C", "RadRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008000, 0x0083FF, 1, 0xF0, " 6A", "RadRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008400, 0x0087FF, 1, 0x0F, " 6D", "TilRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008400, 0x0087FF, 1, 0xF0, " 6B", "TilRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008800, 0x008BFF, 1, 0x0F, " 6K", "RadRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008800, 0x008BFF, 1, 0xF0, " 6J", "RadRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008C00, 0x008FFF, 1, 0x0F, " 6L", "TilRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x008C00, 0x008FFF, 1, 0xF0, " 6H", "TilRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x009800, 0x009BFF, 1, 0x0F, " 6M", "WorRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x009800, 0x009BFF, 1, 0xF0, " 6F", "WorRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x009C00, 0x009FFF, 1, 0x0F, " 6N", "WorRam"}, // 2114
                                                  {NO_BANK_SWITCH, 0x009C00, 0x009FFF, 1, 0xF0, " 6E", "WorRam"}, // 2114
                                                  {0}
                                                }; // end of list

//
// RAM region is the same for all games on this board set.
//
static const RAM_REGION s_ramRegionByteOnly[] PROGMEM = { //                                            "012", "012345"
                                                          {NO_BANK_SWITCH, 0x008000, 0x0083FF, 1, 0xFF, "6AC", "RadRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x008400, 0x0087FF, 1, 0xFF, "6BD", "TilRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x008800, 0x008BFF, 1, 0xFF, "6JK", "RadRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x008C00, 0x008FFF, 1, 0xFF, "6HL", "TilRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x009800, 0x009BFF, 1, 0xFF, "6FM", "WorRam"}, // 2114
                                                          {NO_BANK_SWITCH, 0x009C00, 0x009FFF, 1, 0xFF, "6EN", "WorRam"}, // 2114
                                                          {0}
                                                        }; // end of list

//
// RAM region is the same for all games on this board set.
//
static const RAM_REGION s_ramRegionWriteOnly[] PROGMEM = { // "012", "012345"
                                                           {0}
                                                         }; // end of list

//
// Input region is the same for all games on this board set.
//
static const INPUT_REGION s_inputRegion[] PROGMEM = { //                             "012", "012345"
                                                      {NO_BANK_SWITCH, 0xa000, 0xFF, "   ", "P1    "},
                                                      {NO_BANK_SWITCH, 0xa080, 0xFF, "   ", "P2    "},
                                                      {NO_BANK_SWITCH, 0xa100, 0xFF, "   ", "DSW   "},
                                                      {0}
                                                    }; // end of list

//
// Output region is the same for all versions on this board set.
//
static const OUTPUT_REGION s_outputRegion[] PROGMEM = { //                                    "012", "012345"
                                                        {NO_BANK_SWITCH, 0x0a080, 0x01, 0x00, "12P", "WatchD"}, //
                                                        {NO_BANK_SWITCH, 0x0a130, 0x01, 0x00, "   ", "ScrolX"}, //
                                                        {NO_BANK_SWITCH, 0x0a140, 0x01, 0x00, "   ", "ScrolY"}, //
                                                        {NO_BANK_SWITCH, 0x0a180, 0x01, 0x00, "12M", "Bang  "}, //
                                                        {NO_BANK_SWITCH, 0x0a181, 0x01, 0x00, "12M", "Int On"}, //
                                                        {NO_BANK_SWITCH, 0x0a182, 0x01, 0x00, "12M", "Snd On"}, //
                                                        {NO_BANK_SWITCH, 0x0a183, 0x01, 0x00, "12M", "FlipSc"}, //
                                                        {NO_BANK_SWITCH, 0x0a184, 0x01, 0x00, "12M", "Led 0 "}, //
                                                        {NO_BANK_SWITCH, 0x0a185, 0x01, 0x00, "12M", "Led 1 "}, //
                                                        {NO_BANK_SWITCH, 0x0a186, 0x01, 0x00, "12M", "CoinLo"}, //
                                                        {NO_BANK_SWITCH, 0x0a187, 0x01, 0x00, "12M", "CoinCo"}, //
                                                        {0}
                                                      }; // end of list

//
// Custom functions implemented for this game.
//
static const CUSTOM_FUNCTION s_customFunction[] PROGMEM = {{NO_CUSTOM_FUNCTION}}; // end of list

CRallyXBaseGame::CRallyXBaseGame(
    const ROM_DATA2N *romData2n,
    const ROM_REGION *romRegion
) : CGame( romData2n,
           romRegion,
           s_ramRegion,
           s_ramRegionByteOnly,
           s_ramRegionWriteOnly,
           s_inputRegion,
           s_outputRegion,
           s_customFunction )
{
    m_cpu = new CZ80ACpu();
    m_cpu = new CZ80ACpu(0,
                         NO_ADDRESS_REMAP,
                         NULL,
                         NO_DATA_REMAP,
                         NULL,
                         CZ80ACpu::CYCLE_TYPE_LADYBUG);
    m_cpu->idle();
}

CRallyXBaseGame::~CRallyXBaseGame(
)
{
    delete m_cpu;
    m_cpu = (ICpu *) NULL;
}

//
// TODO: test interrupt
//
PERROR
CRallyXBaseGame::interruptCheck(
)
{
    return errorNotImplemented;
}

<|endoftext|>


<commit_before>//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// EGLSurfaceTest:
//   Tests pertaining to egl::Surface.
//

#include <ANGLETest.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>

#include "common/angleutils.h"
#include "OSWindow.h"

namespace
{

class EGLSurfaceTest : public testing::Test
{
  protected:
    EGLSurfaceTest()
        : mDisplay(EGL_NO_DISPLAY),
          mWindowSurface(EGL_NO_SURFACE),
          mPbufferSurface(EGL_NO_SURFACE),
          mContext(EGL_NO_CONTEXT),
          mSecondContext(EGL_NO_CONTEXT),
          mOSWindow(nullptr)
    {
    }

    void SetUp() override
    {
        mOSWindow = CreateOSWindow();
        mOSWindow->initialize("EGLSurfaceTest", 64, 64);
    }

    // Release any resources created in the test body
    void TearDown() override
    {
        mOSWindow->destroy();
        SafeDelete(mOSWindow);

        if (mDisplay != EGL_NO_DISPLAY)
        {
            eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);

            if (mWindowSurface != EGL_NO_SURFACE)
            {
                eglDestroySurface(mDisplay, mWindowSurface);
                mWindowSurface = EGL_NO_SURFACE;
            }

            if (mPbufferSurface != EGL_NO_SURFACE)
            {
                eglDestroySurface(mDisplay, mPbufferSurface);
                mPbufferSurface = EGL_NO_SURFACE;
            }

            if (mContext != EGL_NO_CONTEXT)
            {
                eglDestroyContext(mDisplay, mContext);
                mContext = EGL_NO_CONTEXT;
            }

            if (mSecondContext != EGL_NO_CONTEXT)
            {
                eglDestroyContext(mDisplay, mSecondContext);
                mSecondContext = EGL_NO_CONTEXT;
            }

            eglTerminate(mDisplay);
            mDisplay = EGL_NO_DISPLAY;
        }

        ASSERT_TRUE(mWindowSurface == EGL_NO_SURFACE && mContext == EGL_NO_CONTEXT);
    }

    void initializeSurface(EGLenum platformType)
    {
        PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
        ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr);

        const EGLint displayAttributes[] =
        {
            EGL_PLATFORM_ANGLE_TYPE_ANGLE, platformType,
            EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE, EGL_DONT_CARE,
            EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE, EGL_DONT_CARE,
            EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
            EGL_NONE,
        };

        mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, mOSWindow->getNativeDisplay(), displayAttributes);
        ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);

        EGLint majorVersion, minorVersion;
        ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_TRUE);

        eglBindAPI(EGL_OPENGL_ES_API);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        const EGLint configAttributes[] =
        {
            EGL_RED_SIZE, EGL_DONT_CARE,
            EGL_GREEN_SIZE, EGL_DONT_CARE,
            EGL_BLUE_SIZE, EGL_DONT_CARE,
            EGL_ALPHA_SIZE, EGL_DONT_CARE,
            EGL_DEPTH_SIZE, EGL_DONT_CARE,
            EGL_STENCIL_SIZE, EGL_DONT_CARE,
            EGL_SAMPLE_BUFFERS, 0,
            EGL_NONE
        };

        EGLint configCount;
        ASSERT_TRUE(eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount) || (configCount != 1) == EGL_TRUE);

        std::vector<EGLint> surfaceAttributes;
        surfaceAttributes.push_back(EGL_NONE);
        surfaceAttributes.push_back(EGL_NONE);

        // Create first window surface
        mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), &surfaceAttributes[0]);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        mPbufferSurface = eglCreatePbufferSurface(mDisplay, mConfig, &surfaceAttributes[0]);

        EGLint contextAttibutes[] =
        {
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL_NONE
        };

        mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        mSecondContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);
    }

    void runMessageLoopTest(EGLSurface secondSurface, EGLContext secondContext)
    {
        eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        // Make a second context current
        eglMakeCurrent(mDisplay, secondSurface, secondSurface, secondContext);
        eglDestroySurface(mDisplay, mWindowSurface);

        // Create second window surface
        std::vector<EGLint> surfaceAttributes;
        surfaceAttributes.push_back(EGL_NONE);
        surfaceAttributes.push_back(EGL_NONE);

        mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), &surfaceAttributes[0]);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        mOSWindow->signalTestEvent();
        mOSWindow->messageLoop();
        ASSERT_TRUE(mOSWindow->didTestEventFire());

        // Simple operation to test the FBO is set appropriately
        glClear(GL_COLOR_BUFFER_BIT);
    }

    EGLDisplay mDisplay;
    EGLSurface mWindowSurface;
    EGLSurface mPbufferSurface;
    EGLContext mContext;
    EGLContext mSecondContext;
    EGLConfig mConfig;
    OSWindow *mOSWindow;
};

// Test a surface bug where we could have two Window surfaces active
// at one time, blocking message loops. See http://crbug.com/475085
TEST_F(EGLSurfaceTest, MessageLoopBug)
{
    const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
    {
        std::cout << "D3D Platform not supported in ANGLE";
        return;
    }

    initializeSurface(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);

    runMessageLoopTest(EGL_NO_SURFACE, EGL_NO_CONTEXT);
}

// Tests the message loop bug, but with setting a second context
// instead of null.
TEST_F(EGLSurfaceTest, MessageLoopBugContext)
{
    const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
    {
        std::cout << "D3D Platform not supported in ANGLE";
        return;
    }

    initializeSurface(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);

    runMessageLoopTest(mPbufferSurface, mSecondContext);
}

// Test a bug where calling makeCurrent twice would release the surface
TEST_F(EGLSurfaceTest, MakeCurrentTwice)
{
    initializeSurface(EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);

    eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
    ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

    eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
    ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

    // Simple operation to test the FBO is set appropriately
    glClear(GL_COLOR_BUFFER_BIT);
}

// Test that the D3D window surface is correctly resized after calling swapBuffers
TEST_F(EGLSurfaceTest, ResizeD3DWindow)
{
    const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
    {
        std::cout << "D3D Platform not supported in ANGLE";
        return;
    }

    initializeSurface(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);

    eglSwapBuffers(mDisplay, mWindowSurface);
    ASSERT_EGL_SUCCESS();

    EGLint height;
    eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
    ASSERT_EGL_SUCCESS();
    ASSERT_EQ(64, height);  // initial size

    // set window's height to 0
    mOSWindow->resize(64, 0);

    eglSwapBuffers(mDisplay, mWindowSurface);
    ASSERT_EGL_SUCCESS();

    eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
    ASSERT_EGL_SUCCESS();
    ASSERT_EQ(0, height);

    // restore window's height
    mOSWindow->resize(64, 64);

    eglSwapBuffers(mDisplay, mWindowSurface);
    ASSERT_EGL_SUCCESS();

    eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
    ASSERT_EGL_SUCCESS();
    ASSERT_EQ(64, height);
}

}
<commit_msg>EGLSurfaceTest: specify the device type only on d3d platform<commit_after>//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// EGLSurfaceTest:
//   Tests pertaining to egl::Surface.
//

#include <ANGLETest.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>

#include "common/angleutils.h"
#include "OSWindow.h"

namespace
{

class EGLSurfaceTest : public testing::Test
{
  protected:
    EGLSurfaceTest()
        : mDisplay(EGL_NO_DISPLAY),
          mWindowSurface(EGL_NO_SURFACE),
          mPbufferSurface(EGL_NO_SURFACE),
          mContext(EGL_NO_CONTEXT),
          mSecondContext(EGL_NO_CONTEXT),
          mOSWindow(nullptr)
    {
    }

    void SetUp() override
    {
        mOSWindow = CreateOSWindow();
        mOSWindow->initialize("EGLSurfaceTest", 64, 64);
    }

    // Release any resources created in the test body
    void TearDown() override
    {
        mOSWindow->destroy();
        SafeDelete(mOSWindow);

        if (mDisplay != EGL_NO_DISPLAY)
        {
            eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);

            if (mWindowSurface != EGL_NO_SURFACE)
            {
                eglDestroySurface(mDisplay, mWindowSurface);
                mWindowSurface = EGL_NO_SURFACE;
            }

            if (mPbufferSurface != EGL_NO_SURFACE)
            {
                eglDestroySurface(mDisplay, mPbufferSurface);
                mPbufferSurface = EGL_NO_SURFACE;
            }

            if (mContext != EGL_NO_CONTEXT)
            {
                eglDestroyContext(mDisplay, mContext);
                mContext = EGL_NO_CONTEXT;
            }

            if (mSecondContext != EGL_NO_CONTEXT)
            {
                eglDestroyContext(mDisplay, mSecondContext);
                mSecondContext = EGL_NO_CONTEXT;
            }

            eglTerminate(mDisplay);
            mDisplay = EGL_NO_DISPLAY;
        }

        ASSERT_TRUE(mWindowSurface == EGL_NO_SURFACE && mContext == EGL_NO_CONTEXT);
    }

    void initializeSurface(EGLenum platformType)
    {
        PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = reinterpret_cast<PFNEGLGETPLATFORMDISPLAYEXTPROC>(eglGetProcAddress("eglGetPlatformDisplayEXT"));
        ASSERT_TRUE(eglGetPlatformDisplayEXT != nullptr);

        std::vector<EGLint> displayAttributes;
        displayAttributes.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
        displayAttributes.push_back(platformType);
        displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
        displayAttributes.push_back(EGL_DONT_CARE);
        displayAttributes.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
        displayAttributes.push_back(EGL_DONT_CARE);

        if (platformType == EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE || platformType == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
        {
            displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
            displayAttributes.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
        }
        displayAttributes.push_back(EGL_NONE);

        mDisplay = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, mOSWindow->getNativeDisplay(), displayAttributes.data());
        ASSERT_TRUE(mDisplay != EGL_NO_DISPLAY);

        EGLint majorVersion, minorVersion;
        ASSERT_TRUE(eglInitialize(mDisplay, &majorVersion, &minorVersion) == EGL_TRUE);

        eglBindAPI(EGL_OPENGL_ES_API);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        const EGLint configAttributes[] =
        {
            EGL_RED_SIZE, EGL_DONT_CARE,
            EGL_GREEN_SIZE, EGL_DONT_CARE,
            EGL_BLUE_SIZE, EGL_DONT_CARE,
            EGL_ALPHA_SIZE, EGL_DONT_CARE,
            EGL_DEPTH_SIZE, EGL_DONT_CARE,
            EGL_STENCIL_SIZE, EGL_DONT_CARE,
            EGL_SAMPLE_BUFFERS, 0,
            EGL_NONE
        };

        EGLint configCount;
        ASSERT_TRUE(eglChooseConfig(mDisplay, configAttributes, &mConfig, 1, &configCount) || (configCount != 1) == EGL_TRUE);

        std::vector<EGLint> surfaceAttributes;
        surfaceAttributes.push_back(EGL_NONE);
        surfaceAttributes.push_back(EGL_NONE);

        // Create first window surface
        mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), &surfaceAttributes[0]);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        mPbufferSurface = eglCreatePbufferSurface(mDisplay, mConfig, &surfaceAttributes[0]);

        EGLint contextAttibutes[] =
        {
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL_NONE
        };

        mContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        mSecondContext = eglCreateContext(mDisplay, mConfig, nullptr, contextAttibutes);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);
    }

    void runMessageLoopTest(EGLSurface secondSurface, EGLContext secondContext)
    {
        eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        // Make a second context current
        eglMakeCurrent(mDisplay, secondSurface, secondSurface, secondContext);
        eglDestroySurface(mDisplay, mWindowSurface);

        // Create second window surface
        std::vector<EGLint> surfaceAttributes;
        surfaceAttributes.push_back(EGL_NONE);
        surfaceAttributes.push_back(EGL_NONE);

        mWindowSurface = eglCreateWindowSurface(mDisplay, mConfig, mOSWindow->getNativeWindow(), &surfaceAttributes[0]);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
        ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

        mOSWindow->signalTestEvent();
        mOSWindow->messageLoop();
        ASSERT_TRUE(mOSWindow->didTestEventFire());

        // Simple operation to test the FBO is set appropriately
        glClear(GL_COLOR_BUFFER_BIT);
    }

    EGLDisplay mDisplay;
    EGLSurface mWindowSurface;
    EGLSurface mPbufferSurface;
    EGLContext mContext;
    EGLContext mSecondContext;
    EGLConfig mConfig;
    OSWindow *mOSWindow;
};

// Test a surface bug where we could have two Window surfaces active
// at one time, blocking message loops. See http://crbug.com/475085
TEST_F(EGLSurfaceTest, MessageLoopBug)
{
    const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
    {
        std::cout << "D3D Platform not supported in ANGLE";
        return;
    }

    initializeSurface(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);

    runMessageLoopTest(EGL_NO_SURFACE, EGL_NO_CONTEXT);
}

// Tests the message loop bug, but with setting a second context
// instead of null.
TEST_F(EGLSurfaceTest, MessageLoopBugContext)
{
    const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
    {
        std::cout << "D3D Platform not supported in ANGLE";
        return;
    }

    initializeSurface(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);

    runMessageLoopTest(mPbufferSurface, mSecondContext);
}

// Test a bug where calling makeCurrent twice would release the surface
TEST_F(EGLSurfaceTest, MakeCurrentTwice)
{
    initializeSurface(EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE);

    eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
    ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

    eglMakeCurrent(mDisplay, mWindowSurface, mWindowSurface, mContext);
    ASSERT_TRUE(eglGetError() == EGL_SUCCESS);

    // Simple operation to test the FBO is set appropriately
    glClear(GL_COLOR_BUFFER_BIT);
}

// Test that the D3D window surface is correctly resized after calling swapBuffers
TEST_F(EGLSurfaceTest, ResizeD3DWindow)
{
    const char *extensionsString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    if (strstr(extensionsString, "EGL_ANGLE_platform_angle_d3d") == nullptr)
    {
        std::cout << "D3D Platform not supported in ANGLE";
        return;
    }

    initializeSurface(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);

    eglSwapBuffers(mDisplay, mWindowSurface);
    ASSERT_EGL_SUCCESS();

    EGLint height;
    eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
    ASSERT_EGL_SUCCESS();
    ASSERT_EQ(64, height);  // initial size

    // set window's height to 0
    mOSWindow->resize(64, 0);

    eglSwapBuffers(mDisplay, mWindowSurface);
    ASSERT_EGL_SUCCESS();

    eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
    ASSERT_EGL_SUCCESS();
    ASSERT_EQ(0, height);

    // restore window's height
    mOSWindow->resize(64, 64);

    eglSwapBuffers(mDisplay, mWindowSurface);
    ASSERT_EGL_SUCCESS();

    eglQuerySurface(mDisplay, mWindowSurface, EGL_HEIGHT, &height);
    ASSERT_EGL_SUCCESS();
    ASSERT_EQ(64, height);
}

}
<|endoftext|>


<commit_before>#include "../filesystem/path.h"
#include "../filesystem/file_status.h"
#include "../filesystem/fs_operations.h"
#include "../filesystem/directory_iterator.h"
#include "../filesystem/recursive_directory_iterator.h"

#include <cstdio>
#include <iostream>
#include <set>

#include "cppunit-header.h"

namespace fs = filesystem::v1;

class Test_recursive_directory_iterator : public CppUnit::TestFixture
{
	CPPUNIT_TEST_SUITE(Test_recursive_directory_iterator);
	CPPUNIT_TEST(constructors);
	CPPUNIT_TEST(assignment);
	CPPUNIT_TEST(iteration);
	CPPUNIT_TEST(random_tests);
	CPPUNIT_TEST_SUITE_END();

 protected:
	void constructors()
	{
		std::error_code ec;
		fs::recursive_directory_iterator empty;

		CPPUNIT_ASSERT(empty == end(fs::recursive_directory_iterator()));

		CPPUNIT_ASSERT_NO_THROW(fs::recursive_directory_iterator i;);
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator i(fs::path{"/tmp"}););
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator i(fs::path{"/tmp"}, ec););

		CPPUNIT_ASSERT_THROW({
			fs::recursive_directory_iterator j(fs::path("/foo"));
		}, fs::filesystem_error);

		CPPUNIT_ASSERT_THROW({
			fs::recursive_directory_iterator j(fs::path{"/root"});
		}, fs::filesystem_error);

		CPPUNIT_ASSERT_THROW({
			fs::recursive_directory_iterator j(fs::path{""});
		}, fs::filesystem_error);

		ec.clear();
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator j(fs::path("/foo"), ec););
		CPPUNIT_ASSERT(ec);

		ec.clear();
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator j(fs::path("/root"), ec););
		CPPUNIT_ASSERT(ec);

		ec.clear();
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator j(fs::path(""), ec););
		CPPUNIT_ASSERT(ec);
	}

	void assignment()
	{
		fs::recursive_directory_iterator i("/tmp");
		fs::recursive_directory_iterator j("/tmp");
		fs::recursive_directory_iterator empty;

		i = fs::recursive_directory_iterator{};
		i = j;
		i = empty;
	}

	void iteration()
	{
		std::error_code ec;
		std::set<fs::path> paths;

		if (config::verbose) putchar('\n');

		if (config::verbose)
			std::cout << "--------------------------------------------\n";
		fs::recursive_directory_iterator i(
		    "/tmp", fs::directory_options::skip_permission_denied);
		CPPUNIT_ASSERT(i != end(i));

		for (; i != end(i); ++i)
		{
			bool inserted = false;
			if (config::verbose)
				std::cout << " entry: " << i->path().c_str() << '\n';

			std::set<fs::path>::iterator rv;
			std::tie(rv, inserted) = paths.insert(*i);
			CPPUNIT_ASSERT(inserted == true);
		}

		paths.clear();
		if (config::verbose)
			std::cout << "--------------------------------------------\n";
		fs::recursive_directory_iterator j(
		    "/proc", fs::directory_options::skip_permission_denied);
		CPPUNIT_ASSERT(j != end(j));

		for (; j != end(j); ++j)
		{
			bool inserted = false;
			if (config::verbose)
				std::cout << " entry: " << j->path().c_str() << '\n';

			std::set<fs::path>::iterator rv;
			std::tie(rv, inserted) = paths.insert(*j);
			CPPUNIT_ASSERT(inserted == true);
		}

		paths.clear();
		if (config::verbose)
			std::cout << "--------------------------------------------\n";
		fs::recursive_directory_iterator k(
		    "/tmp", fs::directory_options::skip_permission_denied);
		CPPUNIT_ASSERT(k != end(k));

		for (; k != end(k); ++k)
		{
			bool inserted = false;
			if (config::verbose)
				std::cout << " entry: " << k->path().c_str() << '\n';

			std::set<fs::path>::iterator rv;
			std::tie(rv, inserted) = paths.insert(*k);
			CPPUNIT_ASSERT(inserted == true);
		}

		fs::recursive_directory_iterator x = std::move(i);
		CPPUNIT_ASSERT_THROW(++i; , fs::filesystem_error);

		i.increment(ec);

		i = fs::recursive_directory_iterator(fs::path("/tmp"));
		for (auto & j : i)
		{
			CPPUNIT_ASSERT(paths.find(j) != paths.end());
		}
	}

	void random_tests()
	{
		for (const char * s : { ".", "/tmp", "/dev" })
		{
			std::error_code ec;
			auto di = fs::recursive_directory_iterator(s,
			                fs::directory_options::skip_permission_denied);

			if (config::verbose) putchar('\n');

			for (auto & e : di)
			{
#if 0
				if (config::verbose)
					std::cout << "Found dirent: '" << e.path().c_str()
					          << "\n\tstem = '" << e.path().stem().c_str()
					          << "' ext = '" << e.path().extension().c_str()
					          << "'\n";
#endif

				CPPUNIT_ASSERT(  e.path().filename().string()
				              == ( e.path().stem().string()
				                 + e.path().extension().string()));

				fs::file_status st = e.symlink_status(ec);
				uintmax_t links = fs::hard_link_count(e, ec);
				uintmax_t size = 0;

				if (is_regular_file(st))
				{
					size = fs::file_size(e);
				} else if (fs::is_symlink(e, ec))
				{
					size = 0;
				} else
				{
					CPPUNIT_ASSERT_THROW(fs::file_size(e),
					                     fs::filesystem_error);
				}

				if (config::verbose)
					std::cout << "\tNumber of links: " << links << '\n'
					          << "\tSize: " << size
					          << "\tType: " << (int)st.type() << '\n';

				CPPUNIT_ASSERT(  st.type() == fs::file_type::unknown
				              || st.type() == fs::file_type::none
				              || fs::is_other(st)
				              || fs::is_regular_file(st)
				              || fs::is_directory(st)
				              || fs::is_symlink(st));

				if (  fs::is_block_file(st)
				   || fs::is_character_file(st)
				   || fs::is_fifo(st)
				   || fs::is_socket(st))
					CPPUNIT_ASSERT(fs::is_other(st));

				CPPUNIT_ASSERT(e.path().has_filename());
			}
		}
	}
};

CPPUNIT_TEST_SUITE_REGISTRATION(Test_recursive_directory_iterator);
<commit_msg>Fixed a compile error<commit_after>#include "../filesystem/path.h"
#include "../filesystem/file_status.h"
#include "../filesystem/fs_operations.h"
#include "../filesystem/directory_iterator.h"
#include "../filesystem/recursive_directory_iterator.h"

#include <cstdio>
#include <iostream>
#include <set>

#include "cppunit-header.h"

namespace fs = filesystem::v1;

class Test_recursive_directory_iterator : public CppUnit::TestFixture
{
	CPPUNIT_TEST_SUITE(Test_recursive_directory_iterator);
	CPPUNIT_TEST(constructors);
	CPPUNIT_TEST(assignment);
	CPPUNIT_TEST(iteration);
	CPPUNIT_TEST(random_tests);
	CPPUNIT_TEST_SUITE_END();

 protected:
	void constructors()
	{
		std::error_code ec;
		fs::recursive_directory_iterator empty;

		CPPUNIT_ASSERT(empty == end(fs::recursive_directory_iterator()));

		CPPUNIT_ASSERT_NO_THROW(fs::recursive_directory_iterator i;);
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator i(fs::path{"/tmp"}););
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator i(fs::path{"/tmp"}, ec););

		CPPUNIT_ASSERT_THROW({
			fs::recursive_directory_iterator j(fs::path("/foo"));
		}, fs::filesystem_error);

		CPPUNIT_ASSERT_THROW({
			fs::recursive_directory_iterator j(fs::path{"/root"});
		}, fs::filesystem_error);

		CPPUNIT_ASSERT_THROW({
			fs::recursive_directory_iterator j(fs::path{""});
		}, fs::filesystem_error);

		ec.clear();
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator j(fs::path("/foo"), ec););
		CPPUNIT_ASSERT(ec);

		ec.clear();
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator j(fs::path("/root"), ec););
		CPPUNIT_ASSERT(ec);

		ec.clear();
		CPPUNIT_ASSERT_NO_THROW(
			fs::recursive_directory_iterator j(fs::path(""), ec););
		CPPUNIT_ASSERT(ec);
	}

	void assignment()
	{
		fs::recursive_directory_iterator i("/tmp");
		fs::recursive_directory_iterator j("/tmp");
		fs::recursive_directory_iterator empty;

		i = fs::recursive_directory_iterator{};
		i = j;
		i = empty;
	}

	void iteration()
	{
		std::error_code ec;
		std::set<fs::path> paths;

		if (config::verbose) putchar('\n');

		if (config::verbose)
			std::cout << "--------------------------------------------\n";
		fs::recursive_directory_iterator i(
		    "/tmp", fs::directory_options::skip_permission_denied);
		CPPUNIT_ASSERT(i != end(i));

		for (; i != end(i); ++i)
		{
			bool inserted = false;
			if (config::verbose)
				std::cout << " entry: " << i->path().c_str() << '\n';

			std::set<fs::path>::iterator rv;
			std::tie(rv, inserted) = paths.insert(*i);
			CPPUNIT_ASSERT(inserted == true);
		}

		paths.clear();
		if (config::verbose)
			std::cout << "--------------------------------------------\n";
		fs::recursive_directory_iterator j(
		    "/proc", fs::directory_options::skip_permission_denied);
		CPPUNIT_ASSERT(j != end(j));

		for (; j != end(j); ++j)
		{
			bool inserted = false;
			if (config::verbose)
				std::cout << " entry: " << j->path().c_str() << '\n';

			std::set<fs::path>::iterator rv;
			std::tie(rv, inserted) = paths.insert(*j);
			CPPUNIT_ASSERT(inserted == true);
		}

		paths.clear();
		if (config::verbose)
			std::cout << "--------------------------------------------\n";
		fs::recursive_directory_iterator k(
		    "/tmp", fs::directory_options::skip_permission_denied);
		CPPUNIT_ASSERT(k != end(k));

		for (; k != end(k); ++k)
		{
			bool inserted = false;
			if (config::verbose)
				std::cout << " entry: " << k->path().c_str() << '\n';

			std::set<fs::path>::iterator rv;
			std::tie(rv, inserted) = paths.insert(*k);
			CPPUNIT_ASSERT(inserted == true);
		}

		fs::recursive_directory_iterator x = std::move(i);
		CPPUNIT_ASSERT_THROW(++i; , fs::filesystem_error);

		i.increment(ec);

		i = fs::recursive_directory_iterator(fs::path("/tmp"));
		for (auto j = i; j != end(i); ++i)
		{
			CPPUNIT_ASSERT(paths.find(*j) != paths.end());
		}
	}

	void random_tests()
	{
		for (const char * s : { ".", "/tmp", "/dev" })
		{
			std::error_code ec;
			auto di = fs::recursive_directory_iterator(s,
			                fs::directory_options::skip_permission_denied);

			if (config::verbose) putchar('\n');

			for (auto & e : di)
			{
#if 0
				if (config::verbose)
					std::cout << "Found dirent: '" << e.path().c_str()
					          << "\n\tstem = '" << e.path().stem().c_str()
					          << "' ext = '" << e.path().extension().c_str()
					          << "'\n";
#endif

				CPPUNIT_ASSERT(  e.path().filename().string()
				              == ( e.path().stem().string()
				                 + e.path().extension().string()));

				fs::file_status st = e.symlink_status(ec);
				uintmax_t links = fs::hard_link_count(e, ec);
				uintmax_t size = 0;

				if (is_regular_file(st))
				{
					size = fs::file_size(e);
				} else if (fs::is_symlink(e, ec))
				{
					size = 0;
				} else
				{
					CPPUNIT_ASSERT_THROW(fs::file_size(e),
					                     fs::filesystem_error);
				}

				if (config::verbose)
					std::cout << "\tNumber of links: " << links << '\n'
					          << "\tSize: " << size
					          << "\tType: " << (int)st.type() << '\n';

				CPPUNIT_ASSERT(  st.type() == fs::file_type::unknown
				              || st.type() == fs::file_type::none
				              || fs::is_other(st)
				              || fs::is_regular_file(st)
				              || fs::is_directory(st)
				              || fs::is_symlink(st));

				if (  fs::is_block_file(st)
				   || fs::is_character_file(st)
				   || fs::is_fifo(st)
				   || fs::is_socket(st))
					CPPUNIT_ASSERT(fs::is_other(st));

				CPPUNIT_ASSERT(e.path().has_filename());
			}
		}
	}
};

CPPUNIT_TEST_SUITE_REGISTRATION(Test_recursive_directory_iterator);
<|endoftext|>


<commit_before>/** @file
 *
 * @ingroup audioGraphLibrary
 *
 * @brief The TTAudioGraphObject wraps a Jamoma DSP object such that it is possible to build a dynamic graph of audio processing units.
 *
 * @details It is implemented as a #TTObject so that it can receive dynamically bound messages,
 * including notifications from other objects.
 *
 * @authors Timothy Place, Trond Lossius
 *
 * @copyright Copyright © 2010, Timothy Place @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTAudioGraphObject.h"
#include "TTAudioGraphInlet.h"
#include "TTAudioGraphOutlet.h"

#define thisTTClass			TTAudioGraphObject

TTMutexPtr TTAudioGraphObject::sSharedMutex = NULL;

//	Arguments
//	1. (required) The name of the Jamoma DSP object you want to wrap
//	2. (optional) Number of inlets, default = 1
//	3. (optional) Number of outlets, default = 1

TTObjectPtr TTAudioGraphObject::instantiate(TTSymbol& name, TTValue& arguments)
{
	return new TTAudioGraphObject(arguments);
}

extern "C" void TTAudioGraphObject::registerClass()
{
	TTClassRegister(TT("audio.object"), "audio, graph, wrapper", TTAudioGraphObject::instantiate );
}

TTAudioGraphObject :: TTAudioGraphObject (TTValue& arguments) :
	TTGraphObject(arguments),
	mStatus(kTTAudioGraphProcessUnknown),
	mAudioFlags(kTTAudioGraphProcessor),
	mInputSignals(NULL),
	mOutputSignals(NULL),
	mVectorSize(0)
{
	TTSymbol	wrappedObjectName = kTTSymEmpty;
	TTUInt16	numInlets = 1;
	TTUInt16	numOutlets = 1;

	addAttributeWithSetter(NumAudioInlets, kTypeUInt32);
	addAttributeWithSetter(NumAudioOutlets, kTypeUInt32);

	TT_ASSERT(audiograph_correct_instantiation_arg_count, arguments.getSize() > 0);

	arguments.get(0, wrappedObjectName);
	if (arguments.getSize() > 1)
		arguments.get(1, numInlets);
	if (arguments.getSize() > 2)
		arguments.get(2, numOutlets);

	setAttributeValue(TT("numAudioInlets"), numInlets);
	setAttributeValue(TT("numAudioOutlets"), numOutlets);

	// if an object supports the 'setOwner' message, then we tell it that we want to become the owner
	// this is particularly important for the dac object
	TTValue v = TTPtr(this);
	mKernel->sendMessage(TT("setOwner"), v, kTTValNONE);

	if (!sSharedMutex)
		sSharedMutex = new TTMutex(false);
}

TTAudioGraphObject::~TTAudioGraphObject()
{
	TTObjectRelease((TTObjectPtr*)&mInputSignals);
	TTObjectRelease((TTObjectPtr*)&mOutputSignals);
}

TTErr TTAudioGraphObject::setNumAudioInlets(const TTValue& newNumInlets)
{
	TTErr		err = TTObjectInstantiate(kTTSym_audiosignalarray, (TTObjectPtr*)&mInputSignals, newNumInlets);
	TTUInt16	inletCount = newNumInlets;

	mAudioInlets.resize(inletCount);
	mInputSignals->setMaxNumAudioSignals(inletCount);
	mInputSignals->numAudioSignals = inletCount;			// TODO: this array num signals access is kind of clumsy and inconsistent [tap]
	mNumAudioInlets = inletCount;
	return err;
}

TTErr TTAudioGraphObject::setNumAudioOutlets(const TTValue& newNumOutlets)
{
	TTErr		err = TTObjectInstantiate(kTTSym_audiosignalarray, (TTObjectPtr*)&mOutputSignals, newNumOutlets);
	TTUInt16	outletCount = newNumOutlets;

	mAudioOutlets.resize(outletCount);
	mOutputSignals->setMaxNumAudioSignals(outletCount);
	mOutputSignals->numAudioSignals = outletCount;
	mNumAudioOutlets = outletCount;
	return err;
}

void TTAudioGraphObject::prepareAudioDescription()
{
	if (valid && mAudioDescription.mClassName) {
		mAudioDescription.sIndex = 0;
		mAudioDescription.mClassName = kTTSymEmpty;

		prepareDescription();

		for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++)
			inlet->prepareDescriptions();
	}
}

void TTAudioGraphObject::getAudioDescription(TTAudioGraphDescription& desc)
{
	if (mAudioDescription.mClassName) {		// a description for this object has already been created -- use it.
		desc = mAudioDescription;
	}
	else {					// create a new description for this object.
		desc.mClassName = mKernel->getName();
		desc.mObjectInstance = mKernel;
		desc.mNumInlets = mInlets.size();
		desc.mNumOutlets = mOutlets.size();
		desc.mAudioDescriptionsForInlets.clear();
		desc.mID = desc.sIndex++;
		mAudioDescription = desc;

		for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
			TTAudioGraphDescriptionVector	vector;

			inlet->getDescriptions(vector);
			desc.mAudioDescriptionsForInlets.push_back(vector);
		}

//		prepareDescription();
		getDescription(desc.mControlDescription);
	}
}

TTErr TTAudioGraphObject::resetAudio()
{
	sSharedMutex->lock();
	for_each(mAudioInlets.begin(), mAudioInlets.end(), mem_fun_ref(&TTAudioGraphInlet::reset));
	sSharedMutex->unlock();
	return kTTErrNone;
}

TTErr TTAudioGraphObject::connectAudio(TTAudioGraphObjectPtr anObject, TTUInt16 fromOutletNumber, TTUInt16 toInletNumber)
{
	TTErr err;

	// it might seem like connections should not need the critical region:
	// the vector gets a little longer and the new items might be ignored the first time
	// it doesn't change the order or delete things or copy them around in the vector like a drop() does
	// but:
	// if the resize of the vector can't happen in-place, then the whole thing gets copied and the old one destroyed

	sSharedMutex->lock();

	if (toInletNumber+1 > mAudioInlets.size())
		setNumAudioInlets(toInletNumber+1);

	err = mAudioInlets[toInletNumber].connect(anObject, fromOutletNumber);
	sSharedMutex->unlock();
	return err;
}

TTErr TTAudioGraphObject::dropAudio(TTAudioGraphObjectPtr anObject, TTUInt16 fromOutletNumber, TTUInt16 toInletNumber)
{
	TTErr err = kTTErrInvalidValue;

	sSharedMutex->lock();
	if (toInletNumber < mAudioInlets.size())
		err = mAudioInlets[toInletNumber].drop(anObject, fromOutletNumber);
	sSharedMutex->unlock();
	return err;
}

TTErr TTAudioGraphObject::preprocess(const TTAudioGraphPreprocessData& initData)
{
	lock();
	if (valid && mStatus != kTTAudioGraphProcessNotStarted) {
		TTAudioSignalPtr	audioSignal;
		TTUInt16			index = 0;

		mStatus = kTTAudioGraphProcessNotStarted;

		for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
			inlet->preprocess(initData);
			audioSignal = inlet->getBuffer(); // TODO: It seems like we can just cache this once when we init the graph, because the number of inlets cannot change on-the-fly
			mInputSignals->setSignal(index, audioSignal);
			index++;
		}

		index = 0;
		for (TTAudioGraphOutletIter outlet = mAudioOutlets.begin(); outlet != mAudioOutlets.end(); outlet++) {
			audioSignal = outlet->getBuffer();
			mOutputSignals->setSignal(index, audioSignal);
			index++;
		}

		if (mAudioFlags & kTTAudioGraphGenerator) {
			if (mVectorSize != initData.vectorSize) {
				mVectorSize = initData.vectorSize;
				mOutputSignals->allocAllWithVectorSize(initData.vectorSize);
				mInputSignals->setMaxNumAudioSignals(0);
			}
		}
	}
	unlock();
	return kTTErrNone;
}

TTErr TTAudioGraphObject::process(TTAudioSignalPtr& returnedSignal, TTUInt16 forOutletNumber)
{
	lock();
	switch (mStatus) {

		// we have not processed anything yet, so let's get started
		case kTTAudioGraphProcessNotStarted:
			mStatus = kTTAudioGraphProcessingCurrently;

			if (mAudioFlags & kTTAudioGraphGenerator) {			// a generator (or no input)
				getUnitGenerator()->process(mInputSignals, mOutputSignals);
			}
			else {												// a processor
				// zero our collected input samples

				// WE CANNOT DO THIS!!!  IF THE INLET IS JUST A POINTER TO MEMORY IN ANOTHER OBJECT'S OUTLET
				// THEN WE END UP CLEARING THAT OBJECT'S COMPUTED OUTPUT!!!
				// INSTEAD, WE MOVE THE CLEARING INTO THE inlet->process() call
				//mInputSignals->clearAll();

				// pull (process, sum, and collect) all of our source audio
//				for_each(mAudioInlets.begin(), mAudioInlets.end(), mem_fun_ref(&TTAudioGraphInlet::process));
				for(TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet !=  mAudioInlets.end(); inlet++) {
					inlet->process();
				}

				// TEMPORARY -- DUPLICATING CODE FROM PREPROCESS
				// If there is a change in the inlet/source configuration during processing, including channel counts, then the information cached at preprocess is WRONG!
				// If there is feedback, then the problem gets compounded into future pulls on the graph!
				int index = 0;
				for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
					TTAudioSignalPtr audioSignal = inlet->getBuffer(); // TODO: It seems like we can just cache this once when we init the graph, because the number of inlets cannot change on-the-fly
					mInputSignals->setSignal(index, audioSignal);
					index++;
				}

				if (!(mAudioFlags & kTTAudioGraphNonAdapting)) {
					// examples of non-adapting objects are join≈ and matrix≈
					// non-adapting in this case means channel numbers -- vector sizes still adapt
					mOutputSignals->matchNumChannels(mInputSignals);
				}
				mOutputSignals->allocAllWithVectorSize(mInputSignals->getVectorSize());

				// adapt ugen based on the input we are going to process
				getUnitGenerator()->adaptMaxNumChannels(mInputSignals->getMaxNumChannels());
				getUnitGenerator()->setSampleRate(mInputSignals->getSignal(0).getSampleRate());

				// finally, process the audio
				getUnitGenerator()->process(mInputSignals, mOutputSignals);
			}

			// These two lines should be equivalent
			//returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
			returnedSignal = &mOutputSignals->getSignal(forOutletNumber);

			mStatus = kTTAudioGraphProcessComplete;
			break;

		// we already processed everything that needs to be processed, so just set the pointer
		case kTTAudioGraphProcessComplete:
			// These two lines should be equivalent
			//returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
			returnedSignal = &mOutputSignals->getSignal(forOutletNumber);
			break;

		// to prevent feedback / infinite loops, we just hand back the last calculated output here
		case kTTAudioGraphProcessingCurrently:
			// These two lines should be equivalent
			//returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
			returnedSignal = &mOutputSignals->getSignal(forOutletNumber);
			break;

		// we should never get here
		default:
			unlock();
			return kTTErrGeneric;
	}
	unlock();
	return kTTErrNone;
}
<commit_msg>fixes for building graph descriptions that were introduced with the rewrite of TTSymbol.<commit_after>/** @file
 *
 * @ingroup audioGraphLibrary
 *
 * @brief The TTAudioGraphObject wraps a Jamoma DSP object such that it is possible to build a dynamic graph of audio processing units.
 *
 * @details It is implemented as a #TTObject so that it can receive dynamically bound messages,
 * including notifications from other objects.
 *
 * @authors Timothy Place, Trond Lossius
 *
 * @copyright Copyright © 2010, Timothy Place @n
 * This code is licensed under the terms of the "New BSD License" @n
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTAudioGraphObject.h"
#include "TTAudioGraphInlet.h"
#include "TTAudioGraphOutlet.h"

#define thisTTClass			TTAudioGraphObject

TTMutexPtr TTAudioGraphObject::sSharedMutex = NULL;

//	Arguments
//	1. (required) The name of the Jamoma DSP object you want to wrap
//	2. (optional) Number of inlets, default = 1
//	3. (optional) Number of outlets, default = 1

TTObjectPtr TTAudioGraphObject::instantiate(TTSymbol& name, TTValue& arguments)
{
	return new TTAudioGraphObject(arguments);
}

extern "C" void TTAudioGraphObject::registerClass()
{
	TTClassRegister(TT("audio.object"), "audio, graph, wrapper", TTAudioGraphObject::instantiate );
}

TTAudioGraphObject :: TTAudioGraphObject (TTValue& arguments) :
	TTGraphObject(arguments),
	mStatus(kTTAudioGraphProcessUnknown),
	mAudioFlags(kTTAudioGraphProcessor),
	mInputSignals(NULL),
	mOutputSignals(NULL),
	mVectorSize(0)
{
	TTSymbol	wrappedObjectName = kTTSymEmpty;
	TTUInt16	numInlets = 1;
	TTUInt16	numOutlets = 1;

	addAttributeWithSetter(NumAudioInlets, kTypeUInt32);
	addAttributeWithSetter(NumAudioOutlets, kTypeUInt32);

	TT_ASSERT(audiograph_correct_instantiation_arg_count, arguments.getSize() > 0);

	arguments.get(0, wrappedObjectName);
	if (arguments.getSize() > 1)
		arguments.get(1, numInlets);
	if (arguments.getSize() > 2)
		arguments.get(2, numOutlets);

	setAttributeValue(TT("numAudioInlets"), numInlets);
	setAttributeValue(TT("numAudioOutlets"), numOutlets);

	// if an object supports the 'setOwner' message, then we tell it that we want to become the owner
	// this is particularly important for the dac object
	TTValue v = TTPtr(this);
	mKernel->sendMessage(TT("setOwner"), v, kTTValNONE);

	if (!sSharedMutex)
		sSharedMutex = new TTMutex(false);
}

TTAudioGraphObject::~TTAudioGraphObject()
{
	TTObjectRelease((TTObjectPtr*)&mInputSignals);
	TTObjectRelease((TTObjectPtr*)&mOutputSignals);
}

TTErr TTAudioGraphObject::setNumAudioInlets(const TTValue& newNumInlets)
{
	TTErr		err = TTObjectInstantiate(kTTSym_audiosignalarray, (TTObjectPtr*)&mInputSignals, newNumInlets);
	TTUInt16	inletCount = newNumInlets;

	mAudioInlets.resize(inletCount);
	mInputSignals->setMaxNumAudioSignals(inletCount);
	mInputSignals->numAudioSignals = inletCount;			// TODO: this array num signals access is kind of clumsy and inconsistent [tap]
	mNumAudioInlets = inletCount;
	return err;
}

TTErr TTAudioGraphObject::setNumAudioOutlets(const TTValue& newNumOutlets)
{
	TTErr		err = TTObjectInstantiate(kTTSym_audiosignalarray, (TTObjectPtr*)&mOutputSignals, newNumOutlets);
	TTUInt16	outletCount = newNumOutlets;

	mAudioOutlets.resize(outletCount);
	mOutputSignals->setMaxNumAudioSignals(outletCount);
	mOutputSignals->numAudioSignals = outletCount;
	mNumAudioOutlets = outletCount;
	return err;
}

void TTAudioGraphObject::prepareAudioDescription()
{
	if (valid && mAudioDescription.mClassName != kTTSymEmpty) {
		mAudioDescription.sIndex = 0;
		mAudioDescription.mClassName = kTTSymEmpty;

		prepareDescription();

		for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++)
			inlet->prepareDescriptions();
	}
}

void TTAudioGraphObject::getAudioDescription(TTAudioGraphDescription& desc)
{
	if (mAudioDescription.mClassName != kTTSymEmpty) {		// a description for this object has already been created -- use it.
		desc = mAudioDescription;
	}
	else {					// create a new description for this object.
		desc.mClassName = mKernel->getName();
		desc.mObjectInstance = mKernel;
		desc.mNumInlets = mInlets.size();
		desc.mNumOutlets = mOutlets.size();
		desc.mAudioDescriptionsForInlets.clear();
		desc.mID = desc.sIndex++;
		mAudioDescription = desc;

		for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
			TTAudioGraphDescriptionVector	vector;

			inlet->getDescriptions(vector);
			desc.mAudioDescriptionsForInlets.push_back(vector);
		}

//		prepareDescription();
		getDescription(desc.mControlDescription);
	}
}

TTErr TTAudioGraphObject::resetAudio()
{
	sSharedMutex->lock();
	for_each(mAudioInlets.begin(), mAudioInlets.end(), mem_fun_ref(&TTAudioGraphInlet::reset));
	sSharedMutex->unlock();
	return kTTErrNone;
}

TTErr TTAudioGraphObject::connectAudio(TTAudioGraphObjectPtr anObject, TTUInt16 fromOutletNumber, TTUInt16 toInletNumber)
{
	TTErr err;

	// it might seem like connections should not need the critical region:
	// the vector gets a little longer and the new items might be ignored the first time
	// it doesn't change the order or delete things or copy them around in the vector like a drop() does
	// but:
	// if the resize of the vector can't happen in-place, then the whole thing gets copied and the old one destroyed

	sSharedMutex->lock();

	if (toInletNumber+1 > mAudioInlets.size())
		setNumAudioInlets(toInletNumber+1);

	err = mAudioInlets[toInletNumber].connect(anObject, fromOutletNumber);
	sSharedMutex->unlock();
	return err;
}

TTErr TTAudioGraphObject::dropAudio(TTAudioGraphObjectPtr anObject, TTUInt16 fromOutletNumber, TTUInt16 toInletNumber)
{
	TTErr err = kTTErrInvalidValue;

	sSharedMutex->lock();
	if (toInletNumber < mAudioInlets.size())
		err = mAudioInlets[toInletNumber].drop(anObject, fromOutletNumber);
	sSharedMutex->unlock();
	return err;
}

TTErr TTAudioGraphObject::preprocess(const TTAudioGraphPreprocessData& initData)
{
	lock();
	if (valid && mStatus != kTTAudioGraphProcessNotStarted) {
		TTAudioSignalPtr	audioSignal;
		TTUInt16			index = 0;

		mStatus = kTTAudioGraphProcessNotStarted;

		for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
			inlet->preprocess(initData);
			audioSignal = inlet->getBuffer(); // TODO: It seems like we can just cache this once when we init the graph, because the number of inlets cannot change on-the-fly
			mInputSignals->setSignal(index, audioSignal);
			index++;
		}

		index = 0;
		for (TTAudioGraphOutletIter outlet = mAudioOutlets.begin(); outlet != mAudioOutlets.end(); outlet++) {
			audioSignal = outlet->getBuffer();
			mOutputSignals->setSignal(index, audioSignal);
			index++;
		}

		if (mAudioFlags & kTTAudioGraphGenerator) {
			if (mVectorSize != initData.vectorSize) {
				mVectorSize = initData.vectorSize;
				mOutputSignals->allocAllWithVectorSize(initData.vectorSize);
				mInputSignals->setMaxNumAudioSignals(0);
			}
		}
	}
	unlock();
	return kTTErrNone;
}

TTErr TTAudioGraphObject::process(TTAudioSignalPtr& returnedSignal, TTUInt16 forOutletNumber)
{
	lock();
	switch (mStatus) {

		// we have not processed anything yet, so let's get started
		case kTTAudioGraphProcessNotStarted:
			mStatus = kTTAudioGraphProcessingCurrently;

			if (mAudioFlags & kTTAudioGraphGenerator) {			// a generator (or no input)
				getUnitGenerator()->process(mInputSignals, mOutputSignals);
			}
			else {												// a processor
				// zero our collected input samples

				// WE CANNOT DO THIS!!!  IF THE INLET IS JUST A POINTER TO MEMORY IN ANOTHER OBJECT'S OUTLET
				// THEN WE END UP CLEARING THAT OBJECT'S COMPUTED OUTPUT!!!
				// INSTEAD, WE MOVE THE CLEARING INTO THE inlet->process() call
				//mInputSignals->clearAll();

				// pull (process, sum, and collect) all of our source audio
//				for_each(mAudioInlets.begin(), mAudioInlets.end(), mem_fun_ref(&TTAudioGraphInlet::process));
				for(TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet !=  mAudioInlets.end(); inlet++) {
					inlet->process();
				}

				// TEMPORARY -- DUPLICATING CODE FROM PREPROCESS
				// If there is a change in the inlet/source configuration during processing, including channel counts, then the information cached at preprocess is WRONG!
				// If there is feedback, then the problem gets compounded into future pulls on the graph!
				int index = 0;
				for (TTAudioGraphInletIter inlet = mAudioInlets.begin(); inlet != mAudioInlets.end(); inlet++) {
					TTAudioSignalPtr audioSignal = inlet->getBuffer(); // TODO: It seems like we can just cache this once when we init the graph, because the number of inlets cannot change on-the-fly
					mInputSignals->setSignal(index, audioSignal);
					index++;
				}

				if (!(mAudioFlags & kTTAudioGraphNonAdapting)) {
					// examples of non-adapting objects are join≈ and matrix≈
					// non-adapting in this case means channel numbers -- vector sizes still adapt
					mOutputSignals->matchNumChannels(mInputSignals);
				}
				mOutputSignals->allocAllWithVectorSize(mInputSignals->getVectorSize());

				// adapt ugen based on the input we are going to process
				getUnitGenerator()->adaptMaxNumChannels(mInputSignals->getMaxNumChannels());
				getUnitGenerator()->setSampleRate(mInputSignals->getSignal(0).getSampleRate());

				// finally, process the audio
				getUnitGenerator()->process(mInputSignals, mOutputSignals);
			}

			// These two lines should be equivalent
			//returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
			returnedSignal = &mOutputSignals->getSignal(forOutletNumber);

			mStatus = kTTAudioGraphProcessComplete;
			break;

		// we already processed everything that needs to be processed, so just set the pointer
		case kTTAudioGraphProcessComplete:
			// These two lines should be equivalent
			//returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
			returnedSignal = &mOutputSignals->getSignal(forOutletNumber);
			break;

		// to prevent feedback / infinite loops, we just hand back the last calculated output here
		case kTTAudioGraphProcessingCurrently:
			// These two lines should be equivalent
			//returnedSignal = mAudioOutlets[forOutletNumber].mBufferedOutput;
			returnedSignal = &mOutputSignals->getSignal(forOutletNumber);
			break;

		// we should never get here
		default:
			unlock();
			return kTTErrGeneric;
	}
	unlock();
	return kTTErrNone;
}
<|endoftext|>


<commit_before>/*
 * Unit tests for the TTSampleMatrix Object for Jamoma DSP
 * Copyright © 2012, Tim Place & Nathan Wolek
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTSampleMatrix.h"

TTErr TTSampleMatrix::test(TTValue& returnedTestInfo)
{
	int					errorCount = 0;
	int					testAssertionCount = 0;

	TTUInt16			numChannels = 2;
	TTUInt16			numSamples = 50000;
	TTUInt16			returnedChannels, returnedSamples;

	TTTestLog("Test resizing of the SampleMatrix...");

	// TEST 1: the number of channels
	this->setAttributeValue(TT("numChannels"), numChannels);
	this->getAttributeValue(TT("numChannels"), returnedChannels);

	TTTestAssertion("The numChannels has been set properly",
					numChannels == returnedChannels,
					testAssertionCount,
					errorCount);

	// TEST 2: the number of samples
	this->setAttributeValue(TT("lengthInSamples"), numSamples);
	this->getAttributeValue(TT("lengthInSamples"), returnedSamples);

	TTTestAssertion("The lengthInSamples has been set properly",
								numSamples == returnedSamples,
								testAssertionCount,
								errorCount);

	/*

	int					badSampleCount = 0;
	TTAudioObjectPtr	samplematrixObject = NULL;
	TTAudioSignalPtr	input = NULL;
	TTAudioSignalPtr	output = NULL;

	// TODO: test filling with sine wave
	// TODO: test scaling (applying gain)
	// TODO: test normalizing (with optional arg, and also without an optional arg)

	TTObjectInstantiate(TT("samplematrix"), &samplematrixObject, kTTVal1);

	// set some attributes
	samplematrixObject->setAttributeValue(TT("LengthInSamples"), numSamples);
	samplematrixObject->setAttributeValue(TT("NumChannels"), numChannels);

	TTTestAssertion("The LengthInSamples has been set properly",
					samplematrixObject->getAttributeValue(TT("LengthInSamples")) == numSamples,
					testAssertionCount,
					errorCount);

	TTObjectRelease(&input);
	TTObjectRelease(&output);
	TTObjectRelease(&samplematrixObject);

	*/

	// Wrap up the test results to pass back to whoever called this test
	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);
}

<commit_msg>testing two more assertions based on size of matrix<commit_after>/*
 * Unit tests for the TTSampleMatrix Object for Jamoma DSP
 * Copyright © 2012, Tim Place & Nathan Wolek
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTSampleMatrix.h"

TTErr TTSampleMatrix::test(TTValue& returnedTestInfo)
{
	int					errorCount = 0;
	int					testAssertionCount = 0;

	TTUInt16			numChannels = 2;
	TTUInt16			numSamples = 50000;
	TTUInt16			returnedChannels, returnedSamples;

	TTTestLog("Test resizing of the SampleMatrix...");

	// TEST 1: the number of channels
	this->setAttributeValue(TT("numChannels"), numChannels);
	this->getAttributeValue(TT("numChannels"), returnedChannels);

	TTTestAssertion("numChannels is set properly",
					numChannels == returnedChannels,
					testAssertionCount,
					errorCount);

	// TEST 2: the number of samples
	this->setAttributeValue(TT("lengthInSamples"), numSamples);
	this->getAttributeValue(TT("lengthInSamples"), returnedSamples);

	TTTestAssertion("lengthInSamples is set properly",
								numSamples == returnedSamples,
								testAssertionCount,
								errorCount);

	TTTestAssertion("correct amount of data storage calculated",
								this->mDataSize == sizeof(TTFloat64) * numChannels * numSamples,
								testAssertionCount,
								errorCount);
	TTTestAssertion("correct byte-stride between values calculated",
								this->mComponentStride == sizeof(TTFloat64),
								testAssertionCount,
								errorCount);

	/*

	int					badSampleCount = 0;
	TTAudioObjectPtr	samplematrixObject = NULL;
	TTAudioSignalPtr	input = NULL;
	TTAudioSignalPtr	output = NULL;

	// TODO: test filling with sine wave
	// TODO: test scaling (applying gain)
	// TODO: test normalizing (with optional arg, and also without an optional arg)

	TTObjectInstantiate(TT("samplematrix"), &samplematrixObject, kTTVal1);

	// set some attributes
	samplematrixObject->setAttributeValue(TT("LengthInSamples"), numSamples);
	samplematrixObject->setAttributeValue(TT("NumChannels"), numChannels);

	TTTestAssertion("The LengthInSamples has been set properly",
					samplematrixObject->getAttributeValue(TT("LengthInSamples")) == numSamples,
					testAssertionCount,
					errorCount);

	TTObjectRelease(&input);
	TTObjectRelease(&output);
	TTObjectRelease(&samplematrixObject);

	*/

	// Wrap up the test results to pass back to whoever called this test
	return TTTestFinish(testAssertionCount, errorCount, returnedTestInfo);
}

<|endoftext|>


<commit_before>#ifndef __FARVERSION_HPP__
#define __FARVERSION_HPP__
#include "plugin.hpp"

#define FAR_MAJOR_VER FARMANAGERVERSION_MAJOR
#define FAR_MINOR_VER FARMANAGERVERSION_MINOR
#define FAR_BUILD FARMANAGERVERSION_BUILD
#define FARCOMPANYNAME "Eugene Roshal & Far Group"
#define FARGROUPCOPYRIGHT(start_year) "Copyright  " start_year "-2015 Far Group"
#define FARCOPYRIGHT "Copyright  Eugene Roshal 1996-2000, " FARGROUPCOPYRIGHT("2000")
#define FARPRODUCTNAME "Far Manager"

#define FULLMAKEPRODUCTVERSION(major, minor, build) #major "." #minor " build " #build
#define MAKEPRODUCTVERSION(major, minor, build) FULLMAKEPRODUCTVERSION(major, minor, build)

#define FARPRODUCTVERSION MAKEPRODUCTVERSION(FAR_MAJOR_VER, FAR_MINOR_VER, FAR_BUILD)

#define fullgenericpluginrc(major, minor, build, desc, name, filename, copyright, pmajor, pminor, pbuild, pname) \
1 VERSIONINFO \
FILEVERSION major, minor, build, 0 \
PRODUCTVERSION pmajor, pminor, pbuild, 0 \
FILEOS 4 \
FILETYPE 2 \
{ \
 BLOCK "StringFileInfo" \
 { \
  BLOCK "000004E4" \
  { \
   VALUE "CompanyName", FARCOMPANYNAME "\000\000" \
   VALUE "FileDescription", desc "\000" \
   VALUE "FileVersion", MAKEPRODUCTVERSION(major, minor, build) "\000" \
   VALUE "InternalName", name "\000" \
   VALUE "LegalCopyright", copyright "\000\000" \
   VALUE "OriginalFilename", filename "\000" \
   VALUE "ProductName", pname "\000"\
   VALUE "ProductVersion", MAKEPRODUCTVERSION(pmajor, pminor, pbuild) "\000" \
  } \
\
 } \
\
 BLOCK "VarFileInfo" \
 { \
   VALUE "Translation", 0, 0x4e4 \
 } \
\
}

#define genericpluginrc(build, desc, name, filename) fullgenericpluginrc(FAR_MAJOR_VER, FAR_MINOR_VER, build, desc, name, filename, FARCOPYRIGHT, FAR_MAJOR_VER, FAR_MINOR_VER, FAR_BUILD, FARPRODUCTNAME)

#define fullgenericpluginrcwithguid(major, minor, build, desc, name, filename, guid, copyright, pmajor, pminor, pbuild, pname) \
1 VERSIONINFO \
FILEVERSION major, minor, build, 0 \
PRODUCTVERSION pmajor, pminor, pbuild, 0 \
FILEOS 4 \
FILETYPE 2 \
{ \
 BLOCK "StringFileInfo" \
 { \
  BLOCK "000004E4" \
  { \
   VALUE "CompanyName", FARCOMPANYNAME "\000\000" \
   VALUE "FileDescription", desc "\000" \
   VALUE "FileVersion", MAKEPRODUCTVERSION(major, minor, build) "\000" \
   VALUE "InternalName", name "\000" \
   VALUE "LegalCopyright", copyright "\000\000" \
   VALUE "OriginalFilename", filename "\000" \
   VALUE "ProductName", pname "\000"\
   VALUE "ProductVersion", MAKEPRODUCTVERSION(pmajor, pminor, pbuild) "\000" \
   VALUE "PluginGUID", guid "\000" \
  } \
\
 } \
\
 BLOCK "VarFileInfo" \
 { \
   VALUE "Translation", 0, 0x4e4 \
 } \
\
}

#define genericpluginrcwithguid(build, desc, name, filename, guid) fullgenericpluginrcwithguid(FAR_MAJOR_VER, FAR_MINOR_VER, build, desc, name, filename, guid, FARCOPYRIGHT, FAR_MAJOR_VER, FAR_MINOR_VER, FAR_BUILD, FARPRODUCTNAME)

#define fullgenericpluginrc_nobuild(major, minor, desc, name, filename, copyright, pmajor, pminor, pbuild, pname) \
1 VERSIONINFO \
FILEVERSION major, minor, 0, 0 \
PRODUCTVERSION pmajor, pminor, pbuild, 0 \
FILEOS 4 \
FILETYPE 2 \
{ \
 BLOCK "StringFileInfo" \
 { \
  BLOCK "000004E4" \
  { \
   VALUE "CompanyName", FARCOMPANYNAME "\000\000" \
   VALUE "FileDescription", desc "\000" \
   VALUE "FileVersion", #major "." #minor "\000" \
   VALUE "InternalName", name "\000" \
   VALUE "LegalCopyright", copyright "\000\000" \
   VALUE "OriginalFilename", filename "\000" \
   VALUE "ProductName", pname "\000"\
   VALUE "ProductVersion", MAKEPRODUCTVERSION(pmajor, pminor, pbuild) "\000" \
  } \
\
 } \
\
 BLOCK "VarFileInfo" \
 { \
   VALUE "Translation", 0, 0x4e4 \
 } \
\
}

#endif
<commit_msg>(c) ... - 2016<commit_after>#ifndef __FARVERSION_HPP__
#define __FARVERSION_HPP__
#include "plugin.hpp"

#define FAR_MAJOR_VER FARMANAGERVERSION_MAJOR
#define FAR_MINOR_VER FARMANAGERVERSION_MINOR
#define FAR_BUILD FARMANAGERVERSION_BUILD
#define FARCOMPANYNAME "Eugene Roshal & Far Group"
#define FARGROUPCOPYRIGHT(start_year) "Copyright  " start_year "-2016 Far Group"
#define FARCOPYRIGHT "Copyright  Eugene Roshal 1996-2000, " FARGROUPCOPYRIGHT("2000")
#define FARPRODUCTNAME "Far Manager"

#define FULLMAKEPRODUCTVERSION(major, minor, build) #major "." #minor " build " #build
#define MAKEPRODUCTVERSION(major, minor, build) FULLMAKEPRODUCTVERSION(major, minor, build)

#define FARPRODUCTVERSION MAKEPRODUCTVERSION(FAR_MAJOR_VER, FAR_MINOR_VER, FAR_BUILD)

#define fullgenericpluginrc(major, minor, build, desc, name, filename, copyright, pmajor, pminor, pbuild, pname) \
1 VERSIONINFO \
FILEVERSION major, minor, build, 0 \
PRODUCTVERSION pmajor, pminor, pbuild, 0 \
FILEOS 4 \
FILETYPE 2 \
{ \
 BLOCK "StringFileInfo" \
 { \
  BLOCK "000004E4" \
  { \
   VALUE "CompanyName", FARCOMPANYNAME "\000\000" \
   VALUE "FileDescription", desc "\000" \
   VALUE "FileVersion", MAKEPRODUCTVERSION(major, minor, build) "\000" \
   VALUE "InternalName", name "\000" \
   VALUE "LegalCopyright", copyright "\000\000" \
   VALUE "OriginalFilename", filename "\000" \
   VALUE "ProductName", pname "\000"\
   VALUE "ProductVersion", MAKEPRODUCTVERSION(pmajor, pminor, pbuild) "\000" \
  } \
\
 } \
\
 BLOCK "VarFileInfo" \
 { \
   VALUE "Translation", 0, 0x4e4 \
 } \
\
}

#define genericpluginrc(build, desc, name, filename) fullgenericpluginrc(FAR_MAJOR_VER, FAR_MINOR_VER, build, desc, name, filename, FARCOPYRIGHT, FAR_MAJOR_VER, FAR_MINOR_VER, FAR_BUILD, FARPRODUCTNAME)

#define fullgenericpluginrcwithguid(major, minor, build, desc, name, filename, guid, copyright, pmajor, pminor, pbuild, pname) \
1 VERSIONINFO \
FILEVERSION major, minor, build, 0 \
PRODUCTVERSION pmajor, pminor, pbuild, 0 \
FILEOS 4 \
FILETYPE 2 \
{ \
 BLOCK "StringFileInfo" \
 { \
  BLOCK "000004E4" \
  { \
   VALUE "CompanyName", FARCOMPANYNAME "\000\000" \
   VALUE "FileDescription", desc "\000" \
   VALUE "FileVersion", MAKEPRODUCTVERSION(major, minor, build) "\000" \
   VALUE "InternalName", name "\000" \
   VALUE "LegalCopyright", copyright "\000\000" \
   VALUE "OriginalFilename", filename "\000" \
   VALUE "ProductName", pname "\000"\
   VALUE "ProductVersion", MAKEPRODUCTVERSION(pmajor, pminor, pbuild) "\000" \
   VALUE "PluginGUID", guid "\000" \
  } \
\
 } \
\
 BLOCK "VarFileInfo" \
 { \
   VALUE "Translation", 0, 0x4e4 \
 } \
\
}

#define genericpluginrcwithguid(build, desc, name, filename, guid) fullgenericpluginrcwithguid(FAR_MAJOR_VER, FAR_MINOR_VER, build, desc, name, filename, guid, FARCOPYRIGHT, FAR_MAJOR_VER, FAR_MINOR_VER, FAR_BUILD, FARPRODUCTNAME)

#define fullgenericpluginrc_nobuild(major, minor, desc, name, filename, copyright, pmajor, pminor, pbuild, pname) \
1 VERSIONINFO \
FILEVERSION major, minor, 0, 0 \
PRODUCTVERSION pmajor, pminor, pbuild, 0 \
FILEOS 4 \
FILETYPE 2 \
{ \
 BLOCK "StringFileInfo" \
 { \
  BLOCK "000004E4" \
  { \
   VALUE "CompanyName", FARCOMPANYNAME "\000\000" \
   VALUE "FileDescription", desc "\000" \
   VALUE "FileVersion", #major "." #minor "\000" \
   VALUE "InternalName", name "\000" \
   VALUE "LegalCopyright", copyright "\000\000" \
   VALUE "OriginalFilename", filename "\000" \
   VALUE "ProductName", pname "\000"\
   VALUE "ProductVersion", MAKEPRODUCTVERSION(pmajor, pminor, pbuild) "\000" \
  } \
\
 } \
\
 BLOCK "VarFileInfo" \
 { \
   VALUE "Translation", 0, 0x4e4 \
 } \
\
}

#endif
<|endoftext|>


<commit_before>/*
 * This file is part of Wireless Display Software for Linux OS
 *
 * Copyright (C) 2014 Intel Corporation.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "cap_negotiation_state.h"

#include <iostream>

#include "libwds/rtsp/audiocodecs.h"
#include "libwds/rtsp/clientrtpports.h"
#include "libwds/rtsp/connectortype.h"
#include "libwds/rtsp/contentprotection.h"
#include "libwds/rtsp/coupledsink.h"
#include "libwds/rtsp/displayedid.h"
#include "libwds/rtsp/formats3d.h"
#include "libwds/rtsp/i2c.h"
#include "libwds/public/media_manager.h"
#include "libwds/rtsp/getparameter.h"
#include "libwds/rtsp/payload.h"
#include "libwds/rtsp/presentationurl.h"
#include "libwds/rtsp/propertyerrors.h"
#include "libwds/rtsp/reply.h"
#include "libwds/rtsp/setparameter.h"
#include "libwds/rtsp/standbyresumecapability.h"
#include "libwds/rtsp/triggermethod.h"
#include "libwds/rtsp/uibccapability.h"
#include "libwds/rtsp/videoformats.h"

namespace wds {
using rtsp::Message;
using rtsp::Request;
using rtsp::Reply;

namespace sink {

M3Handler::M3Handler(const InitParams& init_params)
  : MessageReceiver<Request::M3>(init_params) {
}

std::unique_ptr<Reply> M3Handler::HandleMessage(Message* message) {
  // FIXME : resolve clashes between wds exported and internal rtsp type names.
  using namespace rtsp;

  auto reply = std::unique_ptr<Reply>(new Reply(rtsp::STATUS_OK));
  auto props = message->payload().get_parameter_properties();
  for (auto it = props.begin(); it != props.end(); ++it) {
      std::shared_ptr<rtsp::Property> new_prop;
      if (*it == PropertyName::name[PropertyType::WFD_AUDIO_CODECS]){
          // FIXME: declare that we support absolutely every audio codec/format,
          // but there should be a MediaManager API for it
          auto codec_lpcm = AudioCodec(LPCM, AudioModes(3), 0);
          auto codec_aac = AudioCodec(AAC, AudioModes(15), 0);
          auto codec_ac3 = AudioCodec(AC3, AudioModes(7), 0);
          std::vector<AudioCodec> codec_list;
          codec_list.push_back(codec_lpcm);
          codec_list.push_back(codec_aac);
          codec_list.push_back(codec_ac3);
          new_prop.reset(new rtsp::AudioCodecs(codec_list));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_VIDEO_FORMATS]){
          new_prop.reset(new rtsp::VideoFormats(ToSinkMediaManager(manager_)->GetNativeVideoFormat(),
              false,
              ToSinkMediaManager(manager_)->GetSupportedH264VideoCodecs()));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_3D_FORMATS]){
          new_prop.reset(new Formats3d());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_CONTENT_PROTECTION]){
          new_prop.reset(new ContentProtection());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_DISPLAY_EDID]){
          new_prop.reset(new DisplayEdid());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_COUPLED_SINK]){
          new_prop.reset(new CoupledSink());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_CLIENT_RTP_PORTS]){
          new_prop.reset(new ClientRtpPorts(ToSinkMediaManager(manager_)->GetLocalRtpPorts().first,
                                            ToSinkMediaManager(manager_)->GetLocalRtpPorts().second));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_I2C]){
          new_prop.reset(new I2C(0));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_UIBC_CAPABILITY]){
          new_prop.reset(new UIBCCapability());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_CONNECTOR_TYPE]){
          new_prop.reset(new rtsp::ConnectorType(ToSinkMediaManager(manager_)->GetConnectorType()));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_STANDBY_RESUME_CAPABILITY]){
          new_prop.reset(new StandbyResumeCapability(false));
          reply->payload().add_property(new_prop);
      } else {
          WDS_ERROR("** GET_PARAMETER: Property not supported");
          return std::unique_ptr<Reply>(new Reply(STATUS_NotImplemented));
      }
  }

  return std::move(reply);
}

M4Handler::M4Handler(const InitParams& init_params)
  : MessageReceiver<Request::M4>(init_params) {
}

std::unique_ptr<Reply> M4Handler::HandleMessage(Message* message) {
  SinkMediaManager* sink_media_manager = ToSinkMediaManager(manager_);

  auto presentation_url =
      static_cast<rtsp::PresentationUrl*>(message->payload().get_property(rtsp::WFD_PRESENTATION_URL).get());
  if (presentation_url) {
    sink_media_manager->SetPresentationUrl(presentation_url->presentation_url_1());
  }

  auto video_formats =
      static_cast<rtsp::VideoFormats*>(message->payload().get_property(rtsp::WFD_VIDEO_FORMATS).get());

  if (!video_formats) {
    WDS_ERROR("Failed to obtain 'wfd-video-formats' in M4 handler.");
    return nullptr;
  }

  const auto& selected_formats = video_formats->GetH264Formats();
  if (selected_formats.size() != 1) {
    WDS_ERROR("Failed to obtain optimal video format from 'wfd-video-formats' in M4 handler.");
    return nullptr;
  }

  if (!sink_media_manager->SetOptimalVideoFormat(selected_formats[0])) {
    auto reply = std::unique_ptr<Reply>(new Reply(rtsp::STATUS_SeeOther));
    auto payload = std::unique_ptr<rtsp::Payload>(new rtsp::Payload());
    std::vector<unsigned short> error_codes = {rtsp::STATUS_UnsupportedMediaType};
    auto property_errors =
        std::make_shared<rtsp::PropertyErrors>(rtsp::WFD_VIDEO_FORMATS, error_codes);
    payload->add_property_error(property_errors);
    reply->set_payload(std::move(payload));
    return std::move(reply);
  }

  return std::unique_ptr<Reply>(new Reply(rtsp::STATUS_OK));
}

class M5Handler final : public MessageReceiver<Request::M5> {
 public:
  M5Handler(const InitParams& init_params)
    : MessageReceiver<Request::M5>(init_params) {
  }
  std::unique_ptr<Reply> HandleMessage(Message* message) override {
    auto property =
        static_cast<rtsp::TriggerMethod*>(message->payload().get_property(rtsp::WFD_TRIGGER_METHOD).get());

    auto reply = std::unique_ptr<Reply>(new Reply(rtsp::STATUS_OK));
    reply->header().set_cseq(message->cseq());
    if (property->method() != rtsp::TriggerMethod::SETUP) {
      reply->set_response_code(rtsp::STATUS_SeeOther);
    }

    return std::move(reply);
  }
};

CapNegotiationState::CapNegotiationState(const InitParams &init_params)
  : MessageSequenceWithOptionalSetHandler(init_params) {
  AddSequencedHandler(make_ptr(new M3Handler(init_params)));
  AddSequencedHandler(make_ptr(new M4Handler(init_params)));
  AddSequencedHandler(make_ptr(new M5Handler(init_params)));

  AddOptionalHandler(make_ptr(new M3Handler(init_params)));
  AddOptionalHandler(make_ptr(new M4Handler(init_params)));
}

}  // sink
}  // wds
<commit_msg>Ignore unknown properties when replying to GET_PARAMETER<commit_after>/*
 * This file is part of Wireless Display Software for Linux OS
 *
 * Copyright (C) 2014 Intel Corporation.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "cap_negotiation_state.h"

#include <iostream>

#include "libwds/rtsp/audiocodecs.h"
#include "libwds/rtsp/clientrtpports.h"
#include "libwds/rtsp/connectortype.h"
#include "libwds/rtsp/contentprotection.h"
#include "libwds/rtsp/coupledsink.h"
#include "libwds/rtsp/displayedid.h"
#include "libwds/rtsp/formats3d.h"
#include "libwds/rtsp/i2c.h"
#include "libwds/public/media_manager.h"
#include "libwds/rtsp/getparameter.h"
#include "libwds/rtsp/payload.h"
#include "libwds/rtsp/presentationurl.h"
#include "libwds/rtsp/propertyerrors.h"
#include "libwds/rtsp/reply.h"
#include "libwds/rtsp/setparameter.h"
#include "libwds/rtsp/standbyresumecapability.h"
#include "libwds/rtsp/triggermethod.h"
#include "libwds/rtsp/uibccapability.h"
#include "libwds/rtsp/videoformats.h"

namespace wds {
using rtsp::Message;
using rtsp::Request;
using rtsp::Reply;

namespace sink {

M3Handler::M3Handler(const InitParams& init_params)
  : MessageReceiver<Request::M3>(init_params) {
}

std::unique_ptr<Reply> M3Handler::HandleMessage(Message* message) {
  // FIXME : resolve clashes between wds exported and internal rtsp type names.
  using namespace rtsp;

  auto reply = std::unique_ptr<Reply>(new Reply(rtsp::STATUS_OK));
  auto props = message->payload().get_parameter_properties();
  for (auto it = props.begin(); it != props.end(); ++it) {
      std::shared_ptr<rtsp::Property> new_prop;
      if (*it == PropertyName::name[PropertyType::WFD_AUDIO_CODECS]){
          // FIXME: declare that we support absolutely every audio codec/format,
          // but there should be a MediaManager API for it
          auto codec_lpcm = AudioCodec(LPCM, AudioModes(3), 0);
          auto codec_aac = AudioCodec(AAC, AudioModes(15), 0);
          auto codec_ac3 = AudioCodec(AC3, AudioModes(7), 0);
          std::vector<AudioCodec> codec_list;
          codec_list.push_back(codec_lpcm);
          codec_list.push_back(codec_aac);
          codec_list.push_back(codec_ac3);
          new_prop.reset(new rtsp::AudioCodecs(codec_list));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_VIDEO_FORMATS]){
          new_prop.reset(new rtsp::VideoFormats(ToSinkMediaManager(manager_)->GetNativeVideoFormat(),
              false,
              ToSinkMediaManager(manager_)->GetSupportedH264VideoCodecs()));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_3D_FORMATS]){
          new_prop.reset(new Formats3d());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_CONTENT_PROTECTION]){
          new_prop.reset(new ContentProtection());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_DISPLAY_EDID]){
          new_prop.reset(new DisplayEdid());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_COUPLED_SINK]){
          new_prop.reset(new CoupledSink());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_CLIENT_RTP_PORTS]){
          new_prop.reset(new ClientRtpPorts(ToSinkMediaManager(manager_)->GetLocalRtpPorts().first,
                                            ToSinkMediaManager(manager_)->GetLocalRtpPorts().second));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_I2C]){
          new_prop.reset(new I2C(0));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_UIBC_CAPABILITY]){
          new_prop.reset(new UIBCCapability());
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_CONNECTOR_TYPE]){
          new_prop.reset(new rtsp::ConnectorType(ToSinkMediaManager(manager_)->GetConnectorType()));
          reply->payload().add_property(new_prop);
      } else if (*it == PropertyName::name[PropertyType::WFD_STANDBY_RESUME_CAPABILITY]){
          new_prop.reset(new StandbyResumeCapability(false));
          reply->payload().add_property(new_prop);
      } else {
          WDS_WARNING("** GET_PARAMETER: Ignoring unsupported property '%s'.", (*it).c_str());
      }
  }

  return std::move(reply);
}

M4Handler::M4Handler(const InitParams& init_params)
  : MessageReceiver<Request::M4>(init_params) {
}

std::unique_ptr<Reply> M4Handler::HandleMessage(Message* message) {
  SinkMediaManager* sink_media_manager = ToSinkMediaManager(manager_);

  auto presentation_url =
      static_cast<rtsp::PresentationUrl*>(message->payload().get_property(rtsp::WFD_PRESENTATION_URL).get());
  if (presentation_url) {
    sink_media_manager->SetPresentationUrl(presentation_url->presentation_url_1());
  }

  auto video_formats =
      static_cast<rtsp::VideoFormats*>(message->payload().get_property(rtsp::WFD_VIDEO_FORMATS).get());

  if (!video_formats) {
    WDS_ERROR("Failed to obtain 'wfd-video-formats' in M4 handler.");
    return nullptr;
  }

  const auto& selected_formats = video_formats->GetH264Formats();
  if (selected_formats.size() != 1) {
    WDS_ERROR("Failed to obtain optimal video format from 'wfd-video-formats' in M4 handler.");
    return nullptr;
  }

  if (!sink_media_manager->SetOptimalVideoFormat(selected_formats[0])) {
    auto reply = std::unique_ptr<Reply>(new Reply(rtsp::STATUS_SeeOther));
    auto payload = std::unique_ptr<rtsp::Payload>(new rtsp::Payload());
    std::vector<unsigned short> error_codes = {rtsp::STATUS_UnsupportedMediaType};
    auto property_errors =
        std::make_shared<rtsp::PropertyErrors>(rtsp::WFD_VIDEO_FORMATS, error_codes);
    payload->add_property_error(property_errors);
    reply->set_payload(std::move(payload));
    return std::move(reply);
  }

  return std::unique_ptr<Reply>(new Reply(rtsp::STATUS_OK));
}

class M5Handler final : public MessageReceiver<Request::M5> {
 public:
  M5Handler(const InitParams& init_params)
    : MessageReceiver<Request::M5>(init_params) {
  }
  std::unique_ptr<Reply> HandleMessage(Message* message) override {
    auto property =
        static_cast<rtsp::TriggerMethod*>(message->payload().get_property(rtsp::WFD_TRIGGER_METHOD).get());

    auto reply = std::unique_ptr<Reply>(new Reply(rtsp::STATUS_OK));
    reply->header().set_cseq(message->cseq());
    if (property->method() != rtsp::TriggerMethod::SETUP) {
      reply->set_response_code(rtsp::STATUS_SeeOther);
    }

    return std::move(reply);
  }
};

CapNegotiationState::CapNegotiationState(const InitParams &init_params)
  : MessageSequenceWithOptionalSetHandler(init_params) {
  AddSequencedHandler(make_ptr(new M3Handler(init_params)));
  AddSequencedHandler(make_ptr(new M4Handler(init_params)));
  AddSequencedHandler(make_ptr(new M5Handler(init_params)));

  AddOptionalHandler(make_ptr(new M3Handler(init_params)));
  AddOptionalHandler(make_ptr(new M4Handler(init_params)));
}

}  // sink
}  // wds
<|endoftext|>