VoIP Integration
|
QTelephony::RegistrationNone | Registration is not currently available. |
QTelephony::RegistrationHome | The user is registered to their home network. |
QTelephony::RegistrationSearching | The service is attempting to register but has not done so yet. |
QTelephony::RegistrationDenied | The service tried to register but was denied, probably because the user's authentication credentials were invalid. |
QTelephony::RegistrationUnknown | The registration state is unknown. This normally only makes sense for GSM networks. For VoIP implementations, use QTelephony::RegistrationNone instead. |
QTelephony::RegistrationRoaming | The user is registered to a network and can place calls, but it is not their usual home network. |
If the Asterisk service is set to the automatic registration mode, then these registration state changes will happen shortly after service initialization. If the service is set to the manual registration mode, then these registration state changes will only happen after the user launches the settings program and manually requests registration.
The other main component of network registration is the list of available network operators. This is used by settings programs to allow the user to choose an alternative network in their current location.
For Asterisk, there is only a single operator: the one configured by the user in the Asterisk.conf file. It therefore doesn't make sense to allow the user to choose another operator and we return an empty list from requestAvailableOperators().
For other VoIP implementations, especially those that can roam between public WiFi hotspots, it may make sense to return a non-empty list from requestAvailableOperators(), giving the user to ability to choose from a list of the networks that are in range.
Once the service has been checked, and the network registered, the next step is to enable the placement of phone calls. Qt Extended achieves this in telephony services with the QPhoneCallProvider interface. Our Asterisk agent needs to inherit from QPhoneCallProvider and override the create() method (iaxcallprovider.h and iaxcallprovider.cpp):
class IaxCallProvider : public QPhoneCallProvider { Q_OBJECT public: IaxCallProvider( IaxTelephonyService *service ); ~IaxCallProvider() {} void stateEvent( struct iaxc_ev_call_state *e ); protected: virtual QPhoneCallImpl *create ( const QString& identifier, const QString& callType ); }; IaxCallProvider::IaxCallProvider( IaxTelephonyService *service ) : QPhoneCallProvider( service->service(), service ) { setCallTypes( QStringList( "Asterisk" ) ); ... } QPhoneCallImpl *IaxCallProvider::create ( const QString& identifier, const QString& callType ) { return new IaxPhoneCall( this, identifier, callType, -1 ); }
The call to QPhoneCallProvider::setCallTypes() in the constructor is very important. It publishes the call types that are understood by the telephony service into the value space. Qt Extended uses this information to select an appropriate service to place an outgoing call. If the setCallTypes() function is not called in the constructor, then it will not be possible to place phone calls using the service.
Call types are typically simple names such as Voice, VoIP, Data, Fax, Video, etc. See the documentation for QPhoneCallManager::create() for a description of how call types are used to select an appropriate telephony service.
The VoIP call type is reserved for use by SIP-based telephony services. We cannot use that for our IAX2 implementation, so we publish the service's call type as Asterisk instead.
By convention, service names start with a lower-case letter, and call type names start with an upper-case letter. This convention is not strictly enforced by Qt Extended, but it can help when diagnosing telephony problems to be able to distinguish a word used as a service name and the same word used as a call type.
This code creates an instance of IaxPhoneCall whenever the user attempts to place an outgoing phone call. It will then be followed by a call to IaxPhoneCall::dial(). The IaxPhoneCall class is declared as follows:
class IaxPhoneCall : public QPhoneCallImpl { Q_OBJECT public: IaxPhoneCall( IaxCallProvider *provider, const QString& identifier, const QString& callType, int callNo ); virtual ~IaxPhoneCall(); virtual void dial( const QDialOptions& options ); virtual void hangup( QPhoneCall::Scope scope ); virtual void accept(); virtual void hold(); virtual void activate( QPhoneCall::Scope scope ); virtual void tone( const QString& tones ); virtual void transfer( const QString& number ); void stateEvent( struct iaxc_ev_call_state *e ); ... };
All telephony services must inherit from QPhoneCallImpl to provide the functions on phone calls. See the documentation for that class for more information on the functionality that is required.
The above applies to outgoing calls. For incoming calls, the Asterisk service detects the call in IaxCallProvider::stateEvent() and then constructs an instance of IaxPhoneCall directly:
void IaxCallProvider::stateEvent( struct iaxc_ev_call_state *e ) { IaxPhoneCall *call = fromCallNo( e->callNo ); if ( call ) { // State change on a known call. call->stateEvent( e ); } else if ( ( e->state & IAXC_CALL_STATE_RINGING ) != 0 ) { // Newly arrived incoming call. beginStateTransaction(); QString identifier = QUuid::createUuid().toString(); IaxPhoneCall *call = new IaxPhoneCall ( this, identifier, "Asterisk", e->callNo ); call->setNumber( e->remote ); call->setActions( QPhoneCallImpl::Transfer ); call->setState( QPhoneCall::Incoming ); endStateTransaction(); } }
While the IAX2 protocol does not support presence, most other VoIP protocols do. Presence can be handled by inheriting from QPresence:
class SipPresence : public QPresence { Q_OBJECT public: SipPresence( SipTelephonyService *service ); ~SipPresence(); public slots: virtual bool startMonitoring( const QString& uri ); virtual bool stopMonitoring( const QString& uri ); virtual void setLocalPresence( QPresence::Status status ); ... };
The VoIP agent must also add two lines to the initialize() function to create the presence interface at startup time:
if ( !supports<QPresence>() ) addInterface( new SipPresence( this ) );
See the documentation for QPresence for more information on the required functionality for the presence interface.
Configuration of VoIP services can be very complicated, which is why we recommend that you write a separate settings program that asks the user for the relevant details and then writes them to a configuration file that the agent daemon can access. For the Asterisk example, the source code for its settings program can be found under examples/asterisk/iaxsettings.
Once the configuration file has been updated, it is necessary to notify the agent daemon that it needs to reload the configuration. If your VoIP agent already has a way of performing this notification, then you can stop here. Or you can use the QTelephonyConfiguration interface that Qt Extended provides.
Our Asterisk agent daemon understands two configuration messages from the iaxsettings program: registration and callerid. The former changes the registration settings, and the latter changes the user's caller-id (name and number) information. We implement this in the IaxConfiguration class (iaxconfiguration.h and iaxconfiguration.cpp):
class IaxConfiguration : public QTelephonyConfiguration { Q_OBJECT public: IaxConfiguration( IaxTelephonyService *service ); ~IaxConfiguration() {} public slots: virtual void update( const QString& name, const QString& value ); virtual void request( const QString& name ); private: IaxTelephonyService *service; }; IaxConfiguration::IaxConfiguration( IaxTelephonyService *service ) : QTelephonyConfiguration( service->service(), service, Server ) { this->service = service; } void IaxConfiguration::update( const QString& name, const QString& ) { // Process messages from the "iaxsettings" program for config updates. if ( name == "registration" ) service->updateRegistrationConfig(); else if ( name == "callerid" ) service->updateCallerIdConfig(); } void IaxConfiguration::request( const QString& name ) { // Not supported - just return an empty value. emit notification( name, QString() ); }
There are two other forms of configuration that can be handled in a special manner: network registration changes and presence changes. The settings program can use QNetworkRegistration::setCurrentOperator() to register to and deregister from the network, and it can use QPresence::setLocalPresence() to update the user's presence state.
It is not a requirement that you use these configuration API's. If your VoIP agent has some other method for changing configuration settings, you are free to use that instead.
New VoIP services need some user interface support in the server to complete the integration. They do this by creating a server task that inherits from QAbstractCallPolicyManager.
The call policy manager tells Qt Extended when the service is active, when network registration changes occur, what call type to use for outgoing call requests, and the icons to display to represent network registration and call types. For Asterisk, the call policy manager is declared as follows (asteriskmanager.h in the server sources):
class AsteriskManager : public QAbstractCallPolicyManager { Q_OBJECT public: AsteriskManager( QObject *parent=0 ); ~AsteriskManager(); virtual QString callType() const; virtual QString trCallType() const; virtual QString callTypeIcon() const; virtual QTelephony::RegistrationState registrationState() const; virtual QAbstractCallPolicyManager::CallHandling handling(const QString& number); virtual bool isAvailable(const QString& number); virtual QString registrationMessage() const; virtual QString registrationIcon() const; ... }; QTOPIA_TASK_INTERFACE(AsteriskManager);
The most important function is QAbstractCallPolicyManager::handling(). This helps the server choose an appropriate telephony service when placing an outgoing call (incoming calls are handled implicitly by the service that first announced them). The handling() function inspects the phone number to determine if it can handle it at present. For Asterisk, the code is as follows (asteriskmanager.cpp):
QAbstractCallPolicyManager::CallHandling AsteriskManager::handling (const QString& number) { // Cannot handle URI's that contain '@' or ':'. if (number.contains(QChar('@')) || number.contains(QChar(':'))) return CannotHandle; // If no network registration, then cannot handle at this time. if (registrationState() != QTelephony::RegistrationHome) return CannotHandle; // Assume that this is a number that we can dial. return CanHandle; }
We first filter out URI's for SIP and other call types that do not use phone numbers. Then we check to see if the Asterisk service is currently registered to the user's home network. If it is, then we indicate that Asterisk can handle the call.
The return value is used by Qt Extended to select the appropriate telephony service to make the call. If two or more call policy managers return CanHandle, then the user will be presented with a list to choose from. In the case of Asterisk, this may happen if the user is registered to both Asterisk via WiFi and a GSM cellular network at the same time.
The allowable return values and their meanings are as follows:
QAbstractCallPolicyManager::CannotHandle | This telephony service cannot handle the requested number. |
QAbstractCallPolicyManager::CanHandle | This telephony service can handle the requested number. |
QAbstractCallPolicyManager::MustHandle | This telephony service must handle the requested number. This is typically used for special emergency calls that must be placed over a GSM network even if an Asterisk network is also registered at the same time. This value overrides the CanHandle answers from all other call policy managers. |
QAbstractCallPolicyManager::NeverHandle | This telephony service would normally return MustHandle because it is supposed to handle the call, but the call cannot be placed right now. This is typically used for emergency numbers when the phone device is in flight mode. This value causes Qt Extended to reject the call immediately without attempting to place it. |
The following summarises the steps involved in integrating a third-party VoIP agent into Qt Extended:
The following are the most common problems that you are likely to encounter while integrating a third-party VoIP agent:
Service not started | You must add a service definition file to $QPEDIR/services/Telephony to tell the Qt Extended server how to launch your telephony service daemon. |
Service starts and then immediately exits | You must use QtopiaApplication::registerRunningTask() to ensure that Qt Extended will keep the daemon running after the Telephony::start() QCop message is received. Upon shutdown, you can call QtopiaApplication::unregisterRunningTask() and your daemon will gracefully exit. |
Service not registered | The service will not be properly registered if you do not call the initialize() function on your QTelephonyService instance. You can detect if this is the case by using vsexplorer to inspect the value space underneath /Communications/QNetworkRegistration/asterisk where asterisk is replaced with the name of your service. There should be entries for requestChannel and responseChannel if the service is properly registered. |
Call types are not registered | It will not be possible to place phone calls if the call types have not been properly registered with setCallTypes(). You can detect this by using vsexplorer to inspect the value space underneath /Communications/QPhoneCallProvider/CallTypes. There should be an entry for your service name (asterisk in our example} listing the supported call types. |
Incoming calls are not announced | Make sure that you have created the QPhoneCallImpl instance correctly, and have emitted a state change using QPhoneCallProvider::beginStateTransaction() and QPhoneCallProvider::endStateTransaction(). The same applies when calls change state. If the state transaction is not sent, the rest of Qt Extended will be unaware that the call has changed state. |
Call policy manager not registered | Make sure that QTOPIA_TASK_INTERFACE(AsteriskManager) appears in the .h file and that QTOPIA_TASK(Asterisk, AsteriskManager), QTOPIA_TASK_PROVIDES(Asterisk, AsteriskManager), and QTOPIA_TASK_PROVIDES(Asterisk, QAbstractCallPolicyManager) appear in the .cpp file, where Asterisk is replaced with the name of your telephony service. |
Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. | Qt qtextended4.4 | |
Copyright © 2012 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD. | ||
Vous avez déniché une erreur ? Un bug ? Une redirection cassée ? Ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP ! |
Copyright © 2000-2012 - www.developpez.com