blob: 8ae12b6c558373b34d115bedf8d45cb46c77ef19 [file] [log] [blame]
// Copyright 2015 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.
#include "base/logging.h"
#include "services/media/common/media_pipe_base.h"
namespace mojo {
namespace media {
MediaPipeBase::MediaPipeBase()
: binding_(this) {
}
MediaPipeBase::~MediaPipeBase() {
Cleanup();
}
MojoResult MediaPipeBase::Init(InterfaceRequest<MediaPipe> request,
uint64_t shared_buffer_size) {
static const MojoCreateSharedBufferOptions opt {
.struct_size = sizeof(MojoDuplicateBufferHandleOptions),
.flags = MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE,
};
// Double init?
if (IsInitialized()) {
return MOJO_RESULT_ALREADY_EXISTS;
}
// Valid size?
DCHECK_GT(shared_buffer_size, 0u);
DCHECK_LE(shared_buffer_size, MediaPipeState::kMaxPayloadLen);
if (!shared_buffer_size ||
(shared_buffer_size > MediaPipeState::kMaxPayloadLen)) {
return MOJO_RESULT_INVALID_ARGUMENT;
}
MojoResult res;
res = CreateSharedBuffer(&opt, shared_buffer_size, &buffer_handle_);
if (MOJO_RESULT_OK == res) {
// TODO(johngro) : We really only need read access to this buffer. Ideally,
// we could request that using flags, but there does not seem to be a way to
// do this right now.
res = MapBuffer(buffer_handle_.get(),
0u,
shared_buffer_size,
&buffer_,
MOJO_MAP_BUFFER_FLAG_NONE);
}
if (MOJO_RESULT_OK != res) {
Cleanup();
} else {
buffer_size_ = shared_buffer_size;
binding_.Bind(request.Pass());
}
return res;
}
bool MediaPipeBase::IsInitialized() const {
DCHECK((!binding_.is_bound() && (buffer_ == nullptr)) ||
(binding_.is_bound() && (buffer_ != nullptr)));
return !!buffer_;
}
void MediaPipeBase::GetState(const GetStateCallback& cbk) {
static const MojoDuplicateBufferHandleOptions options = {
.struct_size = sizeof(*this),
.flags = MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE,
};
MediaPipeStatePtr state_ptr(MediaPipeState::New());
// If we have not been successfully initialized, send back an invalid handle
// and a zero length.
if (!buffer_) {
state_ptr->payload_buffer_len = 0;
} else {
MojoResult res = DuplicateBuffer(buffer_handle_.get(),
&options,
&state_ptr->payload_buffer);
state_ptr->payload_buffer_len = buffer_size_;
DCHECK(MOJO_RESULT_OK == res);
}
cbk.Run(state_ptr.Pass());
}
void MediaPipeBase::SendPacket(MediaPacketPtr packet,
const SendPacketCallback& cbk) {
// If we have not been successfully initialized, then we should not be getting
// packets pushed to us.
if (!buffer_) {
cbk.Run(MediaResult::BAD_STATE);
return;
}
DCHECK(buffer_size_);
// The offset(s) and size(s) of this payload must to reside within the space
// of the shared buffer. If any does not, this send operation is not valid.
const MediaPacketRegionPtr* r = &packet->payload;
size_t i = 0;
while (true) {
if ((*r).is_null()) {
cbk.Run(MediaResult::INVALID_ARGUMENT);
return;
}
auto offset = (*r)->offset;
auto length = (*r)->length;
if ((offset > buffer_size_) || (length > (buffer_size_ - offset))) {
cbk.Run(MediaResult::INVALID_ARGUMENT);
return;
}
if (i >= packet->extra_payload.size()) {
break;
}
r = &packet->extra_payload[i++];
}
// Looks good, send this packet up to the implementation layer.
MediaPacketStatePtr ptr(new MediaPacketState(packet.Pass(), cbk));
OnPacketReceived(std::move(ptr));
}
void MediaPipeBase::Flush(const FlushCallback& cbk) {
// If we have not been successfully initialized, then we should not be getting
// packets pushed to us.
if (!buffer_) {
cbk.Run(MediaResult::BAD_STATE);
return;
}
// Pass the flush request up to the implementation layer
OnFlushRequested(cbk);
}
void MediaPipeBase::Cleanup() {
if (nullptr != buffer_) {
MojoResult res;
res = UnmapBuffer(buffer_);
CHECK(res == MOJO_RESULT_OK);
}
buffer_handle_.reset();
}
MediaPipeBase::MediaPacketState::MediaPacketState(
MediaPacketPtr packet,
const SendPacketCallback& cbk)
: packet_(packet.Pass())
, cbk_(cbk)
, result_(MediaResult::OK) {
DCHECK(packet_);
DCHECK(packet_->payload);
DCHECK(packet_->extra_payload);
}
MediaPipeBase::MediaPacketState::~MediaPacketState() {
cbk_.Run(result_);
}
void MediaPipeBase::MediaPacketState::SetResult(MediaResult result) {
MediaResult tmp = MediaResult::OK;
result_.compare_exchange_strong(tmp, result);
}
} // namespace media
} // namespace mojo