<commit_before>/*

   nsjail
   -----------------------------------------

   Copyright 2014 Google Inc. All Rights Reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

#include "nsjail.h"

#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>

#include <memory>

#include "cmdline.h"
#include "logs.h"
#include "macros.h"
#include "net.h"
#include "sandbox.h"
#include "subproc.h"
#include "util.h"

namespace nsjail {

static __thread int sigFatal = 0;
static __thread bool showProc = false;

static void sigHandler(int sig) {
	if (sig == SIGALRM) {
		return;
	}
	if (sig == SIGCHLD) {
		return;
	}
	if (sig == SIGUSR1 || sig == SIGQUIT) {
		showProc = true;
		return;
	}
	sigFatal = sig;
}

static bool setSigHandler(int sig) {
	LOG_D("Setting sighandler for signal %s (%d)", util::sigName(sig).c_str(), sig);

	sigset_t smask;
	sigemptyset(&smask);

	struct sigaction sa;
	sa.sa_handler = sigHandler;
	sa.sa_mask = smask;
	sa.sa_flags = 0;
	sa.sa_restorer = NULL;

	if (sig == SIGTTIN || sig == SIGTTOU) {
		sa.sa_handler = SIG_IGN;
	};
	if (sigaction(sig, &sa, NULL) == -1) {
		PLOG_E("sigaction(%d)", sig);
		return false;
	}
	return true;
}

static bool setSigHandlers(void) {
	for (const auto& i : nssigs) {
		if (!setSigHandler(i)) {
			return false;
		}
	}
	return true;
}

static bool setTimer(nsjconf_t* nsjconf) {
	if (nsjconf->mode == MODE_STANDALONE_EXECVE) {
		return true;
	}

	struct itimerval it = {
	    .it_interval =
		{
		    .tv_sec = 1,
		    .tv_usec = 0,
		},
	    .it_value =
		{
		    .tv_sec = 1,
		    .tv_usec = 0,
		},
	};
	if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
		PLOG_E("setitimer(ITIMER_REAL)");
		return false;
	}
	return true;
}

static int listenMode(nsjconf_t* nsjconf) {
	int listenfd = net::getRecvSocket(nsjconf->bindhost.c_str(), nsjconf->port);
	if (listenfd == -1) {
		return EXIT_FAILURE;
	}
	for (;;) {
		if (sigFatal > 0) {
			subproc::killAll(nsjconf);
			logs::logStop(sigFatal);
			close(listenfd);
			return EXIT_SUCCESS;
		}
		if (showProc) {
			showProc = false;
			subproc::displayProc(nsjconf);
		}
		int connfd = net::acceptConn(listenfd);
		if (connfd >= 0) {
			subproc::runChild(nsjconf, connfd, connfd, connfd);
			close(connfd);
		}
		subproc::reapProc(nsjconf);
	}
}

static int standaloneMode(nsjconf_t* nsjconf) {
	if (!subproc::runChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) {
		LOG_E("Couldn't launch the child process");
		return 0xff;
	}
	for (;;) {
		int child_status = subproc::reapProc(nsjconf);

		if (subproc::countProc(nsjconf) == 0) {
			if (nsjconf->mode == MODE_STANDALONE_ONCE) {
				return child_status;
			}
			if (!subproc::runChild(
				nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) {
				LOG_E("Couldn't launch the child process");
				return 0xff;
			}
			continue;
		}
		if (showProc) {
			showProc = false;
			subproc::displayProc(nsjconf);
		}
		if (sigFatal > 0) {
			subproc::killAll(nsjconf);
			logs::logStop(sigFatal);
			return (128 + sigFatal);
		}

		pause();
	}
	// not reached
}

std::unique_ptr<struct termios> getTC(int fd) {
	std::unique_ptr<struct termios> trm(new struct termios);

	if (ioctl(fd, TCGETS, trm.get()) == -1) {
		PLOG_D("ioctl(fd=%d, TCGETS) failed", fd);
		return nullptr;
	}
	LOG_D("Saved the current state of the TTY");
	return trm;
}

void setTC(int fd, const struct termios* trm) {
	if (!trm) {
		return;
	}
	if (ioctl(fd, TCSETS, trm) == -1) {
		PLOG_W("ioctl(fd=%d, TCSETS) failed", fd);
		return;
	}
	LOG_D("Restored the previous state of the TTY");
}

}  // namespace nsjail

int main(int argc, char* argv[]) {
	std::unique_ptr<nsjconf_t> nsjconf = cmdline::parseArgs(argc, argv);
	std::unique_ptr<struct termios> trm = nsjail::getTC(STDIN_FILENO);

	if (!nsjconf) {
		LOG_F("Couldn't parse cmdline options");
	}
	if (!nsjconf->clone_newuser && geteuid() != 0) {
		LOG_W("--disable_clone_newuser might require root() privs");
	}
	if (nsjconf->daemonize && (daemon(0, 0) == -1)) {
		PLOG_F("daemon");
	}
	cmdline::logParams(nsjconf.get());
	if (!nsjail::setSigHandlers()) {
		LOG_F("nsjail::setSigHandlers() failed");
	}
	if (!nsjail::setTimer(nsjconf.get())) {
		LOG_F("nsjail::setTimer() failed");
	}
	if (!sandbox::preparePolicy(nsjconf.get())) {
		LOG_F("Couldn't prepare sandboxing policy");
	}

	int ret = 0;
	if (nsjconf->mode == MODE_LISTEN_TCP) {
		ret = nsjail::listenMode(nsjconf.get());
	} else {
		ret = nsjail::standaloneMode(nsjconf.get());
	}

	sandbox::closePolicy(nsjconf.get());
	/* Try to restore the underlying console's params in case some program has changed it */
	nsjail::setTC(STDIN_FILENO, trm.get());

	LOG_D("Returning with %d", ret);
	return ret;
}
<commit_msg>nsjail: clearer new_proc/reap_proc loop<commit_after>/*

   nsjail
   -----------------------------------------

   Copyright 2014 Google Inc. All Rights Reserved.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

#include "nsjail.h"

#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>

#include <memory>

#include "cmdline.h"
#include "logs.h"
#include "macros.h"
#include "net.h"
#include "sandbox.h"
#include "subproc.h"
#include "util.h"

namespace nsjail {

static __thread int sigFatal = 0;
static __thread bool showProc = false;

static void sigHandler(int sig) {
	if (sig == SIGALRM) {
		return;
	}
	if (sig == SIGCHLD) {
		return;
	}
	if (sig == SIGUSR1 || sig == SIGQUIT) {
		showProc = true;
		return;
	}
	sigFatal = sig;
}

static bool setSigHandler(int sig) {
	LOG_D("Setting sighandler for signal %s (%d)", util::sigName(sig).c_str(), sig);

	sigset_t smask;
	sigemptyset(&smask);

	struct sigaction sa;
	sa.sa_handler = sigHandler;
	sa.sa_mask = smask;
	sa.sa_flags = 0;
	sa.sa_restorer = NULL;

	if (sig == SIGTTIN || sig == SIGTTOU) {
		sa.sa_handler = SIG_IGN;
	};
	if (sigaction(sig, &sa, NULL) == -1) {
		PLOG_E("sigaction(%d)", sig);
		return false;
	}
	return true;
}

static bool setSigHandlers(void) {
	for (const auto& i : nssigs) {
		if (!setSigHandler(i)) {
			return false;
		}
	}
	return true;
}

static bool setTimer(nsjconf_t* nsjconf) {
	if (nsjconf->mode == MODE_STANDALONE_EXECVE) {
		return true;
	}

	struct itimerval it = {
	    .it_interval =
		{
		    .tv_sec = 1,
		    .tv_usec = 0,
		},
	    .it_value =
		{
		    .tv_sec = 1,
		    .tv_usec = 0,
		},
	};
	if (setitimer(ITIMER_REAL, &it, NULL) == -1) {
		PLOG_E("setitimer(ITIMER_REAL)");
		return false;
	}
	return true;
}

static int listenMode(nsjconf_t* nsjconf) {
	int listenfd = net::getRecvSocket(nsjconf->bindhost.c_str(), nsjconf->port);
	if (listenfd == -1) {
		return EXIT_FAILURE;
	}
	for (;;) {
		if (sigFatal > 0) {
			subproc::killAll(nsjconf);
			logs::logStop(sigFatal);
			close(listenfd);
			return EXIT_SUCCESS;
		}
		if (showProc) {
			showProc = false;
			subproc::displayProc(nsjconf);
		}
		int connfd = net::acceptConn(listenfd);
		if (connfd >= 0) {
			subproc::runChild(nsjconf, connfd, connfd, connfd);
			close(connfd);
		}
		subproc::reapProc(nsjconf);
	}
}

static int standaloneMode(nsjconf_t* nsjconf) {
	for (;;) {
		if (!subproc::runChild(nsjconf, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO)) {
			LOG_E("Couldn't launch the child process");
			return 0xff;
		}
		for (;;) {
			int child_status = subproc::reapProc(nsjconf);
			if (subproc::countProc(nsjconf) == 0) {
				if (nsjconf->mode == MODE_STANDALONE_ONCE) {
					return child_status;
				}
				break;
			}
			if (showProc) {
				showProc = false;
				subproc::displayProc(nsjconf);
			}
			if (sigFatal > 0) {
				subproc::killAll(nsjconf);
				logs::logStop(sigFatal);
				return (128 + sigFatal);
			}
			pause();
		}
	}
	// not reached
}

std::unique_ptr<struct termios> getTC(int fd) {
	std::unique_ptr<struct termios> trm(new struct termios);

	if (ioctl(fd, TCGETS, trm.get()) == -1) {
		PLOG_D("ioctl(fd=%d, TCGETS) failed", fd);
		return nullptr;
	}
	LOG_D("Saved the current state of the TTY");
	return trm;
}

void setTC(int fd, const struct termios* trm) {
	if (!trm) {
		return;
	}
	if (ioctl(fd, TCSETS, trm) == -1) {
		PLOG_W("ioctl(fd=%d, TCSETS) failed", fd);
		return;
	}
	LOG_D("Restored the previous state of the TTY");
}

}  // namespace nsjail

int main(int argc, char* argv[]) {
	std::unique_ptr<nsjconf_t> nsjconf = cmdline::parseArgs(argc, argv);
	std::unique_ptr<struct termios> trm = nsjail::getTC(STDIN_FILENO);

	if (!nsjconf) {
		LOG_F("Couldn't parse cmdline options");
	}
	if (!nsjconf->clone_newuser && geteuid() != 0) {
		LOG_W("--disable_clone_newuser might require root() privs");
	}
	if (nsjconf->daemonize && (daemon(0, 0) == -1)) {
		PLOG_F("daemon");
	}
	cmdline::logParams(nsjconf.get());
	if (!nsjail::setSigHandlers()) {
		LOG_F("nsjail::setSigHandlers() failed");
	}
	if (!nsjail::setTimer(nsjconf.get())) {
		LOG_F("nsjail::setTimer() failed");
	}
	if (!sandbox::preparePolicy(nsjconf.get())) {
		LOG_F("Couldn't prepare sandboxing policy");
	}

	int ret = 0;
	if (nsjconf->mode == MODE_LISTEN_TCP) {
		ret = nsjail::listenMode(nsjconf.get());
	} else {
		ret = nsjail::standaloneMode(nsjconf.get());
	}

	sandbox::closePolicy(nsjconf.get());
	/* Try to restore the underlying console's params in case some program has changed it */
	nsjail::setTC(STDIN_FILENO, trm.get());

	LOG_D("Returning with %d", ret);
	return ret;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: overlayobjectcell.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2008-03-12 09:34:16 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SDR_OVERLAY_OVERLAYOBJECTCELL_HXX
#define _SDR_OVERLAY_OVERLAYOBJECTCELL_HXX

