chromium/chromecast/media/audio/capture_service/capture_service_receiver.h

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMECAST_MEDIA_AUDIO_CAPTURE_SERVICE_CAPTURE_SERVICE_RECEIVER_H_
#define CHROMECAST_MEDIA_AUDIO_CAPTURE_SERVICE_CAPTURE_SERVICE_RECEIVER_H_

#include <memory>

#include "base/memory/scoped_refptr.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "chromecast/media/audio/capture_service/constants.h"

namespace base {
class SequencedTaskRunner;
class WaitableEvent;
}  // namespace base

namespace net {
class StreamSocket;
}  // namespace net

namespace chromecast {
namespace media {

class CaptureServiceReceiver {
 public:
  // Delegate cannot be destroyed before CaptureServiceReceiver. Note methods of
  // Delegate will always be called from CaptureServiceReceiver's own thread.
  class Delegate {
   public:
    virtual ~Delegate() = default;

    virtual bool OnInitialStreamInfo(
        const capture_service::StreamInfo& stream_info) = 0;

    // Called when more data are received from socket. Return |true| to continue
    // reading messages after OnCaptureData() returns.
    virtual bool OnCaptureData(const char* data, size_t size) = 0;

    // Called when internal error occurs.
    virtual void OnCaptureError() = 0;

    // Called when there is metadata.
    virtual void OnCaptureMetadata(const char* data, size_t size) = 0;
  };

  // The timeout for a connecting socket to stop waiting and report error.
  static constexpr base::TimeDelta kConnectTimeout = base::Seconds(1);

  CaptureServiceReceiver(capture_service::StreamInfo request_stream_info,
                         Delegate* delegate);
  CaptureServiceReceiver(const CaptureServiceReceiver&) = delete;
  CaptureServiceReceiver& operator=(const CaptureServiceReceiver&) = delete;
  ~CaptureServiceReceiver();

  // Starts capture receiving process. It cannot be called if
  // CaptureServiceReceiver has been started and not stopped.
  void Start();
  // Stops capture receiving process synchronously. It will be no-op if Start()
  // has not been started or already been stopped.
  void Stop();

  // Unit test can call this method rather than the public one to inject mocked
  // stream socket.
  void StartWithSocket(std::unique_ptr<net::StreamSocket> connecting_socket);

  // Unit test can set test task runner so as to run test in sync. Must be
  // called after construction and before any other methods.
  void SetTaskRunnerForTest(
      scoped_refptr<base::SequencedTaskRunner> task_runner);

 private:
  class Socket;

  void OnConnected(int result);
  void OnConnectTimeout();
  void StopOnTaskRunner(base::WaitableEvent* finished);

  const capture_service::StreamInfo request_stream_info_;
  Delegate* const delegate_;

  // Socket requires IO thread, and low latency input stream requires high
  // thread priority. Therefore, a private thread instead of the IO thread from
  // browser thread pool is necessary so as to make sure input stream won't be
  // blocked nor block other tasks on the same thread.
  base::Thread io_thread_;
  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  std::unique_ptr<net::StreamSocket> connecting_socket_;
  std::unique_ptr<Socket> socket_;
};

}  // namespace media
}  // namespace chromecast

#endif  // CHROMECAST_MEDIA_AUDIO_CAPTURE_SERVICE_CAPTURE_SERVICE_RECEIVER_H_