Click here to Skip to main content
15,893,381 members
Articles / Desktop Programming / MFC

VideoIPPhone

Rate me:
Please Sign up or sign in to vote.
4.29/5 (7 votes)
12 Mar 2005CPOL 74.4K   8K   72  
VOIP using Microsoft TAPI
/*++

Copyright (c) 1999 - 2000 Microsoft Corporation.  All Rights Reserved.
Module Name:
    callnot.cpp
Abstract:
    Implementation of the ITTAPIEventNotification interface.
    This is an outgoing interface that is defined by TAPI 3.0.  This
    is basically a callback function that TAPI 3.0 calls to inform
    the application of events related to calls (on a specific address)
    Please refer to COM documentation for information on outgoing
    interfaces.
    An application must implement and register this interface in order
    to receive calls and events related to calls
--*/

#include "stdafx.h"
#include "callnot.h"

///////////////////////////////////////////////////////////////////
// DoMessage
///////////////////////////////////////////////////////////////////
void DoMessage(LPWSTR pszMessage)
{
//	char szMessage[255] = {0};
//	int nSize = wcslen(pszMessage);
//	wcstombs(szMessage, pszMessage, nSize);
//	MessageBox(g_hDlg,szMessage,"gszTapi30",MB_OK);
}

///////////////////////////////////////////////////////////////////
// HostWindow
//
// This method takes a pVideoWindow interface pointer and puts
//  the window in our dialog.
//
// The location depends on the iWhere parameter.
//
///////////////////////////////////////////////////////////////////
void HostWindow(IVideoWindow *pVideoWindow,int iWhere)
{
    
    pVideoWindow->put_Owner( (LONG_PTR)g_hDlg );
    pVideoWindow->put_WindowStyle( WS_CHILDWINDOW | WS_BORDER );

    long lWidth, lHeight;
    pVideoWindow->get_Width( &lWidth );
    pVideoWindow->get_Height( &lHeight );

  //  pVideoWindow->SetWindowPosition( VWP_LEFT + (iWhere * (VWP_LEFT + lWidth)),
  //                                   VWP_TOP,
  //                                   lWidth,
  //                                   lHeight );
//ROODOLF : ȭ�� ��ġ �̵�.
	if(iWhere)
	{ //���� ȭ��.
//		pVideoWindow->SetWindowPosition( VWP_LEFT + 178, VWP_TOP + (iWhere * (lHeight)), lWidth - 80, lHeight - 100);
		pVideoWindow->SetWindowPosition( VWP_LEFT + 188, VWP_TOP + 145, 80, 80);
	}
	else
	{
//		pVideoWindow->SetWindowPosition( VWP_LEFT + 160, VWP_TOP + (iWhere * (20 + lHeight)), lWidth - 20, lHeight - 20);
		pVideoWindow->SetWindowPosition( VWP_LEFT + 160, VWP_TOP, 140, 140);
	}
    pVideoWindow->put_Visible( VARIANT_TRUE );
}

///////////////////////////////////////////////////////////////////
// GetVideoRenderTerminalFromStreamEvent
//
// Find out if this stream has a video render terminal. If not,
// we don't need to do anything with this stream. Also note
// if this is the video capture stream or the video render
// stream.
//
///////////////////////////////////////////////////////////////////
HRESULT GetVideoRenderTerminalFromStreamEvent(ITCallMediaEvent  * pCallMediaEvent,ITTerminal ** ppTerminal,BOOL * pfRenderStream)
{
    HRESULT hr;

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

    ITStream * pStream;

    hr = pCallMediaEvent->get_Stream( &pStream );
    
    if ( FAILED(hr) || (pStream == NULL) )
    {
        return E_FAIL;
    }

    //
    // Find out if this is a video stream. If not, fail --
    // we don't care about this stream.
    //

    long lMediaType;

    hr = pStream->get_MediaType(&lMediaType);
    
    if ( FAILED(hr) )
    {
        pStream->Release();

        return hr;
    }

    if ( lMediaType != TAPIMEDIATYPE_VIDEO )
    {
        pStream->Release();

        return E_FAIL;
    }

    //
    // Find out the direction of this stream. We will return this info to the
    // caller.
    //

    TERMINAL_DIRECTION td;

    hr = pStream->get_Direction(&td);
    
    if ( FAILED(hr) )
    {
        pStream->Release();

        return hr;
    }

    *pfRenderStream = (td == TD_RENDER);

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

    IEnumTerminal * pEnumTerminal;

    hr = pStream->EnumerateTerminals( &pEnumTerminal );
    
    pStream->Release();
    
    if ( FAILED(hr) )
    {
        return hr;
    }

    //
    // Search for the first video render terminal and return it. If there are
    // none, fail -- we don't care about this stream.
    //

    while ( S_OK == pEnumTerminal->Next(1, ppTerminal, NULL) )
    {
        if ( SUCCEEDED( (*ppTerminal)->get_Direction(&td) ) )
        {
            if ( td == TD_RENDER )
            {
                // found it; done with enum, but keep ref on terminal
                pEnumTerminal->Release();

                return S_OK;
            }
        }

        // this is not the right one
        (*ppTerminal)->Release();
    }

    pEnumTerminal->Release();

    return E_FAIL; // no terminal found
}
                
///////////////////////////////////////////////////////////////////
// CallEventNotification
//
// The only method in the ITCallEventNotification interface.  This gets
// called by TAPI 3.0 when there is a call event to report. This just
// posts the message to our UI thread, so that we do as little as
// possible on TAPI's callback thread.
//
///////////////////////////////////////////////////////////////////

HRESULT STDMETHODCALLTYPE CTAPIEventNotification::Event(TAPI_EVENT TapiEvent,IDispatch * pEvent)
{
    //
    // Addref the event so it doesn't go away.
    //
    pEvent->AddRef();
    //
    // Post a message to our own UI thread.
    //
    PostMessage(g_hDlg,WM_PRIVATETAPIEVENT,(WPARAM) TapiEvent, (LPARAM) pEvent);
    return S_OK;
}

///////////////////////////////////////////////////////////////////
// OnTapiEvent
//
// This is the real event handler, called on our UI thread when
// the WM_PRIVATETAPIEVENT message is received
//
///////////////////////////////////////////////////////////////////

HRESULT OnTapiEvent(TAPI_EVENT TapiEvent,IDispatch * pEvent)
{
    HRESULT hr;

    switch ( TapiEvent )
    {
        case TE_CALLNOTIFICATION:
        {
            //
            // TE_CALLNOTIFICATION means that the application is being notified
            // of a new call.
            //
            // Note that we don't answer to call at this point.  The application
            // should wait for a CS_OFFERING CallState message before answering
            // the call.
            //

            ITCallNotificationEvent         * pNotify;
            
            hr = pEvent->QueryInterface( IID_ITCallNotificationEvent, (void **)&pNotify );

            if (S_OK != hr)
            {
                DoMessage( L"Incoming call, but failed to get the interface");
            }
            else
            {
                CALL_PRIVILEGE          cp;
                ITCallInfo *            pCall;

                //
                // get the call
                //

                hr = pNotify->get_Call( &pCall );

                pNotify->Release();

                if ( SUCCEEDED(hr) )
                {
                    //
                    // check to see if we own the call
                    //

                    hr = pCall->get_Privilege( &cp );

                    if ( FAILED(hr) || (CP_OWNER != cp) )
                    {
                        //
                        // just ignore it if we don't own it
                        //

                        pCall->Release();

                        pEvent->Release(); // we addrefed it CTAPIEventNotification::Event()

                        return S_OK;
                    }

                    //
                    // Get the ITBasicCallControl interface 
                    //

                    //
                    // If we're already in a call, disconnect the new call.  Otherwise,
                    // save it in our global variable.
                    //

                    ITBasicCallControl * pCallControl;

                    hr = pCall->QueryInterface( IID_ITBasicCallControl,
                                                (void**)&pCallControl );

                    pCall->Release();

                  
                    if ( SUCCEEDED(hr) )
                    {
                        if (g_pCall == NULL)
                        {
                            g_pCall = pCallControl;
                
                            //
                            // update UI
                            //
                        }
                        else
                        {
                            //
                            // Reject this call since we're already in a call
                            //

                            hr = pCallControl->Disconnect(DC_REJECTED);

                            pCallControl->Release();

                            if (FAILED(hr))
                            {
                                break;
                            }
                        }
                    }

                }
            }
            
            break;
        }
        
        case TE_CALLSTATE:
        {
            // TE_CALLSTATE is a call state event.  pEvent is
            // an ITCallStateEvent

            CALL_STATE           cs;
            ITCallStateEvent   * pCallStateEvent;
            ITCallInfo *         pCall;
            ITBasicCallControl * pCallControl;

            // Get the interface
            hr = pEvent->QueryInterface( IID_ITCallStateEvent, (void **)&pCallStateEvent );

            if ( FAILED(hr) )
            {
                break;
            }

            // get the CallInfo interface
            hr = pCallStateEvent->get_Call( &pCall );

            if ( FAILED(hr) )
            {
                pCallStateEvent->Release();
                break;
            }

            //get the ITBasicCallControl interface and compare it to our existing call
            hr = pCall->QueryInterface( IID_ITBasicCallControl,(void**)&pCallControl );

            pCall->Release();

            if (FAILED(hr))
            {
                pCallStateEvent->Release();
                break;
            }

            //ignore call state events for other calls
            if (pCallControl != g_pCall)
            {
                pCallControl->Release();
                pCallStateEvent->Release();
                break;
            }
            pCallControl->Release();

            //
            // This is a call state event for our call
            //

            // get the CallState that we are being notified of.
            hr = pCallStateEvent->get_State( &cs );

            // Release the interface
            pCallStateEvent->Release();

            if ( FAILED(hr) )
            {
                break;
            }

            // if it's offering, update our UI
            if (CS_OFFERING == cs)
            {
                if (1)
                {
                   PostMessage(g_hDlg, WM_ANSWER, 0, 0); 
                }
            }
            else if (CS_DISCONNECTED == cs)
            {
                PostMessage(g_hDlg, WM_DISCONNECT, 0, 0);
            }
            else if (CS_CONNECTED == cs)
            {
                // nothing to do -- we handle connection synchronously
            }
                
            break;
        }

        case TE_CALLMEDIA:
        {
            // TE_CALLMEDIA is a media event.  pEvent is
            // an ITCallMediaEvent

            CALL_MEDIA_EVENT    cme;
            ITCallMediaEvent  * pCallMediaEvent;

            // Get the interface
            hr = pEvent->QueryInterface( IID_ITCallMediaEvent, (void **)&pCallMediaEvent );

            if ( FAILED(hr) )
            {
                break;
            }

            // get the CALL_MEDIA_EVENT that we are being notified of.
            hr = pCallMediaEvent->get_Event( &cme );

            if ( SUCCEEDED(hr) )
            {
                switch ( cme )
                {
                case CME_STREAM_NOT_USED:
                case CME_STREAM_INACTIVE:
                case CME_NEW_STREAM:
                    break;

                case CME_STREAM_FAIL:
//					DoMessage( L"Call media event: stream failed");
                    break;
    
                case CME_TERMINAL_FAIL:
//                    DoMessage( L"Call media event: terminal failed");
                    break;

                case CME_STREAM_ACTIVE:
                {
                    //
                    // Find out if this stream has a video render terminal. If not,
                    // we don't need to do anything with this stream. Also note
                    // if this is the video capture stream or the video render
                    // stream.
                    //

                    ITTerminal * pTerminal;
                    BOOL         fRenderStream;

                    hr = GetVideoRenderTerminalFromStreamEvent(
                                                               pCallMediaEvent,
                                                               &pTerminal,
                                                               &fRenderStream
                                                              );
                
                    if ( SUCCEEDED(hr) )
                    {
                        // Get the video window interface for the terminal
                        IVideoWindow *pVideoWindow = NULL;

                        hr = pTerminal->QueryInterface(IID_IVideoWindow, (void**)&pVideoWindow);
                
                        pTerminal->Release();
            
                        if ( SUCCEEDED(hr) )
                        {
                            // Put this window in our dialog
							if(fRenderStream)
							{
								fRenderStream = 0;
							}
							else
							{
								fRenderStream = 1;
							}
                            HostWindow(pVideoWindow, fRenderStream);
                            pVideoWindow->Release();
                        }
                    }

                    break;
                }
            
                default:
                    break;
                }
            }

            // We no longer need this interface.
            pCallMediaEvent->Release();

            break;
        }

        default:
            break;
    }

    pEvent->Release(); // we addrefed it CTAPIEventNotification::Event()
    
    return S_OK;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer interpay
Korea (Republic of) Korea (Republic of)
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions