| Index: chromecast/media/cma/ipc/media_message_fifo.h
|
| diff --git a/chromecast/media/cma/ipc/media_message_fifo.h b/chromecast/media/cma/ipc/media_message_fifo.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..fe82721a9bd058219b57f824a077f36cc1b23aca
|
| --- /dev/null
|
| +++ b/chromecast/media/cma/ipc/media_message_fifo.h
|
| @@ -0,0 +1,208 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#ifndef CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_
|
| +#define CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_
|
| +
|
| +#include <list>
|
| +
|
| +#include "base/atomicops.h"
|
| +#include "base/basictypes.h"
|
| +#include "base/callback.h"
|
| +#include "base/logging.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/memory/weak_ptr.h"
|
| +#include "base/threading/thread_checker.h"
|
| +
|
| +namespace chromecast {
|
| +namespace media {
|
| +class MediaMemoryChunk;
|
| +class MediaMessage;
|
| +class MediaMessageFlag;
|
| +
|
| +// MediaMessageFifo is a lock free fifo implementation
|
| +// to pass audio/video data from one thread to another or from one process
|
| +// to another one (in that case using shared memory).
|
| +//
|
| +// Assuming the feeder and the consumer have a common block of shared memory
|
| +// (representing the serialized structure of the fifo),
|
| +// the feeder (which must be running on a single thread) instantiates its own
|
| +// instance of MediaMessageFifo, same applies to the consumer.
|
| +//
|
| +// Example: assuming the block of shared memory is given by |mem|, a typical
|
| +// feeder (using MediaMessageFifo instance fifo_feeder) will push messages
|
| +// in the following way:
|
| +// // Create a dummy message to calculate the size of the serialized message.
|
| +// scoped_ptr<MediaMessage> dummy_msg(
|
| +// MediaMessage::CreateDummyMessage(msg_type));
|
| +// // ...
|
| +// // Write all the fields to the dummy message.
|
| +// // ...
|
| +//
|
| +// // Create the real message, once the size of the serialized message
|
| +// // is known.
|
| +// scoped_ptr<MediaMessage> msg(
|
| +// MediaMessage::CreateMessage(
|
| +// msg_type,
|
| +// base::Bind(&MediaMessageFifo::ReserveMemory,
|
| +// base::Unretained(fifo_feeder.get())),
|
| +// dummy_msg->content_size()));
|
| +// if (!msg) {
|
| +// // Not enough space for the message:
|
| +// // retry later (e.g. when receiving a read activity event, meaning
|
| +// // some enough space might have been release).
|
| +// return;
|
| +// }
|
| +// // ...
|
| +// // Write all the fields to the real message
|
| +// // in exactly the same way it was done for the dummy message.
|
| +// // ...
|
| +// // Once message |msg| is going out of scope, then MediaMessageFifo
|
| +// // fifo_feeder is informed that the message is not needed anymore
|
| +// // (i.e. it was fully written), and fifo_feeder can then update
|
| +// // the external write pointer of the fifo so that the consumer
|
| +// // can start consuming this message.
|
| +//
|
| +// A typical consumer (using MediaMessageFifo instance fifo_consumer)
|
| +// will retrive messages in the following way:
|
| +// scoped_ptr<MediaMessage> msg(fifo_consumer->Pop());
|
| +// if (!msg) {
|
| +// // The fifo is empty, i.e. no message left.
|
| +// // Try reading again later (e.g. after receiving a write activity event.
|
| +// return;
|
| +// }
|
| +// // Parse the message using Read functions of MediaMessage:
|
| +// // ...
|
| +// // Once the message is going out of scope, MediaMessageFifo will receive
|
| +// // a notification that the underlying memory can be released
|
| +// // (i.e. the external read pointer can be updated).
|
| +//
|
| +//
|
| +class MediaMessageFifo {
|
| + public:
|
| + // Creates a media message fifo using |mem| as the underlying serialized
|
| + // structure.
|
| + // If |init| is true, the underlying fifo structure is initialized.
|
| + MediaMessageFifo(scoped_ptr<MediaMemoryChunk> mem, bool init);
|
| + ~MediaMessageFifo();
|
| +
|
| + // When the consumer and the feeder are living in two different processes,
|
| + // we might want to convey some messages between these two processes to notify
|
| + // about some fifo activity.
|
| + void ObserveReadActivity(const base::Closure& read_event_cb);
|
| + void ObserveWriteActivity(const base::Closure& write_event_cb);
|
| +
|
| + // Reserves a writeable block of memory at the back of the fifo,
|
| + // corresponding to the serialized structure of the message.
|
| + // Returns NULL if the required size cannot be allocated.
|
| + scoped_ptr<MediaMemoryChunk> ReserveMemory(size_t size);
|
| +
|
| + // Pop a message from the queue.
|
| + // Returns a null pointer if there is no message left.
|
| + scoped_ptr<MediaMessage> Pop();
|
| +
|
| + // Flush the fifo.
|
| + void Flush();
|
| +
|
| + private:
|
| + struct Descriptor {
|
| + size_t size;
|
| + size_t rd_offset;
|
| + size_t wr_offset;
|
| +
|
| + // Ensure the first item has the same alignment as an int64.
|
| + int64 first_item;
|
| + };
|
| +
|
| + // Add some accessors to ensure security on the browser process side.
|
| + size_t current_rd_offset() const;
|
| + size_t current_wr_offset() const;
|
| + size_t internal_rd_offset() const {
|
| + DCHECK_LT(internal_rd_offset_, size_);
|
| + return internal_rd_offset_;
|
| + }
|
| + size_t internal_wr_offset() const {
|
| + DCHECK_LT(internal_wr_offset_, size_);
|
| + return internal_wr_offset_;
|
| + }
|
| +
|
| + // Reserve a block of free memory without doing any check on the available
|
| + // space. Invoke this function only when all the checks have been done.
|
| + scoped_ptr<MediaMemoryChunk> ReserveMemoryNoCheck(size_t size);
|
| +
|
| + // Invoked each time there is a memory region in the free space of the fifo
|
| + // that has possibly been written.
|
| + void OnWrMemoryReleased();
|
| +
|
| + // Invoked each time there is a memory region in the allocated space
|
| + // of the fifo that has possibly been released.
|
| + void OnRdMemoryReleased();
|
| +
|
| + // Functions to modify the internal/external read/write pointers.
|
| + void CommitRead(size_t new_rd_offset);
|
| + void CommitWrite(size_t new_wr_offset);
|
| + void CommitInternalRead(size_t new_rd_offset);
|
| + void CommitInternalWrite(size_t new_wr_offset);
|
| +
|
| + // An instance of MediaMessageFifo must be running on a single thread.
|
| + // If the fifo feeder and consumer are living on 2 different threads
|
| + // or 2 different processes, they must create their own instance
|
| + // of MediaMessageFifo using the same underlying block of (shared) memory
|
| + // in the constructor.
|
| + base::ThreadChecker thread_checker_;
|
| +
|
| + // Callbacks invoked to notify either of some read or write activity on the
|
| + // fifo. This is especially useful when the feeder and consumer are living in
|
| + // two different processes.
|
| + base::Closure read_event_cb_;
|
| + base::Closure write_event_cb_;
|
| +
|
| + // The serialized structure of the fifo.
|
| + scoped_ptr<MediaMemoryChunk> mem_;
|
| +
|
| + // The size in bytes of the fifo is cached locally for security purpose.
|
| + // (the renderer process cannot modify the size and make the browser process
|
| + // access out of range addresses).
|
| + size_t size_;
|
| +
|
| + // TODO(damienv): This is a work-around since atomicops.h does not define
|
| + // an atomic size_t type.
|
| +#if SIZE_MAX == UINT32_MAX
|
| + typedef base::subtle::Atomic32 AtomicSize;
|
| +#elif SIZE_MAX == UINT64_MAX
|
| + typedef base::subtle::Atomic64 AtomicSize;
|
| +#elif
|
| +#error "Unsupported size_t"
|
| +#endif
|
| + AtomicSize* rd_offset_;
|
| + AtomicSize* wr_offset_;
|
| +
|
| + // Internal read offset: this is where data is actually read from.
|
| + // The external offset |rd_offset_| is only used to protect data from being
|
| + // overwritten by the feeder.
|
| + // At any time, the internal read pointer must be between the external read
|
| + // offset and the write offset (circular fifo definition of "between").
|
| + size_t internal_rd_offset_;
|
| + size_t internal_wr_offset_;
|
| +
|
| + // Note: all the memory read/write are followed by a memory fence before
|
| + // updating the rd/wr pointer.
|
| + void* base_;
|
| +
|
| + // Protects the messages that are either being read or written.
|
| + std::list<scoped_refptr<MediaMessageFlag> > rd_flags_;
|
| + std::list<scoped_refptr<MediaMessageFlag> > wr_flags_;
|
| +
|
| + base::WeakPtrFactory<MediaMessageFifo> weak_factory_;
|
| + base::WeakPtr<MediaMessageFifo> weak_this_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(MediaMessageFifo);
|
| +};
|
| +
|
| +} // namespace media
|
| +} // namespace chromecast
|
| +
|
| +#endif // CHROMECAST_MEDIA_CMA_IPC_MEDIA_MESSAGE_FIFO_H_
|
|
|