<commit_before>// Baidu RPC - A framework to host and access services throughout Baidu.
// Copyright (c) 2015 Baidu.com, Inc. All Rights Reserved

// Author: The baidu-rpc authors (pbrpc@baidu.com)
// Date: Fri Jun  5 18:25:40 CST 2015

#include <google/protobuf/descriptor.h>         // MethodDescriptor
#include <google/protobuf/message.h>            // Message
#include <gflags/gflags.h>
#include "base/logging.h"                       // LOG()
#include "base/time.h"
#include "base/iobuf.h"                         // base::IOBuf
#include "brpc/controller.h"               // Controller
#include "brpc/details/controller_private_accessor.h"
#include "brpc/socket.h"                   // Socket
#include "brpc/server.h"                   // Server
#include "brpc/details/server_private_accessor.h"
#include "brpc/span.h"
#include "brpc/redis.h"
#include "brpc/policy/redis_protocol.h"

namespace brpc {

DECLARE_bool(enable_rpcz);

namespace policy {

DEFINE_bool(redis_verbose, false,
            "[DEBUG] Print EVERY redis request/response to stderr");

struct InputResponse : public InputMessageBase {
    bthread_id_t id_wait;
    RedisResponse response;

    // @InputMessageBase
    void DestroyImpl() {
        delete this;
    }
};

// "Message" = "Response" as we only implement the client for redis.
ParseResult ParseRedisMessage(base::IOBuf* source, Socket* socket,
                              bool /*read_eof*/, const void* /*arg*/) {
    if (source->empty()) {
        return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
    }
    // NOTE(gejun): PopPipelinedInfo() is actually more contended than what
    // I thought before. The Socket._pipeline_q is a SPSC queue pushed before
    // sending and popped when response comes back, being protected by a
    // mutex. Previously the mutex is shared with Socket._id_wait_list. When
    // 200 bthreads access one redis-server, ~1.5s in total is spent on
    // contention in 10-second duration. If the mutex is separated, the time
    // drops to ~0.25s. I further replaced PeekPipelinedInfo() with
    // GivebackPipelinedInfo() to lock only once(when receiving response)
    // in most cases, and the time decreases to ~0.14s.
    PipelinedInfo pi;
    if (!socket->PopPipelinedInfo(&pi)) {
        LOG(WARNING) << "No corresponding PipelinedInfo in socket";
        return MakeParseError(PARSE_ERROR_TRY_OTHERS);
    }
    InputResponse* msg = static_cast<InputResponse*>(socket->parsing_context());
    if (msg == NULL) {
        msg = new InputResponse;
        socket->reset_parsing_context(msg);
    }

    if (!msg->response.ConsumePartialIOBuf(*source, pi.count)) {
        socket->GivebackPipelinedInfo(pi);
        return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
    }
    CHECK_EQ((uint32_t)msg->response.reply_size(), pi.count);
    msg->id_wait = pi.id_wait;
    socket->release_parsing_context();
    return MakeMessage(msg);
}

void ProcessRedisResponse(InputMessageBase* msg_base) {
    const int64_t start_parse_us = base::cpuwide_time_us();
    DestroyingPtr<InputResponse> msg(static_cast<InputResponse*>(msg_base));

    const bthread_id_t cid = msg->id_wait;
    Controller* cntl = NULL;
    const int rc = bthread_id_lock(cid, (void**)&cntl);
    if (rc != 0) {
        LOG_IF(FATAL, rc != EINVAL && rc != EPERM)
            << "Fail to lock correlation_id=" << cid << ": " << berror(rc);
        return;
    }

    ControllerPrivateAccessor accessor(cntl);
    Span* span = accessor.span();
    if (span) {
        span->set_base_real_us(msg->base_real_us());
        span->set_received_us(msg->received_us());
        span->set_response_size(msg->response.ByteSize());
        span->set_start_parse_us(start_parse_us);
    }
    const int saved_error = cntl->ErrorCode();
    if (cntl->response() != NULL) {
        if (cntl->response()->GetDescriptor() != RedisResponse::descriptor()) {
            cntl->SetFailed(ERESPONSE, "Must be RedisResponse");
        } else {
            // We work around ParseFrom of pb which is just a placeholder.
            if (msg->response.reply_size() != (int)accessor.pipelined_count()) {
                cntl->SetFailed(ERESPONSE, "pipelined_count=%d of response does "
                                      "not equal request's=%d",
                                      msg->response.reply_size(), accessor.pipelined_count());
            }
            ((RedisResponse*)cntl->response())->Swap(&msg->response);
            if (FLAGS_redis_verbose) {
                std::cerr << "[REDIS RESPONSE] "
                          << *((RedisResponse*)cntl->response())
                          << std::endl;
            }
        }
    } // silently ignore the response.

    // Unlocks correlation_id inside. Revert controller's
    // error code if it version check of `cid' fails
    msg.reset();  // optional, just release resourse ASAP
    accessor.OnResponse(cid, saved_error);
}

void SerializeRedisRequest(base::IOBuf* buf,
                           Controller* cntl,
                           const google::protobuf::Message* request) {
    if (request == NULL) {
        return cntl->SetFailed(EREQUEST, "request is NULL");
    }
    if (request->GetDescriptor() != RedisRequest::descriptor()) {
        return cntl->SetFailed(EREQUEST, "The request is not a RedisRequest");
    }
    const RedisRequest* rr = (const RedisRequest*)request;
    // We work around SerializeTo of pb which is just a placeholder.
    if (!rr->SerializeTo(buf)) {
        return cntl->SetFailed(EREQUEST, "Fail to serialize RedisRequest");
    }
    ControllerPrivateAccessor(cntl).set_pipelined_count(rr->command_size());
    if (FLAGS_redis_verbose) {
        std::cerr << "[REDIS REQUEST] " << *rr << std::endl;
    }
}

void PackRedisRequest(base::IOBuf* buf,
                      SocketMessage**,
                      uint64_t /*correlation_id*/,
                      const google::protobuf::MethodDescriptor*,
                      Controller*,
                      const base::IOBuf& request,
                      const Authenticator* /*auth*/) {
    buf->append(request);
}

const std::string& GetRedisMethodName(
    const google::protobuf::MethodDescriptor*,
    const Controller*) {
    const static std::string REDIS_SERVER_STR = "redis-server";
    return REDIS_SERVER_STR;
}

}  // namespace policy
} // namespace brpc

<commit_msg>Patch svn r35200<commit_after>// Baidu RPC - A framework to host and access services throughout Baidu.
// Copyright (c) 2015 Baidu.com, Inc. All Rights Reserved

// Author: The baidu-rpc authors (pbrpc@baidu.com)
// Date: Fri Jun  5 18:25:40 CST 2015

#include <google/protobuf/descriptor.h>         // MethodDescriptor
#include <google/protobuf/message.h>            // Message
#include <gflags/gflags.h>
#include "base/logging.h"                       // LOG()
#include "base/time.h"
#include "base/iobuf.h"                         // base::IOBuf
#include "brpc/controller.h"               // Controller
#include "brpc/details/controller_private_accessor.h"
#include "brpc/socket.h"                   // Socket
#include "brpc/server.h"                   // Server
#include "brpc/details/server_private_accessor.h"
#include "brpc/span.h"
#include "brpc/redis.h"
#include "brpc/policy/redis_protocol.h"

namespace brpc {

DECLARE_bool(enable_rpcz);

namespace policy {

DEFINE_bool(redis_verbose, false,
            "[DEBUG] Print EVERY redis request/response to stderr");

struct InputResponse : public InputMessageBase {
    bthread_id_t id_wait;
    RedisResponse response;

    // @InputMessageBase
    void DestroyImpl() {
        delete this;
    }
};

// "Message" = "Response" as we only implement the client for redis.
ParseResult ParseRedisMessage(base::IOBuf* source, Socket* socket,
                              bool /*read_eof*/, const void* /*arg*/) {
    if (source->empty()) {
        return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
    }
    // NOTE(gejun): PopPipelinedInfo() is actually more contended than what
    // I thought before. The Socket._pipeline_q is a SPSC queue pushed before
    // sending and popped when response comes back, being protected by a
    // mutex. Previously the mutex is shared with Socket._id_wait_list. When
    // 200 bthreads access one redis-server, ~1.5s in total is spent on
    // contention in 10-second duration. If the mutex is separated, the time
    // drops to ~0.25s. I further replaced PeekPipelinedInfo() with
    // GivebackPipelinedInfo() to lock only once(when receiving response)
    // in most cases, and the time decreases to ~0.14s.
    PipelinedInfo pi;
    if (!socket->PopPipelinedInfo(&pi)) {
        LOG(WARNING) << "No corresponding PipelinedInfo in socket";
        return MakeParseError(PARSE_ERROR_TRY_OTHERS);
    }
    InputResponse* msg = static_cast<InputResponse*>(socket->parsing_context());
    if (msg == NULL) {
        msg = new InputResponse;
        socket->reset_parsing_context(msg);
    }

    if (!msg->response.ConsumePartialIOBuf(*source, pi.count)) {
        socket->GivebackPipelinedInfo(pi);
        return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA);
    }
    CHECK_EQ((uint32_t)msg->response.reply_size(), pi.count);
    msg->id_wait = pi.id_wait;
    socket->release_parsing_context();
    return MakeMessage(msg);
}

void ProcessRedisResponse(InputMessageBase* msg_base) {
    const int64_t start_parse_us = base::cpuwide_time_us();
    DestroyingPtr<InputResponse> msg(static_cast<InputResponse*>(msg_base));

    const bthread_id_t cid = msg->id_wait;
    Controller* cntl = NULL;
    const int rc = bthread_id_lock(cid, (void**)&cntl);
    if (rc != 0) {
        LOG_IF(ERROR, rc != EINVAL && rc != EPERM)
            << "Fail to lock correlation_id=" << cid << ": " << berror(rc);
        return;
    }

    ControllerPrivateAccessor accessor(cntl);
    Span* span = accessor.span();
    if (span) {
        span->set_base_real_us(msg->base_real_us());
        span->set_received_us(msg->received_us());
        span->set_response_size(msg->response.ByteSize());
        span->set_start_parse_us(start_parse_us);
    }
    const int saved_error = cntl->ErrorCode();
    if (cntl->response() != NULL) {
        if (cntl->response()->GetDescriptor() != RedisResponse::descriptor()) {
            cntl->SetFailed(ERESPONSE, "Must be RedisResponse");
        } else {
            // We work around ParseFrom of pb which is just a placeholder.
            if (msg->response.reply_size() != (int)accessor.pipelined_count()) {
                cntl->SetFailed(ERESPONSE, "pipelined_count=%d of response does "
                                      "not equal request's=%d",
                                      msg->response.reply_size(), accessor.pipelined_count());
            }
            ((RedisResponse*)cntl->response())->Swap(&msg->response);
            if (FLAGS_redis_verbose) {
                std::cerr << "[REDIS RESPONSE] "
                          << *((RedisResponse*)cntl->response())
                          << std::endl;
            }
        }
    } // silently ignore the response.

    // Unlocks correlation_id inside. Revert controller's
    // error code if it version check of `cid' fails
    msg.reset();  // optional, just release resourse ASAP
    accessor.OnResponse(cid, saved_error);
}

void SerializeRedisRequest(base::IOBuf* buf,
                           Controller* cntl,
                           const google::protobuf::Message* request) {
    if (request == NULL) {
        return cntl->SetFailed(EREQUEST, "request is NULL");
    }
    if (request->GetDescriptor() != RedisRequest::descriptor()) {
        return cntl->SetFailed(EREQUEST, "The request is not a RedisRequest");
    }
    const RedisRequest* rr = (const RedisRequest*)request;
    // We work around SerializeTo of pb which is just a placeholder.
    if (!rr->SerializeTo(buf)) {
        return cntl->SetFailed(EREQUEST, "Fail to serialize RedisRequest");
    }
    ControllerPrivateAccessor(cntl).set_pipelined_count(rr->command_size());
    if (FLAGS_redis_verbose) {
        std::cerr << "[REDIS REQUEST] " << *rr << std::endl;
    }
}

void PackRedisRequest(base::IOBuf* buf,
                      SocketMessage**,
                      uint64_t /*correlation_id*/,
                      const google::protobuf::MethodDescriptor*,
                      Controller*,
                      const base::IOBuf& request,
                      const Authenticator* /*auth*/) {
    buf->append(request);
}

const std::string& GetRedisMethodName(
    const google::protobuf::MethodDescriptor*,
    const Controller*) {
    const static std::string REDIS_SERVER_STR = "redis-server";
    return REDIS_SERVER_STR;
}

}  // namespace policy
} // namespace brpc

