<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 "webkit/media/android/webmediaplayer_android.h"

#include <string>

#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "media/base/android/media_player_bridge.h"
#include "net/base/mime_util.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCookieJar.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
#include "webkit/media/android/webmediaplayer_proxy_android.h"
#include "webkit/media/webmediaplayer_util.h"
#include "webkit/media/webvideoframe_impl.h"

using WebKit::WebCanvas;
using WebKit::WebMediaPlayerClient;
using WebKit::WebMediaPlayer;
using WebKit::WebRect;
using WebKit::WebSize;
using WebKit::WebTimeRanges;
using WebKit::WebURL;
using WebKit::WebVideoFrame;
using media::MediaPlayerBridge;
using media::VideoFrame;
using webkit_media::WebVideoFrameImpl;

namespace webkit_media {

// Because we create the media player lazily on android, the duration of the
// media is initially unknown to us. This makes the user unable to perform
// seek. To solve this problem, we use a temporary duration of 100 seconds when
// the duration is unknown. And we scale the seek position later when duration
// is available.
// TODO(qinmin): create a thread and use android MediaMetadataRetriever
// class to extract the duration.
static const float kTemporaryDuration = 100.0f;

bool WebMediaPlayerAndroid::incognito_mode_ = false;

WebMediaPlayerAndroid::WebMediaPlayerAndroid(
    WebMediaPlayerClient* client,
    WebKit::WebCookieJar* cookie_jar)
    : client_(client),
      buffered_(1u),
      video_frame_(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())),
      proxy_(new WebMediaPlayerProxyAndroid(base::MessageLoopProxy::current(),
                                            AsWeakPtr())),
      prepared_(false),
      duration_(0),
      pending_seek_(0),
      seeking_(false),
      playback_completed_(false),
      buffered_bytes_(0),
      cookie_jar_(cookie_jar),
      pending_play_event_(false),
      network_state_(WebMediaPlayer::Empty),
      ready_state_(WebMediaPlayer::HaveNothing) {
  video_frame_.reset(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame()));
}

WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
  if (media_player_.get()) {
    media_player_->Stop();
  }
}

void WebMediaPlayerAndroid::InitIncognito(bool incognito_mode) {
  incognito_mode_ = incognito_mode;
}

void WebMediaPlayerAndroid::load(const WebURL& url) {
  url_ = url;

  UpdateNetworkState(WebMediaPlayer::Loading);
  UpdateReadyState(WebMediaPlayer::HaveNothing);

  // Calling InitializeMediaPlayer() will cause android mediaplayer to start
  // buffering and decoding the data. On mobile devices, this costs a lot of
  // data usage and could even introduce performance issues. So we don't
  // initialize the player unless it is a local file. We will start loading
  // the media only when play/seek/fullsceen button is clicked.
  if (url_.SchemeIs("file")) {
    InitializeMediaPlayer();
    return;
  }

  // TODO(qinmin): we need a method to calculate the duration of the media.
  // Android does not provide any function to do that.
  // Set the initial duration value to kTemporaryDuration so that user can
  // touch the seek bar to perform seek. We will scale the seek position later
  // when we got the actual duration.
  duration_ = kTemporaryDuration;

  // Pretend everything has been loaded so that webkit can
  // still call play() and seek().
  UpdateReadyState(WebMediaPlayer::HaveMetadata);
  UpdateReadyState(WebMediaPlayer::HaveEnoughData);
}

void WebMediaPlayerAndroid::cancelLoad() {
  NOTIMPLEMENTED();
}

void WebMediaPlayerAndroid::play() {
  if (media_player_.get()) {
    if (!prepared_)
      pending_play_event_ = true;
    else
      PlayInternal();
  } else {
    pending_play_event_ = true;
    InitializeMediaPlayer();
  }
}

void WebMediaPlayerAndroid::pause() {
  if (media_player_.get()) {
    if (!prepared_)
      pending_play_event_ = false;
    else
      PauseInternal();
  } else {
    // We don't need to load media if pause() is called.
    pending_play_event_ = false;
  }
}

void WebMediaPlayerAndroid::seek(float seconds) {
  // Record the time to seek when OnMediaPrepared() is called.
  pending_seek_ = seconds;

  // Reset |playback_completed_| so that we return the correct current time.
  playback_completed_ = false;

  if (media_player_.get()) {
    if (prepared_)
      SeekInternal(seconds);
  } else {
    InitializeMediaPlayer();
  }
}

bool WebMediaPlayerAndroid::supportsFullscreen() const {
  return true;
}

bool WebMediaPlayerAndroid::supportsSave() const {
  return false;
}

void WebMediaPlayerAndroid::setEndTime(float seconds) {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
}

void WebMediaPlayerAndroid::setRate(float rate) {
  NOTIMPLEMENTED();
}

void WebMediaPlayerAndroid::setVolume(float volume) {
  if (media_player_.get())
    media_player_->SetVolume(volume, volume);
}

void WebMediaPlayerAndroid::setVisible(bool visible) {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
}

bool WebMediaPlayerAndroid::totalBytesKnown() {
  NOTIMPLEMENTED();
  return false;
}

bool WebMediaPlayerAndroid::hasVideo() const {
  // TODO(qinmin): need a better method to determine whether the current media
  // content contains video. Android does not provide any function to do
  // this.
  // We don't know whether the current media content has video unless
  // the player is prepared. If the player is not prepared, we fall back
  // to the mime-type. There may be no mime-type on a redirect URL.
  // In that case, we conservatively assume it contains video so that
  // enterfullscreen call will not fail.
  if (!prepared_) {
    if (!url_.has_path())
      return false;
    std::string mime;
    if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime))
      return true;
    return mime.find("audio/") == std::string::npos;
  }

  return !natural_size_.isEmpty();
}

bool WebMediaPlayerAndroid::hasAudio() const {
  // TODO(hclam): Query status of audio and return the actual value.
  return true;
}

bool WebMediaPlayerAndroid::paused() const {
  if (!prepared_)
    return !pending_play_event_;
  return !media_player_->IsPlaying();
}

bool WebMediaPlayerAndroid::seeking() const {
  return seeking_;
}

float WebMediaPlayerAndroid::duration() const {
  return duration_;
}

float WebMediaPlayerAndroid::currentTime() const {
  // If the player is pending for a seek, return the seek time.
  if (!prepared_ || seeking())
    return pending_seek_;

  // When playback is about to finish, android media player often stops
  // at a time which is smaller than the duration. This makes webkit never
  // know that the playback has finished. To solve this, we set the
  // current time to media duration when OnPlaybackComplete() get called.
  // And return the greater of the two values so that the current
  // time is most updated.
  if (playback_completed_)
    return duration();
  return static_cast<float>(media_player_->GetCurrentTime().InSecondsF());
}

int WebMediaPlayerAndroid::dataRate() const {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
  return 0;
}

WebSize WebMediaPlayerAndroid::naturalSize() const {
  return natural_size_;
}

WebMediaPlayer::NetworkState WebMediaPlayerAndroid::networkState() const {
  return network_state_;
}

WebMediaPlayer::ReadyState WebMediaPlayerAndroid::readyState() const {
  return ready_state_;
}

const WebTimeRanges& WebMediaPlayerAndroid::buffered() {
  return buffered_;
}

float WebMediaPlayerAndroid::maxTimeSeekable() const {
  // TODO(hclam): If this stream is not seekable this should return 0.
  return duration();
}

unsigned long long WebMediaPlayerAndroid::bytesLoaded() const {
  return buffered_bytes_;
}

unsigned long long WebMediaPlayerAndroid::totalBytes() const {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
  return 0;
}

void WebMediaPlayerAndroid::setSize(const WebSize& size) {
  texture_size_ = size;
}

void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas,
                                  const WebKit::WebRect& rect,
                                  uint8_t alpha) {
  NOTIMPLEMENTED();
}

bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
  return false;
}

WebMediaPlayer::MovieLoadType
    WebMediaPlayerAndroid::movieLoadType() const {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
  return WebMediaPlayer::Unknown;
}

float WebMediaPlayerAndroid::mediaTimeForTimeValue(float timeValue) const {
  return ConvertSecondsToTimestamp(timeValue).InSecondsF();
}

unsigned WebMediaPlayerAndroid::decodedFrameCount() const {
  NOTIMPLEMENTED();
  return 0;
}

unsigned WebMediaPlayerAndroid::droppedFrameCount() const {
  NOTIMPLEMENTED();
  return 0;
}

unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const {
  NOTIMPLEMENTED();
  return 0;
}

unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
  NOTIMPLEMENTED();
  return 0;
}

void WebMediaPlayerAndroid::OnMediaPrepared() {
  if (!media_player_.get())
    return;

  prepared_ = true;

  // Update the media duration first so that webkit will get the correct
  // duration when UpdateReadyState is called.
  float dur = duration_;
  duration_ = media_player_->GetDuration().InSecondsF();

  if (url_.SchemeIs("file"))
    UpdateNetworkState(WebMediaPlayer::Loaded);

  if (ready_state_ != WebMediaPlayer::HaveEnoughData) {
    UpdateReadyState(WebMediaPlayer::HaveMetadata);
    UpdateReadyState(WebMediaPlayer::HaveEnoughData);
  } else {
    // If the status is already set to HaveEnoughData, set it again to make sure
    // that Videolayerchromium will get created.
    UpdateReadyState(WebMediaPlayer::HaveEnoughData);
  }

  if (!url_.SchemeIs("file")) {
    // In we have skipped loading, the duration was preset to
    // kTemporaryDuration. We have to update webkit about the new duration.
    if (duration_ != dur) {
      // Scale the |pending_seek_| according to the new duration.
      pending_seek_ = pending_seek_ * duration_ / kTemporaryDuration;
      client_->durationChanged();
    }
  }

  // If media player was recovered from a saved state, consume all the pending
  // events.
  seek(pending_seek_);

  if (pending_play_event_)
    PlayInternal();

  pending_play_event_ = false;
}

void WebMediaPlayerAndroid::OnPlaybackComplete() {
  // Set the current time equal to duration to let webkit know that play back
  // is completed.
  playback_completed_ = true;
  client_->timeChanged();
}

void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) {
  buffered_[0].end = duration() * percentage / 100;
  // Implement a trick here to fake progress event, as WebKit checks
  // consecutive bytesLoaded() to see if any progress made.
  // See HTMLMediaElement::progressEventTimerFired.
  // TODO(qinmin): need a method to calculate the buffered bytes.
  buffered_bytes_++;
}

