text: // Copyright 2019 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 "chrome/renderer/media/webrtc_logging_agent_impl.h"
  
  #include "base/no_destructor.h"
  #include "base/synchronization/lock.h"
  #include "base/threading/sequenced_task_runner_handle.h"
  #include "base/time/time.h"
  #include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
  
  namespace chrome {
  namespace {
  
  constexpr base::TimeDelta kMinTimeSinceLastLogBufferSend =
      base::TimeDelta::FromMilliseconds(100);
  constexpr base::TimeDelta kSendLogBufferDelay =
      base::TimeDelta::FromMilliseconds(200);
  
  // There can be only one registered WebRtcLogMessageDelegate, and so this class
  // abstracts away that detail, so that we can set callbacks more than once. It
  // also abstracts away the detail of what thread the LogMessage call runs on.
  class WebRtcLogMessageDelegateImpl : public blink::WebRtcLogMessageDelegate {
   public:
    static WebRtcLogMessageDelegateImpl* GetInstance() {
      static base::NoDestructor<WebRtcLogMessageDelegateImpl> instance;
      return instance.get();
    }
  
    void Start(
        base::RepeatingCallback<void(mojom::WebRtcLoggingMessagePtr)> callback) {
      auto task_runner = base::SequencedTaskRunnerHandle::Get();
      {
        base::AutoLock locked(lock_);
        task_runner_ = task_runner;
        callback_ = std::move(callback);
      }
      blink::InitWebRtcLogging();
    }
  
    void Stop() {
      {
        base::AutoLock locked(lock_);
        task_runner_ = nullptr;
        callback_.Reset();
      }
    }
  
    // blink::WebRtcLogMessageDelegate methods:
    void LogMessage(const std::string& message) override {
      // Called from a random thread.
      auto data = mojom::WebRtcLoggingMessage::New(base::Time::Now(), message);
      {
        base::AutoLock locked(lock_);
        if (callback_)
          task_runner_->PostTask(FROM_HERE,
                                 base::BindOnce(callback_, std::move(data)));
      }
    }
  
    WebRtcLogMessageDelegateImpl() { blink::InitWebRtcLoggingDelegate(this); }
  
   private:
    ~WebRtcLogMessageDelegateImpl() override = default;
  
    base::Lock lock_;
    base::RepeatingCallback<void(mojom::WebRtcLoggingMessagePtr)> callback_;
    scoped_refptr<base::SequencedTaskRunner> task_runner_;
  };
  
  }  // namespace
  
  WebRtcLoggingAgentImpl::WebRtcLoggingAgentImpl() = default;
  WebRtcLoggingAgentImpl::~WebRtcLoggingAgentImpl() = default;
  
  void WebRtcLoggingAgentImpl::AddReceiver(
      mojo::PendingReceiver<mojom::WebRtcLoggingAgent> receiver) {
    self_receiver_set_.Add(this, std::move(receiver));
  }
  
  void WebRtcLoggingAgentImpl::Start(
      mojo::PendingRemote<mojom::WebRtcLoggingClient> pending_client) {
    // We only support one client at a time. OK to drop any existing client.
    client_.reset();
    client_.Bind(std::move(pending_client));
  
    WebRtcLogMessageDelegateImpl::GetInstance()->Start(base::BindRepeating(
        &WebRtcLoggingAgentImpl::OnNewMessage, weak_factory_.GetWeakPtr()));
  }
  
  void WebRtcLoggingAgentImpl::Stop() {
    if (!log_buffer_.empty())
      SendLogBuffer();
    WebRtcLogMessageDelegateImpl::GetInstance()->Stop();
    if (client_) {
      client_->OnStopped();
      client_.reset();
    }
  }
  
  void WebRtcLoggingAgentImpl::OnNewMessage(
      mojom::WebRtcLoggingMessagePtr message) {
    // We may have already been asked to stop.
    if (!client_)
      return;
  
    log_buffer_.emplace_back(std::move(message));
    if (log_buffer_.size() > 1) {
      // A delayed task has already been posted for sending the buffer contents.
      return;
    }
  
    if ((base::TimeTicks::Now() - last_log_buffer_send_) >
        kMinTimeSinceLastLogBufferSend) {
      SendLogBuffer();
    } else {
      base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
          FROM_HERE,
          base::BindOnce(&WebRtcLoggingAgentImpl::SendLogBuffer,
                         weak_factory_.GetWeakPtr()),
          kSendLogBufferDelay);
    }
  }
  
  void WebRtcLoggingAgentImpl::SendLogBuffer() {
    last_log_buffer_send_ = base::TimeTicks::Now();
    if (client_) {
      client_->OnAddMessages(std::move(log_buffer_));
    } else {
      log_buffer_.clear();
    }
  }
  
  }  // namespace chrome
  