<|endoftext|>


<commit_before>/*
 * File:   CheckpointManager.h
 * Author: remy
 *
 * Created on 21 octobre 2014, 13:59
 */

#include "server/PathFinding.h"
#include "server/serverCheckpoint/ServerCheckpointManager.h"

#include "shared/Utils.h"

ServerCheckpointManager::ServerCheckpointManager()
: m_checkpoints() {

}

ServerCheckpointManager::~ServerCheckpointManager() {

}

void ServerCheckpointManager::initialise(Map *map) {
    PathFinding p;
    sf::Vector2i checkpointsPos[4];

    bool pathFound;
    bool restart = false;

    int attempts = 0;

    do {
        restart = false;
        p.loadMap(&map->getHeightMap());
        sf::Vector2i startPoint = p.choosePoint(PathFinding::area_center);

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

            attempts = 0;

            do {
                checkpointsPos[i] = p.choosePoint((PathFinding::area)(PathFinding::area_north_east + i));
                pathFound = p.find(startPoint, checkpointsPos[i]);
                attempts++;
            } while (!pathFound && attempts <= 1);

            if (!pathFound) {
                // new map
                std::cout << "No path found, changing map" << std::endl;
                delete map;
                std::cout << "Deleted" << std::endl;
                map = new Map(MapHeader(NB_TILES_HEIGHT, NB_TILES_WIDTH, rand()));
                std::cout << "New" << std::endl;
                restart = true;
                break;
            }
        }

    } while (restart);

    std::cout << "This map is good !" << std::endl;
    for (int i = 0; i < 4; ++i) {
        ServerCheckpoint* c = new ServerCheckpoint(checkpointsPos[i]);
        m_checkpoints.push_back(c);
    }
}

void ServerCheckpointManager::release() {
    for (unsigned int i = 0; i < m_checkpoints.size(); ++i) {
        delete m_checkpoints.front();
    }

    m_checkpoints.clear();
}<commit_msg>Removed std::cout<commit_after>/*
 * File:   CheckpointManager.h
 * Author: remy
 *
 * Created on 21 octobre 2014, 13:59
 */

#include "server/PathFinding.h"
#include "server/serverCheckpoint/ServerCheckpointManager.h"

#include "shared/Utils.h"

ServerCheckpointManager::ServerCheckpointManager()
: m_checkpoints() {

}

ServerCheckpointManager::~ServerCheckpointManager() {

}

void ServerCheckpointManager::initialise(Map *map) {
    PathFinding p;
    sf::Vector2i checkpointsPos[4];

    bool pathFound;
    bool restart = false;

    int attempts = 0;

    do {
        restart = false;
        p.loadMap(&map->getHeightMap());
        sf::Vector2i startPoint = p.choosePoint(PathFinding::area_center);

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

            attempts = 0;

            do {
                checkpointsPos[i] = p.choosePoint((PathFinding::area)(PathFinding::area_north_east + i));
                pathFound = p.find(startPoint, checkpointsPos[i]);
                attempts++;
            } while (!pathFound && attempts <= 1);

            if (!pathFound) {
                // new map
                std::cout << "No path found, changing map" << std::endl;
                delete map;
                map = new Map(MapHeader(NB_TILES_HEIGHT, NB_TILES_WIDTH, rand()));
                restart = true;
                break;
            }
        }

    } while (restart);

    for (int i = 0; i < 4; ++i) {
        ServerCheckpoint* c = new ServerCheckpoint(checkpointsPos[i]);
        m_checkpoints.push_back(c);
    }
}

void ServerCheckpointManager::release() {
    for (unsigned int i = 0; i < m_checkpoints.size(); ++i) {
        delete m_checkpoints.front();
    }

    m_checkpoints.clear();
}<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief Infrastructure for RangeInfo
///
/// @file arangod/Aql/RangeInfo.h
///
/// DISCLAIMER
///
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author not James
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include <Basics/Common.h>
#include "Aql/RangeInfo.h"

using namespace triagens::basics;
using namespace triagens::aql;

////////////////////////////////////////////////////////////////////////////////
/// @brief 3-way comparison of the tightness of upper or lower constant
/// RangeInfoBounds.
/// Returns -1 if <left> is tighter than <right>, 1 if <right> is tighter than
/// <left>, and 0 if the bounds are the same. The argument <lowhigh> should be
/// -1 if we are comparing lower bounds and 1 if we are comparing upper bounds.
///
/// If <left> or <right> is a undefined, this indicates no bound.
///
/// If ~ is the comparison and (x,y), (z,t) are RangeInfoBounds (i.e. x,z are
/// Json values, y,t are booleans) that we are comparing as lower bounds, then
/// the following holds:
///
///                 -1  x>z or (x=z, y=false, z=true)
/// (x,y) ~ (z,t) = 0   x=z, y=t
///                 1   z>x or (x=z, y=true, t=false)
///
/// as upper bounds:
///
///                 -1  x<z or (x=z, y=false, z=true)
/// (x,y) ~ (z,t) = 0   x=z, y=t
///                 1   z<x or (x=z, y=true, t=false)
///
/// For example (x<2) is tighter than (x<3) and (x<=2). The bound (x<2) is
/// represented as (2, false), and (x<=2) is (2, true), and so as upper bounds
/// (2, false) ~ (2, true) = -1 indicating that (2,false)=(x<2) is tighter than
/// (2, true)=(x<=2).
////////////////////////////////////////////////////////////////////////////////