void WebMediaPlayerAndroid::OnSeekComplete() {
  seeking_ = false;

  UpdateReadyState(WebMediaPlayer::HaveEnoughData);

  client_->timeChanged();
}

void WebMediaPlayerAndroid::OnMediaError(int error_type) {
  switch (error_type) {
    case MediaPlayerBridge::MEDIA_ERROR_UNKNOWN:
      // When playing an bogus URL or bad file we fire a MEDIA_ERROR_UNKNOWN.
      // As WebKit uses FormatError to indicate an error for bogus URL or bad
      // file we default a MEDIA_ERROR_UNKNOWN to FormatError.
      UpdateNetworkState(WebMediaPlayer::FormatError);
      break;
    case MediaPlayerBridge::MEDIA_ERROR_SERVER_DIED:
      // TODO(zhenghao): Media server died. In this case, the application must
      // release the MediaPlayer object and instantiate a new one.
      UpdateNetworkState(WebMediaPlayer::DecodeError);
      break;
    case MediaPlayerBridge::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
      UpdateNetworkState(WebMediaPlayer::FormatError);
      break;
    case MediaPlayerBridge::MEDIA_ERROR_INVALID_CODE:
      break;
  }
  client_->repaint();
}

void WebMediaPlayerAndroid::OnMediaInfo(int info_type) {
  NOTIMPLEMENTED();
}

void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
  natural_size_.width = width;
  natural_size_.height = height;
}

void WebMediaPlayerAndroid::UpdateNetworkState(
    WebMediaPlayer::NetworkState state) {
  network_state_ = state;
  client_->networkStateChanged();
}

void WebMediaPlayerAndroid::UpdateReadyState(
    WebMediaPlayer::ReadyState state) {
  ready_state_ = state;
  client_->readyStateChanged();
}

void WebMediaPlayerAndroid::SetVideoSurface(jobject j_surface) {
  if (media_player_.get())
    media_player_->SetVideoSurface(j_surface);
}

void WebMediaPlayerAndroid::InitializeMediaPlayer() {
  CHECK(!media_player_.get());
  prepared_ = false;
  media_player_.reset(new MediaPlayerBridge());
  media_player_->SetStayAwakeWhilePlaying();

  std::string cookies;
  if (cookie_jar_ != NULL) {
    WebURL url(url_);
    cookies = UTF16ToUTF8(cookie_jar_->cookies(url, url));
  }
  media_player_->SetDataSource(url_.spec(), cookies, incognito_mode_);

  media_player_->Prepare(
      base::Bind(&WebMediaPlayerProxyAndroid::MediaInfoCallback, proxy_),
      base::Bind(&WebMediaPlayerProxyAndroid::MediaErrorCallback, proxy_),
      base::Bind(&WebMediaPlayerProxyAndroid::VideoSizeChangedCallback, proxy_),
      base::Bind(&WebMediaPlayerProxyAndroid::BufferingUpdateCallback, proxy_),
      base::Bind(&WebMediaPlayerProxyAndroid::MediaPreparedCallback, proxy_));
}

void WebMediaPlayerAndroid::PlayInternal() {
  CHECK(prepared_);

  if (paused())
    media_player_->Start(base::Bind(
        &WebMediaPlayerProxyAndroid::PlaybackCompleteCallback, proxy_));
}

void WebMediaPlayerAndroid::PauseInternal() {
  CHECK(prepared_);
  media_player_->Pause();
}

void WebMediaPlayerAndroid::SeekInternal(float seconds) {
  CHECK(prepared_);
  seeking_ = true;
  media_player_->SeekTo(ConvertSecondsToTimestamp(seconds), base::Bind(
      &WebMediaPlayerProxyAndroid::SeekCompleteCallback, proxy_));
}

WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() {
  return video_frame_.get();
}

void WebMediaPlayerAndroid::putCurrentFrame(
    WebVideoFrame* web_video_frame) {
}

}  // namespace webkit_media
<commit_msg>Align Android's WebMediaPlayer enumeration usage with recent WebKit changes<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 "webkit/media/android/webmediaplayer_android.h"

#include <string>

#include "base/bind.h"
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/utf_string_conversions.h"
#include "media/base/android/media_player_bridge.h"
#include "net/base/mime_util.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebCookieJar.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
#include "webkit/media/android/webmediaplayer_proxy_android.h"
#include "webkit/media/webmediaplayer_util.h"
#include "webkit/media/webvideoframe_impl.h"

using WebKit::WebCanvas;
using WebKit::WebMediaPlayerClient;
using WebKit::WebMediaPlayer;
using WebKit::WebRect;
using WebKit::WebSize;
using WebKit::WebTimeRanges;
using WebKit::WebURL;
using WebKit::WebVideoFrame;
using media::MediaPlayerBridge;
using media::VideoFrame;
using webkit_media::WebVideoFrameImpl;

namespace webkit_media {

// Because we create the media player lazily on android, the duration of the
// media is initially unknown to us. This makes the user unable to perform
// seek. To solve this problem, we use a temporary duration of 100 seconds when
// the duration is unknown. And we scale the seek position later when duration
// is available.
// TODO(qinmin): create a thread and use android MediaMetadataRetriever
// class to extract the duration.
static const float kTemporaryDuration = 100.0f;

bool WebMediaPlayerAndroid::incognito_mode_ = false;

WebMediaPlayerAndroid::WebMediaPlayerAndroid(
    WebMediaPlayerClient* client,
    WebKit::WebCookieJar* cookie_jar)
    : client_(client),
      buffered_(1u),
      video_frame_(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame())),
      proxy_(new WebMediaPlayerProxyAndroid(base::MessageLoopProxy::current(),
                                            AsWeakPtr())),
      prepared_(false),
      duration_(0),
      pending_seek_(0),
      seeking_(false),
      playback_completed_(false),
      buffered_bytes_(0),
      cookie_jar_(cookie_jar),
      pending_play_event_(false),
      network_state_(WebMediaPlayer::NetworkStateEmpty),
      ready_state_(WebMediaPlayer::ReadyStateHaveNothing) {
  video_frame_.reset(new WebVideoFrameImpl(VideoFrame::CreateEmptyFrame()));
}

WebMediaPlayerAndroid::~WebMediaPlayerAndroid() {
  if (media_player_.get()) {
    media_player_->Stop();
  }
}

void WebMediaPlayerAndroid::InitIncognito(bool incognito_mode) {
  incognito_mode_ = incognito_mode;
}

void WebMediaPlayerAndroid::load(const WebURL& url) {
  url_ = url;

  UpdateNetworkState(WebMediaPlayer::NetworkStateLoading);
  UpdateReadyState(WebMediaPlayer::ReadyStateHaveNothing);

  // Calling InitializeMediaPlayer() will cause android mediaplayer to start
  // buffering and decoding the data. On mobile devices, this costs a lot of
  // data usage and could even introduce performance issues. So we don't
  // initialize the player unless it is a local file. We will start loading
  // the media only when play/seek/fullsceen button is clicked.
  if (url_.SchemeIs("file")) {
    InitializeMediaPlayer();
    return;
  }

  // TODO(qinmin): we need a method to calculate the duration of the media.
  // Android does not provide any function to do that.
  // Set the initial duration value to kTemporaryDuration so that user can
  // touch the seek bar to perform seek. We will scale the seek position later
  // when we got the actual duration.
  duration_ = kTemporaryDuration;

  // Pretend everything has been loaded so that webkit can
  // still call play() and seek().
  UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
  UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
}

void WebMediaPlayerAndroid::cancelLoad() {
  NOTIMPLEMENTED();
}

void WebMediaPlayerAndroid::play() {
  if (media_player_.get()) {
    if (!prepared_)
      pending_play_event_ = true;
    else
      PlayInternal();
  } else {
    pending_play_event_ = true;
    InitializeMediaPlayer();
  }
}

void WebMediaPlayerAndroid::pause() {
  if (media_player_.get()) {
    if (!prepared_)
      pending_play_event_ = false;
    else
      PauseInternal();
  } else {
    // We don't need to load media if pause() is called.
    pending_play_event_ = false;
  }
}

void WebMediaPlayerAndroid::seek(float seconds) {
  // Record the time to seek when OnMediaPrepared() is called.
  pending_seek_ = seconds;

  // Reset |playback_completed_| so that we return the correct current time.
  playback_completed_ = false;

  if (media_player_.get()) {
    if (prepared_)
      SeekInternal(seconds);
  } else {
    InitializeMediaPlayer();
  }
}

bool WebMediaPlayerAndroid::supportsFullscreen() const {
  return true;
}

bool WebMediaPlayerAndroid::supportsSave() const {
  return false;
}

void WebMediaPlayerAndroid::setEndTime(float seconds) {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
}

void WebMediaPlayerAndroid::setRate(float rate) {
  NOTIMPLEMENTED();
}

void WebMediaPlayerAndroid::setVolume(float volume) {
  if (media_player_.get())
    media_player_->SetVolume(volume, volume);
}

void WebMediaPlayerAndroid::setVisible(bool visible) {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
}

bool WebMediaPlayerAndroid::totalBytesKnown() {
  NOTIMPLEMENTED();
  return false;
}

bool WebMediaPlayerAndroid::hasVideo() const {
  // TODO(qinmin): need a better method to determine whether the current media
  // content contains video. Android does not provide any function to do
  // this.
  // We don't know whether the current media content has video unless
  // the player is prepared. If the player is not prepared, we fall back
  // to the mime-type. There may be no mime-type on a redirect URL.
  // In that case, we conservatively assume it contains video so that
  // enterfullscreen call will not fail.
  if (!prepared_) {
    if (!url_.has_path())
      return false;
    std::string mime;
    if(!net::GetMimeTypeFromFile(FilePath(url_.path()), &mime))
      return true;
    return mime.find("audio/") == std::string::npos;
  }

  return !natural_size_.isEmpty();
}

bool WebMediaPlayerAndroid::hasAudio() const {
  // TODO(hclam): Query status of audio and return the actual value.
  return true;
}

bool WebMediaPlayerAndroid::paused() const {
  if (!prepared_)
    return !pending_play_event_;
  return !media_player_->IsPlaying();
}

bool WebMediaPlayerAndroid::seeking() const {
  return seeking_;
}

float WebMediaPlayerAndroid::duration() const {
  return duration_;
}

