/* * Copyright 2015, Dario Casalinuovo. All rights reserved. * Distributed under the terms of the MIT License. */ #include "MediaClient.h" #include #include #include #include "MediaClientNode.h" #include "MediaDebug.h" namespace BPrivate { namespace media { class ConnReleaser { public: ConnReleaser(BMediaConnection* conn) : fConn(conn) {} virtual ~ConnReleaser() { fConn->Release(); } bool operator== (const ConnReleaser &c1) { return c1.fConn == this->fConn; } protected: BMediaConnection* Obj() const { return fConn; } private: BMediaConnection* fConn; }; class InputReleaser : public ConnReleaser { public: InputReleaser(BMediaInput* input) : ConnReleaser(input) {} BMediaInput* Obj() const { return dynamic_cast(ConnReleaser::Obj()); } }; class OutputReleaser : public ConnReleaser { public: OutputReleaser(BMediaOutput* output) : ConnReleaser(output) {} BMediaOutput* Obj() const { return dynamic_cast(ConnReleaser::Obj()); } }; } } BMediaClient::BMediaClient(const char* name, media_type type, media_client_kinds kinds) : fLastID(-1) { CALLED(); fNode = new BMediaClientNode(name, this, type); _Init(); fClient.node = fNode->Node(); fClient.kinds = kinds; } BMediaClient::~BMediaClient() { CALLED(); _Deinit(); } const media_client& BMediaClient::Client() const { return fClient; } status_t BMediaClient::InitCheck() const { CALLED(); return fInitErr; } media_client_kinds BMediaClient::Kinds() const { CALLED(); return fClient.Kinds(); } media_type BMediaClient::MediaType() const { CALLED(); // Right now ConsumerType() and ProducerType() are the same. return fNode->ConsumerType(); } status_t BMediaClient::RegisterInput(BMediaInput* input) { input->_ConnectionRegistered(this, ++fLastID); _AddInput(input); return B_OK; } status_t BMediaClient::RegisterOutput(BMediaOutput* output) { output->_ConnectionRegistered(this, ++fLastID); _AddOutput(output); return B_OK; } status_t BMediaClient::Bind(BMediaInput* input, BMediaOutput* output) { CALLED(); if (input == NULL || output == NULL) return B_ERROR; if (input->fOwner != this || output->fOwner != this) return B_ERROR; // TODO: Implement binding one input to more outputs. if (input->fBind != NULL || output->fBind != NULL) return B_ERROR; input->fBind = output; output->fBind = input; return B_OK; } status_t BMediaClient::Unbind(BMediaInput* input, BMediaOutput* output) { CALLED(); if (input == NULL || output == NULL) return B_ERROR; if (input->fOwner != this || output->fOwner != this) return B_ERROR; input->fBind = NULL; output->fBind = NULL; return B_OK; } status_t BMediaClient::Connect(BMediaConnection* ourConnection, BMediaConnection* theirConnection) { CALLED(); return Connect(ourConnection, theirConnection->Connection()); } status_t BMediaClient::Connect(BMediaConnection* ourConnection, const media_connection& theirConnection) { CALLED(); BMediaOutput* output = dynamic_cast(ourConnection); if (output != NULL && theirConnection.IsInput()) return _ConnectInput(output, theirConnection); BMediaInput* input = dynamic_cast(ourConnection); if (input != NULL && theirConnection.IsOutput()) return _ConnectOutput(input, theirConnection); return B_ERROR; } status_t BMediaClient::Connect(BMediaConnection* connection, const media_client& client) { UNIMPLEMENTED(); return B_ERROR; } status_t BMediaClient::Disconnect() { CALLED(); for (int32 i = 0; i < CountInputs(); i++) InputAt(i)->Disconnect(); for (int32 i = 0; i < CountOutputs(); i++) OutputAt(i)->Disconnect(); return B_OK; } int32 BMediaClient::CountInputs() const { CALLED(); return fInputs.CountItems(); } int32 BMediaClient::CountOutputs() const { CALLED(); return fOutputs.CountItems(); } BMediaInput* BMediaClient::InputAt(int32 index) const { CALLED(); return fInputs.ItemAt(index)->Obj(); } BMediaOutput* BMediaClient::OutputAt(int32 index) const { CALLED(); return fOutputs.ItemAt(index)->Obj(); } BMediaInput* BMediaClient::FindInput(const media_connection& input) const { CALLED(); if (!input.IsInput()) return NULL; return _FindInput(input.destination); } BMediaOutput* BMediaClient::FindOutput(const media_connection& output) const { CALLED(); if (!output.IsOutput()) return NULL; return _FindOutput(output.source); } bool BMediaClient::IsStarted() const { CALLED(); return fRunning; } void BMediaClient::ClientRegistered() { CALLED(); } status_t BMediaClient::Start() { CALLED(); status_t err = B_OK; for (int32 i = 0; i < CountOutputs(); i++) { media_node remoteNode = OutputAt(i)->Connection().remote_node; if (remoteNode.kind & B_TIME_SOURCE) err = BMediaRoster::CurrentRoster()->StartTimeSource( remoteNode, BTimeSource::RealTime()); else err = BMediaRoster::CurrentRoster()->StartNode( remoteNode, fNode->TimeSource()->Now()); } return BMediaRoster::CurrentRoster()->StartNode( fNode->Node(), fNode->TimeSource()->Now()); } status_t BMediaClient::Stop() { CALLED(); return BMediaRoster::CurrentRoster()->StopNode( fNode->Node(), fNode->TimeSource()->Now()); } status_t BMediaClient::Seek(bigtime_t mediaTime, bigtime_t performanceTime) { CALLED(); return BMediaRoster::CurrentRoster()->SeekNode(fNode->Node(), mediaTime, performanceTime); } status_t BMediaClient::Roll(bigtime_t start, bigtime_t stop, bigtime_t seek) { CALLED(); return BMediaRoster::CurrentRoster()->RollNode(fNode->Node(), start, stop, seek); } bigtime_t BMediaClient::CurrentTime() const { CALLED(); return fCurrentTime; } BMediaAddOn* BMediaClient::AddOn(int32* id) const { CALLED(); return NULL; } void BMediaClient::HandleStart(bigtime_t performanceTime) { fRunning = true; } void BMediaClient::HandleStop(bigtime_t performanceTime) { fRunning = false; } void BMediaClient::HandleSeek(bigtime_t mediaTime, bigtime_t performanceTime) { } status_t BMediaClient::FormatSuggestion(media_type type, int32 quality, media_format* format) { return B_ERROR; } void BMediaClient::_Init() { CALLED(); BMediaRoster* roster = BMediaRoster::Roster(&fInitErr); if (fInitErr == B_OK && roster != NULL) fInitErr = roster->RegisterNode(fNode); } void BMediaClient::_Deinit() { CALLED(); if (IsStarted()) Stop(); Disconnect(); // This will release the connections too. fInputs.MakeEmpty(true); fOutputs.MakeEmpty(true); fNode->Release(); } void BMediaClient::_AddInput(BMediaInput* input) { CALLED(); fInputs.AddItem(new InputReleaser(input)); } void BMediaClient::_AddOutput(BMediaOutput* output) { CALLED(); fOutputs.AddItem(new OutputReleaser(output)); } BMediaInput* BMediaClient::_FindInput(const media_destination& dest) const { CALLED(); for (int32 i = 0; i < CountInputs(); i++) { if (dest.id == InputAt(i)->_Destination().id) return InputAt(i); } return NULL; } BMediaOutput* BMediaClient::_FindOutput(const media_source& source) const { CALLED(); for (int32 i = 0; i < CountOutputs(); i++) { if (source.id == OutputAt(i)->_Source().id) return OutputAt(i); } return NULL; } status_t BMediaClient::_ConnectInput(BMediaOutput* output, const media_connection& input) { CALLED(); if (input.destination == media_destination::null) return B_MEDIA_BAD_DESTINATION; media_output ourOutput = output->Connection()._BuildMediaOutput(); media_input theirInput = input._BuildMediaInput(); media_format format; // NOTE: We want to set this data in the callbacks if possible. // The correct format should have been set in BMediaConnection::Connected. // TODO: Perhaps add some check assert? status_t ret = BMediaRoster::CurrentRoster()->Connect(ourOutput.source, theirInput.destination, &format, &ourOutput, &theirInput, BMediaRoster::B_CONNECT_MUTED); #if 0 if (ret == B_OK) output->fConnection.format = format; #endif return ret; } status_t BMediaClient::_ConnectOutput(BMediaInput* input, const media_connection& output) { CALLED(); if (output.source == media_source::null) return B_MEDIA_BAD_SOURCE; media_input ourInput = input->Connection()._BuildMediaInput(); media_output theirOutput = output._BuildMediaOutput(); media_format format; // NOTE: We want to set this data in the callbacks if possible. // The correct format should have been set in BMediaConnection::Connected. // TODO: Perhaps add some check assert? status_t ret = BMediaRoster::CurrentRoster()->Connect(theirOutput.source, ourInput.destination, &format, &theirOutput, &ourInput, BMediaRoster::B_CONNECT_MUTED); #if 0 if (ret == B_OK) input->fConnection.format = format; #endif return ret; } status_t BMediaClient::_DisconnectConnection(BMediaConnection* conn) { CALLED(); if (conn->Client() != this) return B_ERROR; const media_connection& handle = conn->Connection(); if (handle.IsInput()) { return BMediaRoster::CurrentRoster()->Disconnect( handle.remote_node.node, handle.source, handle._Node().node, handle.destination); } else { return BMediaRoster::CurrentRoster()->Disconnect( handle._Node().node, handle.source, handle.remote_node.node, handle.destination); } return B_ERROR; } status_t BMediaClient::_ReleaseConnection(BMediaConnection* conn) { if (conn->Client() != this) return B_ERROR; if (conn->Connection().IsInput()) { InputReleaser obj(dynamic_cast(conn)); fInputs.RemoveItem(&obj, false); return B_OK; } else { OutputReleaser obj(dynamic_cast(conn)); fOutputs.RemoveItem(&obj, false); return B_OK; } return B_ERROR; } void BMediaClient::_ReservedMediaClient0() {} void BMediaClient::_ReservedMediaClient1() {} void BMediaClient::_ReservedMediaClient2() {} void BMediaClient::_ReservedMediaClient3() {} void BMediaClient::_ReservedMediaClient4() {} void BMediaClient::_ReservedMediaClient5() {} void BMediaClient::_ReservedMediaClient6() {} void BMediaClient::_ReservedMediaClient7() {} void BMediaClient::_ReservedMediaClient8() {} void BMediaClient::_ReservedMediaClient9() {} void BMediaClient::_ReservedMediaClient10() {}