___________________________________________________ Copyright (C) 1999 Microsoft Corporation. All rights reserved. ___________________________________________________ TAPI 3.0 TAPISend Media Streaming Terminal Sample Application Overview: The purpose of TAPISend sample is to illustrate the use of Media Streaming Terminal for injecting live audio data into a TAPI media stream. TAPISend initiates a TAPI call, opens a wave file and uses Media Streaming Terminal (MST) to send audio data from the file to the remote machine. When the file is processed, TAPISend disconnects the call and exits TAPISend is a command line application. It produces extensive logging to the console window and can be terminated by pressing ctrl+break or closing the application's windows. To run the sample, start TAPIRecv.exe and specify the name of the file to be sent, destination address, and address type as command line arguments: TAPISend <file_name> <destination_address> <address_type> The following address types are allowed (the application is not case-insensitive): PHONENUMBER, CONFERENCE, EMAIL, MACHINE, and IP. Usage examples: TAPISend sound.wav 212-121-1212 phonenumber TAPISend music.wav MYMACHINE machine TAPISend recording.wav 127.0.0.1 IP If the application is started with the number of arguments other than three, it displays usage information. For information on using Media Streaming Terminal to extract data from a TAPI stream, refer to the TAPIRecv sample. Building the Sample To build the sample, set the Platform SDK build environment, then run nmake from the sample's directory. This will build TAPISend.exe. Application Flow The application attempts to make a TAPI call to the destination specified in the command line. Note that for simplicity TAPISend does not do TAPI message processing (it does not create and register with TAPI an object implementing ITTAPIEventNotification). All processing is done on a single thread. Please check documentation, TAPIRecv and other samples for more information on TAPI event notification processing. When the call is connected, TAPISend creates an MST for capture. (The word "capture" is used in DirectShow sense, and indicates the fact that MST "captures" application's data to be introduced into TAPI data stream. See function CreateCaptureMediaStreamingTerminal.) Once a terminal is constructed, the application opens the input file (see CAVIFileReader class for details on media file handling) to get the format of the audio stream that we are about to start sending. The data format is then communicated to the terminal by calling ITAMMediaFormat::put_MediaFormat(). A failure to set format on the terminal may mean that the underlying MSP used for the call requires a specific wave format (as is the case with H323 MSP which requires 16-bit mono 8000 samples per second PCM data). TAPISend uses terminal's ITAllocatorProperties interface to suggest allocator properties for the terminal (number and size of data buffers). If the application chooses to configure allocator properties, it needs to do this before the call is connected and terminal is selected. The default behavior (and the behavior shown in the sample) is to have MST allocate buffers for the data. The application, however, can do its own memory allocation. In this case the application needs to call ITAllocatorProperties::SetAllocateBuffers(FALSE). Later, during sample processing, the application would instruct MST's samples to use application-allocated buffers by calling IMemoryData::SetBuffer on MST samples. Once audio format is configured and allocator properties are suggested, the application selects the terminal on the call's first outgoing audio stream. Reading the samples from the file and submitting them to the MST is done in ReadFileIntoTerminal. In a loop, until connection breaks, or exit is requested, we use terminal's IMediaStream interface to "allocate" samples on the terminal (a call to IMediaStream::AllocateSample, which, in effect returns us a pointer o IStreamSample interface of a sample. The terminal has a limited number of samples. This number can be set and verified via the terminal's ITAllocatorProperties interface. If the application gets ahead of the terminal and all samples have been filled with data and submitted to MST but not yet processed, the call to AllocateSample will block until the MST completes processing of at least one sample and the processed sample becomes available to the application to be refilled. We use the sample's IMemoryData interface to get to its buffer, which is filled with audio data from the file by AVI file reader. After the data is copied to the sample's buffer, the application "returns" the sample to the MST by calling Update() on its the sample's IStreamSample interface. This tells the Media Streaming Terminal that the sample is ready for processing (injecting into TAPI media stream and sending to the destination). Note that if Update() is called while the stream is not yet active, it returns the VFW_E_NOT_COMMITTED error code. Since TAPISend does not process events, and therefore not notified of when the stream is started, the application uses this error code as a sign that the stream is not yet active, and keeps retrying until Update() succeeds. Again, the recommended procedure is to wait for CME_STREAM_ACTIVE call media event before starting sending samples to the MST. To keep track of samples that we have submitted, we also put the sample into a list. This will allow us to insure that, when the whole file is submitted, we don't terminate the call until all samples are completely processed by the MST. This is achieved by calling method IStreamSample::CompletionStatus() on all the samples submitted during file read. Note that the list of samples will have duplicate samples. The correctness of the application does not suffer, but the performance does, and this should be addressed in a real-life application (by making sure the list only has unique entries, for instance). When all samples are submitted, or the user requested exit, we disconnect the call, uninitialize TAPI, and exit. Note that since we don't process events we don't know when the receiving side received all the samples we submitted. So we wait several seconds before disconnecting the call.