float WebMediaPlayerAndroid::currentTime() const {
  // If the player is pending for a seek, return the seek time.
  if (!prepared_ || seeking())
    return pending_seek_;

  // When playback is about to finish, android media player often stops
  // at a time which is smaller than the duration. This makes webkit never
  // know that the playback has finished. To solve this, we set the
  // current time to media duration when OnPlaybackComplete() get called.
  // And return the greater of the two values so that the current
  // time is most updated.
  if (playback_completed_)
    return duration();
  return static_cast<float>(media_player_->GetCurrentTime().InSecondsF());
}

int WebMediaPlayerAndroid::dataRate() const {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
  return 0;
}

WebSize WebMediaPlayerAndroid::naturalSize() const {
  return natural_size_;
}

WebMediaPlayer::NetworkState WebMediaPlayerAndroid::networkState() const {
  return network_state_;
}

WebMediaPlayer::ReadyState WebMediaPlayerAndroid::readyState() const {
  return ready_state_;
}

const WebTimeRanges& WebMediaPlayerAndroid::buffered() {
  return buffered_;
}

float WebMediaPlayerAndroid::maxTimeSeekable() const {
  // TODO(hclam): If this stream is not seekable this should return 0.
  return duration();
}

unsigned long long WebMediaPlayerAndroid::bytesLoaded() const {
  return buffered_bytes_;
}

unsigned long long WebMediaPlayerAndroid::totalBytes() const {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
  return 0;
}

void WebMediaPlayerAndroid::setSize(const WebSize& size) {
  texture_size_ = size;
}

void WebMediaPlayerAndroid::paint(WebKit::WebCanvas* canvas,
                                  const WebKit::WebRect& rect,
                                  uint8_t alpha) {
  NOTIMPLEMENTED();
}

bool WebMediaPlayerAndroid::hasSingleSecurityOrigin() const {
  return false;
}

WebMediaPlayer::MovieLoadType
    WebMediaPlayerAndroid::movieLoadType() const {
  // Deprecated.
  // TODO(qinmin): Remove this from WebKit::WebMediaPlayer as it is never used.
  return WebMediaPlayer::MovieLoadTypeUnknown;
}

float WebMediaPlayerAndroid::mediaTimeForTimeValue(float timeValue) const {
  return ConvertSecondsToTimestamp(timeValue).InSecondsF();
}

unsigned WebMediaPlayerAndroid::decodedFrameCount() const {
  NOTIMPLEMENTED();
  return 0;
}

unsigned WebMediaPlayerAndroid::droppedFrameCount() const {
  NOTIMPLEMENTED();
  return 0;
}

unsigned WebMediaPlayerAndroid::audioDecodedByteCount() const {
  NOTIMPLEMENTED();
  return 0;
}

unsigned WebMediaPlayerAndroid::videoDecodedByteCount() const {
  NOTIMPLEMENTED();
  return 0;
}

void WebMediaPlayerAndroid::OnMediaPrepared() {
  if (!media_player_.get())
    return;

  prepared_ = true;

  // Update the media duration first so that webkit will get the correct
  // duration when UpdateReadyState is called.
  float dur = duration_;
  duration_ = media_player_->GetDuration().InSecondsF();

  if (url_.SchemeIs("file"))
    UpdateNetworkState(WebMediaPlayer::NetworkStateLoaded);

  if (ready_state_ != WebMediaPlayer::ReadyStateHaveEnoughData) {
    UpdateReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
    UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
  } else {
    // If the status is already set to ReadyStateHaveEnoughData, set it again
    // to make sure that Videolayerchromium will get created.
    UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
  }

  if (!url_.SchemeIs("file")) {
    // In we have skipped loading, the duration was preset to
    // kTemporaryDuration. We have to update webkit about the new duration.
    if (duration_ != dur) {
      // Scale the |pending_seek_| according to the new duration.
      pending_seek_ = pending_seek_ * duration_ / kTemporaryDuration;
      client_->durationChanged();
    }
  }

  // If media player was recovered from a saved state, consume all the pending
  // events.
  seek(pending_seek_);

  if (pending_play_event_)
    PlayInternal();

  pending_play_event_ = false;
}

void WebMediaPlayerAndroid::OnPlaybackComplete() {
  // Set the current time equal to duration to let webkit know that play back
  // is completed.
  playback_completed_ = true;
  client_->timeChanged();
}

void WebMediaPlayerAndroid::OnBufferingUpdate(int percentage) {
  buffered_[0].end = duration() * percentage / 100;
  // Implement a trick here to fake progress event, as WebKit checks
  // consecutive bytesLoaded() to see if any progress made.
  // See HTMLMediaElement::progressEventTimerFired.
  // TODO(qinmin): need a method to calculate the buffered bytes.
  buffered_bytes_++;
}

void WebMediaPlayerAndroid::OnSeekComplete() {
  seeking_ = false;

  UpdateReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);

  client_->timeChanged();
}

void WebMediaPlayerAndroid::OnMediaError(int error_type) {
  switch (error_type) {
    case MediaPlayerBridge::MEDIA_ERROR_UNKNOWN:
      // When playing an bogus URL or bad file we fire a MEDIA_ERROR_UNKNOWN.
      // As WebKit uses FormatError to indicate an error for bogus URL or bad
      // file we default a MEDIA_ERROR_UNKNOWN to NetworkStateFormatError.
      UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError);
      break;
    case MediaPlayerBridge::MEDIA_ERROR_SERVER_DIED:
      // TODO(zhenghao): Media server died. In this case, the application must
      // release the MediaPlayer object and instantiate a new one.
      UpdateNetworkState(WebMediaPlayer::NetworkStateDecodeError);
      break;
    case MediaPlayerBridge::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
      UpdateNetworkState(WebMediaPlayer::NetworkStateFormatError);
      break;
    case MediaPlayerBridge::MEDIA_ERROR_INVALID_CODE:
      break;
  }
  client_->repaint();
}

void WebMediaPlayerAndroid::OnMediaInfo(int info_type) {
  NOTIMPLEMENTED();
}

void WebMediaPlayerAndroid::OnVideoSizeChanged(int width, int height) {
  natural_size_.width = width;
  natural_size_.height = height;
}

void WebMediaPlayerAndroid::UpdateNetworkState(
    WebMediaPlayer::NetworkState state) {
  network_state_ = state;
  client_->networkStateChanged();
}

void WebMediaPlayerAndroid::UpdateReadyState(
    WebMediaPlayer::ReadyState state) {
  ready_state_ = state;
  client_->readyStateChanged();
}

void WebMediaPlayerAndroid::SetVideoSurface(jobject j_surface) {
  if (media_player_.get())
    media_player_->SetVideoSurface(j_surface);
}

void WebMediaPlayerAndroid::InitializeMediaPlayer() {
  CHECK(!media_player_.get());
  prepared_ = false;
  media_player_.reset(new MediaPlayerBridge());
  media_player_->SetStayAwakeWhilePlaying();

  std::string cookies;
  if (cookie_jar_ != NULL) {
    WebURL url(url_);
    cookies = UTF16ToUTF8(cookie_jar_->cookies(url, url));
  }
  media_player_->SetDataSource(url_.spec(), cookies, incognito_mode_);

  media_player_->Prepare(
      base::Bind(&WebMediaPlayerProxyAndroid::MediaInfoCallback, proxy_),
      base::Bind(&WebMediaPlayerProxyAndroid::MediaErrorCallback, proxy_),
      base::Bind(&WebMediaPlayerProxyAndroid::VideoSizeChangedCallback, proxy_),
      base::Bind(&WebMediaPlayerProxyAndroid::BufferingUpdateCallback, proxy_),
      base::Bind(&WebMediaPlayerProxyAndroid::MediaPreparedCallback, proxy_));
}

void WebMediaPlayerAndroid::PlayInternal() {
  CHECK(prepared_);

  if (paused())
    media_player_->Start(base::Bind(
        &WebMediaPlayerProxyAndroid::PlaybackCompleteCallback, proxy_));
}

void WebMediaPlayerAndroid::PauseInternal() {
  CHECK(prepared_);
  media_player_->Pause();
}

void WebMediaPlayerAndroid::SeekInternal(float seconds) {
  CHECK(prepared_);
  seeking_ = true;
  media_player_->SeekTo(ConvertSecondsToTimestamp(seconds), base::Bind(
      &WebMediaPlayerProxyAndroid::SeekCompleteCallback, proxy_));
}

WebVideoFrame* WebMediaPlayerAndroid::getCurrentFrame() {
  return video_frame_.get();
}

void WebMediaPlayerAndroid::putCurrentFrame(
    WebVideoFrame* web_video_frame) {
}

}  // namespace webkit_media
<|endoftext|>


<commit_before>//============================================================================
// Name        : DepthOfField.cpp
// Author      : Duarte Peixinho
// Version     :
// Copyright   : ;)
// Description : Game Example
//============================================================================

#include "DepthOfField.h"

using namespace p3d;

DepthOfFieldEffect::DepthOfFieldEffect(Texture* texture1, Texture* texture2, const uint32 Width, const uint32 Height) : IEffect(Width, Height)
{
	// Set RTT
	UseCustomTexture(texture1);
	UseCustomTexture(texture2);
	UseRTT(RTT::Color);
	UseRTT(RTT::Depth);

	// Create Fragment Shader
	FragmentShaderString =
		"float DecodeNativeDepth(float native_z, vec4 z_info_local)\n"
		"{\n"
		"return z_info_local.z / (native_z * z_info_local.w + z_info_local.y);\n"
		"}\n"
		"uniform sampler2D uTex0, uTex1, uTex2, uTex3;\n"
		"uniform float uFocalPosition, uFocalRange, uRatioL, uRatioH;\n"
		"uniform vec2 uNearFar;\n"
		"varying vec2 vTexcoord;\n"
		"void main() {\n"
		"float ratioL = uRatioL;\n"
		"float ratioH = uRatioH;\n"
		"float focalPosition = uFocalPosition;\n"
		"float focalRange = uFocalRange;\n"
		"vec4 z_info_local = vec4(uNearFar.x,uNearFar.y,uNearFar.x*uNearFar.y,uNearFar.x-uNearFar.y);\n"
		"float depth = texture2D(uTex3, vTexcoord).x;\n"
		"float linearDepth = DecodeNativeDepth(depth, z_info_local);\n"
		"float ratio = clamp(abs(focalPosition-linearDepth)-focalRange, 0.0, ratioL);\n"
		"if (ratio < 0.4) gl_FragColor = mix(texture2D(uTex2, vTexcoord), texture2D(uTex1, vTexcoord), ratio / (ratioL - ratioH));\n"
		"else gl_FragColor =  mix(texture2D(uTex1, vTexcoord), texture2D(uTex0, vTexcoord), (ratio-ratioH) / (ratioL - ratioH));\n"
		"}";

	CompileShaders();

	Uniform nearFarPlane;
	nearFarPlane.Name = "uNearFar";
	nearFarPlane.Type = DataType::Vec2;
	nearFarPlane.Usage = PostEffects::NearFarPlane;
	AddUniform(nearFarPlane);

	f32 fPosition = 20.f;
	f32 fRange = 2.f;
	f32 rL = 3.1f;
	f32 rH = 1.0f;

	Uniform focalPosition;
	Uniform focalRange;
	Uniform ratioL;
	Uniform ratioH;

	focalPosition.Name = "uFocalPosition";
	focalPosition.Type = DataType::Float;
	focalPosition.Usage = PostEffects::Other;
	focalPosition.SetValue(&fPosition);
	focalRange.Name = "uFocalRange";
	focalRange.Type = DataType::Float;
	focalRange.Usage = PostEffects::Other;
	focalRange.SetValue(&fRange);
	ratioL.Name = "uRatioL";
	ratioL.Type = DataType::Float;
	ratioL.Usage = PostEffects::Other;
	ratioL.SetValue(&rL);
	ratioH.Name = "uRatioH";
	ratioH.Type = DataType::Float;
	ratioH.Usage = PostEffects::Other;
	ratioH.SetValue(&rH);

	AddUniform(focalPosition);
	AddUniform(focalRange);
	AddUniform(ratioL);
	AddUniform(ratioH);
}

