RealSystem G2, also called the RealMedia Architecture (RMA), is based on the Component Object Model (COM) jointly developed by Microsoft Corporation and Digital Equipment Corporation. RealSystem components use the COM IUnknown::QueryInterface
method to expose their interfaces. The RealSystem COM-style interfaces begin with the prefix "IRMA," which stands for "Interface RealMedia Architecture."
![]() |
Additional Information |
---|
Visit http://www.microsoft.com/com/default.asp for more information on COM. |
RealSystem does not employ all aspects of COM, however. It implements a subset of COM functions to provide cross-platform operation without requiring Windows libraries or Windows-emulation code on UNIX and Macintosh platforms. RealSystem thus eliminates the need for heavyweight Windows components like the registry and the COM and OLE runtime libraries. The following sections describe how RealSystem diverges from COM.
RealSystem does not use the Windows CoCreateInstance
function to create plug-in objects. Instead, each RealSystem plug-in implements RMACreateInstance
, a "C-style" entry point that exposes the IRMAPlugin
interface. RealSystem then uses IRMAPlugin
to determine the plug-in's characteristics. The following, taken from a RealSystem SDK sample file, illustrates the entry point:
STDAPI
RMACreateInstance(IUnknown** ppExFileFormatObj)
{
*ppExFileFormatObj = (IUnknown*)(IRMAPlugin
*)new CMyExampleFileFormat()
;
if (*ppExFileFormatObj != NULL)
{
(*ppExFileFormatObj)-AddRef()
;
return PNR_OK;
}
return PNR_OUTOFMEMORY;
}
![]() |
Note |
---|
On Windows, the plug-in must export RMACreateInstance in its .def file.
|
A RealSystem component can use the C++ new operator to create objects that it alone manipulates. To create objects passed to other RealSystem components, however, a component should use IRMACommonClassFactory
. When RealSystem initializes a component, it passes the component a pointer to the system context. The component can then use this pointer to call IRMACommonClassFactory::CreateInstance
and create new RealSystem objects. The following extract from a RealSystem SDK sample file illustrates a call to this method:
m_pClassFactory-CreateInstance(CLSID_IRMABuffer
, (void**)&pStringObj);
Because RealSystem objects are often utilized by other RealSystem objects, objects must correctly implement reference counting. The COM functions IUnknown::AddRef
and IUnknown::Release
control reference counting and therefore determine each object's lifetime. The following rules describe when RealSystem components need to AddRef
and Release
objects:
AddRef
objects before returning them. When a component finishes with the object, it must Release
the object.
AddRef
the object. When the component finishes with the object, it must Release
the object.
AddRef
the object and then Release
it when finished.
AddRef
the file object they are passed by IRMAFileFormatObject::InitFileFormat
. They must Release
it when they shut down or when they are done playing the stream.
IRMAFileSystemManager
must AddRef
the object passed to them by IRMAFileSystemManagerResponse::FileObjectReady
. They must Release
the object when done with it.
IRMAFileSystemManager
that call IUnknown::QueryInterface
to get a different interface inside IRMAFileSystemManagerResponse::FileObjectReady
do not need to AddRef
the IUnknown
object they are passed except to save it for later use.
RealSystem components function asynchronously, using response interfaces to return data for calls made to them. For example, a file format plug-in may request file data from a file system plug-in through IRMAFileObject
. The file system plug-in then uses IRMAFileResponse
, which the file format plug-in implements, to return the requested data. This asynchronous architecture lets the file format plug-in perform other actions while the file system plug-in prepares the requested data. Given RealSystem's asynchronous nature, a plug-in must be able to handle any call made to it while it is processing data or waiting for a response from another component.
The IRMABuffer
interface, implemented by the RealSystem core and defined in rmapckts.h
, lets RealSystem objects create data buffers managed through COM reference counting. Typically, RealSystem objects use these buffer objects to pass data. For example, a file system plug-in passes stream header data to a file format plug-in through a buffer object.
![]() |
Additional Information |
---|
See "Creating Stream Headers" for more information. |
A RealSystem component does the following to create a buffer object:
IRMABuffer
interface through IRMACommonClassFactory
as described in "Creating a RealSystem Object".
IRMABuffer::SetSize
to set the buffer size. This performs the memory allocation.
IRMABuffer::GetBuffer
to obtain a pointer to the buffer object.
IRMABuffer::Set
to write data to the buffer object.
Any RealSystem component can call IRMABuffer::Set
to modify buffer data (the IUnknown::AddRef
used during object creation means only that the object is not deleted). It is intended, however, that only the buffer creator sets the buffer's contents. Other components that need to modify the buffer should create a new buffer object. If the file format plug-in needs to modify the contents of a stream header buffer passed to it by the file system plug-in, for example, it should create a new buffer object for the modified data.
IUnknown::Release
.
When a component receives a pointer to a buffer object, it calls IRMABuffer::GetSize
to retrieve the buffer size and IRMABuffer::Get
to retrieve the buffer data.
Like IRMABuffer
, the IRMAValues
interface, also implemented by the RealSystem core architecture and defined in rmapckts.h
, is widely used in RealSystem. The IRMAValues
interface lets RealSystem components create general lists that pair names with values. For example, when a file format plug-in receives a buffer of stream header data from a file system plug-in, it creates an IRMAValues
object that contains the buffer data along with other data needed by the rendering plug-in. Each value in an IRMAValues
name/value pair is one of the following:
A RealSystem component does the following to create an IRMAValues
object:
IRMAValues
interface through IRMACommonClassFactory
as described in "Creating a RealSystem Object".
IRMAValues::SetPropertyULONG32
, IRMAValues::SetPropertyBuffer
, or IRMAValues::SetPropertyCString
method as many times as necessary to add name/value pairs to the object.
![]() |
Note |
---|
As with IRMABuffer , it is intended that only the creator of the IRMAValues
interface sets its contents.
|
IUnknown::Release
.
The following example, taken from an SDK sample file, illustrates how to create and populate an IRMAValues
interface that contains an unsigned long and a pointer to an arbitrary buffer:
IRMAValues
* pHeaderObj = NULL;
m_pClassFactory-CreateInstance(CLSID_IRMAValues
, (void**)&pHeaderObj);
if (pHeaderObj != NULL)
{IRMAPlugin
pHeaderObj-SetPropertyULONG32("StreamCount", 1);IRMAPlugin
pHeaderObj-SetPropertyBuffer("OpaqueData", pHeaderDataReadFromFile);
After receiving a pointer to the IRMAValues
interface, a RealSystem component can retrieve a value by name with IRMAValues::GetProperty<
type
>
, where <
type
>
is ULONG32
, Buffer
, or CString
. A component can go through the name/value list with IRMAValues::GetFirstProperty<
type
>
and IRMAValues::GetNextProperty<
type
>
.
RealSystem components use the IRMAPacket
interface, defined in rmapckts.h
, to create data packets streamed between RealServer and its clients. A file format plug-in, for example, prepares packets that RealServer streams to the client. As well, a client's rendering plug-in can use the system's back channel to send packets of information back to its file format plug-in.
![]() |
Additional Information |
---|
See "Sending BackChannel Packets". |
A RealSystem component does the following to create a packet:
IRMAPacket
interface through IRMACommonClassFactory
as described in "Creating a RealSystem Object".
IRMAPacket::Set
to pass the packet a pointer to an IRMABuffer
interface and define the packet properties, such as delivery time and Adaptive Stream Management rules. The packet properties help RealSystem stream packets efficiently. See rmapckts.h
for more information on packet properties.
![]() |
Note |
---|
As with IRMABuffer , it is intended that only the creator of the IRMAPacket
interface sets its contents. This is critical with packets because more than
one renderer may use a packet object.
|
IUnknown::Release
.
The following example, taken from an SDK sample file, illustrates how to create an IRMAPacket
interface:
IRMAPacket* pPacketObj = NULL;
m_pClassFactory-CreateInstance(CLSID_IRMAPacket, (void**)&pPacketObj);
if (pPacketObj != NULL)
{IRMAPlugin
UINT32 deliveryTime = m_NextPacketDeliveryTime;IRMAPlugin
UINT16 streamNoIRMAPlugin
= MY_STREAM_NO;IRMAPlugin
UINT8 ASMFlags = RMA_ASM_SWITCH_ON;IRMAPlugin
UINT16 ASMRuleNo = 0;IRMAPlugin
pPacketObj-Set(pPacketDataReadFromFile, deliveryTime, streamNo, ASMFlags, ASMRuleNo);
After receiving a pointer to the packet interface, a RealSystem component, typically a rendering plug-in, retrieves the packet data with IRMAPacket::Get
. Other methods let a component retrieve specific packet properties. A component can also call IRMAPacket::IsLost
to determine if the packet has been lost. See the rendering plug-in chapter for more information.
Keep the following general points in mind as you develop your plug-ins. Each section on building a plug-in may also have design considerations specific to that type of plug-in.
![]() |
Additional Information |
---|
See "Chapter 13: Audio Services". |
![]() |
Additional Information |
---|
See also "Creating a Plug-In Instance" before you start to build your plug-in. |
The following sections give pointers on compiling your plug-in. Before you start building your own plug-in, you should test-compile some RealSystem G2 SDK sample files. The simplest sample file is the "Hello World" sample.
The RealSystem SDK includes many sample files that you can use as a basis for writing your own plug-ins. The simplest is the "Hello World" plug-in, which prints "Hello World" on the RealServer console. RealNetworks recommends that, before you start building your plug-ins, you learn the basic RealSystem features by modifying, compiling, and testing the "Hello World" sample:
This sample introduces the IUnknown::QueryInterface
, IUnknown::AddRef
, and IUnknown::Release
methods of COM. It also shows how RealServer instantiates a plug-in and discovers its features through the IRMAPlugin
interface. When RealServer starts up, it loads the plug-in as follows:
RMACreateInstance
to create a new instance of the plug-in. See "Creating a Plug-In Instance" for more on this method.
IRMAPlugin::GetPluginInfo
, which returns descriptive information about the plug-in, including its copyright and "more information" URL. The LoadMultiple
attribute must be set to TRUE
for RealServer to launch multiple instances of the plug-in.
IRMAPlugin::InitPlugin
method, passing it a pointer to the RealServer context. The plug-in uses this pointer to query for IRMAErrorMessages
on RealServer and, if it finds that interface, prints "Hello World" on the system console and in the log file.
The sample file contains comments that explain each function. Carry out the following steps to modify and test the sample:
zm_pDescription
, zm_pCopyright
, and zm_pMoreInfoURL
.
![]() |
Additional Information |
---|
See "Compiling a Plug-In" and "Installing Plug-Ins for Testing". |
All RealSystem sample files use the following conventions.
On Windows, RealNetworks recommends using with Microsoft's Visual C++ 4.2 or 6.0.
![]() |
Additional Information |
---|
http://www.microsoft.com/products/ |
sdk\samples\intermed\exffplin\win32\exffplin.mak
To build using Visual C++ from the command line, enter the following command:
nmake /f "makefile.mak" CFG="configuration"
nmake /f "exffplin.mak" CFG="exffplin - Win32 Debug"
nmake /f "exffplin.mak" CFG="exffplin - Win32 Release"
RealSystem G2 SDK sample files were test-compiled with GNU's gcc for UNIX. The UNIX makefile for each sample file is located in the unix
subdirectory under the sample directory. To build the sample with gcc, use this command:
make -f unix/Makefile.<ext
>
where .ext
is the extension that identifies your UNIX platform.
![]() |
Additional Information |
---|
http://www.gnu.org/ |
For the Macintosh, RealSystem G2 SDK sample files were test-compiled with Metrowerk's CodeWarrior 11 and CodeWarrior 12 for Macintosh
![]() |
Additional Information |
---|
http://www.metrowerks.com |
mac
folder within the sample folder.
You should be able to debug your plug-ins by using your standard debugger. In Visual C++ you can simply set up the debugging settings in your DLL's makefile or project to use realplay.exe as your application for debugging.
When you test your plug-ins, do as much "real world" empirical testing of your datatype as possible. Be sure to test under conditions that are less than ideal. For example, try dialing up on 28.8 Kbps modems and playing your datatype over the Internet from a RealServer on a Pentium-75 class machine.
The following are general guidelines for testing how your plug-ins work. This is not a comprehensive list, as testing strategies vary depending on the datatype.
![]() |
Additional Information |
---|
See "Appendix E: RealServer Configuration". |
![]() |
Additional Information |
---|
See "Installing RealPlayer on Windows" for more on the default directory. |
![]() |
Additional Information |
---|
See "Installing RealPlayer on Macintosh" for more on this default folder. |
With TestPlay, you can test streaming datatypes in a client environment other than RealPlayer. For example, you can use TestPlay to mimic the delivery of streaming data directly within a Web browser. After installing TestPlayer as described in "Installing TestPlay", you can run it from a command line with this syntax:
testplay <URL
>
where <URL> is the network or local file to play. Here are some examples:
testplay rtsp://real.myserver.com/clips/newvideo.rm
testplay file:c:\real\rmplayer\welcome.rm
TestPlay opens any required windows and plays the specified presentation. It writes the data from the IRMAClientAdviseSink
interface to the console to demonstrate the information available to a custom client application.
After you have successfully tested your plug-ins by streaming and reading a simple file of your datatype, create multimedia presentations that include your datatype. Then play your presentations using RealPlayer and TestPlay. You define the content of the presentation using SMIL.
You should test that your datatype streams properly from a Web server. Although HTTP streaming is not as robust as RTSP streaming, it provides a reasonable method to stream short clips. As shown in the following figure, RealPlayer must have the file format plug-in and rendering plug-in installed. The HTTP file system plug-in comes with RealPlayer. No plug-ins are used with the Web server, however.
Do the following to stream your datatype with HTTP:
<A HREF="http://hostname/file.smi">