static int CompareRangeInfoBound (RangeInfoBound const& left,
                                  RangeInfoBound const& right,
                                  int lowhigh) {
  if (! left.isDefined()) {
    return (right.isDefined() ? 1 : 0);
  }
  if (! right.isDefined()) {
    return -1;
  }

  int cmp = TRI_CompareValuesJson(left.bound().json(), right.bound().json());
  if (cmp == 0 && (left.inclusive() != right.inclusive())) {
    return (left.inclusive() ? 1 : -1);
  }
  return cmp * lowhigh;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief class RangeInfoBound
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief andCombineLowerBounds, changes the bound in *this and replaces
/// it by the stronger bound of *this and that, interpreting both as lower
/// bounds, this only works for constant bounds.
////////////////////////////////////////////////////////////////////////////////

void RangeInfoBound::andCombineLowerBounds (RangeInfoBound const& that) {
  if (CompareRangeInfoBound(that, *this, -1) == -1) {
    assign(that);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief andCombineUpperBounds, changes the bound in *this and replaces
/// it by the stronger bound of *this and that, interpreting both as upper
/// bounds, this only works for constant bounds.
////////////////////////////////////////////////////////////////////////////////

void RangeInfoBound::andCombineUpperBounds (RangeInfoBound const& that) {
  if (CompareRangeInfoBound(that, *this, 1) == -1) {
    assign(that);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief getExpressionAst, looks up or computes (if necessary) an AST
/// for the variable bound, return nullptr for a constant bound, the new
/// (if needed) nodes are registered with the ast
////////////////////////////////////////////////////////////////////////////////

AstNode const* RangeInfoBound::getExpressionAst(Ast* ast) const {
  if (_expressionAst != nullptr) {
    return _expressionAst;
  }
  if (_isConstant) {
    return nullptr;
  }
  _expressionAst = new AstNode(ast, _bound);
  return _expressionAst;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief class RangeInfo
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor from JSON
////////////////////////////////////////////////////////////////////////////////

RangeInfo::RangeInfo (basics::Json const& json) :
  _var(basics::JsonHelper::checkAndGetStringValue(json.json(), "variable")),
  _attr(basics::JsonHelper::checkAndGetStringValue(json.json(), "attr")),
  _valid(basics::JsonHelper::checkAndGetBooleanValue(json.json(), "valid")),
  _defined(true),
  _equality(basics::JsonHelper::checkAndGetBooleanValue(json.json(), "equality")) {

  Json lows = json.get("lows");
  if (! lows.isList()) {
    THROW_INTERNAL_ERROR("low attribute must be a list");
  }
  Json highs = json.get("highs");
  if (! highs.isList()) {
    THROW_INTERNAL_ERROR("high attribute must be a list");
  }
  // If an exception is thrown from within these loops, then the
  // vectors _low and _high will be destroyed properly, so no
  // try/catch is needed.
  for (size_t i = 0; i < lows.size(); i++) {
    _lows.emplace_back(lows.at(i));
  }
  for (size_t i = 0; i < highs.size(); i++) {
    _highs.emplace_back(highs.at(i));
  }
  _lowConst.assign(json.get("lowConst"));
  _highConst.assign(json.get("highConst"));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief toJson for a RangeInfo
////////////////////////////////////////////////////////////////////////////////

Json RangeInfo::toJson () {
  Json item(basics::Json::Array);
  item("variable", Json(_var))
      ("attr", Json(_attr))
      ("lowConst", _lowConst.toJson())
      ("highConst", _highConst.toJson());
  Json lowList(Json::List, _lows.size());
  for (auto l : _lows) {
    lowList(l.toJson());
  }
  item("lows", lowList);
  Json highList(Json::List, _highs.size());
  for (auto h : _highs) {
    highList(h.toJson());
  }
  item("highs", highList);
  item("valid", Json(_valid));
  item("equality", Json(_equality));
  return item;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief class RangesInfo
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief  insert if there is no range corresponding to variable name <var>,
/// and attribute <name>, and otherwise intersection with existing range
////////////////////////////////////////////////////////////////////////////////

void RangesInfo::insert (RangeInfo newRange) {

  TRI_ASSERT(newRange.isDefined());

  std::unordered_map<std::string, RangeInfo>* oldMap = find(newRange._var);

  if (oldMap == nullptr) {
    std::unordered_map<std::string, RangeInfo> newMap;
    newMap.insert(make_pair(newRange._attr, newRange));
    _ranges.insert(std::make_pair(newRange._var, newMap));
    return;
  }

  auto it = oldMap->find(newRange._attr);

  if (it == oldMap->end()) {
    oldMap->insert(make_pair(newRange._attr, newRange));
    return;
  }

  RangeInfo& oldRange((*it).second);

  oldRange.fuse(newRange);
}

////////////////////////////////////////////////////////////////////////////////
///// @brief fuse, fuse two ranges, must be for the same variable and attribute
////////////////////////////////////////////////////////////////////////////////

void RangeInfo::fuse (RangeInfo const& that) {

  TRI_ASSERT(_var == that._var);
  TRI_ASSERT(_attr == that._attr);

  if (! isValid()) {
    // intersection of the empty set with any set is empty!
    return;
  }

  if (! that.isValid()) {
    // intersection of the empty set with any set is empty!
    invalidate();
    return;
  }

  // The following is a corner case for constant bounds:
  if (_equality && that._equality &&
      _lowConst.isDefined() && that._lowConst.isDefined()) {
    if (! TRI_CheckSameValueJson(_lowConst.bound().json(),
                                 that._lowConst.bound().json())) {
      invalidate();
      return;
    }
  }

  // First sort out the constant low bounds:
  _lowConst.andCombineLowerBounds(that._lowConst);
  // Simply append the variable ones:
  for (auto l : that._lows) {
    _lows.emplace_back(l);
  }

  // Sort out the constant high bounds:
  _highConst.andCombineUpperBounds(that._highConst);
  // Simply append the variable ones:
  for (auto h : that._highs) {
    _highs.emplace_back(h);
  }

  // check the new constant range bounds are valid:
  if (_lowConst.isDefined() && _highConst.isDefined()) {
    int cmp = TRI_CompareValuesJson(_lowConst.bound().json(),
                                    _highConst.bound().json());
    if (cmp == 1) {
      invalidate();
      return;
    }
    if (cmp == 0) {
      if (! (_lowConst.inclusive() && _highConst.inclusive()) ) {
        // range invalid
        invalidate();
      }
      else {
        _equality = true;  // Can only be at most one value
      }
    }
  }
};

////////////////////////////////////////////////////////////////////////////////
/// @brief  insert if there is no range corresponding to variable name <var>,
/// and attribute <name>, and otherwise intersection with existing range
////////////////////////////////////////////////////////////////////////////////

void RangesInfo::insert (std::string var, std::string name,
                         RangeInfoBound low, RangeInfoBound high,
                         bool equality) {
  insert(RangeInfo(var, name, low, high, equality));
};

<commit_msg>Make more const.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief Infrastructure for RangeInfo
///
/// @file arangod/Aql/RangeInfo.h
///
/// DISCLAIMER
///
/// Copyright 2010-2014 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author not James
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include <Basics/Common.h>
#include "Aql/RangeInfo.h"

using namespace triagens::basics;
using namespace triagens::aql;

////////////////////////////////////////////////////////////////////////////////
/// @brief 3-way comparison of the tightness of upper or lower constant
/// RangeInfoBounds.
/// Returns -1 if <left> is tighter than <right>, 1 if <right> is tighter than
/// <left>, and 0 if the bounds are the same. The argument <lowhigh> should be
/// -1 if we are comparing lower bounds and 1 if we are comparing upper bounds.
///
/// If <left> or <right> is a undefined, this indicates no bound.
///
/// If ~ is the comparison and (x,y), (z,t) are RangeInfoBounds (i.e. x,z are
/// Json values, y,t are booleans) that we are comparing as lower bounds, then
/// the following holds:
///
///                 -1  x>z or (x=z, y=false, z=true)
/// (x,y) ~ (z,t) = 0   x=z, y=t
///                 1   z>x or (x=z, y=true, t=false)
///
/// as upper bounds:
///
///                 -1  x<z or (x=z, y=false, z=true)
/// (x,y) ~ (z,t) = 0   x=z, y=t
///                 1   z<x or (x=z, y=true, t=false)
///
/// For example (x<2) is tighter than (x<3) and (x<=2). The bound (x<2) is
/// represented as (2, false), and (x<=2) is (2, true), and so as upper bounds
/// (2, false) ~ (2, true) = -1 indicating that (2,false)=(x<2) is tighter than
/// (2, true)=(x<=2).
////////////////////////////////////////////////////////////////////////////////

static int CompareRangeInfoBound (RangeInfoBound const& left,
                                  RangeInfoBound const& right,
                                  int lowhigh) {
  if (! left.isDefined()) {
    return (right.isDefined() ? 1 : 0);
  }
  if (! right.isDefined()) {
    return -1;
  }

  int cmp = TRI_CompareValuesJson(left.bound().json(), right.bound().json());
  if (cmp == 0 && (left.inclusive() != right.inclusive())) {
    return (left.inclusive() ? 1 : -1);
  }
  return cmp * lowhigh;
};

////////////////////////////////////////////////////////////////////////////////
/// @brief class RangeInfoBound
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief andCombineLowerBounds, changes the bound in *this and replaces
/// it by the stronger bound of *this and that, interpreting both as lower
/// bounds, this only works for constant bounds.
////////////////////////////////////////////////////////////////////////////////

void RangeInfoBound::andCombineLowerBounds (RangeInfoBound const& that) {
  if (CompareRangeInfoBound(that, *this, -1) == -1) {
    assign(that);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief andCombineUpperBounds, changes the bound in *this and replaces
/// it by the stronger bound of *this and that, interpreting both as upper
/// bounds, this only works for constant bounds.
////////////////////////////////////////////////////////////////////////////////

void RangeInfoBound::andCombineUpperBounds (RangeInfoBound const& that) {
  if (CompareRangeInfoBound(that, *this, 1) == -1) {
    assign(that);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief getExpressionAst, looks up or computes (if necessary) an AST
/// for the variable bound, return nullptr for a constant bound, the new
/// (if needed) nodes are registered with the ast
////////////////////////////////////////////////////////////////////////////////

AstNode const* RangeInfoBound::getExpressionAst(Ast* ast) const {
  if (_expressionAst != nullptr) {
    return _expressionAst;
  }
  if (_isConstant) {
    return nullptr;
  }
  _expressionAst = new AstNode(ast, _bound);
  return _expressionAst;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief class RangeInfo
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor from JSON
////////////////////////////////////////////////////////////////////////////////

RangeInfo::RangeInfo (basics::Json const& json) :
  _var(basics::JsonHelper::checkAndGetStringValue(json.json(), "variable")),
  _attr(basics::JsonHelper::checkAndGetStringValue(json.json(), "attr")),
  _valid(basics::JsonHelper::checkAndGetBooleanValue(json.json(), "valid")),
  _defined(true),
  _equality(basics::JsonHelper::checkAndGetBooleanValue(json.json(), "equality")) {

  Json lows = json.get("lows");
  if (! lows.isList()) {
    THROW_INTERNAL_ERROR("low attribute must be a list");
  }
  Json highs = json.get("highs");
  if (! highs.isList()) {
    THROW_INTERNAL_ERROR("high attribute must be a list");
  }
  // If an exception is thrown from within these loops, then the
  // vectors _low and _high will be destroyed properly, so no
  // try/catch is needed.
  for (size_t i = 0; i < lows.size(); i++) {
    _lows.emplace_back(lows.at(i));
  }
  for (size_t i = 0; i < highs.size(); i++) {
    _highs.emplace_back(highs.at(i));
  }
  _lowConst.assign(json.get("lowConst"));
  _highConst.assign(json.get("highConst"));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief toJson for a RangeInfo
////////////////////////////////////////////////////////////////////////////////

Json RangeInfo::toJson () const {
  Json item(basics::Json::Array);
  item("variable", Json(_var))
      ("attr", Json(_attr))
      ("lowConst", _lowConst.toJson())
      ("highConst", _highConst.toJson());
  Json lowList(Json::List, _lows.size());
  for (auto l : _lows) {
    lowList(l.toJson());
  }
  item("lows", lowList);
  Json highList(Json::List, _highs.size());
  for (auto h : _highs) {
    highList(h.toJson());
  }
  item("highs", highList);
  item("valid", Json(_valid));
  item("equality", Json(_equality));
  return item;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief class RangesInfo
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
/// @brief  insert if there is no range corresponding to variable name <var>,
/// and attribute <name>, and otherwise intersection with existing range
////////////////////////////////////////////////////////////////////////////////

void RangesInfo::insert (RangeInfo newRange) {

  TRI_ASSERT(newRange.isDefined());

  std::unordered_map<std::string, RangeInfo>* oldMap = find(newRange._var);

  if (oldMap == nullptr) {
    std::unordered_map<std::string, RangeInfo> newMap;
    newMap.insert(make_pair(newRange._attr, newRange));
    _ranges.insert(std::make_pair(newRange._var, newMap));
    return;
  }

  auto it = oldMap->find(newRange._attr);

  if (it == oldMap->end()) {
    oldMap->insert(make_pair(newRange._attr, newRange));
    return;
  }

  RangeInfo& oldRange((*it).second);

  oldRange.fuse(newRange);
}

////////////////////////////////////////////////////////////////////////////////
///// @brief fuse, fuse two ranges, must be for the same variable and attribute
////////////////////////////////////////////////////////////////////////////////

void RangeInfo::fuse (RangeInfo const& that) {

  TRI_ASSERT(_var == that._var);
  TRI_ASSERT(_attr == that._attr);

  if (! isValid()) {
    // intersection of the empty set with any set is empty!
    return;
  }

  if (! that.isValid()) {
    // intersection of the empty set with any set is empty!
    invalidate();
    return;
  }

  // The following is a corner case for constant bounds:
  if (_equality && that._equality &&
      _lowConst.isDefined() && that._lowConst.isDefined()) {
    if (! TRI_CheckSameValueJson(_lowConst.bound().json(),
                                 that._lowConst.bound().json())) {
      invalidate();
      return;
    }
  }

  // First sort out the constant low bounds:
  _lowConst.andCombineLowerBounds(that._lowConst);
  // Simply append the variable ones:
  for (auto l : that._lows) {
    _lows.emplace_back(l);
  }

  // Sort out the constant high bounds:
  _highConst.andCombineUpperBounds(that._highConst);
  // Simply append the variable ones:
  for (auto h : that._highs) {
    _highs.emplace_back(h);
  }

  // check the new constant range bounds are valid:
  if (_lowConst.isDefined() && _highConst.isDefined()) {
    int cmp = TRI_CompareValuesJson(_lowConst.bound().json(),
                                    _highConst.bound().json());
    if (cmp == 1) {
      invalidate();
      return;
    }
    if (cmp == 0) {
      if (! (_lowConst.inclusive() && _highConst.inclusive()) ) {
        // range invalid
        invalidate();
      }
      else {
        _equality = true;  // Can only be at most one value
      }
    }
  }
};

////////////////////////////////////////////////////////////////////////////////
/// @brief  insert if there is no range corresponding to variable name <var>,
/// and attribute <name>, and otherwise intersection with existing range
////////////////////////////////////////////////////////////////////////////////

void RangesInfo::insert (std::string var, std::string name,
                         RangeInfoBound low, RangeInfoBound high,
                         bool equality) {
  insert(RangeInfo(var, name, low, high, equality));
};

<|endoftext|>


<commit_before>#include "Game.h"

#include <iostream>

void Game::run()
{
	SoundEngine* soundEngine = new SoundEngine();

	soundEngine->init();
	soundEngine->playSound();

	maze = entityFac->createMaze();
	spawnPacman();

//	GameEntity* pill = entityFac->createPill(VecF3(4.0f, 0.0f, 0.0f));
//	GameEntity* bloodyPill = entityFac->createBloodyPill(VecF3(-3.0f, -2.0f, 3.0f));

	startGame();

	gameTimer->reset();
	gameTimer->start();
	do
	{
		double delta = gameTimer->tick();

		// Update game entities
		update(delta);
		for(int i=0; i<(int)entities.size(); i++)
			entities[i]->update(delta);
		maze->update(delta);

		/*Update stuff here*/
		camera->update(delta);
		window->update(delta);
		renderer->update(delta);
		Singleton<ObserverDirector>::get().update(delta);

		renderer->renderFrame();
	} while(window->isActive());
}

void Game::startGame()
{
	//Zoom in
	VecF3 pacPos = entities[0]->getPosition();
	MsgZoom* zoomMsg = new MsgZoom(pacPos.x, pacPos.y, STATE_ZOOM_IN);
	Singleton<ObserverDirector>::get().push(zoomMsg);
}
void Game::endGame()
{
}<commit_msg>Made some changes in Game::run() to test SoundEngine<commit_after>#include "Game.h"

#include <iostream>

#include "../Messaging/MsgSound.h"

void Game::run()
{
	SoundEngine* soundEngine = new SoundEngine();

	soundEngine->init();
	Singleton<ObserverDirector>::get().push(new MsgSound(SOUND_AMBIENT, false));

	Singleton<ObserverDirector>::get().update(1.0f);

	soundEngine->update(1.0f);

	maze = entityFac->createMaze();
	spawnPacman();

//	GameEntity* pill = entityFac->createPill(VecF3(4.0f, 0.0f, 0.0f));
//	GameEntity* bloodyPill = entityFac->createBloodyPill(VecF3(-3.0f, -2.0f, 3.0f));

	startGame();

	gameTimer->reset();
	gameTimer->start();
	do
	{
		double delta = gameTimer->tick();

		// Update game entities
		update(delta);
		for(int i=0; i<(int)entities.size(); i++)
			entities[i]->update(delta);
		maze->update(delta);

		/*Update stuff here*/
		camera->update(delta);
		window->update(delta);
		renderer->update(delta);
		Singleton<ObserverDirector>::get().update(delta);

		renderer->renderFrame();
	} while(window->isActive());
}

void Game::startGame()
{
	//Zoom in
	VecF3 pacPos = entities[0]->getPosition();
	MsgZoom* zoomMsg = new MsgZoom(pacPos.x, pacPos.y, STATE_ZOOM_IN);
	Singleton<ObserverDirector>::get().push(zoomMsg);
}
void Game::endGame()
{
}<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/image_transport_factory.h"

#include <algorithm>
#include <map>

#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/image_transport_client.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "content/public/common/content_switches.h"
#include "gpu/ipc/command_buffer_proxy.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGraphicsContext3D.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_setup.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gl/scoped_make_current.h"

using content::BrowserGpuChannelHostFactory;
using content::GLHelper;

namespace {

ImageTransportFactory* g_factory;

class DefaultTransportFactory
    : public ui::DefaultContextFactory,
      public ImageTransportFactory {
 public:
  DefaultTransportFactory() {
    ui::DefaultContextFactory::Initialize();
  }

  virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
    return this;
  }

  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle(
      ui::Compositor* compositor) OVERRIDE {
    return gfx::GLSurfaceHandle();
  }

  virtual void DestroySharedSurfaceHandle(
      gfx::GLSurfaceHandle surface) OVERRIDE {
  }

  virtual scoped_refptr<ImageTransportClient> CreateTransportClient(
      const gfx::Size& size,
      uint64* transport_handle) OVERRIDE {
    return NULL;
  }

  virtual GLHelper* GetGLHelper(ui::Compositor* compositor) OVERRIDE {
    return NULL;
  }

  virtual gfx::ScopedMakeCurrent* GetScopedMakeCurrent() OVERRIDE {
    return NULL;
  }

  // We don't generate lost context events, so we don't need to keep track of
  // observers
  virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
  }

  virtual void RemoveObserver(
      ImageTransportFactoryObserver* observer) OVERRIDE {
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DefaultTransportFactory);
};

class TestTransportFactory : public DefaultTransportFactory {
 public:
  TestTransportFactory() {}

  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle(
      ui::Compositor* compositor) OVERRIDE {
    return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, true);
  }

  virtual scoped_refptr<ImageTransportClient> CreateTransportClient(
      const gfx::Size& size,
      uint64* transport_handle) OVERRIDE {
#if defined(UI_COMPOSITOR_IMAGE_TRANSPORT)
    scoped_refptr<ImageTransportClient> surface(
        ImageTransportClient::Create(this, size));
    if (!surface || !surface->Initialize(transport_handle)) {
      LOG(ERROR) << "Failed to create ImageTransportClient";
      return NULL;
    }
    return surface;
#else
    return NULL;
#endif
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TestTransportFactory);
};

class ImageTransportClientTexture : public ImageTransportClient {
 public:
  explicit ImageTransportClientTexture(const gfx::Size& size)
      : ImageTransportClient(true, size) {
  }

  virtual bool Initialize(uint64* surface_id) OVERRIDE {
    set_texture_id(*surface_id);
    return true;
  }

  virtual ~ImageTransportClientTexture() {}
  virtual void Update() OVERRIDE {}
  virtual TransportDIB::Handle Handle() const OVERRIDE {
    return TransportDIB::DefaultHandleValue();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture);
};

class GpuProcessTransportFactory;

class CompositorSwapClient
    : public base::SupportsWeakPtr<CompositorSwapClient>,
      public WebGraphicsContext3DSwapBuffersClient {
 public:
  CompositorSwapClient(ui::Compositor* compositor,
                       GpuProcessTransportFactory* factory)
      : compositor_(compositor),
        factory_(factory) {
  }

  ~CompositorSwapClient() {
  }

  virtual void OnViewContextSwapBuffersPosted() OVERRIDE {
    compositor_->OnSwapBuffersPosted();
  }

  virtual void OnViewContextSwapBuffersComplete() OVERRIDE {
    compositor_->OnSwapBuffersComplete();
  }

  virtual void OnViewContextSwapBuffersAborted() OVERRIDE {
    // Recreating contexts directly from here causes issues, so post a task
    // instead.
    // TODO(piman): Fix the underlying issues.
    MessageLoop::current()->PostTask(FROM_HERE,
        base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr()));
  }

 private:
  void OnLostContext();
  ui::Compositor* compositor_;
  GpuProcessTransportFactory* factory_;

  DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient);
};

class GpuProcessTransportFactory : public ui::ContextFactory,
                                   public ImageTransportFactory {
 public:
  GpuProcessTransportFactory() {}
  virtual ~GpuProcessTransportFactory() {
    DCHECK(per_compositor_data_.empty());
  }

  virtual WebKit::WebGraphicsContext3D* CreateContext(
      ui::Compositor* compositor) OVERRIDE {
    return CreateContextCommon(compositor, false);
  }

  virtual WebKit::WebGraphicsContext3D* CreateOffscreenContext(
      ui::Compositor* compositor) OVERRIDE {
    return CreateContextCommon(compositor, true);
  }

  virtual void RemoveCompositor(ui::Compositor* compositor) OVERRIDE {
    PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
    if (it == per_compositor_data_.end())
      return;
    PerCompositorData* data = it->second;
    DCHECK(data);
    GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
    delete data;
    per_compositor_data_.erase(it);
  }

  virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
    return this;
  }

  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle(
      ui::Compositor* compositor) OVERRIDE {
    PerCompositorData* data = per_compositor_data_[compositor];
    if (!data)
      data = CreatePerCompositorData(compositor);
    gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
        gfx::kNullPluginWindow, true);
    handle.parent_gpu_process_id = data->shared_context->GetGPUProcessID();
    handle.parent_client_id = data->shared_context->GetChannelID();
    handle.parent_context_id = data->shared_context->GetContextID();
    handle.parent_texture_id[0] = data->shared_context->createTexture();
    handle.parent_texture_id[1] = data->shared_context->createTexture();
    // Finish is overkill, but flush semantics don't apply cross-channel.
    // TODO(piman): Use a cross-channel synchronization mechanism instead.
    data->shared_context->finish();

    return handle;
  }

  virtual void DestroySharedSurfaceHandle(
      gfx::GLSurfaceHandle surface) OVERRIDE {
    for (PerCompositorDataMap::iterator it = per_compositor_data_.begin();
         it != per_compositor_data_.end(); ++it) {
      PerCompositorData* data = it->second;
      DCHECK(data);
      int gpu_process_id = data->shared_context->GetGPUProcessID();
      uint32 client_id = data->shared_context->GetChannelID();
      uint32 context_id = data->shared_context->GetContextID();
      if (surface.parent_gpu_process_id == gpu_process_id &&
          surface.parent_client_id == client_id &&
          surface.parent_context_id == context_id) {
        data->shared_context->deleteTexture(surface.parent_texture_id[0]);
        data->shared_context->deleteTexture(surface.parent_texture_id[1]);
        data->shared_context->flush();
        break;
      }
    }
  }

  virtual scoped_refptr<ImageTransportClient> CreateTransportClient(
      const gfx::Size& size,
      uint64* transport_handle) {
    scoped_refptr<ImageTransportClientTexture> image(
        new ImageTransportClientTexture(size));
    image->Initialize(transport_handle);
    return image;
  }

  virtual GLHelper* GetGLHelper(ui::Compositor* compositor) {
    PerCompositorData* data = per_compositor_data_[compositor];
    if (!data)
      data = CreatePerCompositorData(compositor);
    if (!data->gl_helper.get()) {
      WebKit::WebGraphicsContext3D* context_for_thread =
          CreateContextCommon(compositor, true);
      if (!context_for_thread)
        return NULL;
      data->gl_helper.reset(new GLHelper(data->shared_context.get(),
                                         context_for_thread));
    }
    return data->gl_helper.get();
  }

  virtual gfx::ScopedMakeCurrent* GetScopedMakeCurrent() { return NULL; }

  virtual void AddObserver(ImageTransportFactoryObserver* observer) {
    observer_list_.AddObserver(observer);
  }

  virtual void RemoveObserver(ImageTransportFactoryObserver* observer) {
    observer_list_.RemoveObserver(observer);
  }

  void OnLostContext(ui::Compositor* compositor) {
    LOG(ERROR) << "Lost UI compositor context.";
    PerCompositorData* data = per_compositor_data_[compositor];
    DCHECK(data);

    // Keep old resources around while we call the observers, but ensure that
    // new resources are created if needed.
    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> old_shared_context(
        data->shared_context.release());
    scoped_ptr<GLHelper> old_helper(data->gl_helper.release());

    // Note: this has the effect of recreating the swap_client, which means we
    // won't get more reports of lost context from the same gpu process. It's a
    // good thing.
    CreateSharedContext(compositor);

    FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
        observer_list_,
        OnLostResources(compositor));
    compositor->OnSwapBuffersAborted();
  }

 private:
  struct PerCompositorData {
    int surface_id;
    scoped_ptr<CompositorSwapClient> swap_client;
    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> shared_context;
    scoped_ptr<GLHelper> gl_helper;
  };

  PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor) {
    DCHECK(!per_compositor_data_[compositor]);

    gfx::AcceleratedWidget widget = compositor->widget();
    GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();

    PerCompositorData* data = new PerCompositorData;
    data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
    tracker->SetSurfaceHandle(
        data->surface_id,
        gfx::GLSurfaceHandle(widget, false));
    per_compositor_data_[compositor] = data;

    CreateSharedContext(compositor);

    return data;
  }

  WebKit::WebGraphicsContext3D* CreateContextCommon(
      ui::Compositor* compositor,
      bool offscreen) {
    PerCompositorData* data = per_compositor_data_[compositor];
    if (!data)
      data = CreatePerCompositorData(compositor);

    WebKit::WebGraphicsContext3D::Attributes attrs;
    attrs.shareResources = true;
    GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
        new WebGraphicsContext3DCommandBufferImpl(
            offscreen ? 0 : data->surface_id,
            GURL(),
            factory,
            data->swap_client->AsWeakPtr()));
    if (!context->Initialize(
        attrs,
        false,
        content::CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
      return NULL;
    return context.release();
  }

  void CreateSharedContext(ui::Compositor* compositor) {
    PerCompositorData* data = per_compositor_data_[compositor];
    DCHECK(data);

    data->swap_client.reset(new CompositorSwapClient(compositor, this));

    GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
    WebKit::WebGraphicsContext3D::Attributes attrs;
    attrs.shareResources = true;
    data->shared_context.reset(new WebGraphicsContext3DCommandBufferImpl(
          0,
          GURL(),
          factory,
          data->swap_client->AsWeakPtr()));
    if (!data->shared_context->Initialize(
        attrs,
        false,
        content::CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)) {
      // If we can't recreate contexts, we won't be able to show the UI. Better
      // crash at this point.
      LOG(FATAL) << "Failed to initialize compositor shared context.";
    }
    if (!data->shared_context->makeContextCurrent()) {
      // If we can't recreate contexts, we won't be able to show the UI. Better
      // crash at this point.
      LOG(FATAL) << "Failed to make compositor shared context current.";
    }
  }

  typedef std::map<ui::Compositor*, PerCompositorData*> PerCompositorDataMap;
  PerCompositorDataMap per_compositor_data_;
  ObserverList<ImageTransportFactoryObserver> observer_list_;

  DISALLOW_COPY_AND_ASSIGN(GpuProcessTransportFactory);
};

void CompositorSwapClient::OnLostContext() {
  factory_->OnLostContext(compositor_);
  // Note: previous line destroyed this. Don't access members from now on.
}

}  // anonymous namespace

// static
void ImageTransportFactory::Initialize() {
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kTestCompositor)) {
    ui::SetupTestCompositor();
  }
  if (ui::IsTestCompositorEnabled()) {
    g_factory = new TestTransportFactory();
  } else {
    g_factory = new GpuProcessTransportFactory();
  }
  ui::ContextFactory::SetInstance(g_factory->AsContextFactory());
}

// static
void ImageTransportFactory::Terminate() {
  ui::ContextFactory::SetInstance(NULL);
  delete g_factory;
  g_factory = NULL;
}

// static
ImageTransportFactory* ImageTransportFactory::GetInstance() {
  return g_factory;
}
<commit_msg>Disable GpuProcessTransportFactory on Windows temporarily<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "content/browser/renderer_host/image_transport_factory.h"

#include <algorithm>
#include <map>

#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/gpu_surface_tracker.h"
#include "content/browser/renderer_host/image_transport_client.h"
#include "content/common/gpu/client/gl_helper.h"
#include "content/common/gpu/client/gpu_channel_host.h"
#include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
#include "content/common/gpu/gpu_process_launch_causes.h"
#include "content/public/common/content_switches.h"
#include "gpu/ipc/command_buffer_proxy.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebGraphicsContext3D.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/compositor_setup.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/size.h"
#include "ui/gl/scoped_make_current.h"

using content::BrowserGpuChannelHostFactory;
using content::GLHelper;

namespace {

ImageTransportFactory* g_factory;

class DefaultTransportFactory
    : public ui::DefaultContextFactory,
      public ImageTransportFactory {
 public:
  DefaultTransportFactory() {
    ui::DefaultContextFactory::Initialize();
  }

  virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
    return this;
  }

  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle(
      ui::Compositor* compositor) OVERRIDE {
    return gfx::GLSurfaceHandle();
  }

  virtual void DestroySharedSurfaceHandle(
      gfx::GLSurfaceHandle surface) OVERRIDE {
  }

  virtual scoped_refptr<ImageTransportClient> CreateTransportClient(
      const gfx::Size& size,
      uint64* transport_handle) OVERRIDE {
    return NULL;
  }

  virtual GLHelper* GetGLHelper(ui::Compositor* compositor) OVERRIDE {
    return NULL;
  }

  virtual gfx::ScopedMakeCurrent* GetScopedMakeCurrent() OVERRIDE {
    return NULL;
  }

  // We don't generate lost context events, so we don't need to keep track of
  // observers
  virtual void AddObserver(ImageTransportFactoryObserver* observer) OVERRIDE {
  }

  virtual void RemoveObserver(
      ImageTransportFactoryObserver* observer) OVERRIDE {
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DefaultTransportFactory);
};

class TestTransportFactory : public DefaultTransportFactory {
 public:
  TestTransportFactory() {}

  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle(
      ui::Compositor* compositor) OVERRIDE {
    return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, true);
  }

  virtual scoped_refptr<ImageTransportClient> CreateTransportClient(
      const gfx::Size& size,
      uint64* transport_handle) OVERRIDE {
#if defined(UI_COMPOSITOR_IMAGE_TRANSPORT)
    scoped_refptr<ImageTransportClient> surface(
        ImageTransportClient::Create(this, size));
    if (!surface || !surface->Initialize(transport_handle)) {
      LOG(ERROR) << "Failed to create ImageTransportClient";
      return NULL;
    }
    return surface;
#else
    return NULL;
#endif
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(TestTransportFactory);
};

class ImageTransportClientTexture : public ImageTransportClient {
 public:
  explicit ImageTransportClientTexture(const gfx::Size& size)
      : ImageTransportClient(true, size) {
  }

  virtual bool Initialize(uint64* surface_id) OVERRIDE {
    set_texture_id(*surface_id);
    return true;
  }

  virtual ~ImageTransportClientTexture() {}
  virtual void Update() OVERRIDE {}
  virtual TransportDIB::Handle Handle() const OVERRIDE {
    return TransportDIB::DefaultHandleValue();
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(ImageTransportClientTexture);
};

class GpuProcessTransportFactory;

class CompositorSwapClient
    : public base::SupportsWeakPtr<CompositorSwapClient>,
      public WebGraphicsContext3DSwapBuffersClient {
 public:
  CompositorSwapClient(ui::Compositor* compositor,
                       GpuProcessTransportFactory* factory)
      : compositor_(compositor),
        factory_(factory) {
  }

  ~CompositorSwapClient() {
  }

  virtual void OnViewContextSwapBuffersPosted() OVERRIDE {
    compositor_->OnSwapBuffersPosted();
  }

  virtual void OnViewContextSwapBuffersComplete() OVERRIDE {
    compositor_->OnSwapBuffersComplete();
  }

  virtual void OnViewContextSwapBuffersAborted() OVERRIDE {
    // Recreating contexts directly from here causes issues, so post a task
    // instead.
    // TODO(piman): Fix the underlying issues.
    MessageLoop::current()->PostTask(FROM_HERE,
        base::Bind(&CompositorSwapClient::OnLostContext, this->AsWeakPtr()));
  }

 private:
  void OnLostContext();
  ui::Compositor* compositor_;
  GpuProcessTransportFactory* factory_;

  DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient);
};

class GpuProcessTransportFactory : public ui::ContextFactory,
                                   public ImageTransportFactory {
 public:
  GpuProcessTransportFactory() {}
  virtual ~GpuProcessTransportFactory() {
    DCHECK(per_compositor_data_.empty());
  }

  virtual WebKit::WebGraphicsContext3D* CreateContext(
      ui::Compositor* compositor) OVERRIDE {
    return CreateContextCommon(compositor, false);
  }

  virtual WebKit::WebGraphicsContext3D* CreateOffscreenContext(
      ui::Compositor* compositor) OVERRIDE {
    return CreateContextCommon(compositor, true);
  }

  virtual void RemoveCompositor(ui::Compositor* compositor) OVERRIDE {
    PerCompositorDataMap::iterator it = per_compositor_data_.find(compositor);
    if (it == per_compositor_data_.end())
      return;
    PerCompositorData* data = it->second;
    DCHECK(data);
    GpuSurfaceTracker::Get()->RemoveSurface(data->surface_id);
    delete data;
    per_compositor_data_.erase(it);
  }

  virtual ui::ContextFactory* AsContextFactory() OVERRIDE {
    return this;
  }

  virtual gfx::GLSurfaceHandle CreateSharedSurfaceHandle(
      ui::Compositor* compositor) OVERRIDE {
    PerCompositorData* data = per_compositor_data_[compositor];
    if (!data)
      data = CreatePerCompositorData(compositor);
    gfx::GLSurfaceHandle handle = gfx::GLSurfaceHandle(
        gfx::kNullPluginWindow, true);
    handle.parent_gpu_process_id = data->shared_context->GetGPUProcessID();
    handle.parent_client_id = data->shared_context->GetChannelID();
    handle.parent_context_id = data->shared_context->GetContextID();
    handle.parent_texture_id[0] = data->shared_context->createTexture();
    handle.parent_texture_id[1] = data->shared_context->createTexture();
    // Finish is overkill, but flush semantics don't apply cross-channel.
    // TODO(piman): Use a cross-channel synchronization mechanism instead.
    data->shared_context->finish();

    return handle;
  }

  virtual void DestroySharedSurfaceHandle(
      gfx::GLSurfaceHandle surface) OVERRIDE {
    for (PerCompositorDataMap::iterator it = per_compositor_data_.begin();
         it != per_compositor_data_.end(); ++it) {
      PerCompositorData* data = it->second;
      DCHECK(data);
      int gpu_process_id = data->shared_context->GetGPUProcessID();
      uint32 client_id = data->shared_context->GetChannelID();
      uint32 context_id = data->shared_context->GetContextID();
      if (surface.parent_gpu_process_id == gpu_process_id &&
          surface.parent_client_id == client_id &&
          surface.parent_context_id == context_id) {
        data->shared_context->deleteTexture(surface.parent_texture_id[0]);
        data->shared_context->deleteTexture(surface.parent_texture_id[1]);
        data->shared_context->flush();
        break;
      }
    }
  }

  virtual scoped_refptr<ImageTransportClient> CreateTransportClient(
      const gfx::Size& size,
      uint64* transport_handle) {
    scoped_refptr<ImageTransportClientTexture> image(
        new ImageTransportClientTexture(size));
    image->Initialize(transport_handle);
    return image;
  }

  virtual GLHelper* GetGLHelper(ui::Compositor* compositor) {
    PerCompositorData* data = per_compositor_data_[compositor];
    if (!data)
      data = CreatePerCompositorData(compositor);
    if (!data->gl_helper.get()) {
      WebKit::WebGraphicsContext3D* context_for_thread =
          CreateContextCommon(compositor, true);
      if (!context_for_thread)
        return NULL;
      data->gl_helper.reset(new GLHelper(data->shared_context.get(),
                                         context_for_thread));
    }
    return data->gl_helper.get();
  }

  virtual gfx::ScopedMakeCurrent* GetScopedMakeCurrent() { return NULL; }

  virtual void AddObserver(ImageTransportFactoryObserver* observer) {
    observer_list_.AddObserver(observer);
  }

  virtual void RemoveObserver(ImageTransportFactoryObserver* observer) {
    observer_list_.RemoveObserver(observer);
  }

  void OnLostContext(ui::Compositor* compositor) {
    LOG(ERROR) << "Lost UI compositor context.";
    PerCompositorData* data = per_compositor_data_[compositor];
    DCHECK(data);

    // Keep old resources around while we call the observers, but ensure that
    // new resources are created if needed.
    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> old_shared_context(
        data->shared_context.release());
    scoped_ptr<GLHelper> old_helper(data->gl_helper.release());

    // Note: this has the effect of recreating the swap_client, which means we
    // won't get more reports of lost context from the same gpu process. It's a
    // good thing.
    CreateSharedContext(compositor);

    FOR_EACH_OBSERVER(ImageTransportFactoryObserver,
        observer_list_,
        OnLostResources(compositor));
    compositor->OnSwapBuffersAborted();
  }

 private:
  struct PerCompositorData {
    int surface_id;
    scoped_ptr<CompositorSwapClient> swap_client;
    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> shared_context;
    scoped_ptr<GLHelper> gl_helper;
  };

  PerCompositorData* CreatePerCompositorData(ui::Compositor* compositor) {
    DCHECK(!per_compositor_data_[compositor]);

    gfx::AcceleratedWidget widget = compositor->widget();
    GpuSurfaceTracker* tracker = GpuSurfaceTracker::Get();

    PerCompositorData* data = new PerCompositorData;
    data->surface_id = tracker->AddSurfaceForNativeWidget(widget);
    tracker->SetSurfaceHandle(
        data->surface_id,
        gfx::GLSurfaceHandle(widget, false));
    per_compositor_data_[compositor] = data;

    CreateSharedContext(compositor);

    return data;
  }

  WebKit::WebGraphicsContext3D* CreateContextCommon(
      ui::Compositor* compositor,
      bool offscreen) {
    PerCompositorData* data = per_compositor_data_[compositor];
    if (!data)
      data = CreatePerCompositorData(compositor);

    WebKit::WebGraphicsContext3D::Attributes attrs;
    attrs.shareResources = true;
    GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
    scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context(
        new WebGraphicsContext3DCommandBufferImpl(
            offscreen ? 0 : data->surface_id,
            GURL(),
            factory,
            data->swap_client->AsWeakPtr()));
    if (!context->Initialize(
        attrs,
        false,
        content::CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE))
      return NULL;
    return context.release();
  }

  void CreateSharedContext(ui::Compositor* compositor) {
    PerCompositorData* data = per_compositor_data_[compositor];
    DCHECK(data);

    data->swap_client.reset(new CompositorSwapClient(compositor, this));

    GpuChannelHostFactory* factory = BrowserGpuChannelHostFactory::instance();
    WebKit::WebGraphicsContext3D::Attributes attrs;
    attrs.shareResources = true;
    data->shared_context.reset(new WebGraphicsContext3DCommandBufferImpl(
          0,
          GURL(),
          factory,
          data->swap_client->AsWeakPtr()));
    if (!data->shared_context->Initialize(
        attrs,
        false,
        content::CAUSE_FOR_GPU_LAUNCH_WEBGRAPHICSCONTEXT3DCOMMANDBUFFERIMPL_INITIALIZE)) {
      // If we can't recreate contexts, we won't be able to show the UI. Better
      // crash at this point.
      LOG(FATAL) << "Failed to initialize compositor shared context.";
    }
    if (!data->shared_context->makeContextCurrent()) {
      // If we can't recreate contexts, we won't be able to show the UI. Better
      // crash at this point.
      LOG(FATAL) << "Failed to make compositor shared context current.";
    }
  }

  typedef std::map<ui::Compositor*, PerCompositorData*> PerCompositorDataMap;
  PerCompositorDataMap per_compositor_data_;
  ObserverList<ImageTransportFactoryObserver> observer_list_;

  DISALLOW_COPY_AND_ASSIGN(GpuProcessTransportFactory);
};

void CompositorSwapClient::OnLostContext() {
  factory_->OnLostContext(compositor_);
  // Note: previous line destroyed this. Don't access members from now on.
}

}  // anonymous namespace

// static
void ImageTransportFactory::Initialize() {
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kTestCompositor)) {
    ui::SetupTestCompositor();
  }
  if (ui::IsTestCompositorEnabled()) {
    g_factory = new TestTransportFactory();
  } else {
#if defined(OS_WIN)
    g_factory = new DefaultTransportFactory();
#else
    g_factory = new GpuProcessTransportFactory();
#endif
  }
  ui::ContextFactory::SetInstance(g_factory->AsContextFactory());
}

// static
void ImageTransportFactory::Terminate() {
  ui::ContextFactory::SetInstance(NULL);
  delete g_factory;
  g_factory = NULL;
}

// static
ImageTransportFactory* ImageTransportFactory::GetInstance() {
  return g_factory;
}
<|endoftext|>


<commit_before>#include <assert.h>
#include <stdio.h>
#include "MemoryMap.h"

CMemoryMap::~CMemoryMap()
{
	DeleteMap(m_readMap);
	DeleteMap(m_writeMap);
    DeleteMap(m_instructionMap);
}

void CMemoryMap::InsertReadMap(uint32 nStart, uint32 nEnd, void* pPointer, unsigned char nKey)
{
	InsertMap(m_readMap, nStart, nEnd, pPointer, nKey);
}

void CMemoryMap::InsertReadMap(uint32 start, uint32 end, const MemoryMapHandlerType& handler, unsigned char key)
{
    InsertMap(m_readMap, start, end, handler, key);
}

void CMemoryMap::InsertWriteMap(uint32 nStart, uint32 nEnd, void* pPointer, unsigned char nKey)
{
	InsertMap(m_writeMap, nStart, nEnd, pPointer, nKey);
}

void CMemoryMap::InsertWriteMap(uint32 start, uint32 end, const MemoryMapHandlerType& handler, unsigned char key)
{
    InsertMap(m_writeMap, start, end, handler, key);
}

void CMemoryMap::InsertInstructionMap(uint32 start, uint32 end, void* pointer, unsigned char key)
{
    InsertMap(m_instructionMap, start, end, pointer, key);
}

CMemoryMap::MEMORYMAPELEMENT* CMemoryMap::GetReadMap(uint32 address)
{
    return GetMap(m_readMap, address);
}

CMemoryMap::MEMORYMAPELEMENT* CMemoryMap::GetWriteMap(uint32 address)
{
    return GetMap(m_writeMap, address);
}

void CMemoryMap::SetWriteNotifyHandler(const WriteNotifyHandlerType& WriteNotifyHandler)
{
	m_WriteNotifyHandler = WriteNotifyHandler;
}

void CMemoryMap::InsertMap(MemoryMapListType& memoryMap, uint32 start, uint32 end, void* pointer, unsigned char key)
{
    assert(memoryMap.find(key) == memoryMap.end());
    MEMORYMAPELEMENT element;
	element.nStart      = start;
	element.nEnd        = end;
	element.pPointer    = pointer;
	element.nType       = MEMORYMAP_TYPE_MEMORY;
    memoryMap[key] = element;
}

void CMemoryMap::InsertMap(MemoryMapListType& memoryMap, uint32 start, uint32 end, const MemoryMapHandlerType& handler, unsigned char key)
{
    assert(memoryMap.find(key) == memoryMap.end());
    MEMORYMAPELEMENT element;
	element.nStart      = start;
	element.nEnd        = end;
    element.handler     = handler;
    element.pPointer    = NULL;
	element.nType       = MEMORYMAP_TYPE_FUNCTION;
    memoryMap[key] = element;
}

void CMemoryMap::DeleteMap(MemoryMapListType& memoryMap)
{
    memoryMap.clear();
}

CMemoryMap::MEMORYMAPELEMENT* CMemoryMap::GetMap(MemoryMapListType& memoryMap, uint32 nAddress)
{
    for(MemoryMapListType::iterator element(memoryMap.begin());
        memoryMap.end() != element; element++)
    {
        MEMORYMAPELEMENT& mapElement(element->second);
		if(nAddress <= mapElement.nEnd)
		{
			if(!(nAddress >= mapElement.nStart)) return NULL;
			return &mapElement;
		}
    }
    return NULL;
}

uint8 CMemoryMap::GetByte(uint32 nAddress)
{
	MEMORYMAPELEMENT* e;
	e = GetMap(m_readMap, nAddress);
	if(e == NULL) return 0xCC;
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		return *(uint8*)&((uint8*)e->pPointer)[nAddress - e->nStart];
		break;
	case MEMORYMAP_TYPE_FUNCTION:
        return static_cast<uint8>(e->handler(nAddress, 0));
		break;
	default:
		assert(0);
		return 0xCC;
		break;
	}
}

void CMemoryMap::SetByte(uint32 nAddress, uint8 nValue)
{
	MEMORYMAPELEMENT* e;
	e = GetMap(m_writeMap, nAddress);
	if(e == NULL)
	{
		printf("MemoryMap: Wrote to unmapped memory (0x%0.8X, 0x%0.4X).\r\n", nAddress, nValue);
		return;
	}
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		*(uint8*)&((uint8*)e->pPointer)[nAddress - e->nStart] = nValue;
		break;
	case MEMORYMAP_TYPE_FUNCTION:
        e->handler(nAddress, nValue);
		break;
	default:
		assert(0);
		break;
	}

	if(m_WriteNotifyHandler)
	{
		m_WriteNotifyHandler(nAddress);
	}
}