#ifndef _SDR_OVERLAY_OVERLAYOBJECT_HXX
#include <svx/sdr/overlay/overlayobject.hxx>
#endif

#include <vector>

//////////////////////////////////////////////////////////////////////////////

// #114409#
namespace sdr
{
    namespace overlay
    {
        enum CellOverlayType { CELL_OVERLAY_INVERT, CELL_OVERLAY_HATCH, CELL_OVERLAY_TRANSPARENT, CELL_OVERLAY_LIGHT_TRANSPARENT };

        // OverlayObjectCell - used for cell cursor, selection and AutoFill handle

        class SVX_DLLPUBLIC OverlayObjectCell : public OverlayObject
        {
        public:
            typedef ::std::vector< basegfx::B2DRange > RangeVector;

        private:
            CellOverlayType mePaintType;
            RangeVector     maRectangles;

            virtual void drawGeometry(OutputDevice& rOutputDevice);
            virtual void createBaseRange(OutputDevice& rOutputDevice);

        public:
            OverlayObjectCell( CellOverlayType eType, const Color& rColor, const RangeVector& rRects);
            virtual ~OverlayObjectCell();

            virtual void transform(const basegfx::B2DHomMatrix& rMatrix);
        };

    } // end of namespace overlay
} // end of namespace sdr

//////////////////////////////////////////////////////////////////////////////

#endif //_SDR_OVERLAY_OVERLAYLINE_HXX

// eof
<commit_msg>INTEGRATION: CWS changefileheader (1.2.36); FILE MERGED 2008/04/01 12:47:53 thb 1.2.36.2: #i85898# Stripping all external header guards 2008/03/31 14:19:02 rt 1.2.36.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: overlayobjectcell.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _SDR_OVERLAY_OVERLAYOBJECTCELL_HXX
#define _SDR_OVERLAY_OVERLAYOBJECTCELL_HXX

#include <svx/sdr/overlay/overlayobject.hxx>

#include <vector>

//////////////////////////////////////////////////////////////////////////////

// #114409#
namespace sdr
{
    namespace overlay
    {
        enum CellOverlayType { CELL_OVERLAY_INVERT, CELL_OVERLAY_HATCH, CELL_OVERLAY_TRANSPARENT, CELL_OVERLAY_LIGHT_TRANSPARENT };

        // OverlayObjectCell - used for cell cursor, selection and AutoFill handle

        class SVX_DLLPUBLIC OverlayObjectCell : public OverlayObject
        {
        public:
            typedef ::std::vector< basegfx::B2DRange > RangeVector;

        private:
            CellOverlayType mePaintType;
            RangeVector     maRectangles;

            virtual void drawGeometry(OutputDevice& rOutputDevice);
            virtual void createBaseRange(OutputDevice& rOutputDevice);

        public:
            OverlayObjectCell( CellOverlayType eType, const Color& rColor, const RangeVector& rRects);
            virtual ~OverlayObjectCell();

            virtual void transform(const basegfx::B2DHomMatrix& rMatrix);
        };

    } // end of namespace overlay
} // end of namespace sdr

//////////////////////////////////////////////////////////////////////////////

#endif //_SDR_OVERLAY_OVERLAYLINE_HXX

// eof
<|endoftext|>


<commit_before>/*****************************************************************************
 * chromecast_demux.cpp: Chromecast demux filter module for vlc
 *****************************************************************************
 * Copyright © 2015-2016 VideoLAN
 *
 * Authors: Steve Lhomme <robux4@videolabs.io>
 *
 * This program 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 program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_demux.h>

#include "chromecast_common.h"

#include <new>

struct demux_sys_t
{
    demux_sys_t(demux_t * const demux, chromecast_common * const renderer)
        :p_demux(demux)
        ,p_renderer(renderer)
        ,i_length(-1)
        ,demuxReady(false)
        ,canSeek(false)
        ,m_seektime( VLC_TS_INVALID )
    {
        demux_t *p_last_demux = demux->p_next;
        while (p_last_demux->p_next)
            p_last_demux = p_last_demux->p_next;
        input_thread_t *p_input = p_last_demux->p_input;
        input_item_t *p_item = input_GetItem( p_input );
        if ( p_item )
        {
            char *psz_title = input_item_GetTitleFbName( p_item );
            p_renderer->pf_set_title( p_renderer->p_opaque, psz_title );
            free( psz_title );

            psz_title = input_item_GetArtworkURL( p_item );
            p_renderer->pf_set_artwork( p_renderer->p_opaque, psz_title );
            free( psz_title );
        }

        p_renderer->pf_set_input_state( p_renderer->p_opaque,
                                        (input_state_e) var_GetInteger( p_input, "state" ) );
        var_AddCallback( p_input, "intf-event", InputEvent, this );
    }

    ~demux_sys_t()
    {
        demux_t *p_last_demux = p_demux->p_next;
        while (p_last_demux->p_next)
            p_last_demux = p_last_demux->p_next;
        input_thread_t *p_input = p_last_demux->p_input;
        var_DelCallback( p_input, "intf-event", InputEvent, this );

        p_renderer->pf_set_title( p_renderer->p_opaque, NULL );
        p_renderer->pf_set_artwork( p_renderer->p_opaque, NULL );
    }

    /**
     * @brief getPlaybackTime
     * @return the current playback time on the device or VLC_TS_INVALID if unknown
     */
    mtime_t getPlaybackTime()
    {
        return p_renderer->pf_get_time( p_renderer->p_opaque );
    }

    double getPlaybackPosition()
    {
        return p_renderer->pf_get_position( p_renderer->p_opaque );
    }

    void setCanSeek( bool canSeek )
    {
        this->canSeek = canSeek;
    }

    bool seekTo( double pos )
    {
        if (i_length == -1)
            return false;
        return seekTo( mtime_t( i_length * pos ) );
    }

    bool seekTo( mtime_t i_pos )
    {
        if ( !canSeek )
            return false;

        /* seeking will be handled with the Chromecast */
        m_seektime = i_pos;
        p_renderer->pf_request_seek( p_renderer->p_opaque, i_pos );

        return true;
    }

    void setLength( mtime_t length )
    {
        this->i_length = length;
        p_renderer->pf_set_length( p_renderer->p_opaque, length );
    }

    int Demux()
    {
        if (!demuxReady)
        {
            msg_Dbg(p_demux, "wait to demux");
            p_renderer->pf_wait_app_started( p_renderer->p_opaque );
            demuxReady = true;
            msg_Dbg(p_demux, "ready to demux");
        }

        /* hold the data while seeking */
        /* wait until the device is buffering for data after the seek command */
        if ( m_seektime != VLC_TS_INVALID )
        {
            p_renderer->pf_wait_seek_done( p_renderer->p_opaque );
            m_seektime = VLC_TS_INVALID;
        }

        return demux_Demux( p_demux->p_next );
    }

protected:
    demux_t     * const p_demux;
    chromecast_common  * const p_renderer;
    mtime_t       i_length;
    bool          demuxReady;
    bool          canSeek;
    /* seek time kept while waiting for the chromecast to "seek" */
    mtime_t       m_seektime;

    static int InputEvent( vlc_object_t *p_this, char const *psz_var,
                           vlc_value_t oldval, vlc_value_t val, void * );
};

static int Demux( demux_t *p_demux_filter )
{
    demux_sys_t *p_sys = p_demux_filter->p_sys;

    return p_sys->Demux();
}

static int Control( demux_t *p_demux_filter, int i_query, va_list args)
{
    demux_sys_t *p_sys = p_demux_filter->p_sys;

    switch (i_query)
    {
    case DEMUX_GET_POSITION:
        *va_arg( args, double * ) = p_sys->getPlaybackPosition();
        return VLC_SUCCESS;

    case DEMUX_GET_TIME:
        *va_arg(args, int64_t *) = p_sys->getPlaybackTime();
        return VLC_SUCCESS;

    case DEMUX_GET_LENGTH:
    {
        int ret;
        va_list ap;

        va_copy( ap, args );
        ret = demux_vaControl( p_demux_filter->p_next, i_query, args );
        if( ret == VLC_SUCCESS )
            p_sys->setLength( *va_arg( ap, int64_t * ) );
        va_end( ap );
        return ret;
    }

    case DEMUX_CAN_SEEK:
    {
        int ret;
        va_list ap;

        va_copy( ap, args );
        ret = demux_vaControl( p_demux_filter->p_next, i_query, args );
        if( ret == VLC_SUCCESS )
            p_sys->setCanSeek( *va_arg( ap, bool* ) );
        va_end( ap );
        return ret;
    }

    case DEMUX_SET_POSITION:
    {
        va_list ap;

        va_copy( ap, args );
        double pos = va_arg( ap, double );
        va_end( ap );

        if ( p_sys->getPlaybackTime() == VLC_TS_INVALID )
        {
            msg_Dbg( p_demux_filter, "internal seek to %f when the playback didn't start", pos );
            break; // seek before device started, likely on-the-fly restart
        }

        if ( !p_sys->seekTo( pos ) )
        {
            msg_Err( p_demux_filter, "failed to seek to %f", pos );
            return VLC_EGENERIC;
        }
        break;
    }

    case DEMUX_SET_TIME:
    {
        va_list ap;

        va_copy( ap, args );
        mtime_t pos = va_arg( ap, mtime_t );
        va_end( ap );

        if ( p_sys->getPlaybackTime() == VLC_TS_INVALID )
        {
            msg_Dbg( p_demux_filter, "internal seek to %" PRId64 " when the playback didn't start", pos );
            break; // seek before device started, likely on-the-fly restart
        }

        if ( !p_sys->seekTo( pos ) )
        {
            msg_Err( p_demux_filter, "failed to seek to time %" PRId64, pos );
            return VLC_EGENERIC;
        }
        break;
    }
    }

    return demux_vaControl( p_demux_filter->p_next, i_query, args );
}

int demux_sys_t::InputEvent( vlc_object_t *p_this, char const *psz_var,
                                    vlc_value_t oldval, vlc_value_t val, void *p_data )
{
    VLC_UNUSED(psz_var);
    VLC_UNUSED(oldval);
    input_thread_t *p_input = reinterpret_cast<input_thread_t*>( p_this );
    demux_sys_t *p_sys = reinterpret_cast<demux_sys_t*>( p_data );

    if( val.i_int == INPUT_EVENT_STATE )
        p_sys->p_renderer->pf_set_input_state( p_sys->p_renderer->p_opaque,
                                               (input_state_e) var_GetInteger( p_input, "state" ) );

    return VLC_SUCCESS;
}

int Open(vlc_object_t *p_this)
{
    demux_t *p_demux = reinterpret_cast<demux_t*>(p_this);
    chromecast_common *p_renderer = reinterpret_cast<chromecast_common *>(
                var_InheritAddress( p_demux, CC_SHARED_VAR_NAME ) );
    if ( p_renderer == NULL )
    {
        msg_Warn( p_this, "using Chromecast demuxer with no sout" );
        return VLC_ENOOBJ;
    }

    demux_sys_t *p_sys = new(std::nothrow) demux_sys_t( p_demux, p_renderer );
    if (unlikely(p_sys == NULL))
        return VLC_ENOMEM;

    p_demux->p_sys = p_sys;
    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;

    return VLC_SUCCESS;
}

void Close(vlc_object_t *p_this)
{
    demux_t *p_demux = reinterpret_cast<demux_t*>(p_this);
    demux_sys_t *p_sys = p_demux->p_sys;

    delete p_sys;
}

vlc_module_begin ()
    set_shortname( "cc_demux" )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )
    set_description( N_( "chromecast demux wrapper" ) )
    set_capability( "demux_filter", 0 )
    add_shortcut( "cc_demux" )
    set_callbacks( Open, Close )
