OLD | NEW |
(Empty) | |
| 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 |
| 20 namespace chromecast { |
| 21 namespace media { |
| 22 class MediaMemoryChunk; |
| 23 class MediaMessage; |
| 24 class 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 // |
| 84 class 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_ |
OLD | NEW |