//////////////////////////////////////////////////////////////////
//LSB First Memory Map Implementation
//////////////////////////////////////////////////////////////////

uint16 CMemoryMap_LSBF::GetHalf(uint32 nAddress)
{
	MEMORYMAPELEMENT* e;
	if(nAddress & 0x01)
	{
		//Unaligned access (shouldn't happen)
		assert(0);
	}
	e = GetMap(m_readMap, nAddress);
	if(e == NULL) return 0xCCCC;
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		return *(uint16*)&((uint8*)e->pPointer)[nAddress - e->nStart];
		break;
	default:
        return static_cast<uint16>(e->handler(nAddress, 0));
		break;
	}
}

uint32 CMemoryMap_LSBF::GetWord(uint32 nAddress)
{
    assert((nAddress & 0x03) == 0);
	MEMORYMAPELEMENT* e = GetMap(m_readMap, nAddress);
	if(e == NULL) return 0xCCCCCCCC;
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		return *(uint32*)&((uint8*)e->pPointer)[nAddress - e->nStart];
		break;
	case MEMORYMAP_TYPE_FUNCTION:
        return e->handler(nAddress, 0);
		break;
	default:
		assert(0);
		return 0xCCCCCCCC;
		break;
	}
}

uint32 CMemoryMap_LSBF::GetInstruction(uint32 address)
{
    assert((address & 0x03) == 0);
	MEMORYMAPELEMENT* e = GetMap(m_instructionMap, address);
	if(e == NULL) return 0xCCCCCCCC;
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		return *reinterpret_cast<uint32*>(&reinterpret_cast<uint8*>(e->pPointer)[address - e->nStart]);
		break;
	default:
		assert(0);
		return 0xCCCCCCCC;
		break;
	}
}