vlc_module_end ()
<commit_msg>chromecast: demux: use DEMUX_GET_META by default to get the title and artwork URL<commit_after>/*****************************************************************************
 * chromecast_demux.cpp: Chromecast demux filter module for vlc
 *****************************************************************************
 * Copyright © 2015-2016 VideoLAN
 *
 * Authors: Steve Lhomme <robux4@videolabs.io>
 *
 * This program 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 program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_demux.h>

#include "chromecast_common.h"

#include <new>

struct demux_sys_t
{
    demux_sys_t(demux_t * const demux, chromecast_common * const renderer)
        :p_demux(demux)
        ,p_renderer(renderer)
        ,i_length(-1)
        ,demuxReady(false)
        ,canSeek(false)
        ,m_seektime( VLC_TS_INVALID )
    {
        vlc_meta_t *p_meta = vlc_meta_New();
        if( likely(p_meta != NULL) )
        {
            if (demux_Control( demux->p_next, DEMUX_GET_META, p_meta) == VLC_SUCCESS)
            {
                const char *meta = vlc_meta_Get( p_meta, vlc_meta_Title );
                if ( meta != NULL )
                    p_renderer->pf_set_title( p_renderer->p_opaque, meta );
                meta = vlc_meta_Get( p_meta, vlc_meta_ArtworkURL );
                if ( meta != NULL )
                    p_renderer->pf_set_artwork( p_renderer->p_opaque, meta );
            }
            vlc_meta_Delete(p_meta);
        }
        p_renderer->pf_set_input_state( p_renderer->p_opaque,
                                        (input_state_e) var_GetInteger( p_input, "state" ) );
        var_AddCallback( p_input, "intf-event", InputEvent, this );
    }

    ~demux_sys_t()
    {
        demux_t *p_last_demux = p_demux->p_next;
        while (p_last_demux->p_next)
            p_last_demux = p_last_demux->p_next;
        input_thread_t *p_input = p_last_demux->p_input;
        var_DelCallback( p_input, "intf-event", InputEvent, this );

        p_renderer->pf_set_title( p_renderer->p_opaque, NULL );
        p_renderer->pf_set_artwork( p_renderer->p_opaque, NULL );
    }

    /**
     * @brief getPlaybackTime
     * @return the current playback time on the device or VLC_TS_INVALID if unknown
     */
    mtime_t getPlaybackTime()
    {
        return p_renderer->pf_get_time( p_renderer->p_opaque );
    }

    double getPlaybackPosition()
    {
        return p_renderer->pf_get_position( p_renderer->p_opaque );
    }

    void setCanSeek( bool canSeek )
    {
        this->canSeek = canSeek;
    }

    bool seekTo( double pos )
    {
        if (i_length == -1)
            return false;
        return seekTo( mtime_t( i_length * pos ) );
    }

    bool seekTo( mtime_t i_pos )
    {
        if ( !canSeek )
            return false;

        /* seeking will be handled with the Chromecast */
        m_seektime = i_pos;
        p_renderer->pf_request_seek( p_renderer->p_opaque, i_pos );

        return true;
    }

    void setLength( mtime_t length )
    {
        this->i_length = length;
        p_renderer->pf_set_length( p_renderer->p_opaque, length );
    }

    int Demux()
    {
        if (!demuxReady)
        {
            msg_Dbg(p_demux, "wait to demux");
            p_renderer->pf_wait_app_started( p_renderer->p_opaque );
            demuxReady = true;
            msg_Dbg(p_demux, "ready to demux");
        }

        /* hold the data while seeking */
        /* wait until the device is buffering for data after the seek command */
        if ( m_seektime != VLC_TS_INVALID )
        {
            p_renderer->pf_wait_seek_done( p_renderer->p_opaque );
            m_seektime = VLC_TS_INVALID;
        }

        return demux_Demux( p_demux->p_next );
    }

protected:
    demux_t     * const p_demux;
    chromecast_common  * const p_renderer;
    mtime_t       i_length;
    bool          demuxReady;
    bool          canSeek;
    /* seek time kept while waiting for the chromecast to "seek" */
    mtime_t       m_seektime;

    static int InputEvent( vlc_object_t *p_this, char const *psz_var,
                           vlc_value_t oldval, vlc_value_t val, void * );
};

static int Demux( demux_t *p_demux_filter )
{
    demux_sys_t *p_sys = p_demux_filter->p_sys;

    return p_sys->Demux();
}

static int Control( demux_t *p_demux_filter, int i_query, va_list args)
{
    demux_sys_t *p_sys = p_demux_filter->p_sys;

    switch (i_query)
    {
    case DEMUX_GET_POSITION:
        *va_arg( args, double * ) = p_sys->getPlaybackPosition();
        return VLC_SUCCESS;

    case DEMUX_GET_TIME:
        *va_arg(args, int64_t *) = p_sys->getPlaybackTime();
        return VLC_SUCCESS;

    case DEMUX_GET_LENGTH:
    {
        int ret;
        va_list ap;

        va_copy( ap, args );
        ret = demux_vaControl( p_demux_filter->p_next, i_query, args );
        if( ret == VLC_SUCCESS )
            p_sys->setLength( *va_arg( ap, int64_t * ) );
        va_end( ap );
        return ret;
    }

    case DEMUX_CAN_SEEK:
    {
        int ret;
        va_list ap;

        va_copy( ap, args );
        ret = demux_vaControl( p_demux_filter->p_next, i_query, args );
        if( ret == VLC_SUCCESS )
            p_sys->setCanSeek( *va_arg( ap, bool* ) );
        va_end( ap );
        return ret;
    }

    case DEMUX_SET_POSITION:
    {
        va_list ap;

        va_copy( ap, args );
        double pos = va_arg( ap, double );
        va_end( ap );

        if ( p_sys->getPlaybackTime() == VLC_TS_INVALID )
        {
            msg_Dbg( p_demux_filter, "internal seek to %f when the playback didn't start", pos );
            break; // seek before device started, likely on-the-fly restart
        }

        if ( !p_sys->seekTo( pos ) )
        {
            msg_Err( p_demux_filter, "failed to seek to %f", pos );
            return VLC_EGENERIC;
        }
        break;
    }

    case DEMUX_SET_TIME:
    {
        va_list ap;

        va_copy( ap, args );
        mtime_t pos = va_arg( ap, mtime_t );
        va_end( ap );

        if ( p_sys->getPlaybackTime() == VLC_TS_INVALID )
        {
            msg_Dbg( p_demux_filter, "internal seek to %" PRId64 " when the playback didn't start", pos );
            break; // seek before device started, likely on-the-fly restart
        }

        if ( !p_sys->seekTo( pos ) )
        {
            msg_Err( p_demux_filter, "failed to seek to time %" PRId64, pos );
            return VLC_EGENERIC;
        }
        break;
    }
    }

    return demux_vaControl( p_demux_filter->p_next, i_query, args );
}

int demux_sys_t::InputEvent( vlc_object_t *p_this, char const *psz_var,
                                    vlc_value_t oldval, vlc_value_t val, void *p_data )
{
    VLC_UNUSED(psz_var);
    VLC_UNUSED(oldval);
    input_thread_t *p_input = reinterpret_cast<input_thread_t*>( p_this );
    demux_sys_t *p_sys = reinterpret_cast<demux_sys_t*>( p_data );

    if( val.i_int == INPUT_EVENT_STATE )
        p_sys->p_renderer->pf_set_input_state( p_sys->p_renderer->p_opaque,
                                               (input_state_e) var_GetInteger( p_input, "state" ) );

    return VLC_SUCCESS;
}

int Open(vlc_object_t *p_this)
{
    demux_t *p_demux = reinterpret_cast<demux_t*>(p_this);
    chromecast_common *p_renderer = reinterpret_cast<chromecast_common *>(
                var_InheritAddress( p_demux, CC_SHARED_VAR_NAME ) );
    if ( p_renderer == NULL )
    {
        msg_Warn( p_this, "using Chromecast demuxer with no sout" );
        return VLC_ENOOBJ;
    }

    demux_sys_t *p_sys = new(std::nothrow) demux_sys_t( p_demux, p_renderer );
    if (unlikely(p_sys == NULL))
        return VLC_ENOMEM;

    p_demux->p_sys = p_sys;
    p_demux->pf_demux = Demux;
    p_demux->pf_control = Control;

    return VLC_SUCCESS;
}

void Close(vlc_object_t *p_this)
{
    demux_t *p_demux = reinterpret_cast<demux_t*>(p_this);
    demux_sys_t *p_sys = p_demux->p_sys;

    delete p_sys;
}

vlc_module_begin ()
    set_shortname( "cc_demux" )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_DEMUX )
    set_description( N_( "chromecast demux wrapper" ) )
    set_capability( "demux_filter", 0 )
    add_shortcut( "cc_demux" )
    set_callbacks( Open, Close )
vlc_module_end ()
<|endoftext|>


<commit_before>/*
 *  5/3/17
 *  Student author: Anthony Sarkis
 */

#include <random>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <map>

#include "particle_filter.h"

using namespace std;

void ParticleFilter::init(double x, double y, double theta, double std[]) {
	// Initialize all particles to first position (based on estimates of
	//   x, y, theta and their uncertainties from GPS)

	num_particles = 100;

	random_device rd;
    mt19937 gen(rd());
	normal_distribution<double> dist_x(		x, 		std[0]) ;
	normal_distribution<double> dist_y(		y, 		std[1]) ;
	normal_distribution<double> dist_psi(	theta, 	std[2]);

	weights.resize(num_particles) ;
	particles.resize(num_particles) ;

	for (int i = 0; i < num_particles; ++i) {

		particles[i].id 	= i ;
		particles[i].x 		= dist_x(gen) ;  // Add random Gaussian noise to each particle.
		particles[i].y 		= dist_y(gen) ;
		particles[i].theta 	= dist_psi(gen) ;
		particles[i].weight = 1.0 ;
		// cout << "Sample " << i + 1 << " " << sample_x << " " << sample_y << " " << sample_psi << endl;
	}

	is_initialized = true;
	cout << "Initialization complete" << endl;
}

void ParticleFilter::prediction(double delta_t, double std_pos[], double velocity, double yaw_rate) {

	// cout << "start prediction" << endl;
	random_device rd;
    mt19937 gen(rd());

	for (int i = 0; 	i < num_particles; 		i++) {

		const double theta = particles[i].theta ;

		// cout << "Prediction step:" << i << endl;

		// Add measurements

		if ( fabs(yaw_rate) > 0.001) {		// Turning

			const double velocity_yaw_rate = velocity / yaw_rate ;
			const double yaw_rate_delta_t  = yaw_rate * delta_t ;

			particles[i].x +=  velocity_yaw_rate * (sin(theta + yaw_rate_delta_t) - sin(theta)) ;
			particles[i].y +=  velocity_yaw_rate * (cos(theta) - cos(theta + yaw_rate_delta_t)) ;
			particles[i].theta += yaw_rate * delta_t ;
		}

		else {		// Going straight

			const double velocity_delta_t = velocity * delta_t ;

			particles[i].x += velocity_delta_t * cos(theta) ;
			particles[i].y += velocity_delta_t * sin(theta) ;
			// theta excluded as no updates
		}

		// add random Gaussian noise
		normal_distribution<double> dist_x(		0, 	std_pos[0]) ;
		normal_distribution<double> dist_y(		0, 	std_pos[1]) ;
		normal_distribution<double> dist_psi(	0, 	std_pos[2]);

		particles[i].x 		+= dist_x(	gen) ;  // += since normal_distribution centere on 0.
		particles[i].y 		+= dist_y(	gen) ;
		particles[i].theta 	+= dist_psi(gen) ;
	}
	// cout << "prediction complete" << endl;
}

