⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tapisend.cpp

📁 tapi3.0实现的数据发送程序
💻 CPP
📖 第 1 页 / 共 4 页
字号:
    
    pAddress->Release();
    pAddress = NULL;


    if (FAILED(hr))
    {
        LogError("CreateCaptureMediaStreamingTerminal: "
                 "failed to QI pAddress for ITTerminalSupport");

        return NULL;
    }

    
    //
    // get string for the terminal's class id
    //

    LPOLESTR psTerminalClass = NULL;

    hr = StringFromIID(CLSID_MediaStreamTerminal, &psTerminalClass);

    if (FAILED(hr))
    {
        LogError("CreateCaptureMediaStreamingTerminal: "
                 "Failed to generate string from terminal's class id");

        pTerminalSupport->Release();
        pTerminalSupport = NULL;

        return NULL;
    }


    //
    // make bstr out of the class id
    //

    BSTR bstrTerminalClass = SysAllocString (psTerminalClass);


    //
    // free the string returned by StringFromIID
    //

    CoTaskMemFree(psTerminalClass);
    psTerminalClass = NULL;


    if (NULL == bstrTerminalClass)
    {

        LogError("CreateCaptureMediaStreamingTerminal: "
                 "Failed to allocate BSTR for terminal class");

        pTerminalSupport->Release();
        pTerminalSupport = NULL;

        return NULL;
    }

    

    //
    // create media streaming terminal
    //
    
    ITTerminal *pTerminal = NULL;

    hr = pTerminalSupport->CreateTerminal(bstrTerminalClass,
                                          TAPIMEDIATYPE_AUDIO,
                                          TD_CAPTURE,
                                          &pTerminal);

    
    //
    // release resources no longer needed
    //

    SysFreeString(bstrTerminalClass);

    pTerminalSupport->Release();
    pTerminalSupport = NULL;


    if (FAILED(hr))
    {
        LogError("CreateCaptureMediaStreamingTerminal: "
                 "failed to create media streaming terminal hr = 0x%lx", hr);

        return NULL;
    }


    //
    // successfully created media streaming terminal. return.
    //

    LogMessage("CreateCaptureMediaStreamingTerminal: "
               "Terminal created successfully");

    return pTerminal;

}



///////////////////////////////////////////////////////////////////////////////
//
// SetTerminalFormat
//
// tell media streaming terminal the format of the data we are going to provide
//
///////////////////////////////////////////////////////////////////////////////

HRESULT SetTerminalFormat(IN ITTerminal *pTerminal, 
                          IN WAVEFORMATEX *pWaveFormat)
{

    HRESULT hr = E_FAIL;


    //
    // log format requested
    //

    LogMessage("SetTerminalFormat: starting.");
    LogFormat(pWaveFormat);

    
    ITAMMediaFormat *pIMediaFormat = NULL;
    
    hr = pTerminal->QueryInterface(IID_ITAMMediaFormat, 
                                   (void **)&pIMediaFormat);

    if (FAILED(hr)) 
    { 
    
        LogError("SetTerminalFormat: Failed to set terminal format");

        return hr; 
    }


    //
    // fill the media format structure 
    //

    AM_MEDIA_TYPE MediaType;

    ZeroMemory(&MediaType, sizeof(AM_MEDIA_TYPE));

    MediaType.majortype            = MEDIATYPE_Audio;
    MediaType.subtype              = MEDIASUBTYPE_PCM;
    MediaType.bFixedSizeSamples    = TRUE;
    MediaType.bTemporalCompression = FALSE;
    MediaType.lSampleSize          = pWaveFormat->nBlockAlign;
    MediaType.formattype           = FORMAT_WaveFormatEx;
    MediaType.pUnk                 = NULL;

    MediaType.cbFormat             = sizeof(WAVEFORMATEX) + 
                                     pWaveFormat->cbSize;

    MediaType.pbFormat             = (BYTE*)pWaveFormat;

    
    //
    // set the requested format 
    //

    hr = pIMediaFormat->put_MediaFormat(&MediaType);
    
    if (FAILED(hr))
    {

        //
        // try to see what format the terminal wanted
        //

        LogError("SetTerminalFormat: failed to set format");

        AM_MEDIA_TYPE *pMediaFormat = NULL;

        HRESULT hr2 = pIMediaFormat->get_MediaFormat(&pMediaFormat);


        if (SUCCEEDED(hr2))
        {

            if (pMediaFormat->formattype == FORMAT_WaveFormatEx)
            {

                //
                // log the terminal's format
                //

                LogError("SetTerminalFormat: terminal's format is");
                LogFormat((WAVEFORMATEX*) pMediaFormat->pbFormat);

            }
            else 
            {

                LogError("SetTerminalFormat: "
                         "terminal's format is not WAVEFORMATEX");
            }


            //
            // note: we are responsible for deallocating the format returned by
            // get_MediaFormat
            //

            DeleteMediaType(pMediaFormat);

        } //  succeeded to get terminal's format
        else
        {

            LogError("SetTerminalFormat: failed to get terminal's format");

        }

    } // failed to set format


    pIMediaFormat->Release();
    pIMediaFormat = NULL;

    LogMessage("SetTerminalFormat: completed");
    
    return hr;
}


