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
4
#
include
<
QtMultimedia
/
private
/
qandroidaudiosource_p
.
h
>
5
6
#
include
<
QtCore
/
qcoreapplication
.
h
>
7
#
include
<
QtCore
/
qpermissions
.
h
>
8
9
#
include
<
QtMultimedia
/
private
/
qandroidaudiojnitypes_p
.
h
>
10
#
include
<
QtMultimedia
/
private
/
qandroidaudioutil_p
.
h
>
11
12
QT_BEGIN_NAMESPACE
13
14
namespace
QtAAudio
{
15
16
Q_STATIC_LOGGING_CATEGORY(
qLcAndroidAudioSource
,
"qt.multimedia.android.audiosource"
)
17
18
QAndroidAudioSourceStream
::
QAndroidAudioSourceStream
(
QAudioDevice
device
,
19
const
QAudioFormat
&
format
,
20
std
::
optional
<
int
>
ringbufferSize
,
21
QAndroidAudioSource
*
parent
,
float
volume
,
22
std
::
optional
<
int32_t
>
hardwareBufferFrames
)
23
:
QtMultimediaPrivate
::
QPlatformAudioSourceStream
(
std
::
move
(
device
),
format
,
ringbufferSize
,
24
hardwareBufferFrames
,
volume
),
25
m_parent
(
parent
)
26
{
27
QtAAudio
::
StreamBuilder
builder
(
format
);
28
29
qCDebug
(
qLcAndroidAudioSource
) <<
"Creating source for device id:"
<<
m_audioDevice
.
id
()
30
<<
", description:"
<<
m_audioDevice
.
description
();
31
32
builder
.
deviceId
=
m_audioDevice
.
id
().
toInt
();
33
34
// Set buffer parameters
35
builder
.
bufferCapacity
=
m_hardwareBufferFrames
? *
m_hardwareBufferFrames
: 1024;
36
37
// NOTE: AAudio doesn't support UINT8, so convert to INT16 if that's requested
38
if
(
format
.
sampleFormat
() ==
QAudioFormat
::
UInt8
) {
39
m_hostFormat
=
format
;
40
m_hostFormat
->
setSampleFormat
(
QAudioFormat
::
Int16
);
41
}
42
43
// Set builder parameters for audio source
44
builder
.
params
.
sharingMode
=
AAUDIO_SHARING_MODE_SHARED
;
45
builder
.
params
.
direction
=
AAUDIO_DIRECTION_INPUT
;
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
);
53
Q_ASSERT
(
stream
);
54
auto
audioSpan
=
stream
->
getHostSpan
(
audioData
,
numFrames
);
55
return
stream
->
m_audioCallback
?
stream
->
processCallback
(
audioSpan
)
56
:
stream
->
processRingbuffer
(
audioSpan
,
numFrames
);
57
};
58
builder
.
errorCallback
= [](
AAudioStream
*,
void
*
userData
,
aaudio_result_t
error
) ->
void
{
59
auto
*
stream
=
reinterpret_cast
<
QAndroidAudioSourceStream
*>(
userData
);
60
Q_ASSERT
(
stream
);
61
stream
->
handleError
(
error
);
62
};
63
64
builder
.
setupBuilder
();
65
66
if
(!
QtJniTypes
::
QtAudioDeviceManager
::
callStaticMethod
<
jboolean
>(
"prepareAudioInput"
,
67
m_audioDevice
.
id
().
toInt
()))
68
qCWarning
(
qLcAndroidAudioSource
) <<
"Preparation failed for device:"
<<
m_audioDevice
.
id
().
toInt
();
69
70
m_stream
=
std
::
make_unique
<
QtAAudio
::
Stream
>(
builder
);
71
if
(
builder
.
format
.
sampleFormat
() !=
format
.
sampleFormat
()) {
72
// Original sample format unsupported, so doing sample format conversion
73
Q_ASSERT
(
builder
.
format
.
sampleFormat
() ==
QAudioFormat
::
Float
);
74
m_hostFormat
=
builder
.
format
;
75
}
76
}
77
78
QAndroidAudioSourceStream
::~
QAndroidAudioSourceStream
()
79
{
80
QtJniTypes
::
QtAudioDeviceManager
::
callStaticMethod
<
void
>(
"releaseAudioDevice"
,
81
m_audioDevice
.
id
().
toInt
());
82
}
83
84
bool
QAndroidAudioSourceStream
::
open
()
85
{
86
QMicrophonePermission
permission
;
87
88
const
bool
permitted
=
qApp
->
checkPermission
(
permission
) ==
Qt
::
PermissionStatus
::
Granted
;
89
if
(!
permitted
) {
90
qWarning
(
"Missing microphone permission!"
);
91
requestStop
();
92
return
false
;
93
}
94
95
if
(!
m_stream
->
isOpen
()) {
96
qCWarning
(
qLcAndroidAudioSource
) <<
"Stream null"
;
97
requestStop
();
98
return
false
;
99
}
100
101
if
(!
m_stream
->
areStreamParametersRespected
())
102
qCWarning
(
qLcAndroidAudioSource
) <<
"Stream parameters not correct"
;
103
104
return
true
;
105
}
106
107
bool
QAndroidAudioSourceStream
::
start
(
QIODevice
*
device
)
108
{
109
Q_ASSERT
(
thread
()->
isCurrentThread
());
110
setQIODevice
(
device
);
111
createQIODeviceConnections
(
device
);
112
113
if
(!
m_stream
->
start
()) {
114
requestStop
();
115
return
false
;
116
}
117
118
return
true
;
119
}
120
121
QIODevice
*
QAndroidAudioSourceStream
::
start
()
122
{
123
auto
*
device
=
createRingbufferReaderDevice
();
124
return
start
(
device
) ?
device
:
nullptr
;
125
}
126
127
bool
QAndroidAudioSourceStream
::
start
(
AudioCallback
&&
callback
)
128
{
129
Q_ASSERT
(
thread
()->
isCurrentThread
());
130
m_audioCallback
=
std
::
move
(
callback
);
131
132
if
(!
m_stream
->
start
()) {
133
requestStop
();
134
return
false
;
135
}
136
137
return
true
;
138
}
139
140
void
QAndroidAudioSourceStream
::
suspend
()
141
{
142
Q_ASSERT
(
thread
()->
isCurrentThread
());
143
m_stream
->
stop
();
144
}
145
146
void
QAndroidAudioSourceStream
::
resume
()
147
{
148
Q_ASSERT
(
thread
()->
isCurrentThread
());
149
m_stream
->
start
();
150
}
151
152
void
QAndroidAudioSourceStream
::
stop
(
ShutdownPolicy
policy
)
153
{
154
Q_ASSERT
(
thread
()->
isCurrentThread
());
155
requestStop
();
156
157
m_stream
->
stop
();
158
159
disconnectQIODeviceConnections
();
160
finalizeQIODevice
(
policy
);
161
162
if
(
policy
==
ShutdownPolicy
::
DiscardRingbuffer
)
163
emptyRingbuffer
();
164
}
165
166
void
QAndroidAudioSourceStream
::
updateStreamIdle
(
bool
idle
)
167
{
168
if
(
m_parent
)
169
m_parent
->
updateStreamIdle
(
idle
);
170
}
171
172
QSpan
<
const
std
::
byte
>
173
QAndroidAudioSourceStream
::
getHostSpan
(
void
*
audioData
,
174
int
numFrames
)
const
noexcept
QT_MM_NONBLOCKING
175
{
176
qsizetype
byteAmount
=
m_hostFormat
?
m_hostFormat
->
bytesForFrames
(
numFrames
)
177
:
m_format
.
bytesForFrames
(
numFrames
);
178
return
QSpan
{
reinterpret_cast
<
const
std
::
byte
*>(
audioData
),
byteAmount
};
179
}
180
181
aaudio_data_callback_result_t
182
QAndroidAudioSourceStream
::
processRingbuffer
(
QSpan
<
const
std
::
byte
>
audioSpan
,
183
int
numFrames
)
noexcept
QT_MM_NONBLOCKING
184
{
185
auto
framesWritten
=
m_hostFormat
186
?
QPlatformAudioSourceStream
::
process
(
187
audioSpan
,
numFrames
,
188
QAudioHelperInternal
::
toNativeSampleFormat
(
m_hostFormat
->
sampleFormat
()))
189
:
QPlatformAudioSourceStream
::
process
(
audioSpan
,
numFrames
);
190
191
if
(
framesWritten
!=
static_cast
<
uint64_t
>(
numFrames
) &&
isStopRequested
())
192
return
AAUDIO_CALLBACK_RESULT_STOP
;
193
194
return
AAUDIO_CALLBACK_RESULT_CONTINUE
;
195
}
196
197
aaudio_data_callback_result_t
198
QAndroidAudioSourceStream
::
processCallback
(
QSpan
<
const
std
::
byte
>
audioSpan
)
noexcept
QT_MM_NONBLOCKING
199
{
200
if
(
isStopRequested
())
201
return
AAUDIO_CALLBACK_RESULT_STOP
;
202
203
if
(
m_hostFormat
)
204
QtMultimediaPrivate
::
runAudioCallback
(*
m_audioCallback
,
audioSpan
,
m_format
,
volume
(),
205
*
m_hostFormat
);
206
else
207
QtMultimediaPrivate
::
runAudioCallback
(*
m_audioCallback
,
audioSpan
,
m_format
,
volume
());
208
209
return
AAUDIO_CALLBACK_RESULT_CONTINUE
;
210
}
211
212
void
QAndroidAudioSourceStream
::
handleError
(
aaudio_result_t
)
213
{
214
// Handle as IO error which closes the stream
215
requestStop
();
216
invokeOnAppThread
([
this
] {
217
// clang-format off
218
handleIOError
(
m_parent
);
219
// clang-format on
220
});
221
}
222
223
QAndroidAudioSource
::
QAndroidAudioSource
(
QAudioDevice
device
,
const
QAudioFormat
&
format
,
224
QObject
*
parent
)
225
:
BaseClass
(
std
::
move
(
device
),
format
,
parent
)
226
{
227
}
228
229
QAndroidAudioSource
::~
QAndroidAudioSource
()
230
=
default
;
231
232
}
// namespace QtAAudio
233
234
QT_END_NAMESPACE
QtAAudio
Definition
qaaudiostream.cpp:58
qtmultimedia
src
multimedia
android
qandroidaudiosource.cpp
Generated on
for Qt by
1.16.1