void CMemoryMap_LSBF::SetHalf(uint32 nAddress, uint16 nValue)
{
	MEMORYMAPELEMENT* e;
	if(nAddress & 0x01)
	{
        //Unaligned access (shouldn't happen)
		assert(0);
	}
	e = GetMap(m_writeMap, nAddress);
	if(e == NULL)
	{
		printf("MemoryMap: Wrote to unmapped memory (0x%0.8X, 0x%0.4X).\r\n", nAddress, nValue);
		return;
	}
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		*reinterpret_cast<uint16*>(&reinterpret_cast<uint8*>(e->pPointer)[nAddress - e->nStart]) = nValue;
		break;
	case MEMORYMAP_TYPE_FUNCTION:
		e->handler(nAddress, nValue);
		break;
	default:
		assert(0);
		break;
	}

	if(m_WriteNotifyHandler)
	{
		m_WriteNotifyHandler(nAddress);
	}
}

void CMemoryMap_LSBF::SetWord(uint32 nAddress, uint32 nValue)
{
	MEMORYMAPELEMENT* e;
	if(nAddress & 0x03)
	{
        //Unaligned access (shouldn't happen)
		assert(0);
	}
	e = GetMap(m_writeMap, nAddress);
	if(e == NULL)
	{
		printf("MemoryMap: Wrote to unmapped memory (0x%0.8X, 0x%0.8X).\r\n", nAddress, nValue);
		return;
	}
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		*(uint32*)&((uint8*)e->pPointer)[nAddress - e->nStart] = nValue;
		break;
	case MEMORYMAP_TYPE_FUNCTION:
        e->handler(nAddress, nValue);
		break;
	default:
		assert(0);
		break;
	}

	if(m_WriteNotifyHandler)
	{
		m_WriteNotifyHandler(nAddress);
	}
}
<commit_msg>Cleaned up code a little bit.<commit_after>#include <assert.h>
#include <stdio.h>
#include "MemoryMap.h"