void ParticleFilter::dataAssociation( std::vector<LandmarkObs> predicted,
									  std::vector<LandmarkObs>& observations) {
    // helper during the updateWeights phase.

	double difference ;
	double threshold = 9999999.0;

	for (unsigned int i = 0;	i < observations.size();	 i++){

		// Find the predicted measurement that is closest to each observed measurement
		difference = dist( predicted[i].x,    predicted[i].y,
						   observations[i].x, observations[i].y) ;

		if (difference < threshold) {

			threshold = difference ;
			observations[i].id = predicted[i].id ;  // assign the measurement to this particular landmark

		// cout << "difference " << difference << "\t observation ids: " << observations[i].id << endl;
		}
	}
}

void ParticleFilter::updateWeights(double sensor_range, double std_landmark[],
		std::vector<LandmarkObs> observations, Map map_landmarks) {

	// cout << "Starting update weights" << endl;

	vector<LandmarkObs> transformed_observations ;
	const int observations_size = observations.size() ;
	transformed_observations.resize(observations_size) ;

	// 1. Convert particle observations to global frame
	for (int i = 0; 	i < num_particles; 		i++) {

		// cout << "Update step: \t" << i << endl;

		for (int k = 0; 	k < observations_size;		k++) {

			// Pre-compute terms
			const double particle_theta = particles[i].theta ;
			const double cos_theta 		= cos(particle_theta) ;
			const double sin_theta 		= sin(particle_theta) ;

			// Create placeholder for transformations
			LandmarkObs single_transformed_observation ;

			// p_x + (obs_x * cos(theta)) - (obs_y * sin(theta))
			single_transformed_observation.x =  particles[i].x    +
											   (observations[k].x * cos_theta) -
											   (observations[k].y * sin_theta) ;

			// p_y + (obs_x * sin(theta)) + (obs_y * cos(theta))
			single_transformed_observation.y =  particles[i].y    +
											   (observations[k].x * sin_theta) +
											   (observations[k].y * cos_theta) ;

			transformed_observations[k] = single_transformed_observation ;
		}

		// cout << "Transformation complete" << endl;

		// 2. Only keep landmarks that are within range
		vector<LandmarkObs> reasonable_landmarks ;
		reasonable_landmarks.resize(num_particles) ;  // for debugging

		int landmark_limit = map_landmarks.landmark_list.size() ;

		for (int q = 0;		q < landmark_limit;		q++){

			const double landmark_position_x = map_landmarks.landmark_list[q].x_f ;
			const double landmark_position_y = map_landmarks.landmark_list[q].y_f ;

			// 2.1 Compare particle distance to landmark distance
			double difference = dist( landmark_position_x, landmark_position_y,
						   	          particles[i].x, particles[i].y );
			// cout << difference << "  " << sensor_range << endl;

			// 2.2 Only look at landmarks within sensor range
			if (difference <= sensor_range) {

				const int landmark_id = map_landmarks.landmark_list[q].id_i ;

				reasonable_landmarks.push_back( LandmarkObs { landmark_id,
															  landmark_position_x,
															  landmark_position_y }) ;
			}
			// cout << reasonable_landmarks.size() << endl;
		}

		// 3. Associate each predicted measurement to it's closest point
		dataAssociation(reasonable_landmarks, transformed_observations) ;
		// cout << "dataAssociation complete, reasonable landmarks size: " << reasonable_landmarks.size() << endl;

		// 4. Weight distribution
		// Pre compute
		const double standard_x 			= std_landmark[0] ;
		const double standard_y 			= std_landmark[1] ;
		const double standard_x_squared_2	= (standard_x * standard_x) * 2 ;
		const double standard_y_squared_2	= (standard_y * standard_y) * 2;
		const double part_1 				= 1 / (2 * M_PI * standard_x * standard_y) ;
		// cout << part_1 << endl;

		double weight_placeholder = particles[i].weight ;
		// if reasonable landmarks have been found
		if (reasonable_landmarks.size() > 0) {

			for (unsigned int zzz = 0; 	zzz < observations.size();	zzz++) {

				const double x 				= observations[zzz].x ;
				const double u_x 			= reasonable_landmarks[zzz].x ;
				const double y 			  	= observations[zzz].y ;
				const double u_y 		  	= reasonable_landmarks[zzz].y ;
				const double x_ux_squared 	= (x - u_x) * (x - u_x) ;
				const double y_uy_squared 	= (y - u_y) * (y - u_y) ;
				const double part_2 		= x_ux_squared / (standard_x_squared_2) +
									 		  y_uy_squared / (standard_y_squared_2) ;
				double exp_part_2			= exp(-part_2) ;

				// cout << weight_placeholder << endl;
				// cout << part_1 << "\t" << part_2 << "\t" << exp_part_2 << endl;

				if (exp_part_2 < .001) {
					exp_part_2 = .001;
				}

				weight_placeholder *= part_1 * exp_part_2 ;

				// cout << weight_placeholder << endl;
				// cout << "x " << x << "\tu_x " << u_x << "\ty " << y << "\tu_y " <<  u_y << endl ;
			}
		}
		else {
			weights[i] 			= 0.0000000001 ;
			particles[i].weight = 0.0000000001 ;
			cout << "No reasonable landmarks" << endl;
		}

		weights[i] 			= weight_placeholder ;
		particles[i].weight = weight_placeholder ;
		// cout << "Weight update complete" << endl;
	}
}

void ParticleFilter::resample() {
	// Resample particles with replacement with probability proportional to their weight.
	// cout << "Resample started " << " " << particles.size() << endl;

	// from http://en.cppreference.com/w/cpp/numeric/random/discrete_distribution
    random_device rd;
    mt19937 gen(rd());
	discrete_distribution<> d(weights.begin(), weights.end());

	// cout << "Number of particles \t" << num_particles << endl;

	vector<Particle> resampled_particles ;
	resampled_particles.resize(num_particles) ;

    for(int n = 0;	n < num_particles;	n++) {

    	// cout << "Resample step: \t" << n << endl;

    	int new_index = d(gen);
    	// cout << new_index << endl ;
        resampled_particles[n] = particles[new_index];
    }
    // cout << "Resample complete" << endl;
    particles = resampled_particles ;
}

void ParticleFilter::write(std::string filename) {
	// You don't need to modify this file.
	std::ofstream dataFile;
	dataFile.open(filename, std::ios::app);
	for (int i = 0; i < num_particles; ++i) {
		dataFile << particles[i].x << " " << particles[i].y << " " << particles[i].theta << "\n";
	}
	dataFile.close();
}
<commit_msg>many more fixes... updateWeights() needs to be refacted<commit_after>/*
 *  5/3/17
 *  Student author: Anthony Sarkis
 */

#include <random>
#include <algorithm>
#include <iostream>
#include <numeric>
#include <map>

#include "particle_filter.h"

using namespace std;

void ParticleFilter::init(double x, double y, double theta, double std[]) {
	// Initialize all particles to first position (based on estimates of
	//   x, y, theta and their uncertainties from GPS)

	num_particles = 100;

	random_device rd;
    mt19937 gen(rd());
	// default_random_engine gen;

	normal_distribution<double> dist_x(		x, 		std[0]) ;
	normal_distribution<double> dist_y(		y, 		std[1]) ;
	normal_distribution<double> dist_psi(	theta, 	std[2]);

	weights.resize(num_particles) ;
	particles.resize(num_particles) ;

	for (int i = 0; i < num_particles; ++i) {

		particles[i].id 	= i ;
		particles[i].x 		= dist_x(gen) ;  // Add random Gaussian noise to each particle.
		particles[i].y 		= dist_y(gen) ;
		particles[i].theta 	= dist_psi(gen) ;
		particles[i].weight = 1.0 ;
		// cout << "Sample " << i + 1 << " " << sample_x << " " << sample_y << " " << sample_psi << endl;
	}

	is_initialized = true;
	cout << "Initialization complete" << endl;
}

void ParticleFilter::prediction(double delta_t, double std_pos[], double velocity, double yaw_rate) {

	// cout << "start prediction" << endl;
	random_device rd;
    mt19937 gen(rd());

	for (int i = 0; 	i < num_particles; 		i++) {

		const double theta = particles[i].theta ;

		// cout << "Prediction step:" << i << endl;

		// Add measurements

		if ( fabs(yaw_rate) > 0.00001) {		// Turning

			const double velocity_yaw_rate = velocity / yaw_rate ;
			const double yaw_rate_delta_t  = yaw_rate * delta_t ;

			particles[i].x 		+=  velocity_yaw_rate * (sin(theta + yaw_rate_delta_t) - sin(theta)) ;
			particles[i].y 		+=  velocity_yaw_rate * (cos(theta) - cos(theta + yaw_rate_delta_t)) ;
			particles[i].theta 	+= yaw_rate * delta_t ;
		}

		else {		// Going straight

			const double velocity_delta_t = velocity * delta_t ;

			particles[i].x += velocity_delta_t * cos(theta) ;
			particles[i].y += velocity_delta_t * sin(theta) ;
			// theta excluded as going straight
		}

		// add random Gaussian noise
		normal_distribution<double> dist_x(		particles[i].x, 	std_pos[0]) ;
		normal_distribution<double> dist_y(		particles[i].y, 	std_pos[1]) ;
		normal_distribution<double> dist_psi(	particles[i].theta, 	std_pos[2]);

		particles[i].x 		= dist_x(	gen) ;  // += since normal_distribution center on 0.
		particles[i].y 		= dist_y(	gen) ;
		particles[i].theta 	= dist_psi(gen) ;
	}
	// cout << "prediction complete" << endl;
}

// IGNORE
void ParticleFilter::dataAssociation( std::vector<LandmarkObs> reasonable_landmarks,
									  std::vector<LandmarkObs>& transformed_observations) {

}

