From 07622ff806324b5d5cf1e208c2110eb193f22103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8ger=20Hanseg=C3=A5rd?= Date: Tue, 12 Dec 2023 14:46:06 +0100 Subject: Move QMediaDevices example to manual tests and improve documentation The Devices example is too simple to have as a full fledged example, and can better be expressed through snippets. Therefore, this patch moves the Devices example to manual tests, and improves the QMediaDevices doc by adding some snippets. Task-number: QTBUG-119117 Pick-to: 6.7 6.6 6.5 Change-Id: Id7c61e4f1b1047b73bae7e0619cf6238a30b8320 Reviewed-by: Artem Dyomin --- examples/multimedia/CMakeLists.txt | 3 - examples/multimedia/devices/CMakeLists.txt | 40 ------ examples/multimedia/devices/devices.pro | 12 -- examples/multimedia/devices/main.cpp | 137 --------------------- examples/multimedia/multimedia.pro | 3 +- .../doc/snippets/multimedia-snippets/devices.cpp | 38 ++++++ src/multimedia/qmediadevices.cpp | 13 ++ tests/manual/devices/CMakeLists.txt | 40 ++++++ tests/manual/devices/devices.pro | 12 ++ tests/manual/devices/main.cpp | 137 +++++++++++++++++++++ 10 files changed, 241 insertions(+), 194 deletions(-) delete mode 100644 examples/multimedia/devices/CMakeLists.txt delete mode 100644 examples/multimedia/devices/devices.pro delete mode 100644 examples/multimedia/devices/main.cpp create mode 100644 src/multimedia/doc/snippets/multimedia-snippets/devices.cpp create mode 100644 tests/manual/devices/CMakeLists.txt create mode 100644 tests/manual/devices/devices.pro create mode 100644 tests/manual/devices/main.cpp diff --git a/examples/multimedia/CMakeLists.txt b/examples/multimedia/CMakeLists.txt index fb5d62383..fc91cc40a 100644 --- a/examples/multimedia/CMakeLists.txt +++ b/examples/multimedia/CMakeLists.txt @@ -2,9 +2,6 @@ # SPDX-License-Identifier: BSD-3-Clause qt_internal_add_example(audiodecoder) -if(NOT ANDROID AND NOT IOS) - qt_internal_add_example(devices) -endif() if(TARGET Qt::Widgets) if(NOT ANDROID AND NOT IOS) qt_internal_add_example(audiodevices) diff --git a/examples/multimedia/devices/CMakeLists.txt b/examples/multimedia/devices/CMakeLists.txt deleted file mode 100644 index d0856af45..000000000 --- a/examples/multimedia/devices/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -cmake_minimum_required(VERSION 3.16) -project(devices LANGUAGES CXX) - -if(ANDROID OR IOS) - message(FATAL_ERROR "This is a commandline tool that is not supported on mobile platforms") -endif() - -set(CMAKE_AUTOMOC ON) - -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") -endif() - -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/devices") - -find_package(Qt6 REQUIRED COMPONENTS Core Gui Multimedia) - -qt_add_executable(devices - main.cpp -) - -set_target_properties(devices PROPERTIES - WIN32_EXECUTABLE TRUE - MACOSX_BUNDLE TRUE -) - -target_link_libraries(devices PUBLIC - Qt::Core - Qt::Gui - Qt::Multimedia -) - -install(TARGETS devices - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) diff --git a/examples/multimedia/devices/devices.pro b/examples/multimedia/devices/devices.pro deleted file mode 100644 index bbc5ecea8..000000000 --- a/examples/multimedia/devices/devices.pro +++ /dev/null @@ -1,12 +0,0 @@ -android|ios: error("This is a commandline tool that is not supported on mobile platforms") - -TEMPLATE = app -TARGET = devices - -SOURCES = main.cpp - -QT += multimedia -CONFIG += console - -target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/devices -INSTALLS += target diff --git a/examples/multimedia/devices/main.cpp b/examples/multimedia/devices/main.cpp deleted file mode 100644 index 6c7f46a0b..000000000 --- a/examples/multimedia/devices/main.cpp +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (C) 2020 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include -#include -#include -#include -#include -#include - -#include - -QString formatToString(QAudioFormat::SampleFormat sampleFormat) -{ - switch (sampleFormat) { - case QAudioFormat::UInt8: - return "UInt8"; - case QAudioFormat::Int16: - return "Int16"; - case QAudioFormat::Int32: - return "Int32"; - case QAudioFormat::Float: - return "Float"; - default: - return "Unknown"; - } -} - -QString positionToString(QCameraDevice::Position position) -{ - switch (position) { - case QCameraDevice::BackFace: - return "BackFace"; - case QCameraDevice::FrontFace: - return "FrontFace"; - default: - return "Unspecified"; - } -} - -void printAudioDeviceInfo(QTextStream &out, const QAudioDevice &deviceInfo) -{ - const auto isDefault = deviceInfo.isDefault() ? "Yes" : "No"; - const auto preferredFormat = deviceInfo.preferredFormat(); - const auto supportedFormats = deviceInfo.supportedSampleFormats(); - out.setFieldWidth(30); - out.setFieldAlignment(QTextStream::AlignLeft); - out << "Name: " << deviceInfo.description() << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Id: " << QString::fromLatin1(deviceInfo.id()) << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Default: " << isDefault << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Preferred Format: " << formatToString(preferredFormat.sampleFormat()) - << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Preferred Rate: " << preferredFormat.sampleRate() << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Preferred Channels: " << preferredFormat.channelCount() << qSetFieldWidth(0) - << Qt::endl; - out.setFieldWidth(30); - out << "Supported Formats: "; - for (auto &format : supportedFormats) - out << qSetFieldWidth(0) << formatToString(format) << " "; - out << Qt::endl; - out.setFieldWidth(30); - out << "Supported Rates: " << qSetFieldWidth(0) << deviceInfo.minimumSampleRate() << " - " - << deviceInfo.maximumSampleRate() << Qt::endl; - out.setFieldWidth(30); - out << "Supported Channels: " << qSetFieldWidth(0) << deviceInfo.minimumChannelCount() << " - " - << deviceInfo.maximumChannelCount() << Qt::endl; - - out << Qt::endl; -} - -void printVideoDeviceInfo(QTextStream &out, const QCameraDevice &cameraDevice) -{ - const auto isDefault = cameraDevice.isDefault() ? "Yes" : "No"; - const auto position = cameraDevice.position(); - const auto photoResolutions = cameraDevice.photoResolutions(); - const auto videoFormats = cameraDevice.videoFormats(); - - out.setFieldWidth(30); - out.setFieldAlignment(QTextStream::AlignLeft); - out << "Name: " << cameraDevice.description() << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Id: " << QString::fromLatin1(cameraDevice.id()) << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Default: " << isDefault << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Position: " << positionToString(position) << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Photo Resolutions: "; - for (auto &resolution : photoResolutions) { - QString s = QString("%1x%2").arg(resolution.width()).arg(resolution.height()); - out << qSetFieldWidth(0) << s << ", "; - } - out.setFieldWidth(10); - out << Qt::endl << Qt::endl; - out << "Supported Video Formats: " << qSetFieldWidth(0) << Qt::endl; - for (auto &format : videoFormats) { - out.setFieldWidth(30); - QString s = - QString("%1x%2").arg(format.resolution().width()).arg(format.resolution().height()); - out << "Resolution: " << s << qSetFieldWidth(0) << Qt::endl; - out.setFieldWidth(30); - out << "Frame Rate: " << qSetFieldWidth(0) << "Min:" << format.minFrameRate() - << " Max:" << format.maxFrameRate() << Qt::endl; - } - - out << Qt::endl; -} - -int main(int argc, char *argv[]) -{ - Q_UNUSED(argc); - Q_UNUSED(argv); - QTextStream out(stdout); - - const auto audioInputDevices = QMediaDevices::audioInputs(); - const auto audioOutputDevices = QMediaDevices::audioOutputs(); - const auto videoInputDevices = QMediaDevices::videoInputs(); - - out << "Audio devices detected: " << Qt::endl; - out << Qt::endl << "Input" << Qt::endl; - for (auto &deviceInfo : audioInputDevices) - printAudioDeviceInfo(out, deviceInfo); - out << Qt::endl << "Output" << Qt::endl; - for (auto &deviceInfo : audioOutputDevices) - printAudioDeviceInfo(out, deviceInfo); - - out << Qt::endl << "Video devices detected: " << Qt::endl; - for (auto &cameraDevice : videoInputDevices) - printVideoDeviceInfo(out, cameraDevice); - - return 0; -} diff --git a/examples/multimedia/multimedia.pro b/examples/multimedia/multimedia.pro index 7267630b5..9adbd797e 100644 --- a/examples/multimedia/multimedia.pro +++ b/examples/multimedia/multimedia.pro @@ -2,8 +2,7 @@ TEMPLATE = subdirs QT_FOR_CONFIG += multimedia-private SUBDIRS += \ - audiodecoder \ - devices + audiodecoder # These examples all need widgets for now (using creator templates that use widgets) qtHaveModule(widgets) { diff --git a/src/multimedia/doc/snippets/multimedia-snippets/devices.cpp b/src/multimedia/doc/snippets/multimedia-snippets/devices.cpp new file mode 100644 index 000000000..652400364 --- /dev/null +++ b/src/multimedia/doc/snippets/multimedia-snippets/devices.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + Q_UNUSED(argc); + Q_UNUSED(argv); + + QTextStream out(stdout); + + //! [Media Audio Input Device Enumeration] + const QList audioDevices = QMediaDevices::audioInputs(); + for (const QAudioDevice &device : audioDevices) + { + out << "ID: " << device.id() << Qt::endl; + out << "Description: " << device.description() << Qt::endl; + out << "Is default: " << (device.isDefault() ? "Yes" : "No") << Qt::endl; + } + //! [Media Audio Input Device Enumeration] + + //! [Media Video Input Device Enumeration] + const QList videoDevices = QMediaDevices::videoInputs(); + for (const QCameraDevice &device : videoDevices) + { + out << "ID: " << device.id() << Qt::endl; + out << "Description: " << device.description() << Qt::endl; + out << "Is default: " << (device.isDefault() ? "Yes" : "No") << Qt::endl; + } + //! [Media Video Input Device Enumeration] + + return 0; +} diff --git a/src/multimedia/qmediadevices.cpp b/src/multimedia/qmediadevices.cpp index 3f37d85a8..fa6f8630e 100644 --- a/src/multimedia/qmediadevices.cpp +++ b/src/multimedia/qmediadevices.cpp @@ -30,6 +30,19 @@ QT_BEGIN_NAMESPACE from the system, it will update the corresponding device list and emit a signal notifying about the change. + The QMediaDevices::audioInputs and QMediaDevices::audioOutputs functions can be used + to enumerate all microphones and speakers/headsets on the system. This example first + gets a list of all connected microphones, and then prints their identifier, description, + and if it is the default device or not. + + \snippet multimedia-snippets/devices.cpp Media Audio Input Device Enumeration + + Similarly, the QMediaDevices::videoInputs will return a list of all connected cameras. + In this example we list all connected cameras and their identifier, description, and + if it is the default camera or not. + + \snippet multimedia-snippets/devices.cpp Media Video Input Device Enumeration + QMediaDevices monitors the system defaults for each device group. It will notify about any changes done through the system settings. For example, if the user selects a new default audio output in the system settings, QMediaDevices will update the default audio diff --git a/tests/manual/devices/CMakeLists.txt b/tests/manual/devices/CMakeLists.txt new file mode 100644 index 000000000..d0856af45 --- /dev/null +++ b/tests/manual/devices/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(devices LANGUAGES CXX) + +if(ANDROID OR IOS) + message(FATAL_ERROR "This is a commandline tool that is not supported on mobile platforms") +endif() + +set(CMAKE_AUTOMOC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/devices") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Multimedia) + +qt_add_executable(devices + main.cpp +) + +set_target_properties(devices PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) + +target_link_libraries(devices PUBLIC + Qt::Core + Qt::Gui + Qt::Multimedia +) + +install(TARGETS devices + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/tests/manual/devices/devices.pro b/tests/manual/devices/devices.pro new file mode 100644 index 000000000..bbc5ecea8 --- /dev/null +++ b/tests/manual/devices/devices.pro @@ -0,0 +1,12 @@ +android|ios: error("This is a commandline tool that is not supported on mobile platforms") + +TEMPLATE = app +TARGET = devices + +SOURCES = main.cpp + +QT += multimedia +CONFIG += console + +target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/devices +INSTALLS += target diff --git a/tests/manual/devices/main.cpp b/tests/manual/devices/main.cpp new file mode 100644 index 000000000..6c7f46a0b --- /dev/null +++ b/tests/manual/devices/main.cpp @@ -0,0 +1,137 @@ +// Copyright (C) 2020 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include +#include +#include +#include +#include +#include + +#include + +QString formatToString(QAudioFormat::SampleFormat sampleFormat) +{ + switch (sampleFormat) { + case QAudioFormat::UInt8: + return "UInt8"; + case QAudioFormat::Int16: + return "Int16"; + case QAudioFormat::Int32: + return "Int32"; + case QAudioFormat::Float: + return "Float"; + default: + return "Unknown"; + } +} + +QString positionToString(QCameraDevice::Position position) +{ + switch (position) { + case QCameraDevice::BackFace: + return "BackFace"; + case QCameraDevice::FrontFace: + return "FrontFace"; + default: + return "Unspecified"; + } +} + +void printAudioDeviceInfo(QTextStream &out, const QAudioDevice &deviceInfo) +{ + const auto isDefault = deviceInfo.isDefault() ? "Yes" : "No"; + const auto preferredFormat = deviceInfo.preferredFormat(); + const auto supportedFormats = deviceInfo.supportedSampleFormats(); + out.setFieldWidth(30); + out.setFieldAlignment(QTextStream::AlignLeft); + out << "Name: " << deviceInfo.description() << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Id: " << QString::fromLatin1(deviceInfo.id()) << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Default: " << isDefault << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Preferred Format: " << formatToString(preferredFormat.sampleFormat()) + << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Preferred Rate: " << preferredFormat.sampleRate() << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Preferred Channels: " << preferredFormat.channelCount() << qSetFieldWidth(0) + << Qt::endl; + out.setFieldWidth(30); + out << "Supported Formats: "; + for (auto &format : supportedFormats) + out << qSetFieldWidth(0) << formatToString(format) << " "; + out << Qt::endl; + out.setFieldWidth(30); + out << "Supported Rates: " << qSetFieldWidth(0) << deviceInfo.minimumSampleRate() << " - " + << deviceInfo.maximumSampleRate() << Qt::endl; + out.setFieldWidth(30); + out << "Supported Channels: " << qSetFieldWidth(0) << deviceInfo.minimumChannelCount() << " - " + << deviceInfo.maximumChannelCount() << Qt::endl; + + out << Qt::endl; +} + +void printVideoDeviceInfo(QTextStream &out, const QCameraDevice &cameraDevice) +{ + const auto isDefault = cameraDevice.isDefault() ? "Yes" : "No"; + const auto position = cameraDevice.position(); + const auto photoResolutions = cameraDevice.photoResolutions(); + const auto videoFormats = cameraDevice.videoFormats(); + + out.setFieldWidth(30); + out.setFieldAlignment(QTextStream::AlignLeft); + out << "Name: " << cameraDevice.description() << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Id: " << QString::fromLatin1(cameraDevice.id()) << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Default: " << isDefault << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Position: " << positionToString(position) << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Photo Resolutions: "; + for (auto &resolution : photoResolutions) { + QString s = QString("%1x%2").arg(resolution.width()).arg(resolution.height()); + out << qSetFieldWidth(0) << s << ", "; + } + out.setFieldWidth(10); + out << Qt::endl << Qt::endl; + out << "Supported Video Formats: " << qSetFieldWidth(0) << Qt::endl; + for (auto &format : videoFormats) { + out.setFieldWidth(30); + QString s = + QString("%1x%2").arg(format.resolution().width()).arg(format.resolution().height()); + out << "Resolution: " << s << qSetFieldWidth(0) << Qt::endl; + out.setFieldWidth(30); + out << "Frame Rate: " << qSetFieldWidth(0) << "Min:" << format.minFrameRate() + << " Max:" << format.maxFrameRate() << Qt::endl; + } + + out << Qt::endl; +} + +int main(int argc, char *argv[]) +{ + Q_UNUSED(argc); + Q_UNUSED(argv); + QTextStream out(stdout); + + const auto audioInputDevices = QMediaDevices::audioInputs(); + const auto audioOutputDevices = QMediaDevices::audioOutputs(); + const auto videoInputDevices = QMediaDevices::videoInputs(); + + out << "Audio devices detected: " << Qt::endl; + out << Qt::endl << "Input" << Qt::endl; + for (auto &deviceInfo : audioInputDevices) + printAudioDeviceInfo(out, deviceInfo); + out << Qt::endl << "Output" << Qt::endl; + for (auto &deviceInfo : audioOutputDevices) + printAudioDeviceInfo(out, deviceInfo); + + out << Qt::endl << "Video devices detected: " << Qt::endl; + for (auto &cameraDevice : videoInputDevices) + printVideoDeviceInfo(out, cameraDevice); + + return 0; +} -- cgit v1.2.3