#include #include "contactsmanager.h" #include "voicecallmanager.h" #include "voicecallmanager_interface.h" #include "voicecall_interface.h" #include "profiled_interface.h" static ComNokiaProfiledInterface *profiled = NULL; static OrgNemomobileVoicecallVoiceCallManagerInterface *vcm = NULL; enum VoiceCallStatus { STATUS_NULL, STATUS_ACTIVE, STATUS_HELD, STATUS_DIALING, STATUS_ALERTING, STATUS_INCOMING, STATUS_WAITING, STATUS_DISCONNECTED }; VoiceCallManager::VoiceCallManager(ContactsManager *contacts, ToqManager *toq) : QObject(toq), _toq(toq), _contacts(contacts), _activeCall(0) { if (!profiled) { qDBusRegisterMetaType(); qDBusRegisterMetaType< QList >(); profiled = new ComNokiaProfiledInterface("com.nokia.profiled", "/com/nokia/profiled", QDBusConnection::sessionBus()); } if (!vcm) { vcm = new OrgNemomobileVoicecallVoiceCallManagerInterface("org.nemomobile.voicecall", "/", QDBusConnection::sessionBus()); } connect(profiled, &ComNokiaProfiledInterface::profile_changed, this, &VoiceCallManager::handleProfileChanged); connect(vcm, &OrgNemomobileVoicecallVoiceCallManagerInterface::activeVoiceCallChanged, this, &VoiceCallManager::handleActiveVoiceCallChanged); _toq->setEndpointListener(ToqConnection::VoiceCallEndpoint, this); } void VoiceCallManager::handleMessage(const ToqConnection::Message &msg) { Q_ASSERT(msg.destination == ToqConnection::VoiceCallEndpoint); switch (msg.type) { case 0: // Call number? if (vcm) { QStringList providers = vcm->providers(); if (providers.isEmpty()) { sendReply(msg, 3, "No service"); return; } QString provider = providers.first().split(":").at(0); QString number = msg.toJson().object().value("dial_number").toString(); if (vcm->dial(provider, number)) { sendReply(msg, 0, "Succesfully dialed"); } else { sendReply(msg, 1, "Wrong number"); } } break; case 1: // Redial? // TODO sendReply(msg, 1, "Could not redial"); break; case 4: // Cancel call if (_activeCall && _activeCall->hangup()) { sendReply(msg, 0, "Succesfully ended"); } else { sendReply(msg, 1, "Could not cancel call"); } break; case 5: // Answer call if (_activeCall && _activeCall->answer()) { sendReply(msg, 0, "Succesfully answered"); } else { sendReply(msg, 1, "Could not answer call"); } break; case 6: // Reject call if (_activeCall && _activeCall->hangup()) { sendReply(msg, 0, "Succesfully rejected"); } else { sendReply(msg, 1, "Could not reject call"); } break; case 7: // End call if (_activeCall && _activeCall->hangup()) { sendReply(msg, 0, "Succesfully ended"); } else { sendReply(msg, 1, "Could not end call"); } break; case 9: // Speaker volume up case 10: // Speaker volume down // TODO sendReply(msg, 1, "TODO"); break; case 11: // Mic mute vcm->setIsMicrophoneMuted(true); sendReply(msg, 0, "Succesfully muted"); break; case 12: // Mic unmute vcm->setIsMicrophoneMuted(false); sendReply(msg, 0, "Succesfully unmuted"); break; case 15: // Phone status _toq->sendReply(msg, 0x400F, buildPhoneStatus()); break; default: qWarning() << "Unknown message" << msg.type; break; } } void VoiceCallManager::setSilentMode(bool silent) { setProfile(silent ? "silent" : "ambience"); } void VoiceCallManager::sendReply(const ToqConnection::Message &msg, int status, const QString &message) { QJsonObject obj; obj.insert("result", status); obj.insert("description", message); _toq->sendReply(msg, 0x4000 | msg.type, obj); } QString VoiceCallManager::getCurrentProfile() { QDBusReply resp = profiled->get_profile(); if (resp.isValid()) { return resp.value(); } else { qWarning() << resp.error().message(); return QString(); } } void VoiceCallManager::setProfile(const QString &name) { QDBusReply resp = profiled->set_profile(name); if (!resp.isValid()) { qWarning() << resp.error().message(); } } QJsonObject VoiceCallManager::buildPhoneStatus() { QJsonObject obj; obj.insert("service", int(1)); // TODO int call_status = 0; int call_setup_status = 0; int call_held = 0; if (_activeCall) { switch (_activeCall->status()) { case STATUS_ACTIVE: call_status = 1; break; case STATUS_HELD: call_status = 1; call_held = 1; break; case STATUS_DIALING: case STATUS_ALERTING: call_status = 1; break; case STATUS_INCOMING: call_status = 0; call_setup_status = 1; break; case STATUS_WAITING: call_status = 1; call_setup_status = 0; break; case STATUS_NULL: case STATUS_DISCONNECTED: default: call_status = 0; call_setup_status = 0; break; } QString phoneNumber = _activeCall->lineId(); auto callerId = _contacts->findNameTypeForPhoneNumber(phoneNumber); obj.insert("caller_id", phoneNumber); obj.insert("caller_name", callerId.name); obj.insert("caller_phone_type", callerId.type); obj.insert("privileged", callerId.favorite); QDateTime callTime = _activeCall->startedAt(); if (callTime.isValid()) { obj.insert("call_time", qint64(_activeCall->startedAt().toTime_t())); } } obj.insert("call_status", call_status); obj.insert("call_setup_status", call_setup_status); obj.insert("call_held", call_held); obj.insert("silence_mode", getCurrentProfile() == "silent" ? 1 : 0); obj.insert("mic_mute", vcm->isMicrophoneMuted() ? 1 : 0); return obj; } void VoiceCallManager::sendPhoneStatusMessage() { _toq->sendMessage(ToqConnection::VoiceCallEndpoint, ToqConnection::VoiceCallEndpoint + 1, 0x8000, buildPhoneStatus()); } void VoiceCallManager::sendPhoneRingMessage() { QJsonObject obj; if (_activeCall) { QString phoneNumber = _activeCall->lineId(); auto callerId = _contacts->findNameTypeForPhoneNumber(phoneNumber); obj.insert("caller_id_present", phoneNumber.isEmpty() ? 0 : 1); obj.insert("caller_id", phoneNumber); obj.insert("caller_name", callerId.name); obj.insert("caller_phone_type", callerId.type); obj.insert("privileged", callerId.favorite); } _toq->sendMessage(ToqConnection::VoiceCallEndpoint, ToqConnection::VoiceCallEndpoint + 1, 0x8001, obj); } void VoiceCallManager::handleProfileChanged(bool changed, bool active, const QString &profile) { Q_UNUSED(changed); Q_UNUSED(active); qDebug() << "Profile changed to" << profile; sendPhoneStatusMessage(); } void VoiceCallManager::handleActiveVoiceCallChanged() { if (_activeCall) { delete _activeCall; } QString id = vcm->activeVoiceCall(); if (!id.isEmpty()) { _activeCall = new OrgNemomobileVoicecallVoiceCallInterface("org.nemomobile.voicecall", QString("/calls/%1").arg(id), vcm->connection(), this); connect(_activeCall, &OrgNemomobileVoicecallVoiceCallInterface::statusChanged, this, &VoiceCallManager::handleActiveVoiceCallStatusChanged); } else { _activeCall = 0; } sendPhoneStatusMessage(); } void VoiceCallManager::handleActiveVoiceCallStatusChanged() { int status = _activeCall->status(); qDebug() << "Status changed" << status << _activeCall->statusText(); if (status == STATUS_INCOMING) { sendPhoneRingMessage(); } sendPhoneStatusMessage(); } QDBusArgument &operator<<(QDBusArgument &argument, const ProfileValue &value) { argument.beginStructure(); argument << value.key << value.val << value.type; argument.endStructure(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, ProfileValue &value) { argument.beginStructure(); argument >> value.key >> value.val >> value.type; argument.endStructure(); return argument; }