DepthOfField::DepthOfField() : ClassName(1024, 768, "Pyros3D - Depth Of Field", WindowType::Close | WindowType::Resize) {}

void DepthOfField::OnResize(const uint32 width, const uint32 height)
{
	// Execute Parent Resize Function
	ClassName::OnResize(width, height);

	// Resize
	Renderer->Resize(width, height);
	projection.Perspective(70.f, (f32)width / (f32)height, 1.f, 1000.f);

	EffectManager->Resize(width, height);
	blurX->Resize(width, height);
	blurY->Resize(width, height);
	resize->Resize((uint32)(width*0.25f), (uint32)(height*0.25f));
	blurXlow->Resize((uint32)(width*0.25f), (uint32)(height*0.25f));
	blurYlow->Resize((uint32)(width*0.25f), (uint32)(height*0.25f));
	depthOfField->Resize((uint32)(width), (uint32)(height));
}

void DepthOfField::Init()
{
	// Initialization

		// Initialize Scene
	Scene = new SceneGraph();

	// Initialize Renderer
	Renderer = new ForwardRenderer(Width, Height);
	Renderer->SetBackground(Vec4(1, 0, 0, 1));
	// Projection
	projection.Perspective(70.f, (f32)Width / (f32)Height, 1.f, 1000.f);

	// Create Camera
	Camera = new GameObject();
	Camera->SetPosition(Vec3(0, 2, 20));

	// Add a Directional Light
	Light = new GameObject();
	dLight = new DirectionalLight(Vec4(1, 1, 1, 1), Vec3(-1, -1, 0));
	Light->Add(dLight);

	Scene->Add(Light);

	// Create Game Object
	modelMesh = new Model("../examples/DepthOfField/assets/suzanne.p3dm", false, ShaderUsage::Diffuse);

	for (uint32 i = 0; i < 10; i++)
	{
		GameObject* Monkey = new GameObject();
		Monkey->SetPosition(Vec3(-23.f + i * 3.f, 0, -15.f + i * 3.f));
		RenderingComponent* rMonkey = new RenderingComponent(modelMesh);
		Monkey->Add(rMonkey);
		Scene->Add(Monkey);

		go.push_back(Monkey);
		rc.push_back(rMonkey);
	}

	// Add Camera to Scene
	Scene->Add(Camera);

	Camera->LookAt(Vec3::ZERO);

	fullResBlur = new Texture();
	fullResBlur->CreateEmptyTexture(TextureType::Texture, TextureDataType::RGBA16F, Width, Height);
	fullResBlur->SetRepeat(TextureRepeat::ClampToEdge, TextureRepeat::ClampToEdge, TextureRepeat::ClampToEdge);
	lowResBlur = new Texture();
	lowResBlur->CreateEmptyTexture(TextureType::Texture, TextureDataType::RGBA16F, (int32)(Width*.25f), (int32)(Height*.25f));
	lowResBlur->SetRepeat(TextureRepeat::ClampToEdge, TextureRepeat::ClampToEdge, TextureRepeat::ClampToEdge);

	EffectManager = new PostEffectsManager(Width, Height);

	blurX = new BlurXEffect(RTT::Color, Width, Height);
	blurY = new BlurYEffect(RTT::LastRTT, Width, Height);
	fullResBlur = blurY->GetTexture();
	resize = new ResizeEffect(RTT::Color, (uint32)(Width*.25f), (uint32)(Height*.25f));
	blurXlow = new BlurXEffect(RTT::LastRTT, (uint32)(Width*.25f), (uint32)(Height*.25f));
	blurYlow = new BlurYEffect(RTT::LastRTT, (uint32)(Width*.25f), (uint32)(Height*.25f));
	lowResBlur = blurYlow->GetTexture();
	depthOfField = new DepthOfFieldEffect(lowResBlur, fullResBlur, Width, Height);

	EffectManager->AddEffect(blurX);
	EffectManager->AddEffect(blurY);
	EffectManager->AddEffect(resize);
	EffectManager->AddEffect(blurXlow);
	EffectManager->AddEffect(blurYlow);
	EffectManager->AddEffect(depthOfField);
}

void DepthOfField::Update()
{
	// Update - Game Loop

		// Update Scene
	Scene->Update(GetTime());

	// Game Logic Here
	for (uint32 i = 0; i < 10; i++)
	{
		go[i]->SetRotation(Vec3(0.f, (f32)GetTime(), 0.f));
	}

	// Render Scene
	EffectManager->CaptureFrame();
	Renderer->PreRender(Camera, Scene);
	Renderer->RenderScene(projection, Camera, Scene);
	EffectManager->EndCapture();

	// Render Post Processing
	EffectManager->ProcessPostEffects(&projection);
}

void DepthOfField::Shutdown()
{
	// All your Shutdown Code Here

		// Remove GameObjects From Scene
	for (uint32 i = 0; i < 10; i++)
	{
		Scene->Remove(go[i]);
		go[i]->Remove(rc[i]);
		delete go[i];
		delete rc[i];
	}

	Scene->Remove(Camera);

	// Delete
	delete modelMesh;
	delete Camera;
	delete Renderer;
	delete Scene;
	delete EffectManager; // this deletes all effects
}

DepthOfField::~DepthOfField() {}
<commit_msg>Small fix on Depth Of Field example<commit_after>//============================================================================
// Name        : DepthOfField.cpp
// Author      : Duarte Peixinho
// Version     :
// Copyright   : ;)
// Description : Game Example
//============================================================================

#include "DepthOfField.h"

using namespace p3d;

DepthOfFieldEffect::DepthOfFieldEffect(Texture* texture1, Texture* texture2, const uint32 Width, const uint32 Height) : IEffect(Width, Height)
{
	// Set RTT
	UseCustomTexture(texture1);
	UseCustomTexture(texture2);
	UseRTT(RTT::Color);
	UseRTT(RTT::Depth);

	// Create Fragment Shader
	FragmentShaderString =
		"float DecodeNativeDepth(float native_z, vec4 z_info_local)\n"
		"{\n"
		"return z_info_local.z / (native_z * z_info_local.w + z_info_local.y);\n"
		"}\n"
		"uniform sampler2D uTex0; // lower res blur\n"
		"uniform sampler2D uTex1; // medium res blur\n"
		"uniform sampler2D uTex2; // high res\n"
		"uniform sampler2D uTex3; // depth\n"
		"uniform float uFocalPosition, uFocalRange, uRatioL, uRatioH;\n"
		"uniform vec2 uNearFar;\n"
		"varying vec2 vTexcoord;\n"
		"void main() {\n"
		"float ratioL = uRatioL;\n"
		"float ratioH = uRatioH;\n"
		"float focalPosition = uFocalPosition;\n"
		"float focalRange = uFocalRange;\n"
		"vec4 z_info_local = vec4(uNearFar.x,uNearFar.y,uNearFar.x*uNearFar.y,uNearFar.x-uNearFar.y);\n"
		"float depth = texture2D(uTex3, vTexcoord).x;\n"
		"float linearDepth = DecodeNativeDepth(depth, z_info_local);\n"
		"float ratio = clamp(abs(focalPosition-linearDepth)-focalRange, 0.0, ratioL);\n"
		"if (ratio < 0.4) gl_FragColor = mix(texture2D(uTex2, vTexcoord), texture2D(uTex1, vTexcoord), ratio / (ratioL - ratioH));\n"
		"else gl_FragColor =  mix(texture2D(uTex1, vTexcoord), texture2D(uTex0, vTexcoord), (ratio-ratioH) / (ratioL - ratioH));\n"
		"}";

	CompileShaders();

	Uniform nearFarPlane;
	nearFarPlane.Name = "uNearFar";
	nearFarPlane.Type = DataType::Vec2;
	nearFarPlane.Usage = PostEffects::NearFarPlane;
	AddUniform(nearFarPlane);

	f32 fPosition = 20.f;
	f32 fRange = 2.f;
	f32 rL = 3.1f;
	f32 rH = 1.0f;

	AddUniform(Uniform("uFocalPosition", Uniforms::DataType::Float, &fPosition));
	AddUniform(Uniform("uFocalRange", Uniforms::DataType::Float, &fRange));
	AddUniform(Uniform("uRatioL", Uniforms::DataType::Float, &rL));
	AddUniform(Uniform("uRatioH", Uniforms::DataType::Float, &rH));
}

DepthOfField::DepthOfField() : ClassName(1024, 768, "Pyros3D - Depth Of Field", WindowType::Close | WindowType::Resize) {}

void DepthOfField::OnResize(const uint32 width, const uint32 height)
{
	// Execute Parent Resize Function
	ClassName::OnResize(width, height);

	// Resize
	Renderer->Resize(width, height);
	projection.Perspective(70.f, (f32)width / (f32)height, 1.f, 1000.f);

	EffectManager->Resize(width, height);
	blurX->Resize(width, height);
	blurY->Resize(width, height);
	resize->Resize((uint32)(width*0.25f), (uint32)(height*0.25f));
	blurXlow->Resize((uint32)(width*0.25f), (uint32)(height*0.25f));
	blurYlow->Resize((uint32)(width*0.25f), (uint32)(height*0.25f));
	depthOfField->Resize((uint32)(width), (uint32)(height));
}