void ParticleFilter::updateWeights(double sensor_range, double std_landmark[],
		std::vector<LandmarkObs> observations, Map map_landmarks) {

	// cout << "Starting update weights" << endl;

	vector<LandmarkObs> transformed_observations ;
	const int observations_size = observations.size() ;
	transformed_observations.resize(observations_size) ;

	// 1. Convert particle observations to global frame
	for (int i = 0; 	i < num_particles; 		i++) {

		// cout << "Update step: \t" << i << endl;

		// Create placeholder for transformations
		LandmarkObs single_transformed_observation ;

		for (int k = 0; 	k < observations_size;		k++) {

			// Pre-compute terms
			const double particle_theta = particles[i].theta ;
			const double cos_theta 		= cos(particle_theta) ;
			const double sin_theta 		= sin(particle_theta) ;

			// p_x + (obs_x * cos(theta)) - (obs_y * sin(theta))
			single_transformed_observation.x =  particles[i].x    +
											   (observations[k].x * cos_theta) -
											   (observations[k].y * sin_theta) ;

			// p_y + (obs_x * sin(theta)) + (obs_y * cos(theta))
			single_transformed_observation.y =  particles[i].y    +
											   (observations[k].x * sin_theta) +
											   (observations[k].y * cos_theta) ;

			transformed_observations[k] = single_transformed_observation ;
		}

		// cout << transformed_observations.size() << endl;

		// cout << "Transformation complete" << endl;

		// 2. Only keep landmarks that are within range

		// reasonable_landmarks 	= landmarks obverserved by particles,
		// 						      that are also within sensor range
		// transformed_observations = observations transformed
		//                            into global reference frame

		vector<LandmarkObs> reasonable_landmarks ;
		int landmark_limit = map_landmarks.landmark_list.size() ;
		reasonable_landmarks.resize(transformed_observations.size()) ;  // for debugging

		vector<int> reasonable_particles_landmark_ids ;
		reasonable_particles_landmark_ids.resize(transformed_observations.size()) ;

		for (unsigned int ggg = 0;	ggg < transformed_observations.size();	 ggg++) {

			for (int q = 0;		q < landmark_limit;		q++){

				const double landmark_position_x = map_landmarks.landmark_list[q].x_f ;
				const double landmark_position_y = map_landmarks.landmark_list[q].y_f ;

				// 2.1 Compare particle distance to landmark distance
				double difference = dist( landmark_position_x, landmark_position_y,
							   	          transformed_observations[ggg].x,
							   	          transformed_observations[ggg].y );
				// cout << difference << "  " << sensor_range << endl;

				// 2.2 Only look at landmarks within sensor range
				if (difference <= sensor_range) {

					const int landmark_id = map_landmarks.landmark_list[q].id_i ;
					// cout << "landmark_id\t" << landmark_id << endl ;

					reasonable_landmarks.push_back( LandmarkObs { landmark_id,
																  landmark_position_x,
																  landmark_position_y }) ;
				}
		}

			// cout << "reasonable_landmarks" << "\t" << reasonable_landmarks[ggg].x
			// << "," << reasonable_landmarks[ggg].y  << endl ;
		}

		// 3. Associate each predicted measurement to it's closest point
		// cout << reasonable_landmarks.size() << "\t" << transformed_observations.size() << endl;
		// loop through all observations
		for (unsigned int jjj = 0;	jjj < transformed_observations.size();	 jjj++){

			double associate_difference ;
			double threshold = 9999999.0 ;
			int current_id ;

			// for each observation, compare it to all reasonable landmarks
			for (unsigned int qqt = 0;	qqt < reasonable_landmarks.size();	 qqt++){

			// Find the predicted measurement that is closest to each observed measurement
			associate_difference = dist( reasonable_landmarks[qqt].x,    reasonable_landmarks[qqt].y,
							   transformed_observations[jjj].x, transformed_observations[jjj].y) ;

				// check if threshold is less than previous
				if (associate_difference < threshold) {

					// if it is, then we have the current lowest ID
					current_id = reasonable_landmarks[qqt].id ;

					// assign the threshold to the current difference
					// so that next loop if the difference is higher it won't update the id.
					threshold = associate_difference ;
				}
			}
			// assign the id of the correct particle from the observation to a list
			reasonable_particles_landmark_ids[jjj] = current_id ;
			// cout << current_id << endl ;
			// cout << reasonable_particles_landmark_ids[jjj] << endl ;
		}

		// cout << "difference \t" << difference << endl ;
		// cout << "reasonable_particles_landmark_ids size: \t" << reasonable_particles_landmark_ids.size()
		// << "\t" << reasonable_landmarks.size() << endl;
		// cout << "dataAssociation complete, reasonable landmarks size: " << reasonable_landmarks.size() << endl;

		// 4. Weight distribution
		// Pre compute
		const double standard_x 			= std_landmark[0] ;
		const double standard_y 			= std_landmark[1] ;
		const double standard_x_squared_2	= (standard_x * standard_x) * 2 ;
		const double standard_y_squared_2	= (standard_y * standard_y) * 2;
		const double part_1 				= 1 / (2 * M_PI * standard_x * standard_y) ;
		// cout << part_1 << endl;
		//cout << reasonable_landmarks.size() << "\t" << transformed_observations.size() << endl;

		double weight_placeholder = 1.0 ;
		// if reasonable landmarks have been found
		if (reasonable_landmarks.size() > 0) {

			// cout << reasonable_particles_landmark_ids.size() << "\t" << transformed_observations.size() << endl;

			for (unsigned int zzz = 0; 	zzz < transformed_observations.size();	zzz++) {

				const int r_p_index			= reasonable_particles_landmark_ids[zzz] ;
				const double x 				= transformed_observations[zzz].x ;
				const double u_x 			= reasonable_landmarks[r_p_index].x ;
				const double y 			  	= transformed_observations[zzz].y ;
				const double u_y 		  	= reasonable_landmarks[r_p_index].y ;
				const double x_ux_squared 	= (x - u_x) * (x - u_x) ;
				const double y_uy_squared 	= (y - u_y) * (y - u_y) ;
				const double part_2 		= x_ux_squared / (standard_x_squared_2) +
									 		  y_uy_squared / (standard_y_squared_2) ;
				double exp_part_2			= exp(-part_2) ;

				// cout << "transformed_observations\t" << x << "," << y <<
				// "\t reasonable_landmarks\t" << u_x << "," << u_y << endl ;

				// cout << weight_placeholder << endl;
				// cout << part_2 << "\t" << exp_part_2 << endl;

				if (exp_part_2 < .00001) {
					exp_part_2 = .00001;
				}

				weight_placeholder *= part_1 * exp_part_2 ;

				// cout << weight_placeholder << endl;
				// cout << "x " << x << "\tu_x " << u_x << "\ty " << y << "\tu_y " <<  u_y << endl ;
			}
		}
		else {
			weights[i] 			= 0.00001 ;
			particles[i].weight = 0.00001 ;
			cout << "No reasonable landmarks" << endl;
		}

		weights[i] 			= weight_placeholder ;
		particles[i].weight = weight_placeholder ;
		// cout << "Weight update complete" << endl;
	}
}

void ParticleFilter::resample() {
	// Resample particles with replacement with probability proportional to their weight.
	// cout << "Resample started " << " " << particles.size() << endl;

	// from http://en.cppreference.com/w/cpp/numeric/random/discrete_distribution
    random_device rd;
    mt19937 gen(rd());
	discrete_distribution<> d(weights.begin(), weights.end());

	// cout << "Number of particles \t" << num_particles << endl;

	vector<Particle> resampled_particles ;
	resampled_particles.resize(num_particles) ;

    for(int n = 0;	n < num_particles;	n++) {

    	// cout << "Resample step: \t" << n << endl;
    	int new_index = d(gen);
    	// cout << new_index << endl ;
        resampled_particles[n] = particles[new_index];
    }
    // cout << "Resample complete" << endl;
    particles = resampled_particles ;
}

void ParticleFilter::write(std::string filename) {
	// You don't need to modify this file.
	std::ofstream dataFile;
	dataFile.open(filename, std::ios::app);
	for (int i = 0; i < num_particles; ++i) {
		dataFile << particles[i].x << " " << particles[i].y << " " << particles[i].theta << "\n";
	}
	dataFile.close();
}
<|endoftext|>


<commit_before><commit_msg>Attempt to fix flakey test.<commit_after><|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <xenia/kernel/xboxkrnl_audio.h>

#include <xenia/emulator.h>
#include <xenia/apu/apu.h>
#include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/xboxkrnl_private.h>
#include <xenia/kernel/util/shim_utils.h>

using namespace xe;
using namespace xe::apu;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;

namespace xe {
namespace kernel {

SHIM_CALL XMACreateContext_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t context_ptr = SHIM_GET_ARG_32(0);

  XELOGD(
      "XMACreateContext(%.8X)",
      context_ptr);

  // TODO(benvanik): allocate and return -- see if size required or just dummy?

  SHIM_SET_RETURN(X_ERROR_ACCESS_DENIED);
}

SHIM_CALL XMAReleaseContext_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t context_ptr = SHIM_GET_ARG_32(0);

  XELOGD(
      "XMAReleaseContext(%.8X)",
      context_ptr);

  // TODO(benvanik): free
}

SHIM_CALL XAudioGetVoiceCategoryVolume_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t unk_0 = SHIM_GET_ARG_32(0);
  uint32_t out_ptr = SHIM_GET_ARG_32(1);

  XELOGD(
      "XAudioGetVoiceCategoryVolume(%.8X, %.8X)",
      unk_0, out_ptr);

  // Expects a floating point single. Volume %?
  SHIM_SET_MEM_32(out_ptr, 0);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioGetSpeakerConfig_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t config_ptr = SHIM_GET_ARG_32(0);

  XELOGD(
      "XAudioGetSpeakerConfig(%.8X)",
      config_ptr);

  SHIM_SET_MEM_32(config_ptr, 1);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioRegisterRenderDriverClient_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t callback_ptr = SHIM_GET_ARG_32(0);
  uint32_t driver_ptr = SHIM_GET_ARG_32(1);

  uint32_t callback = SHIM_MEM_32(callback_ptr + 0);
  uint32_t callback_arg = SHIM_MEM_32(callback_ptr + 4);

  XELOGD(
      "XAudioRegisterRenderDriverClient(%.8X(%.8X, %.8X), %.8X)",
      callback_ptr, callback, callback_arg, driver_ptr);

  auto audio_system = state->emulator()->audio_system();
  audio_system->RegisterClient(callback, callback_arg);

  SHIM_SET_MEM_32(driver_ptr, 0xAADD1100);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioUnregisterRenderDriverClient_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t driver_ptr = SHIM_GET_ARG_32(0);

  XELOGD(
      "XAudioUnregisterRenderDriverClient(%.8X)",
      driver_ptr);

  XEASSERT(driver_ptr == 0xAADD1100);

  auto audio_system = state->emulator()->audio_system();
  audio_system->UnregisterClient();

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioSubmitRenderDriverFrame_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t driver_ptr = SHIM_GET_ARG_32(0);
  uint32_t samples_ptr = SHIM_GET_ARG_32(1);

  XELOGD(
      "XAudioSubmitRenderDriverFrame(%.8X, %.8X)",
      driver_ptr, samples_ptr);

  XEASSERT(driver_ptr == 0xAADD1100);

  auto audio_system = state->emulator()->audio_system();
  audio_system->SubmitFrame(samples_ptr);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

}  // namespace kernel
}  // namespace xe

void xe::kernel::xboxkrnl::RegisterAudioExports(
    ExportResolver* export_resolver, KernelState* state) {
  SHIM_SET_MAPPING("xboxkrnl.exe", XMACreateContext, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAInitializeContext, state);
  SHIM_SET_MAPPING("xboxkrnl.exe", XMAReleaseContext, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAEnableContext, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMADisableContext, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAGetOutputBufferWriteOffset, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetOutputBufferReadOffset, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAGetOutputBufferReadOffset, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetOutputBufferValid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAIsOutputBufferValid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBuffer0Valid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAIsInputBuffer0Valid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBuffer1Valid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAIsInputBuffer1Valid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBuffer0, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBuffer1, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAGetPacketMetadata, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMABlockWhileInUse, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetLoopData, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBufferReadOffset, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAGetInputBufferReadOffset, state);

  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioGetVoiceCategoryVolume, state);
  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioGetSpeakerConfig, state);

  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioRegisterRenderDriverClient, state);
  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioUnregisterRenderDriverClient, state);
  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioSubmitRenderDriverFrame, state);
}
<commit_msg>XAudioGetVoiceCategoryVolumeChangeMask<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <xenia/kernel/xboxkrnl_audio.h>

#include <xenia/emulator.h>
#include <xenia/apu/apu.h>
#include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/xboxkrnl_private.h>
#include <xenia/kernel/util/shim_utils.h>

using namespace xe;
using namespace xe::apu;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;

namespace xe {
namespace kernel {

SHIM_CALL XMACreateContext_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t context_ptr = SHIM_GET_ARG_32(0);

  XELOGD(
      "XMACreateContext(%.8X)",
      context_ptr);

  // TODO(benvanik): allocate and return -- see if size required or just dummy?

  SHIM_SET_RETURN(X_ERROR_ACCESS_DENIED);
}

SHIM_CALL XMAReleaseContext_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t context_ptr = SHIM_GET_ARG_32(0);

  XELOGD(
      "XMAReleaseContext(%.8X)",
      context_ptr);

  // TODO(benvanik): free
}

