blob: ee537603f0a3c0de001cd0adc82611547d2b4224 [file] [log] [blame]
// Copyright (c) 2010 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 <deque>
#include <string>
#include "base/basictypes.h"
#include "base/condition_variable.h"
#include "base/gtest_prod_util.h"
#include "base/lock.h"
#include "base/ref_counted.h"
#include "base/scoped_ptr.h"
#include "base/task.h"
#include "third_party/libjingle/source/talk/base/sigslot.h"
namespace base {
class WaitableEvent;
} // namespace base
namespace talk_base {
class StreamInterface;
} // namespace talk_base
namespace media {
class Buffer;
class DataBuffer;
} // namespace media
namespace remoting {
class JingleThread;
class JingleChannel : public base::RefCountedThreadSafe<JingleChannel> {
enum State {
class Callback {
virtual ~Callback() {}
// Called when state of the connection is changed.
virtual void OnStateChange(JingleChannel* channel, State state) = 0;
// Called when a new packet is received.
virtual void OnPacketReceived(JingleChannel* channel,
scoped_refptr<media::DataBuffer> data) = 0;
virtual ~JingleChannel();
// Puts data to the write buffer.
virtual void Write(scoped_refptr<media::DataBuffer> data);
// Closes the tunnel. If specified, |closed_task| is executed after the
// connection is successfully closed.
virtual void Close();
virtual void Close(Task* closed_task);
// Current state of the tunnel.
State state() const { return state_; }
// JID of the other end of the channel.
const std::string& jid() const { return jid_; }
// Number of bytes currently stored in the write buffer.
size_t write_buffer_size();
// Needs access to constructor, Init().
friend class JingleClient;
// Constructor used by unit test only.
// TODO(hclam): Have to suppress warnings in MSVC.
// Used by JingleClient to create an instance of the channel. |callback|
// must not be NULL.
explicit JingleChannel(Callback* callback);
// Initialized the channel. Ownership of the |stream| is transfered to
// caller. Ownership of |thread| is not.
void Init(JingleThread* thread, talk_base::StreamInterface* stream,
const std::string& jid);
friend class JingleChannelTest;
FRIEND_TEST_ALL_PREFIXES(JingleChannelTest, Init);
FRIEND_TEST_ALL_PREFIXES(JingleChannelTest, Write);
FRIEND_TEST_ALL_PREFIXES(JingleChannelTest, Read);
typedef std::deque<scoped_refptr<media::DataBuffer> > DataQueue;
// Event handler for the stream. It passes stream events from the stream
// to JingleChannel.
class EventHandler : public sigslot::has_slots<> {
explicit EventHandler(JingleChannel* channel) : channel_(channel) {}
// Constructor used only by unit test.
EventHandler() : channel_(NULL) {}
void OnStreamEvent(talk_base::StreamInterface* stream,
int events, int error) {
channel_->OnStreamEvent(stream, events, error);
friend class JingleChannel;
JingleChannel* channel_;
friend class EventHandler;
// Event handler for the stream.
void OnStreamEvent(talk_base::StreamInterface* stream,
int events, int error);
// Writes data from the buffer to the stream. Called
// from OnStreamEvent() in the jingle thread.
void DoWrite();
// Reads data from the stream and puts it to the read buffer.
// Called from OnStreamEvent() in the jingle thread.
void DoRead();
// Used by Close() to actually close the channel.
void DoClose();
// Updates state and calels |callback_| if neccessary.
void SetState(State new_state);
// The thread this channel runs on.
JingleThread* thread_;
// The stream of this channel.
scoped_ptr<talk_base::StreamInterface> stream_;
// Current state of the channel.
State state_;
// Callback that is called on channel events. Initialized in the constructor.
// Must not be called if |closed_| is set to true.
Callback* callback_;
// |closed_| must be set to true after Close() is called. |state_lock_| must
// be locked whenever closed_ is accessed.
Lock state_lock_;
bool closed_;
scoped_ptr<Task> closed_task_;
// Event handler for stream events.
EventHandler event_handler_;
// Jid of the other end of the channel.
std::string jid_;
// Write buffer. |write_lock_| should be locked when accessing |write_queue_|
// and |write_buffer_size_|, but isn't necessary for |current_write_buf_|.
// |current_write_buf_| is accessed only by the jingle thread.
// |write_buffer_size_| stores number of bytes currently in |write_queue_|
// and in |current_write_buf_|.
DataQueue write_queue_;
size_t write_buffer_size_;
Lock write_lock_;
scoped_refptr<media::DataBuffer> current_write_buf_;
size_t current_write_buf_pos_;
} // namespace remoting