| Index: remoting/protocol/host_video_dispatcher.cc | 
| diff --git a/remoting/protocol/host_video_dispatcher.cc b/remoting/protocol/host_video_dispatcher.cc | 
| index b9a12c0294f28ac8e95d65ca52c8e6c000e8334f..95778e13eeb90cc8537d80cd7641db6b62c14edd 100644 | 
| --- a/remoting/protocol/host_video_dispatcher.cc | 
| +++ b/remoting/protocol/host_video_dispatcher.cc | 
| @@ -5,24 +5,84 @@ | 
| #include "remoting/protocol/host_video_dispatcher.h" | 
|  | 
| #include "base/bind.h" | 
| +#include "base/callback_helpers.h" | 
| #include "net/socket/stream_socket.h" | 
| #include "remoting/base/constants.h" | 
| -#include "remoting/proto/video.pb.h" | 
| +#include "remoting/protocol/errors.h" | 
| #include "remoting/protocol/message_serialization.h" | 
|  | 
| namespace remoting { | 
| namespace protocol { | 
|  | 
| +HostVideoDispatcher::PendingFrame::PendingFrame( | 
| +    int frame_id, | 
| +    const ProgressCallback& progress_callback) | 
| +    : frame_id(frame_id), progress_callback(progress_callback) { | 
| +} | 
| + | 
| HostVideoDispatcher::HostVideoDispatcher() | 
| -    : ChannelDispatcherBase(kVideoChannelName) { | 
| +    : ChannelDispatcherBase(kVideoChannelName), | 
| +      frame_id_(0), | 
| +      parser_( | 
| +          base::Bind(&HostVideoDispatcher::OnVideoAck, base::Unretained(this)), | 
| +          reader()) { | 
| } | 
|  | 
| HostVideoDispatcher::~HostVideoDispatcher() { | 
| } | 
|  | 
| -void HostVideoDispatcher::ProcessVideoPacket(scoped_ptr<VideoPacket> packet, | 
| -                                             const base::Closure& done) { | 
| -  writer()->Write(SerializeAndFrameMessage(*packet), done); | 
| +void HostVideoDispatcher::ProcessVideoPacket( | 
| +    scoped_ptr<VideoPacket> packet, | 
| +    const ProgressCallback& progress_callback) { | 
| +  if (SupportsAcks()) { | 
| +    packet->set_frame_id(frame_id_); | 
| +    pending_frames_.push_back(PendingFrame(frame_id_, progress_callback)); | 
| +    frame_id_++; | 
| +  } | 
| + | 
| +  writer()->Write( | 
| +      SerializeAndFrameMessage(*packet), | 
| +      base::Bind(&HostVideoDispatcher::OnPacketSent, base::Unretained(this), | 
| +                 progress_callback)); | 
| +} | 
| + | 
| +bool HostVideoDispatcher::SupportsAcks() { | 
| +  return channel_config().version > kVideoStreamVersionNoAck; | 
| +} | 
| + | 
| +void HostVideoDispatcher::OnPacketSent( | 
| +    const ProgressCallback& progress_callback) { | 
| +  progress_callback.Run(PacketProgress::SENT); | 
| + | 
| +  // For older clients that don't send explicit video Ack message call notify | 
| +  // DONE state as soon as the frame is pushed to the channel. | 
| +  if (!SupportsAcks()) | 
| +    progress_callback.Run(PacketProgress::DONE); | 
| +} | 
| + | 
| +void HostVideoDispatcher::OnVideoAck(scoped_ptr<VideoAck> ack, | 
| +                                     const base::Closure& done) { | 
| +  base::ScopedClosureRunner done_runner(done); | 
| + | 
| +  if (!SupportsAcks()) { | 
| +    LOG(ERROR) << "Unexpected VideoAck message received."; | 
| +    return; | 
| +  } | 
| + | 
| +  if (pending_frames_.empty() || | 
| +      pending_frames_.front().frame_id != ack->frame_id()) { | 
| +    NotifyError(INCOMPATIBLE_PROTOCOL); | 
| +    return; | 
| +  } | 
| + | 
| +  // TODO(sergeyu): Currently the latency information in |ack| is ignored. | 
| +  // Expose it from this class so that CaptureScheduler can utilize it somehow. | 
| +  // See crbug.com/453177 . | 
| + | 
| +  ProgressCallback progress_callback = | 
| +      pending_frames_.front().progress_callback; | 
| +  pending_frames_.pop_front(); | 
| +  progress_callback.Run(PacketProgress::DONE); | 
| } | 
|  | 
| }  // namespace protocol | 
|  |