Edit

Share via


Using The TAPI 3 MSP Base Classes

The following procedure describes how to implement an MSP using ATL version 2.1 or ATL version 3.0 and the MSP base classes. For more information and a list of libraries and headers, see TAPI 3 MSP Base Classes. The content contained in this topic assumes that the developer has a working understanding of ATL and COM, and has experience implementing COM DLLs using ATL.

To implement and MSP using ATL 2.1 or ATL 3.0

  1. Create an IDL file for your MSP. This file defines a CLSID for your MSP. Declare your MSP "coclass" as implementing the ITMSPAddress interface, and declare this interface as the default interface on your class object. For the definition of ITMSPAddress, import the file "msp.idl". Include your MSP "coclass" in a type library for your MSP. If your MSP supports private (custom) interfaces, define them here and include them in your type library. The following code example is an IDL file as described above, without custom interfaces.

    import "msp.idl";
    [
          uuid(4DDB6D35-3BC1-11d2-86F2-006008B0E5D2),
          version(2.0),
          helpstring("Wave MSP 2.0 Type Library")
    ]
    library WAVEMSPLib
    {
    importlib("stdole32.tlb");
    importlib("stdole2.tlb");
    
    [
    uuid(4DDB6D36-3BC1-11d2-86F2-006008B0E5D2),
    helpstring("Wave MSP Class")
    ]
    coclass WaveMSP
    {
    [default] interface ITMSPAddress;
    };
    };
    
  2. Modify your TSP to advertise the CLSID of your MSP when Tapi3.dll requests it. Ensure that (1) your TSP can negotiate TAPI_VERSION3_0 or higher in the TSPI function TSPI_lineNegotiateTSPIVersion, (2) your TSP LINEDEVCAPS structure has the LINEDEVCAPFLAGS_MSP flag set in the dwDevCapFlags member, and (3) your TSP returns your MSP CLSID in the TSPI function TSPI_lineMSPIdentify. This should be the same CLSID specified in your IDL file; for example, the second "uuid" line in the example IDL file in the previous step.

  3. Compile the MSPBase sample application, located in the Platform Software Development Kit (SDK), to create the MSPBaseSample.lib library.

  4. Link your MSP DLL with the MSPBaseSample.lib library.

  5. Include Mspbase.h from the SDK for MSP base class definitions.

  6. Implement your DLL exports (for example, DllMain). Microsoft Visual C++ will generate these for you. In DllMain, on DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH, respectively, use the MSPLOGREGISTER and MSPLOGDEREGISTER macros to enable up logging features for your DLL. Specify the name of your DLL in the MSPLOGDEREGISTER call.

  7. Use the LOG macro, defined in Msplog.h, to output trace messages in the same fashion as the base classes. Define the MSPLOG preprocessor symbol to include logging in your DLL; leave it undefined to build a DLL that does not have logging.

  8. Derive a class from CMSPAddress that implements addresses for your MSP. Declare a global ATL object map which instructs ATL to create an instance of your address class when asked to CoCreate on the CLSID you specified in your IDL file. Also, derive your address class from the ATL CComCoClass template, and include a DECLARE_REGISTRY_RESOURCEID declaration in your address class. Construct a corresponding resource script and header file, as for any other ATL COM DLL.

  9. Implement the required CMSPAddress overrides for your address class. For MSPAddressAddRef and MSPAddressRelease, call the provided helper function templates. For GetCallMediaTypes, simply return a DWORD bitmap with all of your MSP-supported TAPIMEDIAMODEs ORed together. For CreateMSPCall and ShutdownMSPCall, return E_NOTIMPL and compile and link your MSP at this point. Now, verify that you can register and instantiate your MSP from TAPI 3 applications, but not successfully create calls.

  10. Derive a class from CMSPCallMultiGraph to implement your MSP call objects. You may want to derive from CMSPCallBase instead of CMSPCallMultiGraph if the filter-graph-per-stream model does not fit your requirements; this will increase the complexity of the task (as of this writing, all MSPs derive call objects directly from CMSPCallMultiGraph). In your address object, implement CreateMSPCall and ShutdownMSPCall to create and shut down your specific type of call object using the provided helper function templates. In your call object, override CreateStreamObject to return E_NOTIMPL. Override MSPCallAddRef and MSPCallRelease in a manner identical to the corresponding address methods. Again, you should be able to compile and link your MSP; it should now be able to create and shut down calls, but the calls will not do any useful streaming.

  11. Derive a class from CMSPStream to implement your MSP stream objects. In your call object, implement CreateStreamObject to create and initialize your stream object (typically by calling the ATL CreateInstance followed by the ATL _InternalQueryInterface for ITStream followed by calling Init on your stream object). To support a fixed number of streams (this is common for MSPs which do not support modification of stream configurations by other endpoints on the call), override Init, CreateStream, and RemoveStream on your call object. (The call Init creates all of your streams initially, and CreateStream and RemoveStream return the appropriate TAPI error codes to prevent the application from creating or removing streams). Otherwise, override the call's Init method to create some initial default configuration of streams using the media types requested for the call. When creating any default stream objects in your call's Init method, use the InternalCreateStream helper method.

  12. Implement your stream object. The only required override is the get_Name method, which simply returns a friendly name for the stream. In addition, you will need to override several other methods. Exactly which methods to override depends on your implementation and when you decide to perform the various tasks involved in constructing and deconstructing your filter graph. These tasks include creating the appropriate "transport" filters, codecs, and so on, and inserting them and removing them from the filter graphs at the appropriate times. You will also have to use the ITTerminalControl interface on terminal objects to connect the selected terminals to your streams. You may want to override SelectTerminal and UnselectTerminal on your stream object to limit the terminal configurations that your streams will accept; limiting each stream to a single terminal will especially simplify construction of your filter graphs, but will sacrifice application functionality such as video preview. Depending on your implementation, you will place your graph construction, deconstruction, and terminal connection code in the StartStream, StopStream, PauseStream, Initialize, Shutdown, SelectTerminal, and UnselectTerminal methods, or in your own methods based on private TSP communication. Be aware that a stream with no terminals selected must track the desired graph state; a StartStream call followed by a SelectTerminal call on such a stream must result in a data stream. Override most of these methods to ensure that the correct construction, deconstruction, connection, and disconnection happens in each case depending on the state of the stream.

  13. Implement your TSP communication. Override CMSPAddress::ReceiveTSPAddressData and/or CMSPCallBase::ReceiveTSPCallData, and/or by calling PostEvent on your address object, or HandleStreamEvent on your call object (from either your call or stream objects).

  14. Use PostEvent on your address object, or HandleStreamEvent on your call object (from either your call or stream objects) to send call media events to the application via Tapi3.dll. You will typically do this on your stream object, in overridden methods including the ProcessGraphEvent, StopStream, StartStream, PauseStream, SelectTerminal, and UnselectTerminal methods, depending on how you implement your streams.

  15. Implement any desired private interfaces or substreams on your existing objects (address, call, and stream). Usually there are none. Be aware that when implementing your private interfaces, specify the LIBID of your type library from your IDL file. That is, application programmers must use your MSP type library when using your custom interfaces. The standard MSP interfaces, implemented in the MSP base classes, use the Tapi3.dll LIBID and are therefore accessible to all TAPI 3 applications.

  16. If implementing MSP-specific static or dynamic terminal objects or replacements for the default static terminals (not typical), you can use the provided terminal base classes. You will have to override various methods on your address object to provide alternative or additional methods of creating terminal objects.

  17. Implement the IObjectSafety interface on your Address, Call, Stream, and Terminal objects. To use Dispatch Mapper to query for interfaces on your MSP objects, mark your objects as safe for scripting on these interfaces. To do this, implement the IObjectSafety interface on your object. Deriving from CMSPObjectSafetyImpl (a helper class provided in Msputils.h) and adding IObjectSafety to your class's ATL COM_MAP will make your objects safe for scripting on all the interfaces they expose. Be aware that using Dispatch Mapper on MSP objects could be implicit. MSP Address and MSP Call are aggregated by TAPI Address and TAPI Call objects. If Dispatch Mapper is used on the TAPI objects to query for the interfaces exposed by the aggregated MSP objects, the aggregated MSP objects will be queried for safety of the requested interfaces.