Документация
ОС Аврора 5.2.1

Call

Ниже приведены примеры использования класса Call. Данный класс создаётся с помощью класса AudioCall.

  1. .spec-файл:

    // Указываем зависимость для сборки: требуется библиотека callservice для работы с аудио и вызовами
    BuildRequires:  pkgconfig(callservice)
    
  2. .CMake-файл:

    # Ищем модуль callservice с помощью pkg-config и создаем импортированную цель PkgConfig::CALLSERVICE
    pkg_check_modules(CALLSERVICE REQUIRED IMPORTED_TARGET callservice)
    ...
    # Линкуем найденную библиотеку callservice с нашим целевым проектом (${PROJECT_NAME}) в приватном режиме
    target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::CALLSERVICE )
    ...
    
  3. Файл src/audio/audiocall.h:

    #include <QObject>
    #include <QQuickItem>
    #include <QVariantMap>
    #include <QTimer>
    
    // Подключаем заголовочные файлы библиотеки callservice для работы с аудио и вызовами
    #include <audiocontext.h>
    #include <call.h>
    #include <dtmfinterface.h>
    
    // Подключаем локальные заголовочные файлы для управления аудио вводом и выводом
    #include "audioinput.h"
    #include "audiooutput.h"
    
    // Макрос для условной компиляции: если определен, DTMF обрабатывается через отдельный класс-обертку (StandaloneDtmfHandler),
    // иначе класс AudioCall сам множественно наследует и реализует DTMFInterface.
    #define STANDALONE_DTMF
    
    // Используем пространства имен для удобства чтения кода и сокращения имен типов
    using ru::auroraos::call::AudioContext;
    using ru::auroraos::call::Call;
    using ru::auroraos::call::DTMFInterface;
    
    // Класс AudioCall представляет собой аудиовызов, наследуясь от базового класса Call.
    // Условная компиляция: если STANDALONE_DTMF не определен, класс также наследует DTMFInterface.
    class AudioCall
        : public Call
    #ifndef STANDALONE_DTMF
        , public DTMFInterface
    #endif
    {
        Q_OBJECT // Макрос для поддержки сигналов, слотов и метаобъектной системы Qt
    
    #ifndef STANDALONE_DTMF
        // Регистрируем интерфейс DTMFInterface в метаобъектной системе Qt (требуется при множественном наследовании интерфейсов)
        Q_INTERFACES(ru::auroraos::call::DTMFInterface)
    #endif
    
        // Свойства QML, доступные для чтения из QML-кода
        Q_PROPERTY(bool supportsDtmf READ supportsDtmf CONSTANT) // Поддерживает ли вызов DTMF (константное свойство)
        Q_PROPERTY(QString dtmfString READ dtmfString NOTIFY dtmfStringChanged) // Строка с накопленными DTMF-сигналами
        Q_PROPERTY(float microphoneRms READ microphoneRms NOTIFY microphoneRmsChanged) // Среднеквадратичное значение (RMS) громкости микрофона
    
    public:
        // Конструктор класса
        // manager — указатель на менеджер вызовов
        // id — уникальный идентификатор вызова
        // parameters — дополнительные параметры вызова в виде словаря
        // generateTone — флаг, указывающий, нужно ли генерировать тональные сигналы при нажатии DTMF
        // parent — родительский объект QObject для управления временем жизни
        AudioCall(
            ru::auroraos::call::CallManager *manager,
            const QString &id,
            const QVariantMap &parameters,
            bool generateTone,
            QObject *parent);
    
        // Деструктор по умолчанию
        ~AudioCall() = default;
        
        // Методы, доступные для вызова из QML (благодаря макросу Q_INVOKABLE)
        Q_INVOKABLE void accept();    // Принять входящий вызов
        Q_INVOKABLE void disconnect(); // Завершить текущий вызов
    
        // Геттеры для свойств, объявленных в Q_PROPERTY
        bool supportsDtmf() const;
        QString dtmfString() const;
        float microphoneRms() const;
    
    signals:
        // Сигналы, уведомляющие QML-слой об изменении значений соответствующих свойств
        void dtmfStringChanged(const QString &tones);
        void microphoneRmsChanged(float rms);
    
    private:
        // Внутренние методы для управления аудиопотоками
        void startAudio(); // Запуск захвата аудио с микрофона и воспроизведения в динамик/наушник
        void stopAudio();  // Остановка захвата и воспроизведения аудио
    
    private slots:
    #ifndef STANDALONE_DTMF
        // Реализация метода интерфейса DTMFInterface для отправки DTMF-сигналов
        void SendDTMF(const QString &codes) override;
    #else
        // Если используется STANDALONE_DTMF, разрешаем классу StandaloneDtmfHandler доступ к приватным методам
        friend class StandaloneDtmfHandler;
        void SendDTMF(const QString &codes);
    #endif
    
        // Слот для обработки изменений статуса вызова (например, переход в состояние Active или Disconnected)
        void onCallStatusChanged(Call::Status);
    
    private:
        QTimer m_answerTimer;       // Таймер, используемый в данном примере для имитации задержки ответа при исходящем вызове
        AudioInput m_input;         // Объект, управляющий захватом аудио с микрофона
        AudioOutput m_output;       // Объект, управляющий воспроизведением аудио в динамик/наушник
        bool m_supportsDtmf;        // Флаг поддержки DTMF для данного конкретного вызова
        QString m_dtmfString;       // Накопленная строка нажатых DTMF-клавиш
        bool m_generateTone;        // Флаг, указывающий, нужно ли проигрывать тональный сигнал локально при нажатии DTMF
    };
    
    // Макрос Qt для регистрации класса AudioCall в системе типов QML, чтобы его можно было использовать в QML-коде
    QML_DECLARE_TYPE(AudioCall)
    
    #ifdef STANDALONE_DTMF
    // Класс-обертка для обработки DTMF, если включен режим STANDALONE_DTMF.
    // Это позволяет отделить логику DTMF от основного класса AudioCall, если это требуется архитектурой приложения.
    class StandaloneDtmfHandler : public QObject, public DTMFInterface
    {
        Q_OBJECT
        // Регистрируем интерфейс DTMFInterface в метаобъектной системе Qt
        Q_INTERFACES(ru::auroraos::call::DTMFInterface)
    
    public:
        // Конструктор принимает указатель на родительский объект AudioCall
        explicit StandaloneDtmfHandler(AudioCall *parent)
            : QObject(parent)
            , m_call(parent) // Сохраняем указатель на экземпляр AudioCall для делегирования вызовов
        {
        }
    
    public slots:
        // Реализация метода интерфейса DTMFInterface
        // Делегирует вызов метода SendDTMF связанному объекту AudioCall
        void SendDTMF(const QString &codes) override
        {
            m_call->SendDTMF(codes);
        }
    
    private:
        AudioCall *m_call; // Указатель на связанный объект AudioCall
    };
    #endif
    
  4. Файл src/audio/audiocall.cpp:

    // Используем пространства имен для сокращения имен типов
    using ru::auroraos::call::Call;
    using ru::auroraos::call::CallManager;
    
    // Конструктор класса AudioCall
    AudioCall::AudioCall(
            CallManager *manager,
            const QString &id,
            const QVariantMap &parameters,
            bool generateTone,
            QObject *parent)
        // Инициализируем базовый класс Call переданными параметрами
        : Call(manager, id, parameters, parent)
        , m_generateTone(generateTone) // Сохраняем флаг генерации тонального сигнала
    {
        // Связываем сигнал изменения уровня громкости (RMS) от объекта ввода с сигналом нашего класса
        connect(&m_input, &AudioInput::rmsChanged,
                this, &AudioCall::microphoneRmsChanged);
    
    #ifdef STANDALONE_DTMF
        // Проверяем, передан ли параметр "dtmf" в словаре parameters и равен ли он true
        auto dtmf = parameters.find("dtmf");
        if (dtmf != parameters.end() && dtmf->value<bool>()) {
            m_supportsDtmf = true;
            // Если поддержка включена, создаем обработчик и регистрируем его как дополнительный интерфейс
            addInterfaces({ new StandaloneDtmfHandler(this) });
        } else {
            m_supportsDtmf = false;
        }
    #else
        // Если макрос не определен, считаем, что DTMF поддерживается всегда
        m_supportsDtmf = true;
    #endif
    
        // Запускаем или останавливаем аудиопотоки при каждом изменении статуса вызова
        connect(this, &Call::statusChanged,
                this, &AudioCall::onCallStatusChanged);
    
        // Логика для входящих вызовов
        if (incoming()) {
            // При получении сигнала accepted переводим статус в Active
            connect(this, &Call::accepted, [=]() {
                        qDebug() << "вызов принят";
                        setStatus(Call::Active);
                    });
        } else {
            // Логика для исходящих вызовов (используется таймер для имитации установки соединения)
            connect(&m_answerTimer, &QTimer::timeout, [=]() {
                        qDebug() << "отвечено";
                        setStatus(Call::Active); // По истечении таймера переводим вызов в активное состояние
                    });
            m_answerTimer.setInterval(3000);     // Устанавливаем интервал 3 секунды
            m_answerTimer.setSingleShot(true);   // Таймер сработает только один раз
            m_answerTimer.start();               // Запускаем таймер
        }
    
        // Подключаем слоты для логирования остальных событий жизненного цикла вызова
        connect(this, &Call::rejected, [=]() {
                    qDebug() << "вызов отклонен";
                });
        connect(this, &Call::heldChanged, [=](bool held) {
                    qDebug() << "статус удержания изменен" << held;
                });
        connect(this, &Call::disconnected, [=]() {
                    qDebug() << "вызов завершен";
                });
    
        // Принудительно вызываем обработчик статуса при инициализации для настройки аудио
        onCallStatusChanged(this->status());
    }
    
    // Обработка запроса на отправку DTMF-сигналов
    void AudioCall::SendDTMF(const QString &codes)
    {
        qDebug() << codes; // Логируем полученные коды
        m_dtmfString += codes; // Добавляем новые коды к накопленной строке
        emit dtmfStringChanged(m_dtmfString); // Уведомляем QML об изменении свойства
    }
    
    // Возвращает флаг поддержки DTMF
    bool AudioCall::supportsDtmf() const
    {
        return m_supportsDtmf;
    }
    
    // Возвращает накопленную строку DTMF-сигналов
    QString AudioCall::dtmfString() const
    {
        return m_dtmfString;
    }
    
    // Метод, вызываемый из QML для принятия входящего вызова
    void AudioCall::accept()
    {
        if (incoming()) {
            // Если вызов входящий, переводим его в активное состояние
            setStatus(Call::Active);
        }
    }
    
    // Метод, вызываемый из QML для завершения вызова
    void AudioCall::disconnect()
    {
        // Переводим вызов в состояние отключен
        setStatus(Call::Disconnected);
    }
    
    // Возвращает текущее значение RMS (уровень громкости) микрофона
    float AudioCall::microphoneRms() const
    {
        return m_input.rms();
    }
    
    // Запуск аудиопотоков
    void AudioCall::startAudio()
    {
        m_input.start(); // Запускаем захват звука с микрофона
        if (m_generateTone) {
            m_output.start(); // Если требуется, запускаем воспроизведение
        }
    }
    
    // Остановка аудиопотоков
    void AudioCall::stopAudio()
    {
        m_output.stop(); // Останавливаем воспроизведение
        m_input.stop();  // Останавливаем захват звука
    }
    
    // Обработчик изменения статуса вызова
    void AudioCall::onCallStatusChanged(Call::Status)
    {
        // Получаем фактический текущий статус вызова
        Call::Status status = this->status();
        qDebug() << status;
    
        // Управляем аудиопотоками в зависимости от состояния вызова
        switch (status) {
        case Call::Dialing:  // Набор номера
        case Call::Active:   // Активный разговор
            startAudio();    // В этих состояниях аудио должно работать
            break;
        default:             // Для всех остальных состояний
            stopAudio();     // Останавливаем аудио
            break;
        }
    }
    

Мы используем cookies для персонализации сайта и его более удобного использования. Вы можете запретить cookies в настройках браузера.

Пожалуйста ознакомьтесь с политикой использования файлов cookies.