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

📄 processing.cpp

📁 tapi3.0实现
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*


Copyright (c) 1999 - 2000  Microsoft Corporation


Module Name:

    Processing.cpp

Abstract:

    Implementation of the ITTAPIEventNotification interface. An application 
    must implement and register this interface in order to receive calls and 
    events related to calls. See TAPI documentation for more information on 
    this interface.
 
    This file also contains a collection of functions related to event 
    processing

*/


#include "common.h"

#include "Processing.h"

#include "WorkerThread.h"

#include "AVIFileWriter.h"


//
// the name of the file we will save the incoming audio to
//

#define SZ_OUTPUTFILENAME "recording.wav"


//
// the worker thread for asycnhronous message processing
//

CWorkerThread g_WorkerThread;


///////////////////////////////////////////////////////////////////////////////
//
// ITTAPIEventNotification::Event
//
// the method on the tapi callback object that will be called 
// when tapi notifies the application of an event 
//
// this method should return as soon as possible, so we are not 
// going to actually process the events here. Instead, we will post
// events to a worker thread for asynchronous processing.
//
// in a real life application that could be another thread, the
// application's main thread, or we could post events to a window.
//
///////////////////////////////////////////////////////////////////////////////

HRESULT STDMETHODCALLTYPE CTAPIEventNotification::Event(IN TAPI_EVENT TapiEvent,
                                                        IN IDispatch *pEvent)
{
    
    LogMessage("CTAPIEventNotification::Event "
               "posting message for asynchronous processing");

    
    //
    // AddRef the event so it doesn't go away after we return
    //

    pEvent->AddRef();


    //
    // Post a message to our own worker thread to be processed asynchronously
    //

    g_WorkerThread.PostMessage(WM_PRIVATETAPIEVENT,
                              (WPARAM) TapiEvent,
                              (LPARAM) pEvent);

    return S_OK;
}


///////////////////////////////////////////////////////////////////////////////
//
// GetTerminalFromStreamEvent
//
//
// given pCallMediaEvent, find the one and only terminal selected on its stream
//
// return the terminal and S_OK if success, error otherwise
//
///////////////////////////////////////////////////////////////////////////////

HRESULT GetTerminalFromStreamEvent(IN ITCallMediaEvent *pCallMediaEvent,
                                   OUT ITTerminal **ppTerminal)
{

    HRESULT hr = E_FAIL;

    
    //
    // don't return garbage
    //

    *ppTerminal = NULL;


    //
    // Get the stream for this event.
    //

    ITStream *pStream = NULL;
    
    hr = pCallMediaEvent->get_Stream(&pStream);

    if ( FAILED(hr) )
    {
        
        LogMessage("GetTerminalFromStreamEvent: "
                   "Failed to get stream from pCallMediaEvent hr = 0x%lx", hr);

        return hr;
    }


    //
    // Enumerate terminals on this stream.
    //

    IEnumTerminal *pEnumTerminal = NULL;

    hr = pStream->EnumerateTerminals(&pEnumTerminal);

    pStream->Release();
    pStream = NULL;

    if ( FAILED(hr) ) 
    {
        LogMessage("GetTerminalFromStreamEvent: "
                   "Failed to enumerate terminals hr = 0x%lx", hr);
        return hr;
    }

    
    //
    // we should have at most one terminal selected on the stream, so 
    // get the first terminal
    //

    ITTerminal *pTerminal = NULL;

    hr = pEnumTerminal->Next(1, &pTerminal, NULL);

    if ( hr != S_OK )
    {
        LogMessage("GetTerminalFromStreamEvent: "
                   "Failed to get a terminal from enumeration hr = 0x%lx", hr);

        pEnumTerminal->Release();
        pEnumTerminal = NULL;

        return E_FAIL;
    }

    *ppTerminal = pTerminal;

    pTerminal = NULL;

    
    //
    // we should not have any more terminals on this stream, 
    // double-check this.
    //

    hr = pEnumTerminal->Next(1, &pTerminal, NULL);

    if (hr == S_OK)
    {
        LogError("GetTerminalFromStreamEvent: "
                 "more than one terminal on the stream!");

        _ASSERTE(FALSE);

        pTerminal->Release();
        pTerminal = NULL;

    }

    pEnumTerminal->Release();
    pEnumTerminal = NULL;


    return S_OK;
}





///////////////////////////////////////////////////////////////////////////////
//
// IsMessageForActiveCall
//
// return TRUE if the event received is for the currently active call
//
///////////////////////////////////////////////////////////////////////////////

BOOL IsMessageForActiveCall(IN ITCallStateEvent *pCallStateEvent)
{
    
    EnterCriticalSection(&g_CurrentCallCritSection);
    
    //
    // if we don't have an active call we have not received call notification
    // for a call that we own, so return FALSE
    //

    if (NULL == g_pCurrentCall)
    {
        LogMessage("IsMessageForActiveCall: no active call. return FALSE");
    
        LeaveCriticalSection(&g_CurrentCallCritSection);


        return FALSE;
    }


    //
    // get the call corresponding to the event
    //
    
    ITCallInfo *pCallInfo = NULL;
    
    HRESULT hr = pCallStateEvent->get_Call(&pCallInfo);

    if (FAILED(hr))
    {
        LogError("IsMessageForActiveCall: failed to get call. "
                 "returning FALSE");
        
        LeaveCriticalSection(&g_CurrentCallCritSection);

        return FALSE;
    }


    //
    // get IUnknown of the call from the event
    //

    IUnknown *pIncomingCallUnk = NULL;

    hr = pCallInfo->QueryInterface(IID_IUnknown, (void**)&pIncomingCallUnk);

    pCallInfo->Release();
    pCallInfo = NULL;

    if (FAILED(hr))
    {
        LogError("IsMessageForActiveCall: "
                 "failed to qi incoming call for IUnknown. returning FALSE");

        LeaveCriticalSection(&g_CurrentCallCritSection);
        
        return FALSE;
    }


    //
    // get IUnknown of the call from the event
    //

    IUnknown *pCurrentCallUnk = NULL;

    hr = g_pCurrentCall->QueryInterface(IID_IUnknown, (void**)&pCurrentCallUnk);

    LeaveCriticalSection(&g_CurrentCallCritSection);

    if (FAILED(hr))
    {
        LogError("IsMessageForActiveCall: "
                 "Failed to QI current call for IUnknown. returning FALSE.");

        pIncomingCallUnk->Release();
        pIncomingCallUnk = NULL;


        return FALSE;
    }


    //
    // compare IUnknowns of the current call and the event call
    // if they are the same, this is the same call
    //

    BOOL bSameCall = FALSE;

    if (pCurrentCallUnk == pIncomingCallUnk)
    {
        bSameCall = TRUE;
    }
    else
    {
        LogMessage("IsMessageForActiveCall: "
                    "current and event calls are different. returning FALSE.");

        bSameCall = FALSE;
    }

    pCurrentCallUnk->Release();
    pCurrentCallUnk = NULL;
        
    pIncomingCallUnk->Release();
    pIncomingCallUnk = NULL;

    return bSameCall;
}


///////////////////////////////////////////////////////////////////////////////
//
// GetAddressFromCall
//
//
// return ITAddress of the address corresponding to the supplied 
// ITBasicCallControl
//
///////////////////////////////////////////////////////////////////////////////

HRESULT GetAddressFromCall(IN ITBasicCallControl *pCallControl, 
                           OUT ITAddress **ppAddress)
{

    HRESULT hr = E_FAIL;


    //
    // don't return garbage
    //

    *ppAddress = NULL;

    
    //
    // get ITCallInfo so we can get the call's address
    //
    
    ITCallInfo *pCallInfo = NULL;

    hr = pCallControl->QueryInterface(IID_ITCallInfo, (void**)&pCallInfo);

    if (FAILED(hr))
    {
        LogError("GetAddressFromCall: "
                 "Failed to QI call for ITCallInfo");

        return hr;
    }


    //
    // get the call's address
    //

    ITAddress *pAddress = NULL;

    hr = pCallInfo->get_Address(&pAddress);
    
    
    pCallInfo->Release();
    pCallInfo = NULL;


    if (FAILED(hr))
    {
        LogError("GetAddressFromCall: failed to get address");

    }
    else 
    {
        *ppAddress = pAddress;
    }

    return hr;
}


///////////////////////////////////////////////////////////////////////////////
//
// CreateRenderMediaStreamingTerminal
//
// create rendering media streaming terminal. 
//
// if success, return the pointer to the terminal
// if failed, return NULL
//
///////////////////////////////////////////////////////////////////////////////

ITTerminal *CreateRenderMediaStreamingTerminal(IN ITBasicCallControl *pCallControl)
{
    
    HRESULT hr = E_FAIL;


    //
    // get address from call
    //

    ITAddress *pAddress = NULL;

    hr = GetAddressFromCall(pCallControl, &pAddress);

    if (FAILED(hr))
    {
        LogError("CreateRenderMediaStreamingTerminal: failed to get address from call");

        return NULL;
    }

    
    //
    // get the terminal support interface from the address
    //

    ITTerminalSupport *pTerminalSupport = NULL;

    hr = pAddress->QueryInterface( IID_ITTerminalSupport,
                                   (void **)&pTerminalSupport );

    pAddress->Release();
    pAddress = NULL;

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

        return NULL;
    }

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

    WCHAR *pszTerminalClass = NULL;

    hr = StringFromIID(CLSID_MediaStreamTerminal, &pszTerminalClass);

    if (FAILED(hr))
    {
        LogError("CreateRenderMediaStreamingTerminal: "
                 "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 (pszTerminalClass);

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

    CoTaskMemFree(pszTerminalClass);
    pszTerminalClass = NULL;


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

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

    
    //
    // release resources no longer needed
    //

    SysFreeString(bstrTerminalClass);
    bstrTerminalClass = NULL;

    pTerminalSupport->Release();
    pTerminalSupport = NULL;


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

        return NULL;
    }


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

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

    return pTerminal;

}


///////////////////////////////////////////////////////////////////////////////
//
// SetAudioFormat
// 
// tell media streaming terminal the audio format we would like
// to receive
//
///////////////////////////////////////////////////////////////////////////////

HRESULT SetAudioFormat(IN ITTerminal *pTerminal)
{

    HRESULT hr = E_FAIL;
    
    
    //
    // get ITAMMediaFormat interface on the terminal
    //

    ITAMMediaFormat *pITMediaFormat = NULL;

    hr = pTerminal->QueryInterface(IID_ITAMMediaFormat, 
                                   (void **)&pITMediaFormat);

    if (FAILED(hr))
    {
        LogError("SetAudioFormat: failed to QI terminal for ITAMMediaFormat");
     
        return hr;
    }

    //
    // will ask media streaming terminal for audio in this format
    //

    WAVEFORMATEX WaveFormat;

    ZeroMemory(&WaveFormat, sizeof(WAVEFORMATEX));
    
    WaveFormat.wFormatTag = WAVE_FORMAT_PCM; // pcm
    WaveFormat.nChannels = 1;                // mono
    WaveFormat.nSamplesPerSec = 8000;        // 8 khz
    WaveFormat.nAvgBytesPerSec = 16000;      // 16000 bytes per sec
    WaveFormat.nBlockAlign = 2;              // 2 bytes per block 
    WaveFormat.wBitsPerSample = 16;          // 16 bits per sample
    WaveFormat.cbSize = 0;                   // no extra format-specific data

⌨️ 快捷键说明

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