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

CallManager

Ниже приведены примеры использования класса CallManager. Данный класс используется вместе с AudioContext и CallFactoryInterface. Является общим контроллером для создания звонка.

  1. .spec-файл:

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

    # Ищем модуль callservice с помощью pkg-config и создаем импортированную цель PkgConfig::CALLSERVICE
    pkg_check_modules(CALLSERVICE REQUIRED IMPORTED_TARGET callservice)
    ...
    # Линкуем найденную библиотеку callservice с нашим целевым проектом в приватном режиме
    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 обрабатывается через отдельный класс-обертку,
    // иначе класс 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) // Среднеквадратичное значение громкости микрофона
    
    public:
        // Конструктор класса
        AudioCall(
            ru::auroraos::call::CallManager *manager,
            const QString &id,
            const QVariantMap &parameters,
            bool generateTone,
            QObject *parent);
    
        // Деструктор по умолчанию
        ~AudioCall() = default;
    
        // Методы, доступные для вызова из QML
        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
    
        // Слот для обработки изменений статуса вызова
        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
    };
    
  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.