11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chromecast/media/cma/ipc/media_message_fifo.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/atomicops.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/location.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/logging.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/message_loop/message_loop_proxy.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chromecast/media/cma/base/cma_logging.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chromecast/media/cma/ipc/media_memory_chunk.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chromecast/media/cma/ipc/media_message.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chromecast/media/cma/ipc/media_message_type.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace chromecast {
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace media {
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass MediaMessageFlag
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : public base::RefCountedThreadSafe<MediaMessageFlag> {
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // |offset| is the offset in the fifo of the media message.
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  explicit MediaMessageFlag(size_t offset);
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool IsValid() const;
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void Invalidate();
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t offset() const { return offset_; }
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private:
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  friend class base::RefCountedThreadSafe<MediaMessageFlag>;
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual ~MediaMessageFlag();
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const size_t offset_;
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool flag_;
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DISALLOW_COPY_AND_ASSIGN(MediaMessageFlag);
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMediaMessageFlag::MediaMessageFlag(size_t offset)
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  : offset_(offset),
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    flag_(true) {
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMediaMessageFlag::~MediaMessageFlag() {
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool MediaMessageFlag::IsValid() const {
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return flag_;
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFlag::Invalidate() {
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  flag_ = false;
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass FifoOwnedMemory : public MediaMemoryChunk {
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  FifoOwnedMemory(void* data, size_t size,
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  const scoped_refptr<MediaMessageFlag>& flag,
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  const base::Closure& release_msg_cb);
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual ~FifoOwnedMemory();
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // MediaMemoryChunk implementation.
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual void* data() const OVERRIDE { return data_; }
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual size_t size() const OVERRIDE { return size_; }
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  virtual bool valid() const OVERRIDE { return flag_->IsValid(); }
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private:
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::Closure release_msg_cb_;
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void* const data_;
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const size_t size_;
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<MediaMessageFlag> flag_;
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DISALLOW_COPY_AND_ASSIGN(FifoOwnedMemory);
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciFifoOwnedMemory::FifoOwnedMemory(
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    void* data, size_t size,
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<MediaMessageFlag>& flag,
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::Closure& release_msg_cb)
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  : task_runner_(base::MessageLoopProxy::current()),
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    release_msg_cb_(release_msg_cb),
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    data_(data),
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_(size),
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    flag_(flag) {
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciFifoOwnedMemory::~FifoOwnedMemory() {
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Release the flag before notifying that the message has been released.
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  flag_ = scoped_refptr<MediaMessageFlag>();
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!release_msg_cb_.is_null()) {
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (task_runner_->BelongsToCurrentThread()) {
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      release_msg_cb_.Run();
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else {
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      task_runner_->PostTask(FROM_HERE, release_msg_cb_);
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMediaMessageFifo::MediaMessageFifo(
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<MediaMemoryChunk> mem, bool init)
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  : mem_(mem.Pass()),
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    weak_factory_(this) {
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_EQ(reinterpret_cast<uintptr_t>(mem_->data()) % ALIGNOF(Descriptor),
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci           0u);
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_GE(mem_->size(), sizeof(Descriptor));
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  Descriptor* desc = static_cast<Descriptor*>(mem_->data());
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base_ = static_cast<void*>(&desc->first_item);
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(damienv): remove cast when atomic size_t is defined in Chrome.
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Currently, the sign differs.
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  rd_offset_ = reinterpret_cast<AtomicSize*>(&(desc->rd_offset));
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  wr_offset_ = reinterpret_cast<AtomicSize*>(&(desc->wr_offset));
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t max_size = mem_->size() -
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      (static_cast<char*>(base_) - static_cast<char*>(mem_->data()));
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (init) {
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_ = max_size;
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    desc->size = size_;
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    internal_rd_offset_ = 0;
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    internal_wr_offset_ = 0;
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::subtle::Acquire_Store(rd_offset_, 0);
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::subtle::Acquire_Store(wr_offset_, 0);
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else {
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_ = desc->size;
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CHECK_LE(size_, max_size);
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    internal_rd_offset_ = current_rd_offset();
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    internal_wr_offset_ = current_wr_offset();
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CMALOG(kLogControl)
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      << "MediaMessageFifo:" << " init=" << init << " size=" << size_;
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_GT(size_, 0) << size_;
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  weak_this_ = weak_factory_.GetWeakPtr();
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  thread_checker_.DetachFromThread();
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciMediaMessageFifo::~MediaMessageFifo() {
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(thread_checker_.CalledOnValidThread());
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::ObserveReadActivity(
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::Closure& read_event_cb) {
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  read_event_cb_ = read_event_cb;
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::ObserveWriteActivity(
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::Closure& write_event_cb) {
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  write_event_cb_ = write_event_cb;
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciscoped_ptr<MediaMemoryChunk> MediaMessageFifo::ReserveMemory(
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t size_to_reserve) {
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(thread_checker_.CalledOnValidThread());
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Capture first both the read and write offsets.
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // and exit right away if not enough free space.
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t wr_offset = internal_wr_offset();
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t rd_offset = current_rd_offset();
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t allocated_size = (size_ + wr_offset - rd_offset) % size_;
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t free_size = size_ - 1 - allocated_size;
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (free_size < size_to_reserve)
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return scoped_ptr<MediaMemoryChunk>();
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_LE(MediaMessage::minimum_msg_size(), size_to_reserve);
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Note: in the next 2 conditions, we have:
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // trailing_byte_count < size_to_reserve
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // and since at this stage: size_to_reserve <= free_size
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // we also have trailing_byte_count <= free_size
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // which means that all the trailing bytes are free space in the fifo.
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t trailing_byte_count = size_ - wr_offset;
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (trailing_byte_count < MediaMessage::minimum_msg_size()) {
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If there is no space to even write the smallest message,
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // skip the trailing bytes and come back to the beginning of the fifo.
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // (no way to insert a padding message).
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (free_size < trailing_byte_count)
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return scoped_ptr<MediaMemoryChunk>();
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    wr_offset = 0;
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CommitInternalWrite(wr_offset);
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  } else if (trailing_byte_count < size_to_reserve) {
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // At this point, we know we have at least the space to write a message.
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // However, to avoid splitting a message, a padding message is needed.
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<MediaMemoryChunk> mem(
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ReserveMemoryNoCheck(trailing_byte_count));
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<MediaMessage> padding_message(
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        MediaMessage::CreateMessage(PaddingMediaMsg, mem.Pass()));
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Recalculate the free size and exit if not enough free space.
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  wr_offset = internal_wr_offset();
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  allocated_size = (size_ + wr_offset - rd_offset) % size_;
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  free_size = size_ - 1 - allocated_size;
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (free_size < size_to_reserve)
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return scoped_ptr<MediaMemoryChunk>();
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return ReserveMemoryNoCheck(size_to_reserve);
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciscoped_ptr<MediaMessage> MediaMessageFifo::Pop() {
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(thread_checker_.CalledOnValidThread());
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Capture the read and write offsets.
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t rd_offset = internal_rd_offset();
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t wr_offset = current_wr_offset();
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t allocated_size = (size_ + wr_offset - rd_offset) % size_;
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (allocated_size < MediaMessage::minimum_msg_size())
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return scoped_ptr<MediaMessage>();
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t trailing_byte_count = size_ - rd_offset;
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (trailing_byte_count < MediaMessage::minimum_msg_size()) {
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If there is no space to even have the smallest message,
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // skip the trailing bytes and come back to the beginning of the fifo.
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Note: all the trailing bytes correspond to allocated bytes since:
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // trailing_byte_count < MediaMessage::minimum_msg_size() <= allocated_size
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    rd_offset = 0;
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    allocated_size -= trailing_byte_count;
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    trailing_byte_count = size_;
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CommitInternalRead(rd_offset);
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The message should not be longer than the allocated size
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // but since a message is a contiguous area of memory, it should also be
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // smaller than |trailing_byte_count|.
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t max_msg_size = std::min(allocated_size, trailing_byte_count);
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (max_msg_size < MediaMessage::minimum_msg_size())
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return scoped_ptr<MediaMessage>();
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void* msg_src = static_cast<uint8*>(base_) + rd_offset;
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Create a flag to protect the serialized structure of the message
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // from being overwritten.
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The serialized structure starts at offset |rd_offset|.
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<MediaMessageFlag> rd_flag(new MediaMessageFlag(rd_offset));
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  rd_flags_.push_back(rd_flag);
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<MediaMemoryChunk> mem(
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new FifoOwnedMemory(
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          msg_src, max_msg_size, rd_flag,
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::Bind(&MediaMessageFifo::OnRdMemoryReleased, weak_this_)));
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Create the message which wraps its the serialized structure.
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<MediaMessage> message(MediaMessage::MapMessage(mem.Pass()));
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(message);
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Update the internal read pointer.
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  rd_offset = (rd_offset + message->size()) % size_;
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CommitInternalRead(rd_offset);
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return message.Pass();
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::Flush() {
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(thread_checker_.CalledOnValidThread());
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t wr_offset = current_wr_offset();
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Invalidate every memory region before flushing.
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!rd_flags_.empty()) {
2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CMALOG(kLogControl) << "Invalidate flag";
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    rd_flags_.front()->Invalidate();
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    rd_flags_.pop_front();
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Flush by setting the read pointer to the value of the write pointer.
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Update first the internal read pointer then the public one.
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CommitInternalRead(wr_offset);
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CommitRead(wr_offset);
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciscoped_ptr<MediaMemoryChunk> MediaMessageFifo::ReserveMemoryNoCheck(
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    size_t size_to_reserve) {
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t wr_offset = internal_wr_offset();
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Memory block corresponding to the serialized structure of the message.
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void* msg_start = static_cast<uint8*>(base_) + wr_offset;
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<MediaMessageFlag> wr_flag(new MediaMessageFlag(wr_offset));
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  wr_flags_.push_back(wr_flag);
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<MediaMemoryChunk> mem(
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new FifoOwnedMemory(
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          msg_start, size_to_reserve, wr_flag,
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::Bind(&MediaMessageFifo::OnWrMemoryReleased, weak_this_)));
2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Update the internal write pointer.
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  wr_offset = (wr_offset + size_to_reserve) % size_;
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CommitInternalWrite(wr_offset);
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return mem.Pass();
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::OnWrMemoryReleased() {
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(thread_checker_.CalledOnValidThread());
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (wr_flags_.empty()) {
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Sanity check: when there is no protected memory area,
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // the external write offset has no reason to be different from
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // the internal write offset.
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_EQ(current_wr_offset(), internal_wr_offset());
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Update the external write offset.
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!wr_flags_.empty() &&
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         (!wr_flags_.front()->IsValid() || wr_flags_.front()->HasOneRef())) {
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(damienv): Could add a sanity check to make sure the offset is
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // between the external write offset and the read offset (not included).
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    wr_flags_.pop_front();
3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Update the read offset to the first locked memory area
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // or to the internal read pointer if nothing prevents it.
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t external_wr_offset = internal_wr_offset();
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!wr_flags_.empty())
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    external_wr_offset = wr_flags_.front()->offset();
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CommitWrite(external_wr_offset);
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::OnRdMemoryReleased() {
3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(thread_checker_.CalledOnValidThread());
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (rd_flags_.empty()) {
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Sanity check: when there is no protected memory area,
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // the external read offset has no reason to be different from
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // the internal read offset.
3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_EQ(current_rd_offset(), internal_rd_offset());
3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Update the external read offset.
3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  while (!rd_flags_.empty() &&
3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         (!rd_flags_.front()->IsValid() || rd_flags_.front()->HasOneRef())) {
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(damienv): Could add a sanity check to make sure the offset is
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // between the external read offset and the write offset.
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    rd_flags_.pop_front();
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Update the read offset to the first locked memory area
3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // or to the internal read pointer if nothing prevents it.
3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t external_rd_offset = internal_rd_offset();
3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!rd_flags_.empty())
3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    external_rd_offset = rd_flags_.front()->offset();
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CommitRead(external_rd_offset);
3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccisize_t MediaMessageFifo::current_rd_offset() const {
3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(sizeof(size_t), sizeof(AtomicSize));
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t rd_offset = base::subtle::Acquire_Load(rd_offset_);
3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_LT(rd_offset, size_);
3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return rd_offset;
3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccisize_t MediaMessageFifo::current_wr_offset() const {
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(sizeof(size_t), sizeof(AtomicSize));
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // When the fifo consumer acquires the write offset,
3591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // we have to make sure that any possible following reads are actually
3601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // returning results at least inline with the memory snapshot taken
3611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // when the write offset was sampled.
3621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // That's why an Acquire_Load is used here.
3631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  size_t wr_offset = base::subtle::Acquire_Load(wr_offset_);
3641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK_LT(wr_offset, size_);
3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return wr_offset;
3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::CommitRead(size_t new_rd_offset) {
3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Add a memory fence to ensure the message content is completely read
3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // before updating the read offset.
3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::subtle::Release_Store(rd_offset_, new_rd_offset);
3721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Make sure the read pointer has been updated before sending a notification.
3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!read_event_cb_.is_null()) {
3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::subtle::MemoryBarrier();
3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    read_event_cb_.Run();
3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::CommitWrite(size_t new_wr_offset) {
3811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Add a memory fence to ensure the message content is written
3821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // before updating the write offset.
3831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::subtle::Release_Store(wr_offset_, new_wr_offset);
3841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Make sure the write pointer has been updated before sending a notification.
3861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!write_event_cb_.is_null()) {
3871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::subtle::MemoryBarrier();
3881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    write_event_cb_.Run();
3891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::CommitInternalRead(size_t new_rd_offset) {
3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  internal_rd_offset_ = new_rd_offset;
3941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid MediaMessageFifo::CommitInternalWrite(size_t new_wr_offset) {
3971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  internal_wr_offset_ = new_wr_offset;
3981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
4001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace media
4011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace chromecast
402