Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qandroidaudiosource.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
7
8#include <QtCore/qcoreapplication.h>
9#include <QtCore/qpermissions.h>
10
12
13Q_DECLARE_JNI_CLASS(QtAudioDeviceManager,
14 "org/qtproject/qt/android/multimedia/QtAudioDeviceManager");
15
16namespace QtAAudio {
17
18Q_STATIC_LOGGING_CATEGORY(qLcAndroidAudioSource, "qt.multimedia.android.audiosource")
19
21 const QAudioFormat &format,
22 std::optional<int> ringbufferSize,
23 QAndroidAudioSource *parent, float volume,
24 std::optional<int32_t> hardwareBufferFrames)
28{
30
31 qCDebug(qLcAndroidAudioSource) << "Creating source for device id:" << m_audioDevice.id()
32 << ", description:" << m_audioDevice.description();
33
35
36 // Set buffer parameters
38
39 // NOTE: AAudio doesn't support UINT8, so convert to INT16 if that's requested
42
43 // Set builder parameters for audio source
46
47 // TODO: Set input preset based on device
48
49 builder.userData = this;
50 builder.callback = [](AAudioStream *, void *userData, void *audioData,
51 int32_t numFrames) -> int {
52 auto *stream = reinterpret_cast<QAndroidAudioSourceStream *>(userData);
55 };
57 auto *stream = reinterpret_cast<QAndroidAudioSourceStream *>(userData);
60 };
61
63
64 if (!QtJniTypes::QtAudioDeviceManager::callStaticMethod<jboolean>("prepareAudioInput",
66 qCWarning(qLcAndroidAudioSource) << "Preparation failed for device:" << m_audioDevice.id().toInt();
67
69}
70
71QAndroidAudioSourceStream::~QAndroidAudioSourceStream()
72{
73 QtJniTypes::QtAudioDeviceManager::callStaticMethod<void>("releaseAudioDevice",
74 m_audioDevice.id().toInt());
75}
76
78{
79 QMicrophonePermission permission;
80
81 const bool permitted = qApp->checkPermission(permission) == Qt::PermissionStatus::Granted;
82 if (!permitted) {
83 qWarning("Missing microphone permission!");
84 requestStop();
85 return false;
86 }
87
88 if (!m_stream->isOpen()) {
89 qCWarning(qLcAndroidAudioSource) << "Stream null";
90 requestStop();
91 return false;
92 }
93
94 if (!m_stream->areStreamParametersRespected())
95 qCWarning(qLcAndroidAudioSource) << "Stream parameters not correct";
96
97 return true;
98}
99
100bool QAndroidAudioSourceStream::start(QIODevice *device)
101{
102 Q_ASSERT(thread()->isCurrentThread());
103 setQIODevice(device);
104 createQIODeviceConnections(device);
105
106 if (!m_stream->start()) {
107 requestStop();
108 return false;
109 }
110
111 return true;
112}
113
115{
116 auto *device = createRingbufferReaderDevice();
117 return start(device) ? device : nullptr;
118}
119
121{
122 Q_ASSERT(thread()->isCurrentThread());
123 m_stream->stop();
124}
125
127{
128 Q_ASSERT(thread()->isCurrentThread());
129 m_stream->start();
130}
131
132void QAndroidAudioSourceStream::stop(ShutdownPolicy policy)
133{
134 Q_ASSERT(thread()->isCurrentThread());
135 requestStop();
136
137 m_stream->stop();
138
139 disconnectQIODeviceConnections();
140 finalizeQIODevice(policy);
141
142 if (policy == ShutdownPolicy::DiscardRingbuffer)
143 emptyRingbuffer();
144}
145
147{
148 if (m_parent)
149 m_parent->updateStreamIdle(idle);
150}
151
154{
157 * numFrames)
159 QSpan<std::byte> audioSpan{ reinterpret_cast<std::byte *>(audioData), bytesForFrames };
160
161 auto framesWritten =
163
164 if (framesWritten != static_cast<uint64_t>(numFrames) && isStopRequested())
166
168}
169
171{
172 // Handle as IO error which closes the stream
173 requestStop();
174 invokeOnAppThread([this] {
175 // clang-format off
177 // clang-format on
178 });
179}
180
186
187} // namespace QtAAudio
188
189QT_END_NAMESPACE