diff --git a/headers/private/media/NotificationManager.h b/headers/private/media/NotificationManager.h new file mode 100644 index 0000000000..418cee5148 --- /dev/null +++ b/headers/private/media/NotificationManager.h @@ -0,0 +1,51 @@ +/* + * Copyright 2002, Marcus Overhagen. All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#ifndef _NOTIFICATION_MANAGER_H +#define _NOTIFICATION_MANAGER_H + +namespace BPrivate { +namespace media { + +class NotificationManager +{ +public: + NotificationManager(); + ~NotificationManager(); + + status_t Register(const BMessenger ¬ifyHandler, const media_node &node, int32 notificationType); + status_t Unregister(const BMessenger ¬ifyHandler, const media_node &node, int32 notificationType); + + status_t ReportError(const media_node &node, BMediaNode::node_error what, const BMessage * info); + + void NodesCreated(const media_node_id *ids, int32 count); + void NodesDeleted(const media_node_id *ids, int32 count); + void ConnectionMade(const media_input &input, const media_output &output, const media_format &format); + void ConnectionBroken(const media_source &source, const media_destination &destination); + void BuffersCreated(); // XXX fix + void BuffersDeleted(const media_buffer_id *ids, int32 count); + // XXX header file lists: B_MEDIA_TRANSPORT_STATE, /* "state", "location", "realtime" */ + void FormatChanged(const media_source &source, const media_destination &destination, const media_format &format); + status_t ParameterChanged(const media_node &node, int32 parameterid); + void WebChanged(const media_node &node); // XXX fix + // XXX header file lists: B_MEDIA_DEFAULT_CHANGED /* "default", "node" -- handled by BMediaRoster */ + status_t NewParameterValue(const media_node &node, int32 parameterid, bigtime_t when, const void *param, size_t paramsize); + void FlavorsChanged(media_addon_id addonis, int32 newcount, int32 gonecount); + void NodeStopped(const media_node &node, bigtime_t when); // XXX fix + + static bool IsValidNotificationType(int32 notificationType); +private: + status_t SendMessageToMediaServer(BMessage *msg); + +private: + BMessenger *fMessenger; +}; + +}; // namespace media +}; // namespace BPrivate + +extern BPrivate::media::NotificationManager *_NotificationManager; + +#endif // _NOTIFICATION_MANAGER_H diff --git a/src/kits/media/Controllable.cpp b/src/kits/media/Controllable.cpp index 734d3e82e4..9f1617df74 100644 --- a/src/kits/media/Controllable.cpp +++ b/src/kits/media/Controllable.cpp @@ -5,6 +5,7 @@ ***********************************************************************/ #include #include "debug.h" +#include "NotificationManager.h" /************************************************************* * protected BControllable @@ -78,9 +79,8 @@ BControllable::HandleMessage(int32 message, status_t BControllable::BroadcastChangedParameter(int32 id) { - UNIMPLEMENTED(); - - return B_ERROR; + CALLED(); + return _NotificationManager->ParameterChanged(Node(), id); } @@ -90,9 +90,8 @@ BControllable::BroadcastNewParameterValue(bigtime_t when, void *newValue, size_t valueSize) { - UNIMPLEMENTED(); - - return B_ERROR; + CALLED(); + return _NotificationManager->NewParameterValue(Node(), id, when, newValue, valueSize); } diff --git a/src/kits/media/Jamfile b/src/kits/media/Jamfile index 31141eb0f5..2a2f43dd77 100644 --- a/src/kits/media/Jamfile +++ b/src/kits/media/Jamfile @@ -44,6 +44,7 @@ SharedLibrary media : # Internal Functionality PortPool.cpp DormantNodeManager.cpp + NotificationManager.cpp SystemTimeSource.cpp BufferIdCache.cpp SharedBufferList.cpp diff --git a/src/kits/media/MediaNode.cpp b/src/kits/media/MediaNode.cpp index 4ac9d7cfdb..65e0673519 100644 --- a/src/kits/media/MediaNode.cpp +++ b/src/kits/media/MediaNode.cpp @@ -14,6 +14,7 @@ #include "SystemTimeSource.h" #include "debug.h" #include "ServerInterface.h" +#include "NotificationManager.h" // don't rename this one, it's used and exported for binary compatibility int32 BMediaNode::_m_changeTag = 0; @@ -212,11 +213,10 @@ status_t BMediaNode::ReportError(node_error what, const BMessage *info) { - UNIMPLEMENTED(); - // XXX Transmits the error code specified by whichError to anyone - // XXX that's receiving notifications from this node (see - // XXX BMediaRoster::StartWatching() and BMediaRoster::StopWatching() on). - return B_OK; + CALLED(); + // Transmits the error code specified by what to anyone + // that's receiving notifications from this node + return _NotificationManager->ReportError(Node(), what, info); } @@ -227,7 +227,8 @@ BMediaNode::NodeStopped(bigtime_t whenPerformance) // called by derived classes when they have // finished handling a stop request. - // XXX notify anyone who is listening for stop notifications! + // notify anyone who is listening for stop notifications! + _NotificationManager->NodeStopped(Node(), whenPerformance); // XXX If your node is a BBufferProducer, downstream consumers // XXX will be notified that your node stopped (automatically, no less) diff --git a/src/kits/media/MediaRoster.cpp b/src/kits/media/MediaRoster.cpp index cb06c6aaf2..e451850b51 100644 --- a/src/kits/media/MediaRoster.cpp +++ b/src/kits/media/MediaRoster.cpp @@ -17,6 +17,7 @@ #include "PortPool.h" #include "ServerInterface.h" #include "DormantNodeManager.h" +#include "NotificationManager.h" static BMessenger *ServerMessenger = 0; static team_id team; @@ -316,6 +317,19 @@ BMediaRoster::Connect(const media_source & from, media_format * io_format, media_output * out_output, media_input * out_input) +{ + return BMediaRoster::Connect(from, to, io_format, out_output, out_input, 0); +} + + +status_t +BMediaRoster::Connect(const media_source & from, + const media_destination & to, + media_format * io_format, + media_output * out_output, + media_input * out_input, + uint32 in_flags, + void * _reserved) { CALLED(); if (io_format == NULL || out_output == NULL || out_input == NULL) @@ -443,20 +457,6 @@ failed: return rv; } - -status_t -BMediaRoster::Connect(const media_source & from, - const media_destination & to, - media_format * io_format, - media_output * out_output, - media_input * out_input, - uint32 in_flags, - void * _reserved) -{ - UNIMPLEMENTED(); - return B_ERROR; -} - status_t BMediaRoster::Disconnect(media_node_id source_node, @@ -832,8 +832,12 @@ BMediaRoster::GetAllOutputsFor(const media_node & node, status_t BMediaRoster::StartWatching(const BMessenger & where) { - UNIMPLEMENTED(); - return B_ERROR; + CALLED(); + if (!where.IsValid()) { + TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); + return B_BAD_VALUE; + } + return _NotificationManager->Register(where, media_node::null, B_MEDIA_WILDCARD); } @@ -841,8 +845,16 @@ status_t BMediaRoster::StartWatching(const BMessenger & where, int32 notificationType) { - UNIMPLEMENTED(); - return B_ERROR; + CALLED(); + if (!where.IsValid()) { + TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); + return B_BAD_VALUE; + } + if (!BPrivate::media::NotificationManager::IsValidNotificationType(notificationType)) { + TRACE("BMediaRoster::StartWatching: notificationType invalid!\n"); + return B_BAD_VALUE; + } + return _NotificationManager->Register(where, media_node::null, notificationType); } @@ -851,16 +863,29 @@ BMediaRoster::StartWatching(const BMessenger & where, const media_node & node, int32 notificationType) { - UNIMPLEMENTED(); - return B_ERROR; + CALLED(); + if (!where.IsValid()) { + TRACE("BMediaRoster::StartWatching: messenger invalid!\n"); + return B_BAD_VALUE; + } + if (node.node == 0) { + TRACE("BMediaRoster::StartWatching: node invalid!\n"); + return B_MEDIA_BAD_NODE; + } + if (!BPrivate::media::NotificationManager::IsValidNotificationType(notificationType)) { + TRACE("BMediaRoster::StartWatching: notificationType invalid!\n"); + return B_BAD_VALUE; + } + return _NotificationManager->Register(where, node, notificationType); } status_t BMediaRoster::StopWatching(const BMessenger & where) { - UNIMPLEMENTED(); - return B_ERROR; + CALLED(); + // messenger may already be invalid, so we don't check this + return _NotificationManager->Unregister(where, media_node::null, B_MEDIA_WILDCARD); } @@ -868,8 +893,13 @@ status_t BMediaRoster::StopWatching(const BMessenger & where, int32 notificationType) { - UNIMPLEMENTED(); - return B_ERROR; + CALLED(); + // messenger may already be invalid, so we don't check this + if (!BPrivate::media::NotificationManager::IsValidNotificationType(notificationType)) { + TRACE("BMediaRoster::StopWatching: notificationType invalid!\n"); + return B_BAD_VALUE; + } + return _NotificationManager->Unregister(where, media_node::null, notificationType); } @@ -878,8 +908,17 @@ BMediaRoster::StopWatching(const BMessenger & where, const media_node & node, int32 notificationType) { - UNIMPLEMENTED(); - return B_ERROR; + CALLED(); + // messenger may already be invalid, so we don't check this + if (node.node == 0) { + TRACE("BMediaRoster::StopWatching: node invalid!\n"); + return B_MEDIA_BAD_NODE; + } + if (!BPrivate::media::NotificationManager::IsValidNotificationType(notificationType)) { + TRACE("BMediaRoster::StopWatching: notificationType invalid!\n"); + return B_BAD_VALUE; + } + return _NotificationManager->Unregister(where, node, notificationType); } diff --git a/src/kits/media/NotificationManager.cpp b/src/kits/media/NotificationManager.cpp new file mode 100644 index 0000000000..8fe8793cc9 --- /dev/null +++ b/src/kits/media/NotificationManager.cpp @@ -0,0 +1,261 @@ +/* + * Copyright 2002, Marcus Overhagen. All rights reserved. + * Distributed under the terms of the MIT License. + */ +/* This is a interface class for media kit notifications. + * It is private to the media kit which uses it to pass + * notifications up to the media_server which will broadcast + * them. + */ +#include +#include +#include "debug.h" +#include "PortPool.h" +#include "ServerInterface.h" +#include "NotificationManager.h" + +static BPrivate::media::NotificationManager manager; +BPrivate::media::NotificationManager *_NotificationManager = &manager; + +namespace BPrivate { +namespace media { + +NotificationManager::NotificationManager() + : fMessenger(new BMessenger()) +{ + CALLED(); +} + + +NotificationManager::~NotificationManager() +{ + CALLED(); + delete fMessenger; +} + + +status_t +NotificationManager::Register(const BMessenger ¬ifyHandler, const media_node &node, int32 notificationType) +{ + CALLED(); + + + BMessage msg(MEDIA_SERVER_REQUEST_NOTIFICATIONS); + return SendMessageToMediaServer(&msg); +} + + +status_t +NotificationManager::Unregister(const BMessenger ¬ifyHandler, const media_node &node, int32 notificationType) +{ + CALLED(); + + BMessage msg(MEDIA_SERVER_CANCEL_NOTIFICATIONS); + + return SendMessageToMediaServer(&msg); +} + + +status_t +NotificationManager::ReportError(const media_node &node, BMediaNode::node_error what, const BMessage * info) +{ + /* Transmits the error code specified by whichError to anyone that's receiving notifications from + * this node. If info isn't NULL, it's used as a model message for the error notification message. + * The message field "be:node_id" will contain the node ID. + */ + CALLED(); + // sanity check the what value + switch (what) { + case BMediaNode::B_NODE_FAILED_START: + case BMediaNode::B_NODE_FAILED_STOP: + case BMediaNode::B_NODE_FAILED_SEEK: + case BMediaNode::B_NODE_FAILED_SET_RUN_MODE: + case BMediaNode::B_NODE_FAILED_TIME_WARP: + case BMediaNode::B_NODE_FAILED_PREROLL: + case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR: + case BMediaNode::B_NODE_IN_DISTRESS: + break; + default: + TRACE("BMediaNode::ReportError (NotificationManager::ReportError): invalid what!\n"); + return B_BAD_VALUE; + } + BMessage msg; + if (info) + msg = *info; + msg.what = what; + + return SendMessageToMediaServer(&msg); +} + + +void +NotificationManager::NodesCreated(const media_node_id *ids, int32 count) +{ + CALLED(); + BMessage msg(B_MEDIA_NODE_CREATED); + + SendMessageToMediaServer(&msg); +} + + +void +NotificationManager::NodesDeleted(const media_node_id *ids, int32 count) +{ + CALLED(); + BMessage msg(B_MEDIA_NODE_DELETED); + + SendMessageToMediaServer(&msg); +} + + +void +NotificationManager::ConnectionMade(const media_input &input, const media_output &output, const media_format &format) +{ + CALLED(); + BMessage msg(B_MEDIA_CONNECTION_MADE); + + SendMessageToMediaServer(&msg); +} + + +void +NotificationManager::ConnectionBroken(const media_source &source, const media_destination &destination) +{ + CALLED(); + BMessage msg(B_MEDIA_CONNECTION_BROKEN); + + SendMessageToMediaServer(&msg); +} + + +void +NotificationManager::BuffersCreated() // XXX fix +{ + CALLED(); + BMessage msg(B_MEDIA_BUFFER_CREATED); + + SendMessageToMediaServer(&msg); +} + + +void +NotificationManager::BuffersDeleted(const media_buffer_id *ids, int32 count) +{ + CALLED(); + BMessage msg(B_MEDIA_BUFFER_DELETED); + + SendMessageToMediaServer(&msg); +} + + +void +NotificationManager::FormatChanged(const media_source &source, const media_destination &destination, const media_format &format) +{ + CALLED(); + BMessage msg(B_MEDIA_FORMAT_CHANGED); + + SendMessageToMediaServer(&msg); +} + + +status_t +NotificationManager::ParameterChanged(const media_node &node, int32 parameterid) +{ + CALLED(); + BMessage msg(B_MEDIA_PARAMETER_CHANGED); + + return B_OK; +} + + +void +NotificationManager::WebChanged(const media_node &node) // XXX fix +{ + CALLED(); + BMessage msg(B_MEDIA_WEB_CHANGED); + +} + + +status_t +NotificationManager::NewParameterValue(const media_node &node, int32 parameterid, bigtime_t when, const void *param, size_t paramsize) +{ + CALLED(); + BMessage msg(B_MEDIA_NEW_PARAMETER_VALUE); + + return SendMessageToMediaServer(&msg); +} + + +void +NotificationManager::FlavorsChanged(media_addon_id addonis, int32 newcount, int32 gonecount) +{ + CALLED(); + BMessage msg(B_MEDIA_FLAVORS_CHANGED); + + SendMessageToMediaServer(&msg); +} + +void +NotificationManager::NodeStopped(const media_node &node, bigtime_t when) // XXX fix +{ + CALLED(); + BMessage msg(B_MEDIA_NODE_STOPPED); + + SendMessageToMediaServer(&msg); +} + +status_t +NotificationManager::SendMessageToMediaServer(BMessage *msg) +{ + #define TIMEOUT 1000000 + BMessage reply; + status_t rv; + if (!fMessenger->IsValid()) { + TRACE("NotificationManager::SendMessageToMediaServer: setting new messenger target\n"); + *fMessenger = BMessenger(NEW_MEDIA_SERVER_SIGNATURE); + } + rv = fMessenger->SendMessage(msg, &reply, TIMEOUT); + if (rv != B_OK) { + TRACE("NotificationManager::SendMessageToMediaServer: failed to send message\n"); + } else { + rv = reply.what; + } + return rv; +} + +bool +NotificationManager::IsValidNotificationType(int32 notificationType) +{ + switch (notificationType) { + case BMediaNode::B_NODE_FAILED_START: + case BMediaNode::B_NODE_FAILED_STOP: + case BMediaNode::B_NODE_FAILED_SEEK: + case BMediaNode::B_NODE_FAILED_SET_RUN_MODE: + case BMediaNode::B_NODE_FAILED_TIME_WARP: + case BMediaNode::B_NODE_FAILED_PREROLL: + case BMediaNode::B_NODE_FAILED_SET_TIME_SOURCE_FOR: + case BMediaNode::B_NODE_IN_DISTRESS: + case B_MEDIA_WILDCARD: + case B_MEDIA_NODE_CREATED: + case B_MEDIA_NODE_DELETED: + case B_MEDIA_CONNECTION_MADE: + case B_MEDIA_CONNECTION_BROKEN: + case B_MEDIA_BUFFER_CREATED: + case B_MEDIA_BUFFER_DELETED: + case B_MEDIA_TRANSPORT_STATE: + case B_MEDIA_PARAMETER_CHANGED: + case B_MEDIA_FORMAT_CHANGED: + case B_MEDIA_WEB_CHANGED: + case B_MEDIA_DEFAULT_CHANGED: + case B_MEDIA_NEW_PARAMETER_VALUE: + case B_MEDIA_NODE_STOPPED: + case B_MEDIA_FLAVORS_CHANGED: + return true; + default: + return false; + } +} + +}; // namespace media +}; // namespace BPrivate