CMemoryMap::~CMemoryMap()
{
	DeleteMap(m_readMap);
	DeleteMap(m_writeMap);
    DeleteMap(m_instructionMap);
}

void CMemoryMap::InsertReadMap(uint32 nStart, uint32 nEnd, void* pPointer, unsigned char nKey)
{
	InsertMap(m_readMap, nStart, nEnd, pPointer, nKey);
}

void CMemoryMap::InsertReadMap(uint32 start, uint32 end, const MemoryMapHandlerType& handler, unsigned char key)
{
    InsertMap(m_readMap, start, end, handler, key);
}

void CMemoryMap::InsertWriteMap(uint32 nStart, uint32 nEnd, void* pPointer, unsigned char nKey)
{
	InsertMap(m_writeMap, nStart, nEnd, pPointer, nKey);
}

void CMemoryMap::InsertWriteMap(uint32 start, uint32 end, const MemoryMapHandlerType& handler, unsigned char key)
{
    InsertMap(m_writeMap, start, end, handler, key);
}

void CMemoryMap::InsertInstructionMap(uint32 start, uint32 end, void* pointer, unsigned char key)
{
    InsertMap(m_instructionMap, start, end, pointer, key);
}

CMemoryMap::MEMORYMAPELEMENT* CMemoryMap::GetReadMap(uint32 address)
{
    return GetMap(m_readMap, address);
}

CMemoryMap::MEMORYMAPELEMENT* CMemoryMap::GetWriteMap(uint32 address)
{
    return GetMap(m_writeMap, address);
}

void CMemoryMap::SetWriteNotifyHandler(const WriteNotifyHandlerType& WriteNotifyHandler)
{
	m_WriteNotifyHandler = WriteNotifyHandler;
}

void CMemoryMap::InsertMap(MemoryMapListType& memoryMap, uint32 start, uint32 end, void* pointer, unsigned char key)
{
    assert(memoryMap.find(key) == memoryMap.end());
    MEMORYMAPELEMENT element;
	element.nStart      = start;
	element.nEnd        = end;
	element.pPointer    = pointer;
	element.nType       = MEMORYMAP_TYPE_MEMORY;
    memoryMap[key] = element;
}

void CMemoryMap::InsertMap(MemoryMapListType& memoryMap, uint32 start, uint32 end, const MemoryMapHandlerType& handler, unsigned char key)
{
    assert(memoryMap.find(key) == memoryMap.end());
    MEMORYMAPELEMENT element;
	element.nStart      = start;
	element.nEnd        = end;
    element.handler     = handler;
    element.pPointer    = NULL;
	element.nType       = MEMORYMAP_TYPE_FUNCTION;
    memoryMap[key] = element;
}

void CMemoryMap::DeleteMap(MemoryMapListType& memoryMap)
{
    memoryMap.clear();
}

CMemoryMap::MEMORYMAPELEMENT* CMemoryMap::GetMap(MemoryMapListType& memoryMap, uint32 nAddress)
{
    for(MemoryMapListType::iterator element(memoryMap.begin());
        memoryMap.end() != element; element++)
    {
        MEMORYMAPELEMENT& mapElement(element->second);
		if(nAddress <= mapElement.nEnd)
		{
			if(!(nAddress >= mapElement.nStart)) return NULL;
			return &mapElement;
		}
    }
    return NULL;
}

uint8 CMemoryMap::GetByte(uint32 nAddress)
{
	MEMORYMAPELEMENT* e = GetMap(m_readMap, nAddress);
	if(e == NULL) return 0xCC;
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		return *(uint8*)&((uint8*)e->pPointer)[nAddress - e->nStart];
		break;
	case MEMORYMAP_TYPE_FUNCTION:
        return static_cast<uint8>(e->handler(nAddress, 0));
		break;
	default:
		assert(0);
		return 0xCC;
		break;
	}
}

void CMemoryMap::SetByte(uint32 nAddress, uint8 nValue)
{
	MEMORYMAPELEMENT* e = GetMap(m_writeMap, nAddress);
	if(e == NULL)
	{
		printf("MemoryMap: Wrote to unmapped memory (0x%0.8X, 0x%0.4X).\r\n", nAddress, nValue);
		return;
	}
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		*(uint8*)&((uint8*)e->pPointer)[nAddress - e->nStart] = nValue;
		break;
	case MEMORYMAP_TYPE_FUNCTION:
        e->handler(nAddress, nValue);
		break;
	default:
		assert(0);
		break;
	}

	if(m_WriteNotifyHandler)
	{
		m_WriteNotifyHandler(nAddress);
	}
}

//////////////////////////////////////////////////////////////////
//LSB First Memory Map Implementation
//////////////////////////////////////////////////////////////////

uint16 CMemoryMap_LSBF::GetHalf(uint32 nAddress)
{
	if(nAddress & 0x01)
	{
		//Unaligned access (shouldn't happen)
		assert(0);
	}
	MEMORYMAPELEMENT* e = GetMap(m_readMap, nAddress);
	if(e == NULL) return 0xCCCC;
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		return *(uint16*)&((uint8*)e->pPointer)[nAddress - e->nStart];
		break;
	default:
        return static_cast<uint16>(e->handler(nAddress, 0));
		break;
	}
}

uint32 CMemoryMap_LSBF::GetWord(uint32 nAddress)
{
    assert((nAddress & 0x03) == 0);
	MEMORYMAPELEMENT* e = GetMap(m_readMap, nAddress);
	if(e == NULL) return 0xCCCCCCCC;
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		return *(uint32*)&((uint8*)e->pPointer)[nAddress - e->nStart];
		break;
	case MEMORYMAP_TYPE_FUNCTION:
        return e->handler(nAddress, 0);
		break;
	default:
		assert(0);
		return 0xCCCCCCCC;
		break;
	}
}

uint32 CMemoryMap_LSBF::GetInstruction(uint32 address)
{
    assert((address & 0x03) == 0);
	MEMORYMAPELEMENT* e = GetMap(m_instructionMap, address);
	if(e == NULL) return 0xCCCCCCCC;
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		return *reinterpret_cast<uint32*>(&reinterpret_cast<uint8*>(e->pPointer)[address - e->nStart]);
		break;
	default:
		assert(0);
		return 0xCCCCCCCC;
		break;
	}
}

void CMemoryMap_LSBF::SetHalf(uint32 nAddress, uint16 nValue)
{
	if(nAddress & 0x01)
	{
        //Unaligned access (shouldn't happen)
		assert(0);
	}
	MEMORYMAPELEMENT* e = GetMap(m_writeMap, nAddress);
	if(e == NULL)
	{
		printf("MemoryMap: Wrote to unmapped memory (0x%0.8X, 0x%0.4X).\r\n", nAddress, nValue);
		return;
	}
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		*reinterpret_cast<uint16*>(&reinterpret_cast<uint8*>(e->pPointer)[nAddress - e->nStart]) = nValue;
		break;
	case MEMORYMAP_TYPE_FUNCTION:
		e->handler(nAddress, nValue);
		break;
	default:
		assert(0);
		break;
	}

	if(m_WriteNotifyHandler)
	{
		m_WriteNotifyHandler(nAddress);
	}
}

void CMemoryMap_LSBF::SetWord(uint32 nAddress, uint32 nValue)
{
	if(nAddress & 0x03)
	{
        //Unaligned access (shouldn't happen)
		assert(0);
	}
	MEMORYMAPELEMENT* e = GetMap(m_writeMap, nAddress);
	if(e == NULL)
	{
		printf("MemoryMap: Wrote to unmapped memory (0x%0.8X, 0x%0.8X).\r\n", nAddress, nValue);
		return;
	}
	switch(e->nType)
	{
	case MEMORYMAP_TYPE_MEMORY:
		*(uint32*)&((uint8*)e->pPointer)[nAddress - e->nStart] = nValue;
		break;
	case MEMORYMAP_TYPE_FUNCTION:
        e->handler(nAddress, nValue);
		break;
	default:
		assert(0);
		break;
	}

	if(m_WriteNotifyHandler)
	{
		m_WriteNotifyHandler(nAddress);
	}
}
<|endoftext|>


<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "transcodeagent.hh"

#include "sdp-modifier.hh"

static MSList *makeSupportedAudioPayloadList(){
	/* in mediastreamer2, we use normal_bitrate as an IP bitrate, not codec bitrate*/
	payload_type_speex_nb.normal_bitrate=25000;
	payload_type_speex_wb.normal_bitrate=42000;
	payload_type_speex_nb.recv_fmtp=(char *)"vbr=1";

	payload_type_set_number(&payload_type_pcmu8000,0);
	payload_type_set_number(&payload_type_pcma8000,8);
	payload_type_set_number(&payload_type_gsm,3);
	payload_type_set_number(&payload_type_speex_nb,-1);
	payload_type_set_number(&payload_type_speex_wb,-1);
	payload_type_set_number(&payload_type_amr,-1);
	MSList *l=ms_list_append(NULL,&payload_type_pcmu8000);
	l=ms_list_append(l,&payload_type_pcma8000);
	l=ms_list_append(l,&payload_type_gsm);
	l=ms_list_append(l,&payload_type_speex_nb);
	//l=ms_list_append(l,&payload_type_speex_wb);
	l=ms_list_append(l,&payload_type_amr);
	return l;
}

TranscodeAgent::TranscodeAgent(su_root_t *root, const char *locaddr, int port) :
	Agent(root,locaddr,port){

	mTicker=ms_ticker_new();
	mSupportedAudioPayloads=makeSupportedAudioPayloadList();
}

TranscodeAgent::~TranscodeAgent(){
	ms_ticker_destroy(mTicker);
}

bool TranscodeAgent::processSipInfo(CallContext *c, msg_t *msg, sip_t *sip){
	sip_payload_t *payload=sip->sip_payload;
	if (payload!=NULL && payload->pl_data!=NULL) {
		if (sip->sip_content_type!=NULL &&
		    strcasecmp(sip->sip_content_type->c_subtype,"dtmf-relay")==0){
			c->playTone (sip);
			nta_msg_treply(mAgent,msg,200,NULL,TAG_END());
			return true;
		}
	}
	return false;
}

const PayloadType *findPt(const MSList *l, const char *mime, int rate){
	for(;l!=NULL;l=l->next){
		const PayloadType *pt=(PayloadType*)l->data;
		if (pt->clock_rate==rate && strcasecmp(mime,pt->mime_type)==0)
			return pt;
	}
	return NULL;
}

MSList *TranscodeAgent::normalizePayloads(MSList *l){
	MSList *it;
	for(it=l;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)l->data;
		if (pt->normal_bitrate==0){
			const PayloadType *refpt=findPt(mSupportedAudioPayloads,pt->mime_type,pt->clock_rate);
			if (refpt && refpt->normal_bitrate>0){
				ms_message("Using %s at bitrate %i",pt->mime_type,refpt->normal_bitrate);
				pt->normal_bitrate=refpt->normal_bitrate;
			}
		}
	}
	return l;
}

void TranscodeAgent::processNewInvite(CallContext *c, msg_t *msg, sip_t *sip){
	std::string addr;
	int port;
	SdpModifier *m=SdpModifier::createFromSipMsg(c->getHome(), sip);
	c->prepare(sip);
	c->setInitialOffer (m->readPayloads ());
	m->getAudioIpPort (&addr,&port);
	c->getFrontSide()->setRemoteAddr(addr.c_str(),port);
	port=c->getBackSide()->getAudioPort();
	m->changeAudioIpPort(getLocAddr().c_str(),port);
	m->appendNewPayloadsAndRemoveUnsupported(mSupportedAudioPayloads);
	m->update(msg,sip);
	//be in the record-route
	addRecordRoute(c->getHome(),msg,sip);
	c->storeNewInvite (msg);
	delete m;
}