SHIM_CALL XAudioGetSpeakerConfig_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t config_ptr = SHIM_GET_ARG_32(0);

  XELOGD(
      "XAudioGetSpeakerConfig(%.8X)",
      config_ptr);

  SHIM_SET_MEM_32(config_ptr, 1);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioGetVoiceCategoryVolumeChangeMask_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t driver_ptr = SHIM_GET_ARG_32(0);
  uint32_t out_ptr = SHIM_GET_ARG_32(1);

  XELOGD(
      "XAudioGetVoiceCategoryVolumeChangeMask(%.8X, %.8X)",
      driver_ptr, out_ptr);

  XEASSERT(driver_ptr == 0xAADD1100);

  // Checking these bits to see if any voice volume changed.
  // I think.
  SHIM_SET_MEM_32(out_ptr, 0);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioGetVoiceCategoryVolume_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t driver_ptr = SHIM_GET_ARG_32(0);
  uint32_t out_ptr = SHIM_GET_ARG_32(1);

  XELOGD(
      "XAudioGetVoiceCategoryVolume(%.8X, %.8X)",
      driver_ptr, out_ptr);

  XEASSERT(driver_ptr == 0xAADD1100);

  // Expects a floating point single. Volume %?
  SHIM_SET_MEM_32(out_ptr, 0);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioRegisterRenderDriverClient_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t callback_ptr = SHIM_GET_ARG_32(0);
  uint32_t driver_ptr = SHIM_GET_ARG_32(1);

  uint32_t callback = SHIM_MEM_32(callback_ptr + 0);
  uint32_t callback_arg = SHIM_MEM_32(callback_ptr + 4);

  XELOGD(
      "XAudioRegisterRenderDriverClient(%.8X(%.8X, %.8X), %.8X)",
      callback_ptr, callback, callback_arg, driver_ptr);

  auto audio_system = state->emulator()->audio_system();
  audio_system->RegisterClient(callback, callback_arg);

  SHIM_SET_MEM_32(driver_ptr, 0xAADD1100);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioUnregisterRenderDriverClient_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t driver_ptr = SHIM_GET_ARG_32(0);

  XELOGD(
      "XAudioUnregisterRenderDriverClient(%.8X)",
      driver_ptr);

  XEASSERT(driver_ptr == 0xAADD1100);

  auto audio_system = state->emulator()->audio_system();
  audio_system->UnregisterClient();

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

SHIM_CALL XAudioSubmitRenderDriverFrame_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t driver_ptr = SHIM_GET_ARG_32(0);
  uint32_t samples_ptr = SHIM_GET_ARG_32(1);

  XELOGD(
      "XAudioSubmitRenderDriverFrame(%.8X, %.8X)",
      driver_ptr, samples_ptr);

  XEASSERT(driver_ptr == 0xAADD1100);

  auto audio_system = state->emulator()->audio_system();
  audio_system->SubmitFrame(samples_ptr);

  SHIM_SET_RETURN(X_ERROR_SUCCESS);
}

}  // namespace kernel
}  // namespace xe

void xe::kernel::xboxkrnl::RegisterAudioExports(
    ExportResolver* export_resolver, KernelState* state) {
  SHIM_SET_MAPPING("xboxkrnl.exe", XMACreateContext, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAInitializeContext, state);
  SHIM_SET_MAPPING("xboxkrnl.exe", XMAReleaseContext, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAEnableContext, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMADisableContext, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAGetOutputBufferWriteOffset, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetOutputBufferReadOffset, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAGetOutputBufferReadOffset, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetOutputBufferValid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAIsOutputBufferValid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBuffer0Valid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAIsInputBuffer0Valid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBuffer1Valid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAIsInputBuffer1Valid, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBuffer0, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBuffer1, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAGetPacketMetadata, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMABlockWhileInUse, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetLoopData, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMASetInputBufferReadOffset, state);
  // SHIM_SET_MAPPING("xboxkrnl.exe", XMAGetInputBufferReadOffset, state);

  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioGetSpeakerConfig, state);

  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioGetVoiceCategoryVolumeChangeMask, state);
  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioGetVoiceCategoryVolume, state);

  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioRegisterRenderDriverClient, state);
  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioUnregisterRenderDriverClient, state);
  SHIM_SET_MAPPING("xboxkrnl.exe", XAudioSubmitRenderDriverFrame, state);
}
<|endoftext|>


<commit_before>#include <string.h>
#include <windows.h>
#include <shellapi.h>
#include "../Daemon.h"
#include "Win32App.h"

#define ID_ABOUT 2000
#define ID_EXIT 2001

void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
{
    HMENU hPopup = CreatePopupMenu();
    InsertMenu (hPopup, 0, MF_BYPOSITION | MF_STRING, ID_ABOUT, "About...");
    InsertMenu (hPopup, 1, MF_BYPOSITION | MF_STRING, ID_EXIT , "Exit");
    SetMenuDefaultItem (hPopup, ID_ABOUT, FALSE);
    SetFocus (hWnd);
    SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);

    POINT p;
    if (!curpos)
    {
        GetCursorPos (&p);
        curpos = &p;
    }

    WORD cmd = TrackPopupMenu (hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, curpos->x, curpos->y, 0, hWnd, NULL);
    SendMessage (hWnd, WM_COMMAND, cmd, 0);

    DestroyMenu(hPopup);
}

void AddTrayIcon (HWND hWnd, UINT uID, UINT uCallbackMsg, UINT uIcon)
{
    NOTIFYICONDATA nid;
    nid.hWnd = hWnd;
    nid.uID = uID;
    nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nid.uCallbackMessage = uCallbackMsg;
    nid.hIcon = LoadIcon (GetModuleHandle(NULL), IDI_APPLICATION);
    strcpy (nid.szTip, "i2pd");
    Shell_NotifyIcon(NIM_ADD, &nid );
}

void RemoveTrayIcon (HWND hWnd, UINT uID)
{
    NOTIFYICONDATA nid;
    nid.hWnd = hWnd;
    nid.uID = uID;
    Shell_NotifyIcon (NIM_DELETE, &nid);
}

static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_CREATE:
        {
            AddTrayIcon (hWnd, 1, WM_APP, 0);
            return 0;
        }
        case WM_CLOSE:
        {
            RemoveTrayIcon (hWnd, 1);
            PostQuitMessage (0);
            return DefWindowProc (hWnd, uMsg, wParam, lParam);
        }
        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
                case ID_ABOUT:
                {
                    MessageBox( hWnd, TEXT("i2pd"), TEXT("About"), MB_ICONINFORMATION | MB_OK );
                    return 0;
                }
                case ID_EXIT:
                {
                    PostMessage (hWnd, WM_CLOSE, 0, 0);
                    return 0;
                }
            }
            break;
        }
        case WM_APP:
        {
            switch (lParam)
            {
                case WM_RBUTTONUP:
                {
                    SetForegroundWindow (hWnd);
                    ShowPopupMenu(hWnd, NULL, -1);
                    PostMessage (hWnd, WM_APP + 1, 0, 0);
                    return 0;
                }
            }
            break;
        }
    }
    return DefWindowProc( hWnd, uMsg, wParam, lParam);
}

 int WINAPI WinMain (HINSTANCE hInst, HINSTANCE prev, LPSTR cmdline, int show)
 {
    // check if tunning already
    if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
    {
        MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
        return 0;
    }
    // register main window
    WNDCLASSEX wclx;
    memset (&wclx, 0, sizeof(wclx));
    wclx.cbSize = sizeof(wclx);
    wclx.style = 0;
    wclx.lpfnWndProc = &WndProc;
    wclx.cbClsExtra = 0;
    wclx.cbWndExtra = 0;
    wclx.hInstance = hInst;
    wclx.hIcon = LoadIcon (hInst, IDI_APPLICATION);
    wclx.hIconSm = LoadIcon (hInst, IDI_APPLICATION);
    wclx.hCursor = LoadCursor (NULL, IDC_ARROW);
    wclx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wclx.lpszMenuName = NULL;
    wclx.lpszClassName = I2PD_WIN32_CLASSNAME;
    RegisterClassEx (&wclx);
    // create new window
    if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 150, NULL, NULL, hInst, NULL))
    {
        MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
        return 1;
    }

    // init
    char * argv[] = { (char *)"i2pd" };
    Daemon.init(sizeof (argv)/sizeof (argv[0]), argv);
    // start
    Daemon.start ();
    // main loop
    MSG msg;
    while (GetMessage (&msg, NULL, 0, 0 ))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    // atop
    Daemon.stop ();
    // terminate
    UnregisterClass (I2PD_WIN32_CLASSNAME, hInst);
    return msg.wParam;
 }
<commit_msg>set correct icons<commit_after>#include <string.h>
#include <windows.h>
#include <shellapi.h>
//#include "../Daemon.h"
#include "resource.h"
#include "Win32App.h"

#define ID_ABOUT 2000
#define ID_EXIT 2001

#define ID_TRAY_ICON 2050
#define WM_TRAYICON (WM_USER + 1)

void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
{
    HMENU hPopup = CreatePopupMenu();
    InsertMenu (hPopup, 0, MF_BYPOSITION | MF_STRING, ID_ABOUT, "About...");
    InsertMenu (hPopup, 1, MF_BYPOSITION | MF_STRING, ID_EXIT , "Exit");
    SetMenuDefaultItem (hPopup, ID_ABOUT, FALSE);
    SetFocus (hWnd);
    SendMessage (hWnd, WM_INITMENUPOPUP, (WPARAM)hPopup, 0);

    POINT p;
    if (!curpos)
    {
        GetCursorPos (&p);
        curpos = &p;
    }

    WORD cmd = TrackPopupMenu (hPopup, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, curpos->x, curpos->y, 0, hWnd, NULL);
    SendMessage (hWnd, WM_COMMAND, cmd, 0);

    DestroyMenu(hPopup);
}

void AddTrayIcon (HWND hWnd)
{
    NOTIFYICONDATA nid;
    memset(&nid, 0, sizeof(nid));
    nid.cbSize = sizeof(nid);
    nid.hWnd = hWnd;
    nid.uID = ID_TRAY_ICON;
    nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
    nid.uCallbackMessage = WM_TRAYICON;
    // TODO: must set correct icon
   // nid.hIcon = LoadIcon (GetModuleHandle(NULL), MAKEINTRESOURCE (IDI_ICON1));
    {
        char    szIconFile[512];

        GetSystemDirectory( szIconFile, sizeof( szIconFile ) );
        if ( szIconFile[ strlen( szIconFile ) - 1 ] != '\\' )
            strcat( szIconFile, "\\" );
        strcat( szIconFile, "shell32.dll" );
        //  Icon #23 (0-indexed) in shell32.dll is a "help" icon.
        ExtractIconEx( szIconFile, 23, NULL, &(nid.hIcon), 1 );
    }
    strcpy (nid.szTip, "i2pd");
    Shell_NotifyIcon(NIM_ADD, &nid );
}

void RemoveTrayIcon (HWND hWnd)
{
    NOTIFYICONDATA nid;
    nid.hWnd = hWnd;
    nid.uID = ID_TRAY_ICON;
    Shell_NotifyIcon (NIM_DELETE, &nid);
}