///////////////////////////////////////////////////////////////////////////////
//
// SetAllocatorProperties
//
// sets allocator properties to the terminal
//
///////////////////////////////////////////////////////////////////////////////

HRESULT SetAllocatorProperties(IN ITTerminal *pTerminal)
{

    //
    // different buffer sizes may produce different sound quality, depending
    // on the underlying transport that is being used.
    // 
    // this function illustrates how an app can control the number and size of
    // buffers. A multiple of 30 ms (480 bytes at 16-bit 8 KHz PCM) is the most
    // appropriate sample size for IP (especailly G.723.1).
    //
    // However, small buffers can cause poor audio quality on some voice boards.
    //
    // If this method is not called, the allocator properties suggested by the 
    // connecting filter will be used.
    //
    // Note: do not set allocator properties in the applications unless you are
    // sure that sound quality will not degrade as a result. Some MSPs can have
    // their own preferred allocator properties, and will not be able to 
    // provide the best quality if the app sets its own properties, different 
    // from what is preferred by the msp.
    //
    // Also note that ITAllocatorProperties::SetBufferSize allows the app to
    // specify preferred size of the buffer allocated to the application 
    // without affecting terminal's allocator properties.
    //
    
    LogMessage("SetAllocatorProperties: starting.");


    HRESULT hr = E_FAIL;


    //
    // get ITAllocator properties interface on the terminal
    //

    ITAllocatorProperties *pITAllocatorProperties = NULL;


    hr = pTerminal->QueryInterface(IID_ITAllocatorProperties, 
                                   (void **)&pITAllocatorProperties);


    if (FAILED(hr))
    {
        LogError("SetAllocatorProperties: "
                 "failed to QI terminal for ITAllocatorProperties");

        return hr;
    }

    
    //
    // configure allocator properties
    //

    ALLOCATOR_PROPERTIES AllocProps;
    
    AllocProps.cbBuffer   = 4800;
    AllocProps.cBuffers   = 5;
    AllocProps.cbAlign    = 1;
    AllocProps.cbPrefix   = 0;

    
    hr = pITAllocatorProperties->SetAllocatorProperties(&AllocProps);

    if (FAILED(hr))
    {
        LogError("SetAllocatorProperties: failed to set allocator properties. "
                 "hr = 0x%lx", hr);

        pITAllocatorProperties->Release();
        pITAllocatorProperties = NULL;

        return hr;
    }

    
    //
    // ask media streaming terminal to allocate buffers for us. 
    // TRUE is the default, so strictly speaking, we didn't have to call 
    // this method.
    //

    hr = pITAllocatorProperties->SetAllocateBuffers(TRUE);


    pITAllocatorProperties->Release();
    pITAllocatorProperties = NULL;

    
    if (FAILED(hr))
    {
        LogError("SetAllocatorProperties: failed to SetAllocateBuffers, "
                 "hr = 0x%lx", hr);

        return hr;
    }


    //
    // succeeded setting allocator properties
    //

    LogMessage("SetAllocatorProperties: completed");

    return S_OK;
}


///////////////////////////////////////////////////////////////////////////////
//
// ReadFileIntoTerminal
//
// read data from the file and submit it to media streaming terminal
// 
// exit when finished reading the file, user requested exit by pressing 
// ctrl+break, or the connection broke
//
// returns S_FALSE when finished streaming the file, S_OK if user requested 
// exit, failure otherwise
//
///////////////////////////////////////////////////////////////////////////////

