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