/*============================================================================= CAMIDIEndpoints.h $Log: CAMIDIEndpoints.h,v $ Revision 1.3 2004/09/04 21:21:21 dwyatt add MIDIUniqueID optional argument to EndpointInfo constructor Revision 1.2 2003/12/04 19:56:13 dwyatt fixes: - in EndpointInfo copy constructor, null out mDisplayName - don't prepend the device name to the entity name if the entity name already starts with the device name (Edirol UM-4) Revision 1.1 2003/09/24 21:31:11 dwyatt initial checkin created Thu Sep 18 2003, Doug Wyatt Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved $NoKeywords: $ =============================================================================*/ #ifndef __CAMIDIEndpoints_h__ #define __CAMIDIEndpoints_h__ #include #include // ____________________________________________________________________________ // This class manages persistent references to MIDI endpoints, // and provides user-visible names for them. class CAMIDIEndpoints { public: // ____________________________________________________________________________ class EndpointInfo { public: // when asking for pairs, both source and destination are valid, // otherwise only the appropriate MIDIEndpointRef is valid. MIDIEndpointRef mSourceEndpoint; // driver-owned, can be used for I/O MIDIEndpointRef mDestinationEndpoint; // driver-owned, can be used for I/O CFStringRef mDisplayName; MIDIUniqueID mUniqueID; // may refer to a driver or external endpoint. // use this as your permanent reference to it. EndpointInfo(MIDIUniqueID uid=kMIDIInvalidUniqueID) : mSourceEndpoint(NULL), mDestinationEndpoint(NULL), mDisplayName(NULL), mUniqueID(uid) { } EndpointInfo(const EndpointInfo &info) : mDisplayName(NULL) { *this = info; } EndpointInfo & operator = (const EndpointInfo &a) { ReleaseName(); this->mSourceEndpoint = a.mSourceEndpoint; this->mDestinationEndpoint = a.mDestinationEndpoint; this->mDisplayName = a.mDisplayName; if (this->mDisplayName) CFRetain(this->mDisplayName); this->mUniqueID = a.mUniqueID; return *this; } ~EndpointInfo() { ReleaseName(); } private: void ReleaseName() { if (mDisplayName) { CFRelease(mDisplayName); mDisplayName = NULL; } } }; struct EndpointInfoList : public std::vector { ~EndpointInfoList() { for (iterator it = begin(); it != end(); ++it) delete *it; } }; // ____________________________________________________________________________ // options enum { kOptSortByName = 1, kOptIncludeUnconnectedExternalPorts = 2, kOptCombineByPort = 4 // when multiple devices connected to a port, // present only a single endpoint }; // ____________________________________________________________________________ // methods CAMIDIEndpoints(); virtual ~CAMIDIEndpoints(); void UpdateFromCurrentState(); // call this when you get a notification that the state has changed // functions that return lists: do not dispose the pointers contained in the lists! EndpointInfoList * GetSources(UInt32 opts = 0) { return GetEndpoints(kSources, opts); } EndpointInfoList * GetDestinations(UInt32 opts = 0) { return GetEndpoints(kDestinations, opts); } EndpointInfoList * GetEndpointPairs(UInt32 opts = 0) { return GetEndpoints(kPairs, opts); } // A pair of endpoints: based on being part of the same entity. // Considering the possibility of multi-entity USB devices, it's more robust to // consider entities/endpoint pairs as things to communicate bidirectionally with, // as opposed to devices. But in the UI, you might still treat them as "devices" // since most devices have only a single entity. // look up an endpoint by uniqueID in a EndpointInfo struct, return // an updated EndpointInfo. (### options are not currently relevant ###) bool FindSource(EndpointInfo &info, UInt32 opts = 0) { return FindEndpoint(kSources, info, opts); } bool FindDestination(EndpointInfo &info, UInt32 opts = 0) { return FindEndpoint(kDestinations, info, opts); } bool FindPair(EndpointInfo &info, UInt32 opts = 0) { return FindEndpoint(kPairs, info, opts); } protected: // ____________________________________________________________________________ enum EMode { kSources, kDestinations, kPairs }; // ____________________________________________________________________________ // Corresponds to a CoreMIDI source or destination endpoint, except that // in the case of multiple external devices connected to the same driver port, // there is a separate instance for each. class Endpoint { public: Endpoint(MIDIEndpointRef ep, CFStringRef name, MIDIObjectRef connectedObj); ~Endpoint(); MIDIUniqueID UniqueID() const { return mUniqueID; } CFStringRef Name() const { return mName; } // do not release returned reference MIDIEndpointRef IOEndpoint() const { return mIOEndpoint; } bool DriverOwned() const { return mConnectedObj == NULL; } bool EmbeddedOrVirtual() const { return mEmbeddedOrVirtual; } MIDIEntityRef Entity() const { return mEntity; } void SetNext(Endpoint *next) { mNext = next; } Endpoint * Next() const { return mNext; } void SetPairMate(Endpoint *e) { mPairMate = e; } Endpoint * PairMate() const { return mPairMate; } bool GetEndpointInfo(EMode mode, EndpointInfo &outInfo); protected: MIDIUniqueID mUniqueID; MIDIEndpointRef mIOEndpoint; // NULL if unresolved CFStringRef mName; MIDIEntityRef mEntity; bool mEmbeddedOrVirtual; MIDIObjectRef mConnectedObj; Endpoint * mNext; // linked list: driver owned -> connected -> connected ... Endpoint * mPairMate; }; typedef std::vector EndpointList; // ____________________________________________________________________________ // members protected: void Clear(); void AddEndpoints(MIDIEndpointRef endpoint, EndpointList &eplist); EndpointInfoList * GetEndpoints(EMode mode, UInt32 opts); bool FindEndpoint(EMode mode, EndpointInfo &info, UInt32 opts); EndpointList mSources, mDestinations; }; #endif // __CAMIDIEndpoints_h__