media_message_fifo.h revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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#ifndef CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_ 6#define CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_ 7 8#include <list> 9 10#include "base/atomicops.h" 11#include "base/basictypes.h" 12#include "base/callback.h" 13#include "base/logging.h" 14#include "base/macros.h" 15#include "base/memory/ref_counted.h" 16#include "base/memory/scoped_ptr.h" 17#include "base/memory/weak_ptr.h" 18#include "base/threading/thread_checker.h" 19 20namespace chromecast { 21namespace media { 22class MediaMemoryChunk; 23class MediaMessage; 24class MediaMessageFlag; 25 26// MediaMessageFifo is a lock free fifo implementation 27// to pass audio/video data from one thread to another or from one process 28// to another one (in that case using shared memory). 29// 30// Assuming the feeder and the consumer have a common block of shared memory 31// (representing the serialized structure of the fifo), 32// the feeder (which must be running on a single thread) instantiates its own 33// instance of MediaMessageFifo, same applies to the consumer. 34// 35// Example: assuming the block of shared memory is given by |mem|, a typical 36// feeder (using MediaMessageFifo instance fifo_feeder) will push messages 37// in the following way: 38// // Create a dummy message to calculate the size of the serialized message. 39// scoped_ptr<MediaMessage> dummy_msg( 40// MediaMessage::CreateDummyMessage(msg_type)); 41// // ... 42// // Write all the fields to the dummy message. 43// // ... 44// 45// // Create the real message, once the size of the serialized message 46// // is known. 47// scoped_ptr<MediaMessage> msg( 48// MediaMessage::CreateMessage( 49// msg_type, 50// base::Bind(&MediaMessageFifo::ReserveMemory, 51// base::Unretained(fifo_feeder.get())), 52// dummy_msg->content_size())); 53// if (!msg) { 54// // Not enough space for the message: 55// // retry later (e.g. when receiving a read activity event, meaning 56// // some enough space might have been release). 57// return; 58// } 59// // ... 60// // Write all the fields to the real message 61// // in exactly the same way it was done for the dummy message. 62// // ... 63// // Once message |msg| is going out of scope, then MediaMessageFifo 64// // fifo_feeder is informed that the message is not needed anymore 65// // (i.e. it was fully written), and fifo_feeder can then update 66// // the external write pointer of the fifo so that the consumer 67// // can start consuming this message. 68// 69// A typical consumer (using MediaMessageFifo instance fifo_consumer) 70// will retrive messages in the following way: 71// scoped_ptr<MediaMessage> msg(fifo_consumer->Pop()); 72// if (!msg) { 73// // The fifo is empty, i.e. no message left. 74// // Try reading again later (e.g. after receiving a write activity event. 75// return; 76// } 77// // Parse the message using Read functions of MediaMessage: 78// // ... 79// // Once the message is going out of scope, MediaMessageFifo will receive 80// // a notification that the underlying memory can be released 81// // (i.e. the external read pointer can be updated). 82// 83// 84class MediaMessageFifo { 85 public: 86 // Creates a media message fifo using |mem| as the underlying serialized 87 // structure. 88 // If |init| is true, the underlying fifo structure is initialized. 89 MediaMessageFifo(scoped_ptr<MediaMemoryChunk> mem, bool init); 90 ~MediaMessageFifo(); 91 92 // When the consumer and the feeder are living in two different processes, 93 // we might want to convey some messages between these two processes to notify 94 // about some fifo activity. 95 void ObserveReadActivity(const base::Closure& read_event_cb); 96 void ObserveWriteActivity(const base::Closure& write_event_cb); 97 98 // Reserves a writeable block of memory at the back of the fifo, 99 // corresponding to the serialized structure of the message. 100 // Returns NULL if the required size cannot be allocated. 101 scoped_ptr<MediaMemoryChunk> ReserveMemory(size_t size); 102 103 // Pop a message from the queue. 104 // Returns a null pointer if there is no message left. 105 scoped_ptr<MediaMessage> Pop(); 106 107 // Flush the fifo. 108 void Flush(); 109 110 private: 111 struct Descriptor { 112 size_t size; 113 size_t rd_offset; 114 size_t wr_offset; 115 116 // Ensure the first item has the same alignment as an int64. 117 int64 first_item; 118 }; 119 120 // Add some accessors to ensure security on the browser process side. 121 size_t current_rd_offset() const; 122 size_t current_wr_offset() const; 123 size_t internal_rd_offset() const { 124 DCHECK_LT(internal_rd_offset_, size_); 125 return internal_rd_offset_; 126 } 127 size_t internal_wr_offset() const { 128 DCHECK_LT(internal_wr_offset_, size_); 129 return internal_wr_offset_; 130 } 131 132 // Reserve a block of free memory without doing any check on the available 133 // space. Invoke this function only when all the checks have been done. 134 scoped_ptr<MediaMemoryChunk> ReserveMemoryNoCheck(size_t size); 135 136 // Invoked each time there is a memory region in the free space of the fifo 137 // that has possibly been written. 138 void OnWrMemoryReleased(); 139 140 // Invoked each time there is a memory region in the allocated space 141 // of the fifo that has possibly been released. 142 void OnRdMemoryReleased(); 143 144 // Functions to modify the internal/external read/write pointers. 145 void CommitRead(size_t new_rd_offset); 146 void CommitWrite(size_t new_wr_offset); 147 void CommitInternalRead(size_t new_rd_offset); 148 void CommitInternalWrite(size_t new_wr_offset); 149 150 // An instance of MediaMessageFifo must be running on a single thread. 151 // If the fifo feeder and consumer are living on 2 different threads 152 // or 2 different processes, they must create their own instance 153 // of MediaMessageFifo using the same underlying block of (shared) memory 154 // in the constructor. 155 base::ThreadChecker thread_checker_; 156 157 // Callbacks invoked to notify either of some read or write activity on the 158 // fifo. This is especially useful when the feeder and consumer are living in 159 // two different processes. 160 base::Closure read_event_cb_; 161 base::Closure write_event_cb_; 162 163 // The serialized structure of the fifo. 164 scoped_ptr<MediaMemoryChunk> mem_; 165 166 // The size in bytes of the fifo is cached locally for security purpose. 167 // (the renderer process cannot modify the size and make the browser process 168 // access out of range addresses). 169 size_t size_; 170 171 // TODO(damienv): This is a work-around since atomicops.h does not define 172 // an atomic size_t type. 173#if SIZE_MAX == UINT32_MAX 174 typedef base::subtle::Atomic32 AtomicSize; 175#elif SIZE_MAX == UINT64_MAX 176 typedef base::subtle::Atomic64 AtomicSize; 177#elif 178#error "Unsupported size_t" 179#endif 180 AtomicSize* rd_offset_; 181 AtomicSize* wr_offset_; 182 183 // Internal read offset: this is where data is actually read from. 184 // The external offset |rd_offset_| is only used to protect data from being 185 // overwritten by the feeder. 186 // At any time, the internal read pointer must be between the external read 187 // offset and the write offset (circular fifo definition of "between"). 188 size_t internal_rd_offset_; 189 size_t internal_wr_offset_; 190 191 // Note: all the memory read/write are followed by a memory fence before 192 // updating the rd/wr pointer. 193 void* base_; 194 195 // Protects the messages that are either being read or written. 196 std::list<scoped_refptr<MediaMessageFlag> > rd_flags_; 197 std::list<scoped_refptr<MediaMessageFlag> > wr_flags_; 198 199 base::WeakPtrFactory<MediaMessageFifo> weak_factory_; 200 base::WeakPtr<MediaMessageFifo> weak_this_; 201 202 DISALLOW_COPY_AND_ASSIGN(MediaMessageFifo); 203}; 204 205} // namespace media 206} // namespace chromecast 207 208#endif // CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_ 209