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.
5 #ifndef CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_
6 #define CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_
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"
20 namespace chromecast
{
22 class MediaMemoryChunk
;
24 class MediaMessageFlag
;
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).
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.
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));
42 // // Write all the fields to the dummy message.
45 // // Create the real message, once the size of the serialized message
47 // scoped_ptr<MediaMessage> msg(
48 // MediaMessage::CreateMessage(
50 // base::Bind(&MediaMessageFifo::ReserveMemory,
51 // base::Unretained(fifo_feeder.get())),
52 // dummy_msg->content_size()));
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).
60 // // Write all the fields to the real message
61 // // in exactly the same way it was done for the dummy message.
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.
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());
73 // // The fifo is empty, i.e. no message left.
74 // // Try reading again later (e.g. after receiving a write activity event.
77 // // Parse the message using Read functions of MediaMessage:
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).
84 class MediaMessageFifo
{
91 // Ensure the first item has the same alignment as an int64.
96 static const int kDescriptorSize
= sizeof(Descriptor
);
98 // Creates a media message fifo using |mem| as the underlying serialized
100 // If |init| is true, the underlying fifo structure is initialized.
101 MediaMessageFifo(scoped_ptr
<MediaMemoryChunk
> mem
, bool init
);
104 // When the consumer and the feeder are living in two different processes,
105 // we might want to convey some messages between these two processes to notify
106 // about some fifo activity.
107 void ObserveReadActivity(const base::Closure
& read_event_cb
);
108 void ObserveWriteActivity(const base::Closure
& write_event_cb
);
110 // Reserves a writeable block of memory at the back of the fifo,
111 // corresponding to the serialized structure of the message.
112 // Returns NULL if the required size cannot be allocated.
113 scoped_ptr
<MediaMemoryChunk
> ReserveMemory(size_t size
);
115 // Pop a message from the queue.
116 // Returns a null pointer if there is no message left.
117 scoped_ptr
<MediaMessage
> Pop();
123 // Add some accessors to ensure security on the browser process side.
124 size_t current_rd_offset() const;
125 size_t current_wr_offset() const;
126 size_t internal_rd_offset() const {
127 DCHECK_LT(internal_rd_offset_
, size_
);
128 return internal_rd_offset_
;
130 size_t internal_wr_offset() const {
131 DCHECK_LT(internal_wr_offset_
, size_
);
132 return internal_wr_offset_
;
135 // Reserve a block of free memory without doing any check on the available
136 // space. Invoke this function only when all the checks have been done.
137 scoped_ptr
<MediaMemoryChunk
> ReserveMemoryNoCheck(size_t size
);
139 // Invoked each time there is a memory region in the free space of the fifo
140 // that has possibly been written.
141 void OnWrMemoryReleased();
143 // Invoked each time there is a memory region in the allocated space
144 // of the fifo that has possibly been released.
145 void OnRdMemoryReleased();
147 // Functions to modify the internal/external read/write pointers.
148 void CommitRead(size_t new_rd_offset
);
149 void CommitWrite(size_t new_wr_offset
);
150 void CommitInternalRead(size_t new_rd_offset
);
151 void CommitInternalWrite(size_t new_wr_offset
);
153 // An instance of MediaMessageFifo must be running on a single thread.
154 // If the fifo feeder and consumer are living on 2 different threads
155 // or 2 different processes, they must create their own instance
156 // of MediaMessageFifo using the same underlying block of (shared) memory
157 // in the constructor.
158 base::ThreadChecker thread_checker_
;
160 // Callbacks invoked to notify either of some read or write activity on the
161 // fifo. This is especially useful when the feeder and consumer are living in
162 // two different processes.
163 base::Closure read_event_cb_
;
164 base::Closure write_event_cb_
;
166 // The serialized structure of the fifo.
167 scoped_ptr
<MediaMemoryChunk
> mem_
;
169 // The size in bytes of the fifo is cached locally for security purpose.
170 // (the renderer process cannot modify the size and make the browser process
171 // access out of range addresses).
174 // TODO(damienv): This is a work-around since atomicops.h does not define
175 // an atomic size_t type.
176 #if SIZE_MAX == UINT32_MAX
177 typedef base::subtle::Atomic32 AtomicSize
;
178 #elif SIZE_MAX == UINT64_MAX
179 typedef base::subtle::Atomic64 AtomicSize
;
181 #error "Unsupported size_t"
183 AtomicSize
* rd_offset_
;
184 AtomicSize
* wr_offset_
;
186 // Internal read offset: this is where data is actually read from.
187 // The external offset |rd_offset_| is only used to protect data from being
188 // overwritten by the feeder.
189 // At any time, the internal read pointer must be between the external read
190 // offset and the write offset (circular fifo definition of "between").
191 size_t internal_rd_offset_
;
192 size_t internal_wr_offset_
;
194 // Note: all the memory read/write are followed by a memory fence before
195 // updating the rd/wr pointer.
198 // Protects the messages that are either being read or written.
199 std::list
<scoped_refptr
<MediaMessageFlag
> > rd_flags_
;
200 std::list
<scoped_refptr
<MediaMessageFlag
> > wr_flags_
;
202 base::WeakPtr
<MediaMessageFifo
> weak_this_
;
203 base::WeakPtrFactory
<MediaMessageFifo
> weak_factory_
;
205 DISALLOW_COPY_AND_ASSIGN(MediaMessageFifo
);
209 } // namespace chromecast
211 #endif // CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_