int TranscodeAgent::onRequest(msg_t *msg, sip_t *sip){
	CallContext *c;
	if (sip->sip_request->rq_method==sip_method_invite){
		if ((c=static_cast<CallContext*>(mCalls.find(sip)))==NULL){
			c=new CallContext(sip);
			mCalls.store(c);
			processNewInvite(c,msg,sip);
		}else{
			if (c->isNewInvite(sip)){
				processNewInvite(c,msg,sip);
			}else{
				msg=msg_copy(c->getLastForwardedInvite ());
				sip=(sip_t*)msg_object(msg);
				LOGD("Forwarding invite retransmission");
			}
		}
		forwardRequest (msg,sip);
	}else{
		 if (sip->sip_request->rq_method==sip_method_info){
			 if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
				if (processSipInfo(c,msg,sip))
					 goto end;
			}
		 }

		//all other requests go through

		if (sip->sip_request->rq_method==sip_method_bye){
			if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
				mCalls.remove(c);
				delete c;
			}
		}
		forwardRequest(msg,sip);
	}
	end:
	return 0;
}

void TranscodeAgent::process200OkforInvite(CallContext *ctx, msg_t *msg, sip_t *sip){
	LOGD("Processing 200 Ok");
	const MSList *ioffer=ctx->getInitialOffer ();
	std::string addr;
	int port;
	SdpModifier *m=SdpModifier::createFromSipMsg(ctx->getHome(), sip);

	if (ctx->isJoined()) ctx->unjoin();

	m->getAudioIpPort (&addr,&port);
	ctx->getBackSide()->setRemoteAddr(addr.c_str(),port);
	m->changeAudioIpPort (getLocAddr().c_str(),ctx->getFrontSide()->getAudioPort());

	MSList *answer=m->readPayloads ();
	if (answer==NULL){
		LOGE("No payloads in 200Ok");
		delete m;
		return;
	}
	MSList *common=SdpModifier::findCommon (ioffer,mSupportedAudioPayloads);
	if (common!=NULL){
		m->appendNewPayloadsAndRemoveUnsupported(common);
		ms_list_for_each(common,(void(*)(void*))payload_type_destroy);
		ms_list_free(common);
	}
	m->update(msg,sip);
	ctx->storeNewResponse (msg);
	ctx->getBackSide ()->assignPayloads (normalizePayloads(answer));
	ms_list_free(answer);
	// read the modified answer to get payload list in right order:
	answer=m->readPayloads ();
	if (answer==NULL){
		LOGE("No payloads in forwarded 200Ok");
		delete m;
		return;
	}
	ctx->getFrontSide ()->assignPayloads (normalizePayloads(answer));
	ms_list_free(answer);
	ctx->join(mTicker);

	delete m;
}

static bool isEarlyMedia(sip_t *sip){
	if (sip->sip_status->st_status==180 || sip->sip_status->st_status==183){
		sip_payload_t *payload=sip->sip_payload;
		//TODO: should check if it is application/sdp
		return payload!=NULL;
	}
	return false;
}

int TranscodeAgent::onResponse(msg_t *msg, sip_t *sip){
	CallContext *c;
	if (sip->sip_cseq && sip->sip_cseq->cs_method==sip_method_invite){
		if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
			if (sip->sip_status->st_status==200 && c->isNew200Ok(sip)){
				process200OkforInvite (c,msg,sip);
			}else if (isEarlyMedia(sip) && c->isNewEarlyMedia (sip)){
				process200OkforInvite (c,msg,sip);
			}else if (sip->sip_status->st_status==200 || isEarlyMedia(sip)){
				LOGD("This is a 200 or 183  retransmission");
				msg=msg_copy(c->getLastForwaredResponse ());
				sip=(sip_t*)msg_object (msg);
			}
		}
	}
	return forwardResponse (msg,sip);
}

void TranscodeAgent::idle(){
	mCalls.dump();
	mCalls.removeInactives();
}
<commit_msg>fix speex parameters<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "transcodeagent.hh"

#include "sdp-modifier.hh"

static MSList *makeSupportedAudioPayloadList(){
	/* in mediastreamer2, we use normal_bitrate as an IP bitrate, not codec bitrate*/
	payload_type_speex_nb.normal_bitrate=32000;
	payload_type_speex_wb.normal_bitrate=42000;
	payload_type_speex_nb.recv_fmtp=(char *)"vbr=on";

	payload_type_set_number(&payload_type_pcmu8000,0);
	payload_type_set_number(&payload_type_pcma8000,8);
	payload_type_set_number(&payload_type_gsm,3);
	payload_type_set_number(&payload_type_speex_nb,-1);
	payload_type_set_number(&payload_type_speex_wb,-1);
	payload_type_set_number(&payload_type_amr,-1);
	MSList *l=ms_list_append(NULL,&payload_type_pcmu8000);
	l=ms_list_append(l,&payload_type_pcma8000);
	l=ms_list_append(l,&payload_type_gsm);
	l=ms_list_append(l,&payload_type_speex_nb);
	//l=ms_list_append(l,&payload_type_speex_wb);
	l=ms_list_append(l,&payload_type_amr);
	return l;
}

TranscodeAgent::TranscodeAgent(su_root_t *root, const char *locaddr, int port) :
	Agent(root,locaddr,port){

	mTicker=ms_ticker_new();
	mSupportedAudioPayloads=makeSupportedAudioPayloadList();
}

TranscodeAgent::~TranscodeAgent(){
	ms_ticker_destroy(mTicker);
}

bool TranscodeAgent::processSipInfo(CallContext *c, msg_t *msg, sip_t *sip){
	sip_payload_t *payload=sip->sip_payload;
	if (payload!=NULL && payload->pl_data!=NULL) {
		if (sip->sip_content_type!=NULL &&
		    strcasecmp(sip->sip_content_type->c_subtype,"dtmf-relay")==0){
			c->playTone (sip);
			nta_msg_treply(mAgent,msg,200,NULL,TAG_END());
			return true;
		}
	}
	return false;
}

const PayloadType *findPt(const MSList *l, const char *mime, int rate){
	for(;l!=NULL;l=l->next){
		const PayloadType *pt=(PayloadType*)l->data;
		if (pt->clock_rate==rate && strcasecmp(mime,pt->mime_type)==0)
			return pt;
	}
	return NULL;
}

MSList *TranscodeAgent::normalizePayloads(MSList *l){
	MSList *it;
	for(it=l;it!=NULL;it=it->next){
		PayloadType *pt=(PayloadType*)l->data;
		if (pt->normal_bitrate==0){
			const PayloadType *refpt=findPt(mSupportedAudioPayloads,pt->mime_type,pt->clock_rate);
			if (refpt && refpt->normal_bitrate>0){
				ms_message("Using %s at bitrate %i",pt->mime_type,refpt->normal_bitrate);
				pt->normal_bitrate=refpt->normal_bitrate;
			}
		}
	}
	return l;
}

void TranscodeAgent::processNewInvite(CallContext *c, msg_t *msg, sip_t *sip){
	std::string addr;
	int port;
	SdpModifier *m=SdpModifier::createFromSipMsg(c->getHome(), sip);
	c->prepare(sip);
	c->setInitialOffer (m->readPayloads ());
	m->getAudioIpPort (&addr,&port);
	c->getFrontSide()->setRemoteAddr(addr.c_str(),port);
	port=c->getBackSide()->getAudioPort();
	m->changeAudioIpPort(getLocAddr().c_str(),port);
	m->appendNewPayloadsAndRemoveUnsupported(mSupportedAudioPayloads);
	m->update(msg,sip);
	//be in the record-route
	addRecordRoute(c->getHome(),msg,sip);
	c->storeNewInvite (msg);
	delete m;
}

int TranscodeAgent::onRequest(msg_t *msg, sip_t *sip){
	CallContext *c;
	if (sip->sip_request->rq_method==sip_method_invite){
		if ((c=static_cast<CallContext*>(mCalls.find(sip)))==NULL){
			c=new CallContext(sip);
			mCalls.store(c);
			processNewInvite(c,msg,sip);
		}else{
			if (c->isNewInvite(sip)){
				processNewInvite(c,msg,sip);
			}else{
				msg=msg_copy(c->getLastForwardedInvite ());
				sip=(sip_t*)msg_object(msg);
				LOGD("Forwarding invite retransmission");
			}
		}
		forwardRequest (msg,sip);
	}else{
		 if (sip->sip_request->rq_method==sip_method_info){
			 if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
				if (processSipInfo(c,msg,sip))
					 goto end;
			}
		 }

		//all other requests go through

		if (sip->sip_request->rq_method==sip_method_bye){
			if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
				mCalls.remove(c);
				delete c;
			}
		}
		forwardRequest(msg,sip);
	}
	end:
	return 0;
}

void TranscodeAgent::process200OkforInvite(CallContext *ctx, msg_t *msg, sip_t *sip){
	LOGD("Processing 200 Ok");
	const MSList *ioffer=ctx->getInitialOffer ();
	std::string addr;
	int port;
	SdpModifier *m=SdpModifier::createFromSipMsg(ctx->getHome(), sip);

	if (ctx->isJoined()) ctx->unjoin();

	m->getAudioIpPort (&addr,&port);
	ctx->getBackSide()->setRemoteAddr(addr.c_str(),port);
	m->changeAudioIpPort (getLocAddr().c_str(),ctx->getFrontSide()->getAudioPort());

	MSList *answer=m->readPayloads ();
	if (answer==NULL){
		LOGE("No payloads in 200Ok");
		delete m;
		return;
	}
	MSList *common=SdpModifier::findCommon (ioffer,mSupportedAudioPayloads);
	if (common!=NULL){
		m->appendNewPayloadsAndRemoveUnsupported(common);
		ms_list_for_each(common,(void(*)(void*))payload_type_destroy);
		ms_list_free(common);
	}
	m->update(msg,sip);
	ctx->storeNewResponse (msg);
	ctx->getBackSide ()->assignPayloads (normalizePayloads(answer));
	ms_list_free(answer);
	// read the modified answer to get payload list in right order:
	answer=m->readPayloads ();
	if (answer==NULL){
		LOGE("No payloads in forwarded 200Ok");
		delete m;
		return;
	}
	ctx->getFrontSide ()->assignPayloads (normalizePayloads(answer));
	ms_list_free(answer);
	ctx->join(mTicker);

	delete m;
}

static bool isEarlyMedia(sip_t *sip){
	if (sip->sip_status->st_status==180 || sip->sip_status->st_status==183){
		sip_payload_t *payload=sip->sip_payload;
		//TODO: should check if it is application/sdp
		return payload!=NULL;
	}
	return false;
}

int TranscodeAgent::onResponse(msg_t *msg, sip_t *sip){
	CallContext *c;
	if (sip->sip_cseq && sip->sip_cseq->cs_method==sip_method_invite){
		if ((c=static_cast<CallContext*>(mCalls.find(sip)))!=NULL){
			if (sip->sip_status->st_status==200 && c->isNew200Ok(sip)){
				process200OkforInvite (c,msg,sip);
			}else if (isEarlyMedia(sip) && c->isNewEarlyMedia (sip)){
				process200OkforInvite (c,msg,sip);
			}else if (sip->sip_status->st_status==200 || isEarlyMedia(sip)){
				LOGD("This is a 200 or 183  retransmission");
				msg=msg_copy(c->getLastForwaredResponse ());
				sip=(sip_t*)msg_object (msg);
			}
		}
	}
	return forwardResponse (msg,sip);
}

void TranscodeAgent::idle(){
	mCalls.dump();
	mCalls.removeInactives();
}
<|endoftext|>


<commit_before><commit_msg>QtEditor: incfix<commit_after><|endoftext|>