void DepthOfField::Init()
{
	// Initialization

		// Initialize Scene
	Scene = new SceneGraph();

	// Initialize Renderer
	Renderer = new ForwardRenderer(Width, Height);
	Renderer->SetBackground(Vec4(1, 0, 0, 1));
	// Projection
	projection.Perspective(70.f, (f32)Width / (f32)Height, 1.f, 1000.f);

	// Create Camera
	Camera = new GameObject();
	Camera->SetPosition(Vec3(0, 2, 20));

	// Add a Directional Light
	Light = new GameObject();
	dLight = new DirectionalLight(Vec4(1, 1, 1, 1), Vec3(-1, -1, 0));
	Light->Add(dLight);

	Scene->Add(Light);

	// Create Game Object
	modelMesh = new Model("../examples/DepthOfField/assets/suzanne.p3dm", false, ShaderUsage::Diffuse);

	for (uint32 i = 0; i < 10; i++)
	{
		GameObject* Monkey = new GameObject();
		Monkey->SetPosition(Vec3(-23.f + i * 3.f, 0, -15.f + i * 3.f));
		RenderingComponent* rMonkey = new RenderingComponent(modelMesh);
		Monkey->Add(rMonkey);
		Scene->Add(Monkey);

		go.push_back(Monkey);
		rc.push_back(rMonkey);
	}

	// Add Camera to Scene
	Scene->Add(Camera);

	Camera->LookAt(Vec3::ZERO);

	fullResBlur = new Texture();
	fullResBlur->CreateEmptyTexture(TextureType::Texture, TextureDataType::RGBA16F, Width, Height);
	fullResBlur->SetRepeat(TextureRepeat::ClampToEdge, TextureRepeat::ClampToEdge, TextureRepeat::ClampToEdge);
	lowResBlur = new Texture();
	lowResBlur->CreateEmptyTexture(TextureType::Texture, TextureDataType::RGBA16F, (int32)(Width*.25f), (int32)(Height*.25f));
	lowResBlur->SetRepeat(TextureRepeat::ClampToEdge, TextureRepeat::ClampToEdge, TextureRepeat::ClampToEdge);

	EffectManager = new PostEffectsManager(Width, Height);

	blurX = new BlurXEffect(RTT::Color, Width, Height);
	blurY = new BlurYEffect(RTT::LastRTT, Width, Height);
	fullResBlur = blurY->GetTexture();
	resize = new ResizeEffect(RTT::Color, (uint32)(Width*.25f), (uint32)(Height*.25f));
	blurXlow = new BlurXEffect(RTT::LastRTT, (uint32)(Width*.25f), (uint32)(Height*.25f));
	blurYlow = new BlurYEffect(RTT::LastRTT, (uint32)(Width*.25f), (uint32)(Height*.25f));
	lowResBlur = blurYlow->GetTexture();
	depthOfField = new DepthOfFieldEffect(lowResBlur, fullResBlur, Width, Height);

	EffectManager->AddEffect(blurX);
	EffectManager->AddEffect(blurY);
	EffectManager->AddEffect(resize);
	EffectManager->AddEffect(blurXlow);
	EffectManager->AddEffect(blurYlow);
	EffectManager->AddEffect(depthOfField);
}

void DepthOfField::Update()
{
	// Update - Game Loop

		// Update Scene
	Scene->Update(GetTime());

	// Game Logic Here
	for (uint32 i = 0; i < 10; i++)
	{
		go[i]->SetRotation(Vec3(0.f, (f32)GetTime(), 0.f));
	}

	// Render Scene
	EffectManager->CaptureFrame();
	Renderer->PreRender(Camera, Scene);
	Renderer->RenderScene(projection, Camera, Scene);
	EffectManager->EndCapture();

	// Render Post Processing
	EffectManager->ProcessPostEffects(&projection);
}

void DepthOfField::Shutdown()
{
	// All your Shutdown Code Here

		// Remove GameObjects From Scene
	for (uint32 i = 0; i < 10; i++)
	{
		Scene->Remove(go[i]);
		go[i]->Remove(rc[i]);
		delete go[i];
		delete rc[i];
	}

	Scene->Remove(Camera);

	// Delete
	delete modelMesh;
	delete Camera;
	delete Renderer;
	delete Scene;
	delete EffectManager; // this deletes all effects
}

DepthOfField::~DepthOfField() {}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "test/cpp/interop/interop_client.h"

#include <memory>

#include <unistd.h>

#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include "test/proto/test.grpc.pb.h"
#include "test/proto/empty.grpc.pb.h"
#include "test/proto/messages.grpc.pb.h"

namespace grpc {
namespace testing {

namespace {
// The same value is defined by the Java client.
const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904};
const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979};
const int kNumResponseMessages = 2000;
const int kResponseMessageSize = 1030;
const int kReceiveDelayMilliSeconds = 20;
const int kLargeRequestSize = 314159;
const int kLargeResponseSize = 271812;
}  // namespace

InteropClient::InteropClient(std::shared_ptr<ChannelInterface> channel)
    : channel_(channel) {}

void InteropClient::AssertOkOrPrintErrorStatus(const Status& s) {
  if (s.IsOk()) {
    return;
  }
  gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(),
          s.details().c_str());
  GPR_ASSERT(0);
}

void InteropClient::DoEmpty() {
  gpr_log(GPR_INFO, "Sending an empty rpc...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  Empty request = Empty::default_instance();
  Empty response = Empty::default_instance();
  ClientContext context;

  Status s = stub->EmptyCall(&context, request, &response);
  AssertOkOrPrintErrorStatus(s);

  gpr_log(GPR_INFO, "Empty rpc done.");
}

// Shared code to set large payload, make rpc and check response payload.
void InteropClient::PerformLargeUnary(SimpleRequest* request,
                                      SimpleResponse* response) {
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  request->set_response_type(PayloadType::COMPRESSABLE);
  request->set_response_size(kLargeResponseSize);
  grpc::string payload(kLargeRequestSize, '\0');
  request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);

  Status s = stub->UnaryCall(&context, *request, response);

  AssertOkOrPrintErrorStatus(s);
  GPR_ASSERT(response->payload().type() == PayloadType::COMPRESSABLE);
  GPR_ASSERT(response->payload().body() ==
             grpc::string(kLargeResponseSize, '\0'));
}

void InteropClient::DoComputeEngineCreds(
    const grpc::string& default_service_account,
    const grpc::string& oauth_scope) {
  gpr_log(GPR_INFO,
          "Sending a large unary rpc with compute engine credentials ...");
  SimpleRequest request;
  SimpleResponse response;
  request.set_fill_username(true);
  request.set_fill_oauth_scope(true);
  PerformLargeUnary(&request, &response);
  gpr_log(GPR_INFO, "Got username %s", response.username().c_str());
  gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str());
  GPR_ASSERT(!response.username().empty());
  GPR_ASSERT(response.username().c_str() == default_service_account);
  GPR_ASSERT(!response.oauth_scope().empty());
  const char* oauth_scope_str = response.oauth_scope().c_str();
  GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos);
  gpr_log(GPR_INFO, "Large unary with compute engine creds done.");
}

void InteropClient::DoServiceAccountCreds(const grpc::string& username,
                                          const grpc::string& oauth_scope) {
  gpr_log(GPR_INFO,
          "Sending a large unary rpc with service account credentials ...");
  SimpleRequest request;
  SimpleResponse response;
  request.set_fill_username(true);
  request.set_fill_oauth_scope(true);
  PerformLargeUnary(&request, &response);
  GPR_ASSERT(!response.username().empty());
  GPR_ASSERT(!response.oauth_scope().empty());
  GPR_ASSERT(username.find(response.username()) != grpc::string::npos);
  const char* oauth_scope_str = response.oauth_scope().c_str();
  GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos);
  gpr_log(GPR_INFO, "Large unary with service account creds done.");
}

void InteropClient::DoJwtTokenCreds(const grpc::string& username) {
  gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ...");
  SimpleRequest request;
  SimpleResponse response;
  request.set_fill_username(true);
  PerformLargeUnary(&request, &response);
  GPR_ASSERT(!response.username().empty());
  GPR_ASSERT(username.find(response.username()) != grpc::string::npos);
  gpr_log(GPR_INFO, "Large unary with JWT token creds done.");
}

void InteropClient::DoLargeUnary() {
  gpr_log(GPR_INFO, "Sending a large unary rpc...");
  SimpleRequest request;
  SimpleResponse response;
  PerformLargeUnary(&request, &response);
  gpr_log(GPR_INFO, "Large unary done.");
}

void InteropClient::DoRequestStreaming() {
  gpr_log(GPR_INFO, "Sending request steaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  StreamingInputCallRequest request;
  StreamingInputCallResponse response;

  std::unique_ptr<ClientWriter<StreamingInputCallRequest>> stream(
      stub->StreamingInputCall(&context, &response));

  int aggregated_payload_size = 0;
  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
    Payload* payload = request.mutable_payload();
    payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
    GPR_ASSERT(stream->Write(request));
    aggregated_payload_size += request_stream_sizes[i];
  }
  stream->WritesDone();
  Status s = stream->Finish();

  GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size);
  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Request streaming done.");
}

void InteropClient::DoResponseStreaming() {
  gpr_log(GPR_INFO, "Receiving response steaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  StreamingOutputCallRequest request;
  for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
    ResponseParameters* response_parameter = request.add_response_parameters();
    response_parameter->set_size(response_stream_sizes[i]);
  }
  StreamingOutputCallResponse response;
  std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream(
      stub->StreamingOutputCall(&context, request));

  unsigned int i = 0;
  while (stream->Read(&response)) {
    GPR_ASSERT(response.payload().body() ==
               grpc::string(response_stream_sizes[i], '\0'));
    ++i;
  }
  GPR_ASSERT(response_stream_sizes.size() == i);
  Status s = stream->Finish();

  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Response streaming done.");
}