HRESULT ReadFileIntoTerminal(IN CAVIFileReader *pFileReader, 
                             IN ITTerminal *pPlaybackTerminal)
{

    HRESULT hr = E_FAIL;

    LogMessage("ReadFileIntoTerminal: started.");


    Sleep(20000);


    //
    // get terminal's IMediaStream interface
    //

    IMediaStream *pTerminalMediaStream = NULL;

    hr = pPlaybackTerminal->QueryInterface(IID_IMediaStream, 
                                           (void**)&pTerminalMediaStream);

    if (FAILED(hr))
    {
        LogError("ReadFileIntoTerminal: "
                 "failed to QI terminal for IMediaStream");

        return hr;
    }

    
    //
    // create a queue (STL deque) that will hold all the samples that we ever 
    // submitted to media streaming terminal
    //
    // we need this so when we are finished reading the file, we can go through 
    // the list of all the samples that we have submitted and make sure mst 
    // is finished processing them
    //
    // note that samples get reused, the same samples will be put in the queue 
    // more than once. so the size of the queue will be proportional to the 
    // size of the file being played. this might cause problems if
    // the file is big or the source of the samples is unlimited (live audio
    // feed). In this case, the logic can be modified to only enqueue each
    // sample once, by comparing against existing queue entries.
    // 
    
    std::deque<IStreamSample*> SampleQ;


    //
    // count the number of samples that have been submitted
    //

    ULONG nSampleCount = 0;

    
    //
    // keep reading samples from file and sending them.
    // (until user requests exit, there is no more data, or failure)
    //

    while (!g_bExitRequested)
    {
       
        //
        // allocate a sample on the terminal's media stream
        //
        // Note: the call to AllocateSample() will block if we filled all the 
        // samples with data, and there are no more samples for us to fill 
        // (waiting for media streaming terminal to process samples we have
        // submitted). When MST is is done with at least one sample, the call 
        // will return. This logic will ensure that MST always has work and is
        // never starved for samples.
        //

        IStreamSample *pStreamSample = NULL;

        hr = pTerminalMediaStream->AllocateSample(0, &pStreamSample);

        if (FAILED(hr))
        {
            LogError("ReadFileIntoTerminal: "
                     "failed to allocate a sample on terminal's stream");

            break;
        }


        //
        // get IMemoryData on the sample so we can get to the sample's memory 
        // data
        //

        IMemoryData *pSampleMemoryData = NULL;

        hr = pStreamSample->QueryInterface(IID_IMemoryData, 
                                           (void**)&pSampleMemoryData);

        if (FAILED(hr))
        {
            LogError("ReadFileIntoTerminal: failed to qi sample for IMemoryData");

            pStreamSample->Release();
            pStreamSample = NULL;

            break;

        }


        //
        // get to the sample's memory buffer
        //

        DWORD nBufferSize = 0;

        BYTE *pBuffer = NULL;

        hr = pSampleMemoryData->GetInfo(&nBufferSize, &pBuffer, NULL);

        if (FAILED(hr))
        {

            LogError("ReadFileIntoTerminal: "
                     "failed to get info on sample's memory");

            pStreamSample->Release();
            pStreamSample = NULL;

            pSampleMemoryData->Release();
            pSampleMemoryData = NULL;

            break;

        }


        //
        // read file into memory buffer provided by the sample
        //

        LONG nBytesRead = 0;
        
        hr = pFileReader->Read(pBuffer, nBufferSize, &nBytesRead);

        if (FAILED(hr))
        {
            LogError("ReadFileIntoTerminal: failed to read data from file");

            pStreamSample->Release();
            pStreamSample = NULL;

            pSampleMemoryData->Release();
            pSampleMemoryData = NULL;

            break;

        }
        else if (S_FALSE == hr)
        {
            //
            // no more data
            //

            LogMessage("ReadFileIntoTerminal: finished reading file");

            pStreamSample->Release();
            pStreamSample = NULL;

            pSampleMemoryData->Release();
            pSampleMemoryData = NULL;

            break;
        }


        
        //
        // tell the sample how many useful bytes are in the sample's buffer
        //
        
        hr = pSampleMemoryData->SetActual(nBytesRead);

        pSampleMemoryData->Release();
        pSampleMemoryData = NULL;

        if (FAILED(hr))
        {

            LogError("ReadFileIntoTerminal: failed to SetActual (%ld bytes) "
                     "on the sample.", nBytesRead);

            pStreamSample->Release();
            pStreamSample = NULL;

            break;

        }

        
        //
        // we are done with the sample. now let media streaming terminal 
        // process it asynchronously. when the terminal is finished with 
        // the sample, this sample will be returned to us from the call 
        // to AllocateSample()
        //

        hr = pStreamSample->Update(SSUPDATE_ASYNC, NULL, NULL, 0);


        //
        // with some MSPs, starting the stream can be done asynchronously, so
        // there may be a delay between the time when terminal is selected
        // (or call connected) and the time when the stream becomes usable.
        //
        // attempting to use the stream before the stream is active would
        // result in the Update() returning error VFW_E_NOT_COMMITTED.
        //
        // Usually an application would not start using the stream until 
        // it gets media event CME_STREAM_ACTIVE. This requires the app
        // to register a callback interface by calling 
        // ITTAPI::RegisterCallNotifications. Refer to documentation and other 
        // samples for more details on how this is done.
        //
        // To keep things simple, this sample doesn't do event processing.
        // To deal with the problem of using the stream before it becomes 
        // active, we retry Update() until we succeed.
        //
        // Note that there is still a danger that the stream becomes 
        // disconnected before we process the first sample, in which case
        // we will be stuck in a loop, which can be exited when the user
        // presses ctrl+break
        //

        while ( (hr == VFW_E_NOT_COMMITTED)
                && (0 == nSampleCount) 
                && !g_bExitRequested )
        {
            LogMessage("ReadFileIntoTerminal: "
                       "Update returned VFW_E_NOT_COMMITTED. "
                       "Likely cause: stream not yet started. Retrying.");

            Sleep( 1000 );

            hr = pStreamSample->Update(SSUPDATE_ASYNC, NULL, NULL, 0);
        }

        if (FAILED(hr))
        {
            LogError("ReadFileIntoTerminal: failed to Update the sample");

            pStreamSample->Release();
            pStreamSample = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -