    AbstractCallPeer<?, ?> createOutgoingCall(
            CallJabberImpl call,
            String calleeAddress,
            Iterable<PacketExtension> sessionInitiateExtensions)
        throws OperationFailedException
    {
        if (logger.isInfoEnabled())
            logger.info("creating outgoing call...");
        if (protocolProvider.getConnection() == null || call == null)
        {
            throw new OperationFailedException(
                    "Failed to create OutgoingJingleSession."
                        + " We don't have a valid XMPPConnection.",
                    OperationFailedException.INTERNAL_ERROR);
        }
        boolean isGoogle = protocolProvider.isGmailOrGoogleAppsAccount();
        boolean isGoogleVoice = false;
        if(isGoogle)
        {
            if(!calleeAddress.contains("@"))
            {
                calleeAddress += "@" + GOOGLE_VOICE_DOMAIN;
                isGoogleVoice = true;
            }
            else if(calleeAddress.endsWith(GOOGLE_VOICE_DOMAIN))
            {
                isGoogleVoice = true;
            }
        }
        if(calleeAddress.indexOf('@') == -1)
        {
            String serviceName = null;
            String phoneSuffix =
                (String)getProtocolProvider().getAccountID().getAccountProperty(
                    "OVERRIDE_PHONE_SUFFIX");
            if(phoneSuffix == null || phoneSuffix.length() == 0)
            {
                serviceName = "@" + StringUtils.parseServer(
                    getProtocolProvider().getAccountID().getUserID());
            }
            else
            {
                serviceName = "@" + phoneSuffix;
            }
            calleeAddress += serviceName;
        }
        AccountID accountID = getProtocolProvider().getAccountID();
        String bypassDomain = accountID.getAccountPropertyString(
            "TELEPHONY_BYPASS_GTALK_CAPS");
        boolean alwaysCallGtalk = ((bypassDomain != null) &&
                bypassDomain.equals(calleeAddress.substring(
                    calleeAddress.indexOf('@') + 1))) || isGoogleVoice;
        String fullCalleeURI = null;
        DiscoverInfo di = null;
        int bestPriority = -1;
        if(!getProtocolProvider().getConnection().getRoster().contains(
            calleeAddress) && !alwaysCallGtalk)
        {
            throw new OperationFailedException(
                calleeAddress + " does not belong to our contact list",
                OperationFailedException.NOT_FOUND);
        }
        Iterator<Presence> it =
            getProtocolProvider().getConnection().getRoster().getPresences(
                calleeAddress);
        String calleeURI = null;
        boolean isGingle = false;
        String gingleURI = null;
        while(it.hasNext())
        {
            Presence presence = it.next();
            int priority = (presence.getPriority() == Integer.MIN_VALUE) ? 0 :
                presence.getPriority();
            calleeURI = presence.getFrom();
            DiscoverInfo discoverInfo = null;
            try
            {
                discoverInfo =
                    protocolProvider.getDiscoveryManager().
                        discoverInfo(calleeURI);
            }
            catch (XMPPException ex)
            {
                logger.warn("could not retrieve info for " + fullCalleeURI, ex);
            }
            boolean hasGtalkCaps =
                getProtocolProvider().isExtFeatureListSupported(
                    calleeURI, ProtocolProviderServiceJabberImpl.
                        CAPS_GTALK_WEB_VOICE);
            if (discoverInfo != null && discoverInfo.containsFeature(
                ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE))
            {
                if(priority > bestPriority)
                {
                    bestPriority = priority;
                    di = discoverInfo;
                    fullCalleeURI = calleeURI;
                    isGingle = false;
                }
            }
            else
            {
                if(!protocolProvider.isGTalkTesting() && !alwaysCallGtalk)
                {
                    continue;
                }
                if(hasGtalkCaps || alwaysCallGtalk)
                {
                    if(priority > bestPriority)
                    {
                        bestPriority = priority;
                        isGingle = true;
                        gingleURI = calleeURI;
                    }
                }
            }
        }
        if(isGingle)
        {
            if(logger.isInfoEnabled())
            {
                logger.info(gingleURI + ": Google Talk dialect supported");
            }
            fullCalleeURI = gingleURI;
        }
        else if(di != null)
        {
            if (logger.isInfoEnabled())
                logger.info(fullCalleeURI + ": jingle supported ");
        }
        else
        {
            if (logger.isInfoEnabled())
                logger.info(calleeURI +
                        ": jingle and Google Talk not supported ?");
            throw new OperationFailedException(
                    "Failed to create OutgoingJingleSession.\n"
                        + calleeURI + " does not support jingle or Google Talk",
                    OperationFailedException.INTERNAL_ERROR);
        }
        if(logger.isInfoEnabled())
        {
            logger.info("Choose one is: " + fullCalleeURI + " " + bestPriority);
        }
        AbstractCallPeer<?, ?> peer = null;
        try
        {
            if(isGingle)
            {
                logger.info("initiate Gingle call");
                CallGTalkImpl callGTalk = new CallGTalkImpl(this);
                MediaUseCase useCase = call.getMediaUseCase();
                boolean isVideo = call.isLocalVideoAllowed(useCase);
                callGTalk.setLocalVideoAllowed(isVideo, useCase);
                peer = callGTalk.initiateGTalkSession(fullCalleeURI,
                       sessionInitiateExtensions);
            }
            else if(di != null)
            {
                peer
                    = call.initiateSession(
                            fullCalleeURI,
                            di,
                            sessionInitiateExtensions);
            }
        }
        catch(Throwable t)
        {
            if (t instanceof ThreadDeath)
                throw (ThreadDeath) t;
            throw new OperationFailedException(
                    "Failed to create a call",
                    OperationFailedException.INTERNAL_ERROR,
                    t);
        }
        return peer;
    }

    AbstractCallPeer<?, ?> createOutgoingCall(
            CallJabberImpl call,
            String calleeAddress,
            Iterable<PacketExtension> sessionInitiateExtensions)
        throws OperationFailedException
    {
        if (logger.isInfoEnabled())
            logger.info("creating outgoing call...");
        if (protocolProvider.getConnection() == null || call == null)
        {
            throw new OperationFailedException(
                    "Failed to create OutgoingJingleSession."
                        + " We don't have a valid XMPPConnection.",
                    OperationFailedException.INTERNAL_ERROR);
        }
        boolean isGoogle = protocolProvider.isGmailOrGoogleAppsAccount();
        boolean isGoogleVoice = false;
        if(isGoogle)
        {
            if(!calleeAddress.contains("@"))
            {
                calleeAddress += "@" + GOOGLE_VOICE_DOMAIN;
                isGoogleVoice = true;
            }
            else if(calleeAddress.endsWith(GOOGLE_VOICE_DOMAIN))
            {
                isGoogleVoice = true;
            }
        }
        if(calleeAddress.indexOf('@') == -1)
        {
            String serviceName = null;
            String phoneSuffix =
                (String)getProtocolProvider().getAccountID().getAccountProperty(
                    "OVERRIDE_PHONE_SUFFIX");
            if(phoneSuffix == null || phoneSuffix.length() == 0)
            {
                serviceName = "@" + StringUtils.parseServer(
                    getProtocolProvider().getAccountID().getUserID());
            }
            else
            {
                serviceName = "@" + phoneSuffix;
            }
            calleeAddress += serviceName;
        }
        AccountID accountID = getProtocolProvider().getAccountID();
        String bypassDomain = accountID.getAccountPropertyString(
            "TELEPHONY_BYPASS_GTALK_CAPS");
        boolean alwaysCallGtalk = ((bypassDomain != null) &&
                bypassDomain.equals(calleeAddress.substring(
                    calleeAddress.indexOf('@') + 1))) || isGoogleVoice;
        String fullCalleeURI = null;
        DiscoverInfo di = null;
        int bestPriority = -1;
        if(!getProtocolProvider().getConnection().getRoster().contains(
            StringUtils.parseBareAddress(calleeAddress)) && !alwaysCallGtalk)
        {
            throw new OperationFailedException(
                calleeAddress + " does not belong to our contact list",
                OperationFailedException.NOT_FOUND);
        }
        Iterator<Presence> it =
            getProtocolProvider().getConnection().getRoster().getPresences(
                calleeAddress);
        String calleeURI = null;
        boolean isGingle = false;
        String gingleURI = null;
        while(it.hasNext())
        {
            Presence presence = it.next();
            int priority = (presence.getPriority() == Integer.MIN_VALUE) ? 0 :
                presence.getPriority();
            calleeURI = presence.getFrom();
            DiscoverInfo discoverInfo = null;
            try
            {
                discoverInfo =
                    protocolProvider.getDiscoveryManager().
                        discoverInfo(calleeURI);
            }
            catch (XMPPException ex)
            {
                logger.warn("could not retrieve info for " + fullCalleeURI, ex);
            }
            boolean hasGtalkCaps =
                getProtocolProvider().isExtFeatureListSupported(
                    calleeURI, ProtocolProviderServiceJabberImpl.
                        CAPS_GTALK_WEB_VOICE);
            if (discoverInfo != null && discoverInfo.containsFeature(
                ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE))
            {
                if(priority > bestPriority)
                {
                    bestPriority = priority;
                    di = discoverInfo;
                    fullCalleeURI = calleeURI;
                    isGingle = false;
                }
            }
            else
            {
                if(!protocolProvider.isGTalkTesting() && !alwaysCallGtalk)
                {
                    continue;
                }
                if(hasGtalkCaps || alwaysCallGtalk)
                {
                    if(priority > bestPriority)
                    {
                        bestPriority = priority;
                        isGingle = true;
                        gingleURI = calleeURI;
                    }
                }
            }
        }
        if(isGingle)
        {
            if(logger.isInfoEnabled())
            {
                logger.info(gingleURI + ": Google Talk dialect supported");
            }
            fullCalleeURI = gingleURI;
        }
        else if(di != null)
        {
            if (logger.isInfoEnabled())
                logger.info(fullCalleeURI + ": jingle supported ");
        }
        else
        {
            if (logger.isInfoEnabled())
                logger.info(calleeURI +
                        ": jingle and Google Talk not supported ?");
            throw new OperationFailedException(
                    "Failed to create OutgoingJingleSession.\n"
                        + calleeURI + " does not support jingle or Google Talk",
                    OperationFailedException.INTERNAL_ERROR);
        }
        if(logger.isInfoEnabled())
        {
            logger.info("Choose one is: " + fullCalleeURI + " " + bestPriority);
        }
        AbstractCallPeer<?, ?> peer = null;
        try
        {
            if(isGingle)
            {
                logger.info("initiate Gingle call");
                CallGTalkImpl callGTalk = new CallGTalkImpl(this);
                MediaUseCase useCase = call.getMediaUseCase();
                boolean isVideo = call.isLocalVideoAllowed(useCase);
                callGTalk.setLocalVideoAllowed(isVideo, useCase);
                peer = callGTalk.initiateGTalkSession(fullCalleeURI,
                       sessionInitiateExtensions);
            }
            else if(di != null)
            {
                peer
                    = call.initiateSession(
                            fullCalleeURI,
                            di,
                            sessionInitiateExtensions);
            }
        }
        catch(Throwable t)
        {
            if (t instanceof ThreadDeath)
                throw (ThreadDeath) t;
            throw new OperationFailedException(
                    "Failed to create a call",
                    OperationFailedException.INTERNAL_ERROR,
                    t);
        }
        return peer;
    }