void InteropClient::DoResponseStreamingWithSlowConsumer() {
  gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  StreamingOutputCallRequest request;

  for (int i = 0; i < kNumResponseMessages; ++i) {
    ResponseParameters* response_parameter = request.add_response_parameters();
    response_parameter->set_size(kResponseMessageSize);
  }
  StreamingOutputCallResponse response;
  std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream(
      stub->StreamingOutputCall(&context, request));

  int i = 0;
  while (stream->Read(&response)) {
    GPR_ASSERT(response.payload().body() ==
               grpc::string(kResponseMessageSize, '\0'));
    gpr_log(GPR_INFO, "received message %d", i);
    usleep(kReceiveDelayMilliSeconds * 1000);
    ++i;
  }
  GPR_ASSERT(kNumResponseMessages == i);
  Status s = stream->Finish();

  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Response streaming done.");
}

void InteropClient::DoHalfDuplex() {
  gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
                                     StreamingOutputCallResponse>>
      stream(stub->HalfDuplexCall(&context));

  StreamingOutputCallRequest request;
  ResponseParameters* response_parameter = request.add_response_parameters();
  for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
    response_parameter->set_size(response_stream_sizes[i]);
    GPR_ASSERT(stream->Write(request));
  }
  stream->WritesDone();

  unsigned int i = 0;
  StreamingOutputCallResponse response;
  while (stream->Read(&response)) {
    GPR_ASSERT(response.payload().has_body());
    GPR_ASSERT(response.payload().body() ==
               grpc::string(response_stream_sizes[i], '\0'));
    ++i;
  }
  GPR_ASSERT(response_stream_sizes.size() == i);
  Status s = stream->Finish();
  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Half-duplex streaming rpc done.");
}

void InteropClient::DoPingPong() {
  gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
                                     StreamingOutputCallResponse>>
      stream(stub->FullDuplexCall(&context));

  StreamingOutputCallRequest request;
  request.set_response_type(PayloadType::COMPRESSABLE);
  ResponseParameters* response_parameter = request.add_response_parameters();
  Payload* payload = request.mutable_payload();
  StreamingOutputCallResponse response;
  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
    response_parameter->set_size(response_stream_sizes[i]);
    payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
    GPR_ASSERT(stream->Write(request));
    GPR_ASSERT(stream->Read(&response));
    GPR_ASSERT(response.payload().has_body());
    GPR_ASSERT(response.payload().body() ==
               grpc::string(response_stream_sizes[i], '\0'));
  }

  stream->WritesDone();
  GPR_ASSERT(!stream->Read(&response));
  Status s = stream->Finish();
  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Ping pong streaming done.");
}

void InteropClient::DoCancelAfterBegin() {
  gpr_log(GPR_INFO, "Sending request steaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  StreamingInputCallRequest request;
  StreamingInputCallResponse response;

  std::unique_ptr<ClientWriter<StreamingInputCallRequest>> stream(
      stub->StreamingInputCall(&context, &response));

  gpr_log(GPR_INFO, "Trying to cancel...");
  context.TryCancel();
  Status s = stream->Finish();
  GPR_ASSERT(s.code() == StatusCode::CANCELLED);
  gpr_log(GPR_INFO, "Canceling streaming done.");
}

void InteropClient::DoCancelAfterFirstResponse() {
  gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
                                     StreamingOutputCallResponse>>
      stream(stub->FullDuplexCall(&context));

  StreamingOutputCallRequest request;
  request.set_response_type(PayloadType::COMPRESSABLE);
  ResponseParameters* response_parameter = request.add_response_parameters();
  response_parameter->set_size(31415);
  request.mutable_payload()->set_body(grpc::string(27182, '\0'));
  StreamingOutputCallResponse response;
  GPR_ASSERT(stream->Write(request));
  GPR_ASSERT(stream->Read(&response));
  GPR_ASSERT(response.payload().has_body());
  GPR_ASSERT(response.payload().body() == grpc::string(31415, '\0'));
  gpr_log(GPR_INFO, "Trying to cancel...");
  context.TryCancel();

  Status s = stream->Finish();
  gpr_log(GPR_INFO, "Canceling pingpong streaming done.");
}

}  // namespace testing
}  // namespace grpc
<commit_msg>Correct the test request/response size, to be consistent with the test spec:https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md<commit_after>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "test/cpp/interop/interop_client.h"

#include <memory>

#include <unistd.h>

#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
#include <grpc++/status.h>
#include <grpc++/stream.h>
#include "test/proto/test.grpc.pb.h"
#include "test/proto/empty.grpc.pb.h"
#include "test/proto/messages.grpc.pb.h"

namespace grpc {
namespace testing {

namespace {
// The same value is defined by the Java client.
const std::vector<int> request_stream_sizes = {27182, 8, 1828, 45904};
const std::vector<int> response_stream_sizes = {31415, 9, 2653, 58979};
const int kNumResponseMessages = 2000;
const int kResponseMessageSize = 1030;
const int kReceiveDelayMilliSeconds = 20;
const int kLargeRequestSize = 271828;
const int kLargeResponseSize = 314159;
}  // namespace

InteropClient::InteropClient(std::shared_ptr<ChannelInterface> channel)
    : channel_(channel) {}

void InteropClient::AssertOkOrPrintErrorStatus(const Status& s) {
  if (s.IsOk()) {
    return;
  }
  gpr_log(GPR_INFO, "Error status code: %d, message: %s", s.code(),
          s.details().c_str());
  GPR_ASSERT(0);
}

void InteropClient::DoEmpty() {
  gpr_log(GPR_INFO, "Sending an empty rpc...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  Empty request = Empty::default_instance();
  Empty response = Empty::default_instance();
  ClientContext context;

  Status s = stub->EmptyCall(&context, request, &response);
  AssertOkOrPrintErrorStatus(s);

  gpr_log(GPR_INFO, "Empty rpc done.");
}

// Shared code to set large payload, make rpc and check response payload.
void InteropClient::PerformLargeUnary(SimpleRequest* request,
                                      SimpleResponse* response) {
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  request->set_response_type(PayloadType::COMPRESSABLE);
  request->set_response_size(kLargeResponseSize);
  grpc::string payload(kLargeRequestSize, '\0');
  request->mutable_payload()->set_body(payload.c_str(), kLargeRequestSize);

  Status s = stub->UnaryCall(&context, *request, response);

  AssertOkOrPrintErrorStatus(s);
  GPR_ASSERT(response->payload().type() == PayloadType::COMPRESSABLE);
  GPR_ASSERT(response->payload().body() ==
             grpc::string(kLargeResponseSize, '\0'));
}

void InteropClient::DoComputeEngineCreds(
    const grpc::string& default_service_account,
    const grpc::string& oauth_scope) {
  gpr_log(GPR_INFO,
          "Sending a large unary rpc with compute engine credentials ...");
  SimpleRequest request;
  SimpleResponse response;
  request.set_fill_username(true);
  request.set_fill_oauth_scope(true);
  PerformLargeUnary(&request, &response);
  gpr_log(GPR_INFO, "Got username %s", response.username().c_str());
  gpr_log(GPR_INFO, "Got oauth_scope %s", response.oauth_scope().c_str());
  GPR_ASSERT(!response.username().empty());
  GPR_ASSERT(response.username().c_str() == default_service_account);
  GPR_ASSERT(!response.oauth_scope().empty());
  const char* oauth_scope_str = response.oauth_scope().c_str();
  GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos);
  gpr_log(GPR_INFO, "Large unary with compute engine creds done.");
}

void InteropClient::DoServiceAccountCreds(const grpc::string& username,
                                          const grpc::string& oauth_scope) {
  gpr_log(GPR_INFO,
          "Sending a large unary rpc with service account credentials ...");
  SimpleRequest request;
  SimpleResponse response;
  request.set_fill_username(true);
  request.set_fill_oauth_scope(true);
  PerformLargeUnary(&request, &response);
  GPR_ASSERT(!response.username().empty());
  GPR_ASSERT(!response.oauth_scope().empty());
  GPR_ASSERT(username.find(response.username()) != grpc::string::npos);
  const char* oauth_scope_str = response.oauth_scope().c_str();
  GPR_ASSERT(oauth_scope.find(oauth_scope_str) != grpc::string::npos);
  gpr_log(GPR_INFO, "Large unary with service account creds done.");
}

void InteropClient::DoJwtTokenCreds(const grpc::string& username) {
  gpr_log(GPR_INFO, "Sending a large unary rpc with JWT token credentials ...");
  SimpleRequest request;
  SimpleResponse response;
  request.set_fill_username(true);
  PerformLargeUnary(&request, &response);
  GPR_ASSERT(!response.username().empty());
  GPR_ASSERT(username.find(response.username()) != grpc::string::npos);
  gpr_log(GPR_INFO, "Large unary with JWT token creds done.");
}

void InteropClient::DoLargeUnary() {
  gpr_log(GPR_INFO, "Sending a large unary rpc...");
  SimpleRequest request;
  SimpleResponse response;
  PerformLargeUnary(&request, &response);
  gpr_log(GPR_INFO, "Large unary done.");
}

void InteropClient::DoRequestStreaming() {
  gpr_log(GPR_INFO, "Sending request steaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  StreamingInputCallRequest request;
  StreamingInputCallResponse response;

  std::unique_ptr<ClientWriter<StreamingInputCallRequest>> stream(
      stub->StreamingInputCall(&context, &response));

  int aggregated_payload_size = 0;
  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
    Payload* payload = request.mutable_payload();
    payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
    GPR_ASSERT(stream->Write(request));
    aggregated_payload_size += request_stream_sizes[i];
  }
  stream->WritesDone();
  Status s = stream->Finish();

  GPR_ASSERT(response.aggregated_payload_size() == aggregated_payload_size);
  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Request streaming done.");
}

void InteropClient::DoResponseStreaming() {
  gpr_log(GPR_INFO, "Receiving response steaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  StreamingOutputCallRequest request;
  for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
    ResponseParameters* response_parameter = request.add_response_parameters();
    response_parameter->set_size(response_stream_sizes[i]);
  }
  StreamingOutputCallResponse response;
  std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream(
      stub->StreamingOutputCall(&context, request));

  unsigned int i = 0;
  while (stream->Read(&response)) {
    GPR_ASSERT(response.payload().body() ==
               grpc::string(response_stream_sizes[i], '\0'));
    ++i;
  }
  GPR_ASSERT(response_stream_sizes.size() == i);
  Status s = stream->Finish();

  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Response streaming done.");
}

void InteropClient::DoResponseStreamingWithSlowConsumer() {
  gpr_log(GPR_INFO, "Receiving response steaming rpc with slow consumer ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  StreamingOutputCallRequest request;

  for (int i = 0; i < kNumResponseMessages; ++i) {
    ResponseParameters* response_parameter = request.add_response_parameters();
    response_parameter->set_size(kResponseMessageSize);
  }
  StreamingOutputCallResponse response;
  std::unique_ptr<ClientReader<StreamingOutputCallResponse>> stream(
      stub->StreamingOutputCall(&context, request));

  int i = 0;
  while (stream->Read(&response)) {
    GPR_ASSERT(response.payload().body() ==
               grpc::string(kResponseMessageSize, '\0'));
    gpr_log(GPR_INFO, "received message %d", i);
    usleep(kReceiveDelayMilliSeconds * 1000);
    ++i;
  }
  GPR_ASSERT(kNumResponseMessages == i);
  Status s = stream->Finish();

  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Response streaming done.");
}

void InteropClient::DoHalfDuplex() {
  gpr_log(GPR_INFO, "Sending half-duplex streaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
                                     StreamingOutputCallResponse>>
      stream(stub->HalfDuplexCall(&context));

  StreamingOutputCallRequest request;
  ResponseParameters* response_parameter = request.add_response_parameters();
  for (unsigned int i = 0; i < response_stream_sizes.size(); ++i) {
    response_parameter->set_size(response_stream_sizes[i]);
    GPR_ASSERT(stream->Write(request));
  }
  stream->WritesDone();

  unsigned int i = 0;
  StreamingOutputCallResponse response;
  while (stream->Read(&response)) {
    GPR_ASSERT(response.payload().has_body());
    GPR_ASSERT(response.payload().body() ==
               grpc::string(response_stream_sizes[i], '\0'));
    ++i;
  }
  GPR_ASSERT(response_stream_sizes.size() == i);
  Status s = stream->Finish();
  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Half-duplex streaming rpc done.");
}

void InteropClient::DoPingPong() {
  gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
                                     StreamingOutputCallResponse>>
      stream(stub->FullDuplexCall(&context));

  StreamingOutputCallRequest request;
  request.set_response_type(PayloadType::COMPRESSABLE);
  ResponseParameters* response_parameter = request.add_response_parameters();
  Payload* payload = request.mutable_payload();
  StreamingOutputCallResponse response;
  for (unsigned int i = 0; i < request_stream_sizes.size(); ++i) {
    response_parameter->set_size(response_stream_sizes[i]);
    payload->set_body(grpc::string(request_stream_sizes[i], '\0'));
    GPR_ASSERT(stream->Write(request));
    GPR_ASSERT(stream->Read(&response));
    GPR_ASSERT(response.payload().has_body());
    GPR_ASSERT(response.payload().body() ==
               grpc::string(response_stream_sizes[i], '\0'));
  }

  stream->WritesDone();
  GPR_ASSERT(!stream->Read(&response));
  Status s = stream->Finish();
  AssertOkOrPrintErrorStatus(s);
  gpr_log(GPR_INFO, "Ping pong streaming done.");
}

void InteropClient::DoCancelAfterBegin() {
  gpr_log(GPR_INFO, "Sending request steaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  StreamingInputCallRequest request;
  StreamingInputCallResponse response;

  std::unique_ptr<ClientWriter<StreamingInputCallRequest>> stream(
      stub->StreamingInputCall(&context, &response));

  gpr_log(GPR_INFO, "Trying to cancel...");
  context.TryCancel();
  Status s = stream->Finish();
  GPR_ASSERT(s.code() == StatusCode::CANCELLED);
  gpr_log(GPR_INFO, "Canceling streaming done.");
}

void InteropClient::DoCancelAfterFirstResponse() {
  gpr_log(GPR_INFO, "Sending Ping Pong streaming rpc ...");
  std::unique_ptr<TestService::Stub> stub(TestService::NewStub(channel_));

  ClientContext context;
  std::unique_ptr<ClientReaderWriter<StreamingOutputCallRequest,
                                     StreamingOutputCallResponse>>
      stream(stub->FullDuplexCall(&context));

  StreamingOutputCallRequest request;
  request.set_response_type(PayloadType::COMPRESSABLE);
  ResponseParameters* response_parameter = request.add_response_parameters();
  response_parameter->set_size(31415);
  request.mutable_payload()->set_body(grpc::string(27182, '\0'));
  StreamingOutputCallResponse response;
  GPR_ASSERT(stream->Write(request));
  GPR_ASSERT(stream->Read(&response));
  GPR_ASSERT(response.payload().has_body());
  GPR_ASSERT(response.payload().body() == grpc::string(31415, '\0'));
  gpr_log(GPR_INFO, "Trying to cancel...");
  context.TryCancel();

  Status s = stream->Finish();
  gpr_log(GPR_INFO, "Canceling pingpong streaming done.");
}

}  // namespace testing
}  // namespace grpc
<|endoftext|>


<commit_before>/*
 * Simple and efficient C++ client for Open Pixel Control
 *
 * Copyright (c) 2014 Micah Elizabeth Scott <micah@scanlime.org>
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include "opcclient.h"

OPCClient::OPCClient()
{
    fd = -1;
    memset(&address, 0, sizeof address);
}

OPCClient::~OPCClient()
{
    closeSocket();
}

void OPCClient::closeSocket()
{
    if (isConnected()) {
        close(fd);
        fd = -1;
    }
}

bool OPCClient::resolve(const char *hostport, int defaultPort)
{
    fd = -1;

    char *host = strdup(hostport);
    char *colon = strchr(host, ':');
    int port = defaultPort;
    bool success = false;

    if (colon) {
        *colon = '\0';
        port = strtol(colon + 1, 0, 10);
    }

    if (port) {
        struct addrinfo *addr;
        getaddrinfo(*host ? host : "localhost", 0, 0, &addr);

        for (struct addrinfo *i = addr; i; i = i->ai_next) {
            if (i->ai_family == PF_INET) {
                memcpy(&address, i->ai_addr, sizeof address);
                address.sin_port = htons(port);
                success = true;
                break;
            }
        }
        freeaddrinfo(addr);
    }

    free(host);
    return success;
}

bool OPCClient::isConnected()
{
    return fd > 0;
}

bool OPCClient::write(const uint8_t *data, ssize_t length)
{
    if (!isConnected()) {
        if (!connectSocket()) {
            return false;
        }
    }

    while (length > 0) {
        int result = send(fd, data, length, 0);
        if (result <= 0) {
            closeSocket();
            return false;
        }
        length -= result;
        data += result;
    }

    return true;
}

bool OPCClient::write(const std::vector<uint8_t> &data)
{
    return write(&data[0], data.size());
}

bool OPCClient::connectSocket()
{
    fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (connect(fd, (struct sockaddr*) &address, sizeof address) < 0) {
        close(fd);
        return false;
    }

    int flag = 1;
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof flag);

    return true;
}
<commit_msg>Disable SIGPIPE<commit_after>/*
 * Simple and efficient C++ client for Open Pixel Control
 *
 * Copyright (c) 2014 Micah Elizabeth Scott <micah@scanlime.org>
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include "opcclient.h"

OPCClient::OPCClient()
{
    fd = -1;
    memset(&address, 0, sizeof address);
}

OPCClient::~OPCClient()
{
    closeSocket();
}

void OPCClient::closeSocket()
{
    if (isConnected()) {
        close(fd);
        fd = -1;
    }
}

bool OPCClient::resolve(const char *hostport, int defaultPort)
{
    fd = -1;

    char *host = strdup(hostport);
    char *colon = strchr(host, ':');
    int port = defaultPort;
    bool success = false;

    if (colon) {
        *colon = '\0';
        port = strtol(colon + 1, 0, 10);
    }

    if (port) {
        struct addrinfo *addr;
        getaddrinfo(*host ? host : "localhost", 0, 0, &addr);

        for (struct addrinfo *i = addr; i; i = i->ai_next) {
            if (i->ai_family == PF_INET) {
                memcpy(&address, i->ai_addr, sizeof address);
                address.sin_port = htons(port);
                success = true;
                break;
            }
        }
        freeaddrinfo(addr);
    }

    free(host);
    return success;
}

bool OPCClient::isConnected()
{
    return fd > 0;
}

bool OPCClient::write(const uint8_t *data, ssize_t length)
{
    if (!isConnected()) {
        if (!connectSocket()) {
            return false;
        }
    }

    while (length > 0) {
        int result = send(fd, data, length, 0);
        if (result <= 0) {
            closeSocket();
            return false;
        }
        length -= result;
        data += result;
    }

    return true;
}

bool OPCClient::write(const std::vector<uint8_t> &data)
{
    return write(&data[0], data.size());
}

bool OPCClient::connectSocket()
{
    fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (connect(fd, (struct sockaddr*) &address, sizeof address) < 0) {
        close(fd);
        return false;
    }

    int flag = 1;
    setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*) &flag, sizeof flag);

    flag = 1;
    setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, (char*) &flag, sizeof flag);

    return true;
}
<|endoftext|>


<commit_before>/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES 3.1 Module
 * -------------------------------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * 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.
 *
 *//*!
 * \file
 * \brief Multisample interpolation state query tests
 *//*--------------------------------------------------------------------*/

#include "es31fShaderMultisampleInterpolationStateQueryTests.hpp"
#include "tcuTestLog.hpp"
#include "gluCallLogWrapper.hpp"
#include "gluContextInfo.hpp"
#include "gluRenderContext.hpp"
#include "glsStateQueryUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"

namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace
{

using namespace gls::StateQueryUtil;

class InterpolationOffsetCase : public TestCase
{
public:
	enum TestType
	{
		TEST_MIN_OFFSET = 0,
		TEST_MAX_OFFSET,

		TEST_LAST
	};

						InterpolationOffsetCase		(Context& context, const char* name, const char* desc, QueryType verifier, TestType testType);
						~InterpolationOffsetCase	(void);

	void				init						(void);
	IterateResult		iterate						(void);

private:
	const QueryType		m_verifier;
	const TestType		m_testType;
};

InterpolationOffsetCase::InterpolationOffsetCase (Context& context, const char* name, const char* desc, QueryType verifier, TestType testType)
	: TestCase		(context, name, desc)
	, m_verifier	(verifier)
	, m_testType	(testType)
{
	DE_ASSERT(m_testType < TEST_LAST);
}

InterpolationOffsetCase::~InterpolationOffsetCase (void)
{
}

void InterpolationOffsetCase::init (void)
{
	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
		throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension");
}

InterpolationOffsetCase::IterateResult InterpolationOffsetCase::iterate (void)
{
	glu::CallLogWrapper 	gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
	gl.enableLogging(true);

	if (m_testType == TEST_MAX_OFFSET)
		verifyStateFloatMin(result, gl, GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, 0.5, m_verifier);
	else if (m_testType == TEST_MIN_OFFSET)
		verifyStateFloatMax(result, gl, GL_MIN_FRAGMENT_INTERPOLATION_OFFSET, -0.5, m_verifier);
	else
		DE_ASSERT(false);

	result.setTestContextResult(m_testCtx);
	return STOP;
}

class FragmentInterpolationOffsetBitsCase : public TestCase
{
public:
						FragmentInterpolationOffsetBitsCase		(Context& context, const char* name, const char* desc, QueryType verifier);
						~FragmentInterpolationOffsetBitsCase	(void);

	void				init									(void);
	IterateResult		iterate									(void);

private:
	const QueryType		m_verifier;
};

FragmentInterpolationOffsetBitsCase::FragmentInterpolationOffsetBitsCase (Context& context, const char* name, const char* desc, QueryType verifier)
	: TestCase		(context, name, desc)
	, m_verifier	(verifier)
{
}

FragmentInterpolationOffsetBitsCase::~FragmentInterpolationOffsetBitsCase (void)
{
}

void FragmentInterpolationOffsetBitsCase::init (void)
{
	if (!m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
		throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension");
}

FragmentInterpolationOffsetBitsCase::IterateResult FragmentInterpolationOffsetBitsCase::iterate (void)
{
	glu::CallLogWrapper 	gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
	gl.enableLogging(true);

	verifyStateIntegerMin(result, gl, GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, 4, m_verifier);

	result.setTestContextResult(m_testCtx);
	return STOP;
}

} // anonymous

ShaderMultisampleInterpolationStateQueryTests::ShaderMultisampleInterpolationStateQueryTests (Context& context)
	: TestCaseGroup(context, "multisample_interpolation", "Test multisample interpolation states")
{
}

ShaderMultisampleInterpolationStateQueryTests::~ShaderMultisampleInterpolationStateQueryTests (void)
{
}

void ShaderMultisampleInterpolationStateQueryTests::init (void)
{
	static const struct Verifier
	{
		QueryType		verifier;
		const char*		name;
		const char*		desc;
	} verifiers[] =
	{
		{ QUERY_BOOLEAN,	"get_boolean",		"Test using getBoolean"		},
		{ QUERY_INTEGER,	"get_integer",		"Test using getInteger"		},
		{ QUERY_FLOAT,		"get_float",		"Test using getFloat"		},
		{ QUERY_INTEGER64,	"get_integer64",	"Test using getInteger64"	},
	};

	// .min_fragment_interpolation_offset
	{
		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "min_fragment_interpolation_offset", "Test MIN_FRAGMENT_INTERPOLATION_OFFSET");
		addChild(group);

		for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(verifiers); ++verifierNdx)
			group->addChild(new InterpolationOffsetCase(m_context, verifiers[verifierNdx].name, verifiers[verifierNdx].desc, verifiers[verifierNdx].verifier, InterpolationOffsetCase::TEST_MIN_OFFSET));
	}

	// .max_fragment_interpolation_offset
	{
		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "max_fragment_interpolation_offset", "Test MAX_FRAGMENT_INTERPOLATION_OFFSET");
		addChild(group);

		for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(verifiers); ++verifierNdx)
			group->addChild(new InterpolationOffsetCase(m_context, verifiers[verifierNdx].name, verifiers[verifierNdx].desc, verifiers[verifierNdx].verifier, InterpolationOffsetCase::TEST_MAX_OFFSET));
	}

	// .fragment_interpolation_offset_bits
	{
		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "fragment_interpolation_offset_bits", "Test FRAGMENT_INTERPOLATION_OFFSET_BITS");
		addChild(group);

		for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(verifiers); ++verifierNdx)
			group->addChild(new FragmentInterpolationOffsetBitsCase(m_context, verifiers[verifierNdx].name, verifiers[verifierNdx].desc, verifiers[verifierNdx].verifier));
	}
}

} // Functional
} // gles31
} // deqp
<commit_msg>Check for context version or extension support.<commit_after>/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES 3.1 Module
 * -------------------------------------------------
 *
 * Copyright 2014 The Android Open Source Project
 *
 * 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.
 *
 *//*!
 * \file
 * \brief Multisample interpolation state query tests
 *//*--------------------------------------------------------------------*/

#include "es31fShaderMultisampleInterpolationStateQueryTests.hpp"
#include "tcuTestLog.hpp"
#include "gluCallLogWrapper.hpp"
#include "gluContextInfo.hpp"
#include "gluRenderContext.hpp"
#include "glsStateQueryUtil.hpp"
#include "glwEnums.hpp"
#include "glwFunctions.hpp"

namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace
{

using namespace gls::StateQueryUtil;

class InterpolationOffsetCase : public TestCase
{
public:
	enum TestType
	{
		TEST_MIN_OFFSET = 0,
		TEST_MAX_OFFSET,

		TEST_LAST
	};

						InterpolationOffsetCase		(Context& context, const char* name, const char* desc, QueryType verifier, TestType testType);
						~InterpolationOffsetCase	(void);

	void				init						(void);
	IterateResult		iterate						(void);

private:
	const QueryType		m_verifier;
	const TestType		m_testType;
};

InterpolationOffsetCase::InterpolationOffsetCase (Context& context, const char* name, const char* desc, QueryType verifier, TestType testType)
	: TestCase		(context, name, desc)
	, m_verifier	(verifier)
	, m_testType	(testType)
{
	DE_ASSERT(m_testType < TEST_LAST);
}

InterpolationOffsetCase::~InterpolationOffsetCase (void)
{
}

void InterpolationOffsetCase::init (void)
{
	const bool isES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));

	if (!isES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
		throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension");
}

InterpolationOffsetCase::IterateResult InterpolationOffsetCase::iterate (void)
{
	glu::CallLogWrapper 	gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
	gl.enableLogging(true);

	if (m_testType == TEST_MAX_OFFSET)
		verifyStateFloatMin(result, gl, GL_MAX_FRAGMENT_INTERPOLATION_OFFSET, 0.5, m_verifier);
	else if (m_testType == TEST_MIN_OFFSET)
		verifyStateFloatMax(result, gl, GL_MIN_FRAGMENT_INTERPOLATION_OFFSET, -0.5, m_verifier);
	else
		DE_ASSERT(false);

	result.setTestContextResult(m_testCtx);
	return STOP;
}

class FragmentInterpolationOffsetBitsCase : public TestCase
{
public:
						FragmentInterpolationOffsetBitsCase		(Context& context, const char* name, const char* desc, QueryType verifier);
						~FragmentInterpolationOffsetBitsCase	(void);

	void				init									(void);
	IterateResult		iterate									(void);

private:
	const QueryType		m_verifier;
};

FragmentInterpolationOffsetBitsCase::FragmentInterpolationOffsetBitsCase (Context& context, const char* name, const char* desc, QueryType verifier)
	: TestCase		(context, name, desc)
	, m_verifier	(verifier)
{
}

FragmentInterpolationOffsetBitsCase::~FragmentInterpolationOffsetBitsCase (void)
{
}

void FragmentInterpolationOffsetBitsCase::init (void)
{
	const bool isES32 = glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::es(3, 2));

	if (!isES32 && !m_context.getContextInfo().isExtensionSupported("GL_OES_shader_multisample_interpolation"))
		throw tcu::NotSupportedError("Test requires GL_OES_shader_multisample_interpolation extension");
}

FragmentInterpolationOffsetBitsCase::IterateResult FragmentInterpolationOffsetBitsCase::iterate (void)
{
	glu::CallLogWrapper 	gl		(m_context.getRenderContext().getFunctions(), m_testCtx.getLog());
	tcu::ResultCollector	result	(m_testCtx.getLog(), " // ERROR: ");
	gl.enableLogging(true);

	verifyStateIntegerMin(result, gl, GL_FRAGMENT_INTERPOLATION_OFFSET_BITS, 4, m_verifier);

	result.setTestContextResult(m_testCtx);
	return STOP;
}

} // anonymous

ShaderMultisampleInterpolationStateQueryTests::ShaderMultisampleInterpolationStateQueryTests (Context& context)
	: TestCaseGroup(context, "multisample_interpolation", "Test multisample interpolation states")
{
}

ShaderMultisampleInterpolationStateQueryTests::~ShaderMultisampleInterpolationStateQueryTests (void)
{
}

void ShaderMultisampleInterpolationStateQueryTests::init (void)
{
	static const struct Verifier
	{
		QueryType		verifier;
		const char*		name;
		const char*		desc;
	} verifiers[] =
	{
		{ QUERY_BOOLEAN,	"get_boolean",		"Test using getBoolean"		},
		{ QUERY_INTEGER,	"get_integer",		"Test using getInteger"		},
		{ QUERY_FLOAT,		"get_float",		"Test using getFloat"		},
		{ QUERY_INTEGER64,	"get_integer64",	"Test using getInteger64"	},
	};

	// .min_fragment_interpolation_offset
	{
		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "min_fragment_interpolation_offset", "Test MIN_FRAGMENT_INTERPOLATION_OFFSET");
		addChild(group);

		for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(verifiers); ++verifierNdx)
			group->addChild(new InterpolationOffsetCase(m_context, verifiers[verifierNdx].name, verifiers[verifierNdx].desc, verifiers[verifierNdx].verifier, InterpolationOffsetCase::TEST_MIN_OFFSET));
	}

	// .max_fragment_interpolation_offset
	{
		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "max_fragment_interpolation_offset", "Test MAX_FRAGMENT_INTERPOLATION_OFFSET");
		addChild(group);

		for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(verifiers); ++verifierNdx)
			group->addChild(new InterpolationOffsetCase(m_context, verifiers[verifierNdx].name, verifiers[verifierNdx].desc, verifiers[verifierNdx].verifier, InterpolationOffsetCase::TEST_MAX_OFFSET));
	}

	// .fragment_interpolation_offset_bits
	{
		tcu::TestCaseGroup* const group = new tcu::TestCaseGroup(m_testCtx, "fragment_interpolation_offset_bits", "Test FRAGMENT_INTERPOLATION_OFFSET_BITS");
		addChild(group);

		for (int verifierNdx = 0; verifierNdx < DE_LENGTH_OF_ARRAY(verifiers); ++verifierNdx)
			group->addChild(new FragmentInterpolationOffsetBitsCase(m_context, verifiers[verifierNdx].name, verifiers[verifierNdx].desc, verifiers[verifierNdx].verifier));
	}
}

} // Functional
} // gles31
} // deqp
<|endoftext|>