Документация
ОС Аврора 5.2.1
AudioContext
Ниже приведены примеры использования класса AudioContext.
-
.spec-файл:
// Указываем зависимость для сборки: требуется библиотека callservice для работы с аудио и вызовами BuildRequires: pkgconfig(callservice) -
.CMake-файл:
# Ищем модуль callservice с помощью pkg-config и создаем импортированную цель PkgConfig::CALLSERVICE pkg_check_modules(CALLSERVICE REQUIRED IMPORTED_TARGET callservice) ... # Линкуем найденную библиотеку callservice с нашим целевым проектом в приватном режиме target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::CALLSERVICE) ... -
Файл
src/audio/audiocall.h:// Подключаем стандартные заголовочные файлы Qt #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 ¶meters, 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 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 }; // Макрос Qt для регистрации класса AudioCall в системе типов QML QML_DECLARE_TYPE(AudioCall) #ifdef STANDALONE_DTMF // Класс-обертка для обработки DTMF, если включен режим STANDALONE_DTMF 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 -
Файл
src/audio/audiocall.cpp:// Используем пространства имен для сокращения имен типов using ru::auroraos::call::Call; using ru::auroraos::call::CallManager; // Конструктор класса AudioCall AudioCall::AudioCall( CallManager *manager, const QString &id, const QVariantMap ¶meters, 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; } }