From 5854fc4a7ae44143076c5fcedb0ef052d993cc3c Mon Sep 17 00:00:00 2001 From: Dario Casalinuovo Date: Sat, 18 Feb 2017 20:40:38 +0100 Subject: [PATCH] MediaClient: Add remaining wiring for input/output functionality * BufferReceived is renamed HandleBuffer. * Update doc. * Implement buffer production private methods. --- .../private/media/experimental/MediaClient.h | 4 +- .../media/experimental/MediaConnection.h | 12 +-- .../media/experimental/SimpleMediaClient.h | 2 +- src/kits/media/experimental/MediaClient.cpp | 9 +-- .../media/experimental/MediaClientNode.cpp | 77 +++++++++++++++---- src/kits/media/experimental/MediaClientNode.h | 4 + .../media/experimental/MediaConnection.cpp | 27 ++++--- .../media/experimental/SimpleMediaClient.cpp | 2 +- 8 files changed, 91 insertions(+), 46 deletions(-) diff --git a/headers/private/media/experimental/MediaClient.h b/headers/private/media/experimental/MediaClient.h index 2f7e593d360..64aabb3cefd 100755 --- a/headers/private/media/experimental/MediaClient.h +++ b/headers/private/media/experimental/MediaClient.h @@ -61,7 +61,7 @@ class BMediaClient { // When those functions return, the BMediaConnection is added to the // list and is visible to other nodes as not connected. Any input/output - // should be registered to a BMediaClient to become something useful. + // should be registered to a BMediaClient to become visible in the system. virtual status_t RegisterInput(BMediaInput* input); virtual status_t RegisterOutput(BMediaOutput* output); @@ -81,7 +81,7 @@ class BMediaClient { // BMediaClient::Format() will be used, in case both aren't specified // an error is returned. The first parameter should always belong to // this node, the second will be a connection obtained from another - // BMediaClient. + // BMediaClient. Unregistered connections will be registered automatically. virtual status_t Connect(BMediaConnection* ourConnection, BMediaConnection* theirConnection); diff --git a/headers/private/media/experimental/MediaConnection.h b/headers/private/media/experimental/MediaConnection.h index d6139f2cff7..632ab059650 100644 --- a/headers/private/media/experimental/MediaConnection.h +++ b/headers/private/media/experimental/MediaConnection.h @@ -25,6 +25,7 @@ class BMediaClientNode; // the BufferReceived function will be called so that you can process the BBuffer, // and once the function returns the output will be automatically forwarded // to the connection B SendBuffer method. +// It's not possible to mix a BMediaInput with a BMediaOutput in the same class. class BMediaConnection { public: const media_connection& Connection() const; @@ -39,7 +40,7 @@ class BMediaConnection { bool IsConnected() const; // This allow to specify a format that will be used while - // connecting to another node. See BMediaClient::SetFormat. + // connecting to another node. void SetAcceptedFormat( const media_format& format); const media_format& AcceptedFormat() const; @@ -48,10 +49,6 @@ class BMediaConnection { // for this connection. size_t BufferSize() const; - // Represents the duration of one buffer depends on the format set or - // negotiated for this connection. - bigtime_t BufferDuration() const; - // Disconnect this connection. When a connection is disconnected, // it can be reused as brand new. status_t Disconnect(); @@ -99,9 +96,6 @@ class BMediaConnection { // see BMediaClient::Bind. BMediaConnection* fBind; - size_t fBufferSize; - bigtime_t fBufferDuration; - BBufferGroup* fBufferGroup; bool fConnected; @@ -140,7 +134,7 @@ class BMediaInput : public virtual BMediaConnection { // Callbacks virtual status_t FormatChanged(const media_format& format); - virtual void BufferReceived(BBuffer* buffer); + virtual void HandleBuffer(BBuffer* buffer); private: media_input _MediaInput() const; diff --git a/headers/private/media/experimental/SimpleMediaClient.h b/headers/private/media/experimental/SimpleMediaClient.h index 3c9368cb848..27d9818063d 100755 --- a/headers/private/media/experimental/SimpleMediaClient.h +++ b/headers/private/media/experimental/SimpleMediaClient.h @@ -135,7 +135,7 @@ class BSimpleMediaInput : public BSimpleMediaConnection, public BMediaInput { virtual void Connected(const media_format& format); virtual void Disconnected(); - virtual void BufferReceived(BBuffer* buffer); + virtual void HandleBuffer(BBuffer* buffer); }; diff --git a/src/kits/media/experimental/MediaClient.cpp b/src/kits/media/experimental/MediaClient.cpp index fcd6c741829..f8f03a23f8f 100755 --- a/src/kits/media/experimental/MediaClient.cpp +++ b/src/kits/media/experimental/MediaClient.cpp @@ -224,9 +224,7 @@ status_t BMediaClient::Connect(BMediaConnection* connection, const media_client& client) { - CALLED(); - - // TODO: implement this + UNIMPLEMENTED(); return B_ERROR; } @@ -467,7 +465,7 @@ BMediaClient::_Deinit() { CALLED(); - if (fRunning) + if (IsRunning()) Stop(); Disconnect(); @@ -556,9 +554,6 @@ BMediaClient::_ConnectOutput(BMediaInput* input, media_output theirOutput = output._MediaOutput(); media_format format = input->AcceptedFormat(); - // TODO manage the node problems - //fNode->ActivateInternalConnect(false); - return BMediaRoster::CurrentRoster()->Connect(theirOutput.source, ourInput.destination, &format, &theirOutput, &ourInput, BMediaRoster::B_CONNECT_MUTED); diff --git a/src/kits/media/experimental/MediaClientNode.cpp b/src/kits/media/experimental/MediaClientNode.cpp index 17ad530a28d..23e3565e128 100755 --- a/src/kits/media/experimental/MediaClientNode.cpp +++ b/src/kits/media/experimental/MediaClientNode.cpp @@ -382,14 +382,7 @@ BMediaClientNode::SetBufferGroup(const media_source& source, BBufferGroup* group return B_OK; } - bigtime_t latency = 0; - GetLatency(&latency); - int32 count = int32(latency / conn->BufferDuration() + 2); - - if (count < 3) - count = 3; - - conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), count); + conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), 3); if (conn->fBufferGroup == NULL) return B_NO_MEMORY; @@ -450,8 +443,12 @@ BMediaClientNode::Connect(status_t status, const media_source& source, conn->SetAcceptedFormat(format); strcpy(name, Name()); - // TODO: Allocate buffers, add correct latency estimate - // and buffer duration mode. + // TODO: add correct latency estimate + SetEventLatency(1000); + + conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), 3); + if (conn->fBufferGroup == NULL) + TRACE("Can't allocate the buffer group\n"); conn->Connected(format); } @@ -492,7 +489,7 @@ BMediaClientNode::GetLatency(bigtime_t* outLatency) CALLED(); // TODO: finish latency handling - *outLatency = 0; + *outLatency = 1000; return B_OK; } @@ -600,7 +597,7 @@ BMediaClientNode::_HandleBuffer(BBuffer* buffer) BMediaInput* conn = fOwner->_FindInput(dest); if (conn != NULL) - conn->BufferReceived(buffer); + conn->HandleBuffer(buffer); // TODO: Investigate system level latency logging @@ -620,8 +617,58 @@ BMediaClientNode::_ProduceNewBuffer(const media_timed_event* event, if (RunState() != BMediaEventLooper::B_STARTED) return; - // We get the data through the event - // so that we know which connection + // The connection is get through the event + BMediaOutput* output + = dynamic_cast((BMediaConnection*)event->pointer); + if (output == NULL) + return; + + if (output->IsEnabled()) { + BBuffer* buffer = _GetNextBuffer(output, event->event_time); + + if (buffer != NULL) { + if (output->SendBuffer(buffer) != B_OK) { + TRACE("BMediaClientNode: Failed to send buffer\n"); + // The output failed, let's recycle the buffer + buffer->Recycle(); + } + } + } + + bigtime_t time = 0; + media_format format = output->AcceptedFormat(); + if (format.IsAudio()) { + size_t nFrames = format.u.raw_audio.buffer_size + / ((format.u.raw_audio.format + & media_raw_audio_format::B_AUDIO_SIZE_MASK) + * format.u.raw_audio.channel_count); + output->fFramesSent += nFrames; + + time = fStartTime + bigtime_t((1000000LL * output->fFramesSent) + / (int32)format.u.raw_audio.frame_rate); + } + + media_timed_event nextEvent(time, B_NEW_BUFFER); + EventQueue()->AddEvent(nextEvent); +} + + +BBuffer* +BMediaClientNode::_GetNextBuffer(BMediaOutput* output, bigtime_t eventTime) +{ + CALLED(); + + BBuffer* buffer = NULL; + if (output->fBufferGroup->RequestBuffer(buffer, 0) != B_OK) { + TRACE("MediaClientNode:::_GetNextBuffer: Failed to get the buffer\n"); + return NULL; + } + + media_header* header = buffer->Header(); + header->type = output->AcceptedFormat().type; + header->size_used = output->BufferSize(); + header->time_source = TimeSource()->ID(); + header->start_time = eventTime; - // event.pointer == connection + return buffer; } diff --git a/src/kits/media/experimental/MediaClientNode.h b/src/kits/media/experimental/MediaClientNode.h index e7a27c60e3e..8287c0ac27b 100755 --- a/src/kits/media/experimental/MediaClientNode.h +++ b/src/kits/media/experimental/MediaClientNode.h @@ -16,8 +16,10 @@ namespace BPrivate { namespace media { + class BMediaClient; class BMediaConnection; +class BMediaOutput; class BMediaClientNode : public BBufferConsumer, public BBufferProducer, public BMediaEventLooper { @@ -132,6 +134,8 @@ class BMediaClientNode : public BBufferConsumer, public BBufferProducer, void _HandleBuffer(BBuffer* buffer); void _ProduceNewBuffer(const media_timed_event* event, bigtime_t late); + BBuffer* _GetNextBuffer(BMediaOutput* output, + bigtime_t eventTime); BMediaClient* fOwner; bigtime_t fStartTime; diff --git a/src/kits/media/experimental/MediaConnection.cpp b/src/kits/media/experimental/MediaConnection.cpp index 06bddac0e18..91b8bc5823b 100644 --- a/src/kits/media/experimental/MediaConnection.cpp +++ b/src/kits/media/experimental/MediaConnection.cpp @@ -122,23 +122,22 @@ BMediaConnection::Release() } -// TODO: The data represented by the following two functions should be -// automatically calculated depending on the media_format. size_t BMediaConnection::BufferSize() const { CALLED(); - return fBufferSize; -} - + switch (fConnection.format.type) { + case B_MEDIA_RAW_AUDIO: + return fConnection.format.u.raw_audio.buffer_size; -bigtime_t -BMediaConnection::BufferDuration() const -{ - CALLED(); + case B_MEDIA_RAW_VIDEO: + return fConnection.format.u.raw_video.display.bytes_per_row * + fConnection.format.u.raw_video.display.line_count; - return fBufferDuration; + default: + return 0; + } } @@ -251,7 +250,7 @@ BMediaInput::FormatChanged(const media_format& format) void -BMediaInput::BufferReceived(BBuffer* buffer) +BMediaInput::HandleBuffer(BBuffer* buffer) { CALLED(); @@ -310,6 +309,9 @@ BMediaOutput::SetEnabled(bool enabled) status_t BMediaOutput::PrepareToConnect(media_format* format) { + if (!format_is_compatible(AcceptedFormat(), *format)) + return B_ERROR; + SetAcceptedFormat(*format); return B_OK; @@ -336,6 +338,9 @@ BMediaOutput::SendBuffer(BBuffer* buffer) { CALLED(); + if (!IsConnected()) + return B_ERROR; + return fOwner->fNode->SendBuffer(buffer, this); } diff --git a/src/kits/media/experimental/SimpleMediaClient.cpp b/src/kits/media/experimental/SimpleMediaClient.cpp index d0a6740d04a..e3501b0f8c0 100644 --- a/src/kits/media/experimental/SimpleMediaClient.cpp +++ b/src/kits/media/experimental/SimpleMediaClient.cpp @@ -186,7 +186,7 @@ BSimpleMediaInput::Disconnected() void -BSimpleMediaInput::BufferReceived(BBuffer* buffer) +BSimpleMediaInput::HandleBuffer(BBuffer* buffer) { CALLED();