static LRESULT CALLBACK WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_CREATE:
        {
            AddTrayIcon (hWnd);
            break;
        }
        case WM_CLOSE:
        {
            RemoveTrayIcon (hWnd);
            PostQuitMessage (0);
            break;
        }
        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
                case ID_ABOUT:
                {
                    MessageBox( hWnd, TEXT("i2pd"), TEXT("About"), MB_ICONINFORMATION | MB_OK );
                    return 0;
                }
                case ID_EXIT:
                {
                    PostMessage (hWnd, WM_CLOSE, 0, 0);
                    return 0;
                }
            }
            break;
        }
        case WM_TRAYICON:
        {
            SetForegroundWindow (hWnd);
            switch (lParam)
            {
                case WM_RBUTTONUP:
                {
                    SetForegroundWindow (hWnd);
                    ShowPopupMenu(hWnd, NULL, -1);
                    PostMessage (hWnd, WM_APP + 1, 0, 0);
                    break;
                }
            }
            break;
        }
    }
    return DefWindowProc( hWnd, uMsg, wParam, lParam);
}

 int WINAPI WinMain (HINSTANCE hInst, HINSTANCE prev, LPSTR cmdline, int show)
 {
    // check if tunning already
    if (FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")))
    {
        MessageBox(NULL, TEXT("I2Pd is running already"), TEXT("Warning"), MB_OK);
        return 0;
    }
    // register main window
    WNDCLASSEX wclx;
    memset (&wclx, 0, sizeof(wclx));
    wclx.cbSize = sizeof(wclx);
    wclx.style = 0;
    wclx.lpfnWndProc = WndProc;
    wclx.cbClsExtra = 0;
    wclx.cbWndExtra = 0;
    wclx.hInstance = hInst;
    wclx.hIcon = LoadIcon (hInst, MAKEINTRESOURCE (IDI_ICON1));
    wclx.hIconSm = LoadIcon (hInst, MAKEINTRESOURCE (IDI_ICON1));
    wclx.hCursor = LoadCursor (NULL, IDC_ARROW);
    wclx.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wclx.lpszMenuName = NULL;
    wclx.lpszClassName = I2PD_WIN32_CLASSNAME;
    RegisterClassEx (&wclx);
    // create new window
    if (!CreateWindow(I2PD_WIN32_CLASSNAME, TEXT("i2pd"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 250, 150, NULL, NULL, hInst, NULL))
    {
        MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
        return 1;
    }

  /*  // init
    char * argv[] = { (char *)"i2pd" };
    Daemon.init(sizeof (argv)/sizeof (argv[0]), argv);
    // start
    Daemon.start ();*/
    // main loop
    MSG msg;
    while (GetMessage (&msg, NULL, 0, 0 ))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
   /* // atop
    Daemon.stop ();*/
    // terminate
    UnregisterClass (I2PD_WIN32_CLASSNAME, hInst);
    return msg.wParam;
 }
<|endoftext|>


<commit_before>/* router_integration_test.cc
   Jeremy Barnes, 21 November 2012
   Copyright (c) 2012 Datacratic.  All rights reserved.

   Overall integration test for the router stack.
*/

#include "augmentor_ex.h"

#include "rtbkit/core/router/router.h"
#include "rtbkit/core/post_auction/post_auction_loop.h"
#include "rtbkit/core/agent_configuration/agent_configuration_service.h"
#include "rtbkit/core/banker/master_banker.h"
#include "rtbkit/core/banker/slave_banker.h"
#include "jml/utils/rng.h"
#include "rtbkit/core/monitor/monitor.h"
#include "jml/utils/pair_utils.h"
#include "jml/utils/environment.h"
#include "jml/arch/timers.h"
#include "soa/service/testing/redis_temporary_server.h"
#include "testing/generic_exchange_connector.h"
#include "testing/mock_exchange.h"
#include "rtbkit/testing/test_agent.h"
#include <boost/thread.hpp>
#include <netdb.h>
#include <memory>

using namespace std;
using namespace ML;
using namespace Redis;
using namespace Datacratic;
using namespace RTBKIT;

/******************************************************************************/
/* COMPONENTS                                                                 */
/******************************************************************************/

/** Initializes the various components of the RTBKit stack. */
struct Components
{

    std::shared_ptr<ServiceProxies> proxies;

    // See init for an inline description of the various components.

    RedisTemporaryServer redis;
    Router router1, router2;
    PostAuctionLoop postAuctionLoop;
    MasterBanker masterBanker;
    SlaveBudgetController budgetController;
    AgentConfigurationService agentConfig;
    Monitor monitor;
    MonitorProviderProxy monitorProxy;
    TestAgent agent;
    FrequencyCapAugmentor augmentor;

    // \todo Add a PAL event subscriber.

    vector<unique_ptr<GenericExchangeConnector> > exchangeConnectors;
    vector<int> exchangePorts;

    Components(std::shared_ptr<ServiceProxies> proxies)
        : proxies(proxies),
          router1(proxies, "router1"),
          router2(proxies, "router2"),
          postAuctionLoop(proxies, "pas1"),
          masterBanker(proxies, "masterBanker"),
          agentConfig(proxies, "agentConfigurationService"),
          monitor(proxies, "monitor"),
          monitorProxy(proxies->zmqContext, monitor),
          agent(proxies, "agent1"),
          augmentor(proxies, "frequency-cap-ex")
    {
    }

    void shutdown()
    {
        router1.shutdown();
        router2.shutdown();
        postAuctionLoop.shutdown();

        budgetController.shutdown();
        masterBanker.shutdown();

        agent.shutdown();
        augmentor.shutdown();
        agentConfig.shutdown();

        monitorProxy.shutdown();
        monitor.shutdown();

        cerr << "done shutdown" << endl;
    }

    void init()
    {
        const string agentUri = "tcp://127.0.0.1:1234";

        // Setup a monitor which ensures that any instability in the system will
        // throttle the bid request stream. In other words, it ensures you won't
        // go bankrupt.
        monitor.init();
        monitor.bindTcp();
        monitor.start();

        // Setup and agent configuration service which is used to notify all
        // interested services of changes to the agent configuration.
        agentConfig.init();
        agentConfig.bindTcp();
        agentConfig.start();

        // Setup a master banker used to keep the canonical budget of the
        // various bidding agent accounts. The data contained in this service is
        // periodically persisted to redis.
        masterBanker.init(std::make_shared<RedisBankerPersistence>(redis));
        masterBanker.bindTcp();
        masterBanker.start();

        // Setup a slave banker that we can use to manipulate and peak at the
        // budgets during the test.
        budgetController.init(proxies->config);
        budgetController.start();

        // Each router contains a slave masterBanker which is periodically
        // synced with the master banker.
        auto makeSlaveBanker = [=] (const std::string & name)
            {
                auto res = std::make_shared<SlaveBanker>
                (proxies->zmqContext, proxies->config, name);
                res->start();
                return res;
            };

        // Setup a post auction loop (PAL) which handles all exchange events
        // that don't need to be processed in real-time (wins, loss, etc).
        postAuctionLoop.init();
        postAuctionLoop.setBanker(makeSlaveBanker("pas1"));
        postAuctionLoop.bindTcp();
        postAuctionLoop.start();

        // Setup two routers which will manage the bid request stream coming
        // from the exchange, the augmentations coming from the augmentors (to
        // be added to the test) and the bids coming from the agents. Along the
        // way it also applies various filters based on agent configuration
        // while ensuring that all the real-time constraints are respected.

        router1.init();
        router1.setBanker(makeSlaveBanker("router1"));
        router1.bindTcp();
        router1.start();

        router2.init();
        router2.setBanker(makeSlaveBanker("router2"));
        router2.bindTcp();
        router2.start();

        // Setup an exchange connector for each router which will act as the
        // middle men between the exchange and the router.

        exchangeConnectors.emplace_back(
                new GenericExchangeConnector(&router1, Json::Value()));

        exchangeConnectors.emplace_back(
                new GenericExchangeConnector(&router2, Json::Value()));

        for (auto& connector : exchangeConnectors) {
            connector->enableUntil(Date::positiveInfinity());

            int port = connector->init(-1, "localhost", 2 /* threads */);
            exchangePorts.push_back(port);
        }

        // monitorProxy queries all specified services once per second and
        // feeds the Monitor with the aggregate result
        monitorProxy.init(proxies->config,
                          {"router1", "router2", "pas1", "masterBanker"});
        monitorProxy.start();

        // Our bidding agent which listens to the bid request stream from all
        // available routers and decide who gets to see your awesome pictures of
        // kittens.
        agent.start(agentUri, "test-agent");
        agent.configure();

        // Our augmentor which does frequency capping for our agent.
        augmentor.init();
        augmentor.start();
    }
};

/******************************************************************************/
/* SETUP                                                                      */
/******************************************************************************/

void setupAgent(TestAgent& agent)
{
    // Set our frequency cap to 42. This has two effects: 1) it instructs the
    // router that we want bid requests destined for our agent to first be
    // augmented with frequency capping information and 2) it instructs our
    // augmentor to place the pass-frequency-cap-ex tag on our bid request if
    // our agent has seen a given user less then 42 times.
    agent.config.addAugmentation("frequency-cap-ex", Json::Value(42));

    // Instructs the router to only keep bid requests that have this tag. In
    // other words keep only the bid requests that haven't reached our frequency
    // cap limit.
    agent.config.augmentationFilter.include.push_back("pass-frequency-cap-ex");

    // This lambda implements our incredibly sophisticated bidding strategy.
    agent.onBidRequest = [&] (
            double timestamp,
            const Id & id,
            std::shared_ptr<BidRequest> br,
            const Json::Value & spots,
            double timeLeftMs,
            const Json::Value & augmentations)
        {
            Json::Value response;
            response[0]["creative"] = spots[0]["creatives"][0];
            response[0]["price"] = 10000;
            response[0]["priority"] = 1;

            Json::Value metadata;
            agent.doBid(id, response, metadata);

            ML::atomic_inc(agent.numBidRequests);
        };
}

/** Transfer a given budget to each router for a given account. */
void allocateBudget(
        SlaveBudgetController& budgetController,
        const AccountKey& account,
        Amount budget)
{
    budgetController.addAccountSync(account);
    budgetController.setBudgetSync(account[0], budget);
    budgetController.topupTransferSync(account, USD(10));

    cerr << budgetController.getAccountSummarySync(account[0], -1) << endl;

    // Syncing is done periodically so we have to wait a bit before the router
    // will have a budget available. Necessary because the bid request stream
    // for this test isn't infinit.
    cerr << "sleeping so that the slave accounts can sync up" << endl;
    ML::sleep(2.1);

    auto summary = budgetController.getAccountSummarySync(account[0], -1);
    cerr << summary << endl;

    ExcAssertEqual(
            summary.subAccounts["testStrategy"].subAccounts["router1"].budget,
            USD(0.10));

    ExcAssertEqual(
            summary.subAccounts["testStrategy"].subAccounts["router2"].budget,
            USD(0.10));
}

/** Some debugging output for the banker. */
void dumpAccounts(
        SlaveBudgetController& budgetController,
        const AccountKey & name, const AccountSummary & a)
{
    cerr << name << ": " << endl;
    cerr << budgetController.getAccountSync(name) << endl;

    for (auto & sub: a.subAccounts) {
        dumpAccounts(budgetController, name.childKey(sub.first), sub.second);
    }
};

/******************************************************************************/
/* MAIN                                                                       */
/******************************************************************************/

/** Small example problem that spins up the various components of the RTBKit
    stack, sends a bunch of bid requests through it then print some stats.

 */
int main(int argc, char ** argv)
{
    // Controls the length of the test.
    enum {
        nExchangeThreads = 10,
        nBidRequestsPerThread = 200
    };

    auto proxies = std::make_shared<ServiceProxies>();

    // If we had a zookeeper instance running, we could use it to do service
    // discovery. Since we don't, ServiceProxies will just default to using a
    // local service map.
    if (false) proxies->useZookeeper("zookeeper.datacratic.com", "stats");

    // If we had a carbon instance running, we could use it to log events. Since
    // we don't, ServiceProxies will just default to using a local equivalent.
    if (false) proxies->logToCarbon("carbon.datacratic.com", "stats");

    // Setups up the various component of the RTBKit stack. See Components::init
    // for more details.
    Components components(proxies);
    components.init();

    // Some extra customization for our agent to make it extra special. See
    // setupAgent for more details.
    setupAgent(components.agent);

    // Setup an initial budgeting for the test.
    allocateBudget(
            components.budgetController,
            {"testCampaign", "testStrategy"},
            USD(1000));

    boost::thread_group threads;

    int numDone = 0;

    // Uses MockExchange to simulates a very basic exchange for the test.
    auto doExchangeThread = [&] (int threadId)
        {
            string exchangeName = string("exchange-") + to_string(threadId);

            MockExchange exchange(proxies, exchangeName);
            exchange.init(threadId, components.exchangePorts);
            exchange.start(nBidRequestsPerThread);

            ML::atomic_inc(numDone);
        };

    // Start up the exchange threads which should let bid requests flow through
    // our stack.
    for (unsigned i = 0;  i < nExchangeThreads;  ++i)
        threads.create_thread(std::bind(doExchangeThread, i));

    // Dump the budget stats while we wait for the test to finish.
    while (numDone < nExchangeThreads) {
        auto summary = components.budgetController.getAccountSummarySync(
                {"testCampaign"}, -1);
        cerr <<  summary << endl;

        dumpAccounts(components.budgetController, {"testCampaign"}, summary);
        ML::sleep(1.0);
    }

    // Test is done; clean up time.

    threads.join_all();
    components.shutdown();

    components.proxies->events->dump(cerr);
}

<commit_msg>adapted to new Monitor api<commit_after>/* router_integration_test.cc
   Jeremy Barnes, 21 November 2012
   Copyright (c) 2012 Datacratic.  All rights reserved.

   Overall integration test for the router stack.
*/

#include "augmentor_ex.h"

#include "rtbkit/core/router/router.h"
#include "rtbkit/core/post_auction/post_auction_loop.h"
#include "rtbkit/core/agent_configuration/agent_configuration_service.h"
#include "rtbkit/core/banker/master_banker.h"
#include "rtbkit/core/banker/slave_banker.h"
#include "jml/utils/rng.h"
#include "rtbkit/core/monitor/monitor_endpoint.h"
#include "jml/utils/pair_utils.h"
#include "jml/utils/environment.h"
#include "jml/arch/timers.h"
#include "soa/service/testing/redis_temporary_server.h"
#include "testing/generic_exchange_connector.h"
#include "testing/mock_exchange.h"
#include "rtbkit/testing/test_agent.h"
#include <boost/thread.hpp>
#include <netdb.h>
#include <memory>

using namespace std;
using namespace ML;
using namespace Redis;
using namespace Datacratic;
using namespace RTBKIT;

/******************************************************************************/
/* COMPONENTS                                                                 */
/******************************************************************************/

/** Initializes the various components of the RTBKit stack. */
struct Components
{

    std::shared_ptr<ServiceProxies> proxies;

    // See init for an inline description of the various components.

    RedisTemporaryServer redis;
    Router router1, router2;
    PostAuctionLoop postAuctionLoop;
    MasterBanker masterBanker;
    SlaveBudgetController budgetController;
    AgentConfigurationService agentConfig;
    MonitorEndpoint monitor;
    TestAgent agent;
    FrequencyCapAugmentor augmentor;

    // \todo Add a PAL event subscriber.

    vector<unique_ptr<GenericExchangeConnector> > exchangeConnectors;
    vector<int> exchangePorts;

    Components(std::shared_ptr<ServiceProxies> proxies)
        : proxies(proxies),
          router1(proxies, "router1"),
          router2(proxies, "router2"),
          postAuctionLoop(proxies, "pas1"),
          masterBanker(proxies, "masterBanker"),
          agentConfig(proxies, "agentConfigurationService"),
          monitor(proxies, "monitor"),
          agent(proxies, "agent1"),
          augmentor(proxies, "frequency-cap-ex")
    {
    }

    void shutdown()
    {
        router1.shutdown();
        router2.shutdown();
        postAuctionLoop.shutdown();

        budgetController.shutdown();
        masterBanker.shutdown();

        agent.shutdown();
        augmentor.shutdown();
        agentConfig.shutdown();

        monitor.shutdown();

        cerr << "done shutdown" << endl;
    }

    void init()
    {
        const string agentUri = "tcp://127.0.0.1:1234";

        // Setup a monitor which ensures that any instability in the system will
        // throttle the bid request stream. In other words, it ensures you won't
        // go bankrupt.
        monitor.init({"router1", "router2", "pas1", "masterBanker"});
        monitor.bindTcp();
        monitor.start();

        // Setup and agent configuration service which is used to notify all
        // interested services of changes to the agent configuration.
        agentConfig.init();
        agentConfig.bindTcp();
        agentConfig.start();

        // Setup a master banker used to keep the canonical budget of the
        // various bidding agent accounts. The data contained in this service is
        // periodically persisted to redis.
        masterBanker.init(std::make_shared<RedisBankerPersistence>(redis));
        masterBanker.bindTcp();
        masterBanker.start();

        // Setup a slave banker that we can use to manipulate and peak at the
        // budgets during the test.
        budgetController.init(proxies->config);
        budgetController.start();

        // Each router contains a slave masterBanker which is periodically
        // synced with the master banker.
        auto makeSlaveBanker = [=] (const std::string & name)
            {
                auto res = std::make_shared<SlaveBanker>
                (proxies->zmqContext, proxies->config, name);
                res->start();
                return res;
            };

        // Setup a post auction loop (PAL) which handles all exchange events
        // that don't need to be processed in real-time (wins, loss, etc).
        postAuctionLoop.init();
        postAuctionLoop.setBanker(makeSlaveBanker("pas1"));
        postAuctionLoop.bindTcp();
        postAuctionLoop.start();

        // Setup two routers which will manage the bid request stream coming
        // from the exchange, the augmentations coming from the augmentors (to
        // be added to the test) and the bids coming from the agents. Along the
        // way it also applies various filters based on agent configuration
        // while ensuring that all the real-time constraints are respected.

        router1.init();
        router1.setBanker(makeSlaveBanker("router1"));
        router1.bindTcp();
        router1.start();

        router2.init();
        router2.setBanker(makeSlaveBanker("router2"));
        router2.bindTcp();
        router2.start();

        // Setup an exchange connector for each router which will act as the
        // middle men between the exchange and the router.

        exchangeConnectors.emplace_back(
                new GenericExchangeConnector(&router1, Json::Value()));

        exchangeConnectors.emplace_back(
                new GenericExchangeConnector(&router2, Json::Value()));

        for (auto& connector : exchangeConnectors) {
            connector->enableUntil(Date::positiveInfinity());

            int port = connector->init(-1, "localhost", 2 /* threads */);
            exchangePorts.push_back(port);
        }

        // Our bidding agent which listens to the bid request stream from all
        // available routers and decide who gets to see your awesome pictures of
        // kittens.
        agent.start(agentUri, "test-agent");
        agent.configure();

        // Our augmentor which does frequency capping for our agent.
        augmentor.init();
        augmentor.start();
    }
};

/******************************************************************************/
/* SETUP                                                                      */
/******************************************************************************/

void setupAgent(TestAgent& agent)
{
    // Set our frequency cap to 42. This has two effects: 1) it instructs the
    // router that we want bid requests destined for our agent to first be
    // augmented with frequency capping information and 2) it instructs our
    // augmentor to place the pass-frequency-cap-ex tag on our bid request if
    // our agent has seen a given user less then 42 times.
    agent.config.addAugmentation("frequency-cap-ex", Json::Value(42));

    // Instructs the router to only keep bid requests that have this tag. In
    // other words keep only the bid requests that haven't reached our frequency
    // cap limit.
    agent.config.augmentationFilter.include.push_back("pass-frequency-cap-ex");

    // This lambda implements our incredibly sophisticated bidding strategy.
    agent.onBidRequest = [&] (
            double timestamp,
            const Id & id,
            std::shared_ptr<BidRequest> br,
            const Json::Value & spots,
            double timeLeftMs,
            const Json::Value & augmentations)
        {
            Json::Value response;
            response[0]["creative"] = spots[0]["creatives"][0];
            response[0]["price"] = 10000;
            response[0]["priority"] = 1;

            Json::Value metadata;
            agent.doBid(id, response, metadata);

            ML::atomic_inc(agent.numBidRequests);
        };
}

/** Transfer a given budget to each router for a given account. */
void allocateBudget(
        SlaveBudgetController& budgetController,
        const AccountKey& account,
        Amount budget)
{
    budgetController.addAccountSync(account);
    budgetController.setBudgetSync(account[0], budget);
    budgetController.topupTransferSync(account, USD(10));

    cerr << budgetController.getAccountSummarySync(account[0], -1) << endl;

    // Syncing is done periodically so we have to wait a bit before the router
    // will have a budget available. Necessary because the bid request stream
    // for this test isn't infinit.
    cerr << "sleeping so that the slave accounts can sync up" << endl;
    ML::sleep(2.1);

    auto summary = budgetController.getAccountSummarySync(account[0], -1);
    cerr << summary << endl;

    ExcAssertEqual(
            summary.subAccounts["testStrategy"].subAccounts["router1"].budget,
            USD(0.10));

    ExcAssertEqual(
            summary.subAccounts["testStrategy"].subAccounts["router2"].budget,
            USD(0.10));
}

/** Some debugging output for the banker. */
void dumpAccounts(
        SlaveBudgetController& budgetController,
        const AccountKey & name, const AccountSummary & a)
{
    cerr << name << ": " << endl;
    cerr << budgetController.getAccountSync(name) << endl;

    for (auto & sub: a.subAccounts) {
        dumpAccounts(budgetController, name.childKey(sub.first), sub.second);
    }
};

/******************************************************************************/
/* MAIN                                                                       */
/******************************************************************************/

/** Small example problem that spins up the various components of the RTBKit
    stack, sends a bunch of bid requests through it then print some stats.

 */
int main(int argc, char ** argv)
{
    // Controls the length of the test.
    enum {
        nExchangeThreads = 10,
        nBidRequestsPerThread = 200
    };

    auto proxies = std::make_shared<ServiceProxies>();

    // If we had a zookeeper instance running, we could use it to do service
    // discovery. Since we don't, ServiceProxies will just default to using a
    // local service map.
    if (false) proxies->useZookeeper("zookeeper.datacratic.com", "stats");

    // If we had a carbon instance running, we could use it to log events. Since
    // we don't, ServiceProxies will just default to using a local equivalent.
    if (false) proxies->logToCarbon("carbon.datacratic.com", "stats");

    // Setups up the various component of the RTBKit stack. See Components::init
    // for more details.
    Components components(proxies);
    components.init();

    // Some extra customization for our agent to make it extra special. See
    // setupAgent for more details.
    setupAgent(components.agent);

    // Setup an initial budgeting for the test.
    allocateBudget(
            components.budgetController,
            {"testCampaign", "testStrategy"},
            USD(1000));

    boost::thread_group threads;

    int numDone = 0;

    // Uses MockExchange to simulates a very basic exchange for the test.
    auto doExchangeThread = [&] (int threadId)
        {
            string exchangeName = string("exchange-") + to_string(threadId);

            MockExchange exchange(proxies, exchangeName);
            exchange.init(threadId, components.exchangePorts);
            exchange.start(nBidRequestsPerThread);

            ML::atomic_inc(numDone);
        };

    // Start up the exchange threads which should let bid requests flow through
    // our stack.
    for (unsigned i = 0;  i < nExchangeThreads;  ++i)
        threads.create_thread(std::bind(doExchangeThread, i));

    // Dump the budget stats while we wait for the test to finish.
    while (numDone < nExchangeThreads) {
        auto summary = components.budgetController.getAccountSummarySync(
                {"testCampaign"}, -1);
        cerr <<  summary << endl;

        dumpAccounts(components.budgetController, {"testCampaign"}, summary);
        ML::sleep(1.0);
    }

    // Test is done; clean up time.

    threads.join_all();
    components.shutdown();

    components.proxies->events->dump(cerr);
}

<|endoftext|>