Home | History | Annotate | Download | only in ipc
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chromecast/media/cma/ipc/media_message.h"
      6 
      7 #include <limits>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/logging.h"
     11 #include "chromecast/media/cma/ipc/media_memory_chunk.h"
     12 
     13 namespace chromecast {
     14 namespace media {
     15 
     16 // static
     17 scoped_ptr<MediaMessage> MediaMessage::CreateDummyMessage(
     18     uint32 type) {
     19   return scoped_ptr<MediaMessage>(
     20       new MediaMessage(type, std::numeric_limits<size_t>::max()));
     21 }
     22 
     23 // static
     24 scoped_ptr<MediaMessage> MediaMessage::CreateMessage(
     25     uint32 type,
     26     const MemoryAllocatorCB& memory_allocator,
     27     size_t msg_content_capacity) {
     28   size_t msg_size = minimum_msg_size() + msg_content_capacity;
     29 
     30   // Make the message size a multiple of the alignment
     31   // so that if we have proper alignment for array of messages.
     32   size_t end_alignment = msg_size % ALIGNOF(SerializedMsg);
     33   if (end_alignment != 0)
     34     msg_size += ALIGNOF(SerializedMsg) - end_alignment;
     35 
     36   scoped_ptr<MediaMemoryChunk> memory(memory_allocator.Run(msg_size));
     37   if (!memory)
     38     return scoped_ptr<MediaMessage>();
     39 
     40   return scoped_ptr<MediaMessage>(new MediaMessage(type, memory.Pass()));
     41 }
     42 
     43 // static
     44 scoped_ptr<MediaMessage> MediaMessage::CreateMessage(
     45     uint32 type,
     46     scoped_ptr<MediaMemoryChunk> memory) {
     47   return scoped_ptr<MediaMessage>(new MediaMessage(type, memory.Pass()));
     48 }
     49 
     50 // static
     51 scoped_ptr<MediaMessage> MediaMessage::MapMessage(
     52     scoped_ptr<MediaMemoryChunk> memory) {
     53   return scoped_ptr<MediaMessage>(new MediaMessage(memory.Pass()));
     54 }
     55 
     56 MediaMessage::MediaMessage(uint32 type, size_t msg_size)
     57   : is_dummy_msg_(true),
     58     cached_header_(&cached_msg_.header),
     59     msg_(&cached_msg_),
     60     msg_read_only_(&cached_msg_),
     61     rd_offset_(0) {
     62   cached_header_->size = msg_size;
     63   cached_header_->type = type;
     64   cached_header_->content_size = 0;
     65 }
     66 
     67 MediaMessage::MediaMessage(uint32 type, scoped_ptr<MediaMemoryChunk> memory)
     68   : is_dummy_msg_(false),
     69     cached_header_(&cached_msg_.header),
     70     msg_(static_cast<SerializedMsg*>(memory->data())),
     71     msg_read_only_(msg_),
     72     mem_(memory.Pass()),
     73     rd_offset_(0) {
     74   CHECK(mem_->valid());
     75   CHECK_GE(mem_->size(), minimum_msg_size());
     76 
     77   // Check memory alignment:
     78   // needed to cast properly |msg_dst| to a SerializedMsg.
     79   CHECK_EQ(
     80       reinterpret_cast<uintptr_t>(mem_->data()) % ALIGNOF(SerializedMsg), 0u);
     81 
     82   // Make sure that |mem_->data()| + |mem_->size()| is also aligned correctly.
     83   // This is needed if we append a second serialized message next to this one.
     84   // The second serialized message must be aligned correctly.
     85   // It is similar to what a compiler is doing for arrays of structures.
     86   CHECK_EQ(mem_->size() % ALIGNOF(SerializedMsg), 0u);
     87 
     88   cached_header_->size = mem_->size();
     89   cached_header_->type = type;
     90   cached_header_->content_size = 0;
     91   msg_->header = *cached_header_;
     92 }
     93 
     94 MediaMessage::MediaMessage(scoped_ptr<MediaMemoryChunk> memory)
     95   : is_dummy_msg_(false),
     96     cached_header_(&cached_msg_.header),
     97     msg_(NULL),
     98     msg_read_only_(static_cast<SerializedMsg*>(memory->data())),
     99     mem_(memory.Pass()),
    100     rd_offset_(0) {
    101   CHECK(mem_->valid());
    102 
    103   // Check memory alignment.
    104   CHECK_EQ(
    105       reinterpret_cast<uintptr_t>(mem_->data()) % ALIGNOF(SerializedMsg), 0u);
    106 
    107   // Cache the message header which cannot be modified while reading.
    108   CHECK_GE(mem_->size(), minimum_msg_size());
    109   *cached_header_ = msg_read_only_->header;
    110   CHECK_GE(cached_header_->size, minimum_msg_size());
    111 
    112   // Make sure if we have 2 consecutive serialized messages in memory,
    113   // the 2nd message is also aligned correctly.
    114   CHECK_EQ(cached_header_->size % ALIGNOF(SerializedMsg), 0u);
    115 
    116   size_t max_content_size = cached_header_->size - minimum_msg_size();
    117   CHECK_LE(cached_header_->content_size, max_content_size);
    118 }
    119 
    120 MediaMessage::~MediaMessage() {
    121 }
    122 
    123 bool MediaMessage::IsSerializedMsgAvailable() const {
    124   return !is_dummy_msg_ && mem_->valid();
    125 }
    126 
    127 bool MediaMessage::WriteBuffer(const void* src, size_t size) {
    128   // No message to write into.
    129   if (!msg_)
    130     return false;
    131 
    132   // The underlying memory was invalidated.
    133   if (!is_dummy_msg_ && !mem_->valid())
    134     return false;
    135 
    136   size_t max_content_size = cached_header_->size - minimum_msg_size();
    137   if (cached_header_->content_size + size > max_content_size) {
    138     cached_header_->content_size = max_content_size;
    139     msg_->header.content_size = cached_header_->content_size;
    140     return false;
    141   }
    142 
    143   // Write the message only for non-dummy messages.
    144   if (!is_dummy_msg_) {
    145     uint8* wr_ptr = &msg_->content + cached_header_->content_size;
    146     memcpy(wr_ptr, src, size);
    147   }
    148 
    149   cached_header_->content_size += size;
    150   msg_->header.content_size = cached_header_->content_size;
    151   return true;
    152 }
    153 
    154 bool MediaMessage::ReadBuffer(void* dst, size_t size) {
    155   // No read possible for a dummy message.
    156   if (is_dummy_msg_)
    157     return false;
    158 
    159   // The underlying memory was invalidated.
    160   if (!mem_->valid())
    161     return false;
    162 
    163   if (rd_offset_ + size > cached_header_->content_size) {
    164     rd_offset_ = cached_header_->content_size;
    165     return false;
    166   }
    167 
    168   const uint8* rd_ptr = &msg_read_only_->content + rd_offset_;
    169   memcpy(dst, rd_ptr, size);
    170   rd_offset_ += size;
    171   return true;
    172 }
    173 
    174 void* MediaMessage::GetWritableBuffer(size_t size) {
    175   // No read possible for a dummy message.
    176   if (is_dummy_msg_)
    177     return NULL;
    178 
    179   // The underlying memory was invalidated.
    180   if (!mem_->valid())
    181     return NULL;
    182 
    183   if (rd_offset_ + size > cached_header_->content_size) {
    184     rd_offset_ = cached_header_->content_size;
    185     return NULL;
    186   }
    187 
    188   uint8* rd_ptr = &msg_read_only_->content + rd_offset_;
    189   rd_offset_ += size;
    190   return rd_ptr;
    191 }
    192 
    193 const void* MediaMessage::GetBuffer(size_t size) {
    194   return GetWritableBuffer(size);
    195 }
    196 
    197 }  // namespace media
    198 }  // namespace chromecast
    199