MediaClient: Add remaining wiring for input/output functionality
* BufferReceived is renamed HandleBuffer. * Update doc. * Implement buffer production private methods.
This commit is contained in:
parent
58be34781b
commit
5854fc4a7a
|
@ -61,7 +61,7 @@ public:
|
||||||
|
|
||||||
// When those functions return, the BMediaConnection is added to the
|
// When those functions return, the BMediaConnection is added to the
|
||||||
// list and is visible to other nodes as not connected. Any input/output
|
// 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 RegisterInput(BMediaInput* input);
|
||||||
virtual status_t RegisterOutput(BMediaOutput* output);
|
virtual status_t RegisterOutput(BMediaOutput* output);
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ public:
|
||||||
// BMediaClient::Format() will be used, in case both aren't specified
|
// BMediaClient::Format() will be used, in case both aren't specified
|
||||||
// an error is returned. The first parameter should always belong to
|
// an error is returned. The first parameter should always belong to
|
||||||
// this node, the second will be a connection obtained from another
|
// 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,
|
virtual status_t Connect(BMediaConnection* ourConnection,
|
||||||
BMediaConnection* theirConnection);
|
BMediaConnection* theirConnection);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ class BMediaClientNode;
|
||||||
// the BufferReceived function will be called so that you can process the BBuffer,
|
// the BufferReceived function will be called so that you can process the BBuffer,
|
||||||
// and once the function returns the output will be automatically forwarded
|
// and once the function returns the output will be automatically forwarded
|
||||||
// to the connection B SendBuffer method.
|
// to the connection B SendBuffer method.
|
||||||
|
// It's not possible to mix a BMediaInput with a BMediaOutput in the same class.
|
||||||
class BMediaConnection {
|
class BMediaConnection {
|
||||||
public:
|
public:
|
||||||
const media_connection& Connection() const;
|
const media_connection& Connection() const;
|
||||||
|
@ -39,7 +40,7 @@ public:
|
||||||
bool IsConnected() const;
|
bool IsConnected() const;
|
||||||
|
|
||||||
// This allow to specify a format that will be used while
|
// This allow to specify a format that will be used while
|
||||||
// connecting to another node. See BMediaClient::SetFormat.
|
// connecting to another node.
|
||||||
void SetAcceptedFormat(
|
void SetAcceptedFormat(
|
||||||
const media_format& format);
|
const media_format& format);
|
||||||
const media_format& AcceptedFormat() const;
|
const media_format& AcceptedFormat() const;
|
||||||
|
@ -48,10 +49,6 @@ public:
|
||||||
// for this connection.
|
// for this connection.
|
||||||
size_t BufferSize() const;
|
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,
|
// Disconnect this connection. When a connection is disconnected,
|
||||||
// it can be reused as brand new.
|
// it can be reused as brand new.
|
||||||
status_t Disconnect();
|
status_t Disconnect();
|
||||||
|
@ -99,9 +96,6 @@ private:
|
||||||
// see BMediaClient::Bind.
|
// see BMediaClient::Bind.
|
||||||
BMediaConnection* fBind;
|
BMediaConnection* fBind;
|
||||||
|
|
||||||
size_t fBufferSize;
|
|
||||||
bigtime_t fBufferDuration;
|
|
||||||
|
|
||||||
BBufferGroup* fBufferGroup;
|
BBufferGroup* fBufferGroup;
|
||||||
|
|
||||||
bool fConnected;
|
bool fConnected;
|
||||||
|
@ -140,7 +134,7 @@ protected:
|
||||||
// Callbacks
|
// Callbacks
|
||||||
virtual status_t FormatChanged(const media_format& format);
|
virtual status_t FormatChanged(const media_format& format);
|
||||||
|
|
||||||
virtual void BufferReceived(BBuffer* buffer);
|
virtual void HandleBuffer(BBuffer* buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
media_input _MediaInput() const;
|
media_input _MediaInput() const;
|
||||||
|
|
|
@ -135,7 +135,7 @@ protected:
|
||||||
virtual void Connected(const media_format& format);
|
virtual void Connected(const media_format& format);
|
||||||
virtual void Disconnected();
|
virtual void Disconnected();
|
||||||
|
|
||||||
virtual void BufferReceived(BBuffer* buffer);
|
virtual void HandleBuffer(BBuffer* buffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -224,9 +224,7 @@ status_t
|
||||||
BMediaClient::Connect(BMediaConnection* connection,
|
BMediaClient::Connect(BMediaConnection* connection,
|
||||||
const media_client& client)
|
const media_client& client)
|
||||||
{
|
{
|
||||||
CALLED();
|
UNIMPLEMENTED();
|
||||||
|
|
||||||
// TODO: implement this
|
|
||||||
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -467,7 +465,7 @@ BMediaClient::_Deinit()
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
if (fRunning)
|
if (IsRunning())
|
||||||
Stop();
|
Stop();
|
||||||
|
|
||||||
Disconnect();
|
Disconnect();
|
||||||
|
@ -556,9 +554,6 @@ BMediaClient::_ConnectOutput(BMediaInput* input,
|
||||||
media_output theirOutput = output._MediaOutput();
|
media_output theirOutput = output._MediaOutput();
|
||||||
media_format format = input->AcceptedFormat();
|
media_format format = input->AcceptedFormat();
|
||||||
|
|
||||||
// TODO manage the node problems
|
|
||||||
//fNode->ActivateInternalConnect(false);
|
|
||||||
|
|
||||||
return BMediaRoster::CurrentRoster()->Connect(theirOutput.source,
|
return BMediaRoster::CurrentRoster()->Connect(theirOutput.source,
|
||||||
ourInput.destination, &format, &theirOutput, &ourInput,
|
ourInput.destination, &format, &theirOutput, &ourInput,
|
||||||
BMediaRoster::B_CONNECT_MUTED);
|
BMediaRoster::B_CONNECT_MUTED);
|
||||||
|
|
|
@ -382,14 +382,7 @@ BMediaClientNode::SetBufferGroup(const media_source& source, BBufferGroup* group
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bigtime_t latency = 0;
|
conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), 3);
|
||||||
GetLatency(&latency);
|
|
||||||
int32 count = int32(latency / conn->BufferDuration() + 2);
|
|
||||||
|
|
||||||
if (count < 3)
|
|
||||||
count = 3;
|
|
||||||
|
|
||||||
conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), count);
|
|
||||||
if (conn->fBufferGroup == NULL)
|
if (conn->fBufferGroup == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
@ -450,8 +443,12 @@ BMediaClientNode::Connect(status_t status, const media_source& source,
|
||||||
conn->SetAcceptedFormat(format);
|
conn->SetAcceptedFormat(format);
|
||||||
strcpy(name, Name());
|
strcpy(name, Name());
|
||||||
|
|
||||||
// TODO: Allocate buffers, add correct latency estimate
|
// TODO: add correct latency estimate
|
||||||
// and buffer duration mode.
|
SetEventLatency(1000);
|
||||||
|
|
||||||
|
conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), 3);
|
||||||
|
if (conn->fBufferGroup == NULL)
|
||||||
|
TRACE("Can't allocate the buffer group\n");
|
||||||
|
|
||||||
conn->Connected(format);
|
conn->Connected(format);
|
||||||
}
|
}
|
||||||
|
@ -492,7 +489,7 @@ BMediaClientNode::GetLatency(bigtime_t* outLatency)
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
// TODO: finish latency handling
|
// TODO: finish latency handling
|
||||||
*outLatency = 0;
|
*outLatency = 1000;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,7 +597,7 @@ BMediaClientNode::_HandleBuffer(BBuffer* buffer)
|
||||||
BMediaInput* conn = fOwner->_FindInput(dest);
|
BMediaInput* conn = fOwner->_FindInput(dest);
|
||||||
|
|
||||||
if (conn != NULL)
|
if (conn != NULL)
|
||||||
conn->BufferReceived(buffer);
|
conn->HandleBuffer(buffer);
|
||||||
|
|
||||||
// TODO: Investigate system level latency logging
|
// TODO: Investigate system level latency logging
|
||||||
|
|
||||||
|
@ -620,8 +617,58 @@ BMediaClientNode::_ProduceNewBuffer(const media_timed_event* event,
|
||||||
if (RunState() != BMediaEventLooper::B_STARTED)
|
if (RunState() != BMediaEventLooper::B_STARTED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// We get the data through the event
|
// The connection is get through the event
|
||||||
// so that we know which connection
|
BMediaOutput* output
|
||||||
|
= dynamic_cast<BMediaOutput*>((BMediaConnection*)event->pointer);
|
||||||
|
if (output == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
// event.pointer == connection
|
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;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,10 @@
|
||||||
|
|
||||||
namespace BPrivate { namespace media {
|
namespace BPrivate { namespace media {
|
||||||
|
|
||||||
|
|
||||||
class BMediaClient;
|
class BMediaClient;
|
||||||
class BMediaConnection;
|
class BMediaConnection;
|
||||||
|
class BMediaOutput;
|
||||||
|
|
||||||
class BMediaClientNode : public BBufferConsumer, public BBufferProducer,
|
class BMediaClientNode : public BBufferConsumer, public BBufferProducer,
|
||||||
public BMediaEventLooper {
|
public BMediaEventLooper {
|
||||||
|
@ -132,6 +134,8 @@ private:
|
||||||
void _HandleBuffer(BBuffer* buffer);
|
void _HandleBuffer(BBuffer* buffer);
|
||||||
void _ProduceNewBuffer(const media_timed_event* event,
|
void _ProduceNewBuffer(const media_timed_event* event,
|
||||||
bigtime_t late);
|
bigtime_t late);
|
||||||
|
BBuffer* _GetNextBuffer(BMediaOutput* output,
|
||||||
|
bigtime_t eventTime);
|
||||||
|
|
||||||
BMediaClient* fOwner;
|
BMediaClient* fOwner;
|
||||||
bigtime_t fStartTime;
|
bigtime_t fStartTime;
|
||||||
|
|
|
@ -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
|
size_t
|
||||||
BMediaConnection::BufferSize() const
|
BMediaConnection::BufferSize() const
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
return fBufferSize;
|
switch (fConnection.format.type) {
|
||||||
}
|
case B_MEDIA_RAW_AUDIO:
|
||||||
|
return fConnection.format.u.raw_audio.buffer_size;
|
||||||
|
|
||||||
|
case B_MEDIA_RAW_VIDEO:
|
||||||
|
return fConnection.format.u.raw_video.display.bytes_per_row *
|
||||||
|
fConnection.format.u.raw_video.display.line_count;
|
||||||
|
|
||||||
bigtime_t
|
default:
|
||||||
BMediaConnection::BufferDuration() const
|
return 0;
|
||||||
{
|
}
|
||||||
CALLED();
|
|
||||||
|
|
||||||
return fBufferDuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -251,7 +250,7 @@ BMediaInput::FormatChanged(const media_format& format)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BMediaInput::BufferReceived(BBuffer* buffer)
|
BMediaInput::HandleBuffer(BBuffer* buffer)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
|
@ -310,6 +309,9 @@ BMediaOutput::SetEnabled(bool enabled)
|
||||||
status_t
|
status_t
|
||||||
BMediaOutput::PrepareToConnect(media_format* format)
|
BMediaOutput::PrepareToConnect(media_format* format)
|
||||||
{
|
{
|
||||||
|
if (!format_is_compatible(AcceptedFormat(), *format))
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
SetAcceptedFormat(*format);
|
SetAcceptedFormat(*format);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
@ -336,6 +338,9 @@ BMediaOutput::SendBuffer(BBuffer* buffer)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
|
if (!IsConnected())
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
return fOwner->fNode->SendBuffer(buffer, this);
|
return fOwner->fNode->SendBuffer(buffer, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -186,7 +186,7 @@ BSimpleMediaInput::Disconnected()
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BSimpleMediaInput::BufferReceived(BBuffer* buffer)
|
BSimpleMediaInput::HandleBuffer(BBuffer* buffer)
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue