Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqnxaudiorecorder.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 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
5
6#include <QtCore/qcoreapplication.h>
7
8#include <private/qmediastoragelocation_p.h>
9
10#include <mm/renderer.h>
11
12#include <sys/stat.h>
13#include <sys/strm.h>
14
16{
17 QByteArray devicePath = QByteArrayLiteral("snd:/dev/snd/") + deviceId + QByteArrayLiteral("?");
18
19 if (settings.audioSampleRate() > 0)
20 devicePath += QByteArrayLiteral("frate=") + QByteArray::number(settings.audioSampleRate());
21
22 if (settings.audioChannelCount() > 0)
23 devicePath += QByteArrayLiteral("nchan=") + QByteArray::number(settings.audioChannelCount());
24
25 return devicePath;
26}
27
29
31 : QObject(parent)
32{
33 openConnection();
34}
35
37{
38 stop();
39 closeConnection();
40}
41
42void QQnxAudioRecorder::openConnection()
43{
44 static int idCounter = 0;
45
46 m_connection = ConnectionUniquePtr { mmr_connect(nullptr) };
47
48 if (!m_connection) {
49 qWarning("QQnxAudioRecorder: Unable to connect to the multimedia renderer");
50 return;
51 }
52
53 m_id = idCounter++;
54
55 char contextName[256];
56
57 std::snprintf(contextName, sizeof contextName, "QQnxAudioRecorder_%d_%llu",
59
60 m_context = ContextUniquePtr { mmr_context_create(m_connection.get(),
61 contextName, 0, S_IRWXU|S_IRWXG|S_IRWXO) };
62
63 if (m_context) {
64 startMonitoring();
65 } else {
66 qWarning("QQnxAudioRecorder: Unable to create context");
67 closeConnection();
68 }
69}
70
71void QQnxAudioRecorder::closeConnection()
72{
73 m_context.reset();
74 m_context.reset();
75
76 stopMonitoring();
77}
78
79void QQnxAudioRecorder::attach()
80{
81 if (isAttached())
82 return;
83
84 const QString container = m_encoderSettings.mimeType().preferredSuffix();
87
88 m_audioId = mmr_output_attach(m_context.get(), qPrintable(location), "file");
89
90 if (m_audioId == -1) {
91 qWarning("QQnxAudioRecorder: mmr_output_attach() for file failed");
92 return;
93 }
94
95 configureOutputBitRate();
96
97 const QByteArray devicePath = buildDevicePath(m_inputDeviceId, m_encoderSettings);
98
99 if (mmr_input_attach(m_context.get(), devicePath.constData(), "track") != 0) {
100 qWarning("QQnxAudioRecorder: mmr_input_attach() failed");
101 detach();
102 } else {
104 }
105}
106
107void QQnxAudioRecorder::detach()
108{
109 if (!isAttached())
110 return;
111
112 mmr_input_detach(m_context.get());
113 mmr_output_detach(m_context.get(), m_audioId);
114
115 m_audioId = -1;
116}
117
118void QQnxAudioRecorder::configureOutputBitRate()
119{
120 const int bitRate = m_encoderSettings.audioBitRate();
121
122 if (!isAttached() || bitRate <= 0)
123 return;
124
125 char buf[12];
126 std::snprintf(buf, sizeof buf, "%d", bitRate);
127
128 strm_dict_t *dict = strm_dict_new();
129 dict = strm_dict_set(dict, "audio_bitrate", buf);
130
131 if (mmr_output_parameters(m_context.get(), m_audioId, dict) != 0)
132 qWarning("mmr_output_parameters: setting bitrate failed");
133}
134
135bool QQnxAudioRecorder::isAttached() const
136{
137 return m_context && m_audioId != -1;
138}
139
141{
142 m_inputDeviceId = id;
143}
144
146{
147 m_outputUrl = url;
148}
149
154
156{
157 if (!isAttached()) {
158 attach();
159
160 if (!isAttached())
161 return;
162 }
163
164 if (mmr_play(m_context.get()) != 0)
165 qWarning("QQnxAudioRecorder: mmr_play() failed");
166}
167
169{
170 if (!isAttached())
171 return;
172
173 mmr_stop(m_context.get());
174
175 detach();
176}
177
178void QQnxAudioRecorder::startMonitoring()
179{
180 m_eventThread = std::make_unique<QQnxMediaEventThread>(m_context.get());
181
182 connect(m_eventThread.get(), &QQnxMediaEventThread::eventPending,
183 this, &QQnxAudioRecorder::readEvents);
184
185 m_eventThread->setObjectName(QStringLiteral("MmrAudioEventThread-") + QString::number(m_id));
186 m_eventThread->start();
187}
188
189void QQnxAudioRecorder::stopMonitoring()
190{
191 if (m_eventThread)
192 m_eventThread.reset();
193}
194
195void QQnxAudioRecorder::readEvents()
196{
197 while (const mmr_event_t *event = mmr_event_get(m_context.get())) {
198 if (event->type == MMR_EVENT_NONE)
199 break;
200
201 switch (event->type) {
202 case MMR_EVENT_STATUS:
203 handleMmEventStatus(event);
204 break;
205 case MMR_EVENT_STATE:
206 handleMmEventState(event);
207 break;
208 case MMR_EVENT_ERROR:
209 handleMmEventError(event);
210 break;
212 case MMR_EVENT_NONE:
216 case MMR_EVENT_INPUT:
217 case MMR_EVENT_OUTPUT:
219 case MMR_EVENT_TRKPAR:
220 case MMR_EVENT_OTHER:
221 break;
222 }
223 }
224
225 if (m_eventThread)
226 m_eventThread->signalRead();
227}
228
229void QQnxAudioRecorder::handleMmEventStatus(const mmr_event_t *event)
230{
231 if (!event || event->type != MMR_EVENT_STATUS)
232 return;
233
234 if (!event->pos_str)
235 return;
236
237 const QByteArray valueBa(event->pos_str);
238
239 bool ok;
240 const qint64 duration = valueBa.toLongLong(&ok);
241
242 if (!ok)
243 qCritical("Could not parse duration from '%s'", valueBa.constData());
244 else
245 durationChanged(duration);
246}
247
248void QQnxAudioRecorder::handleMmEventState(const mmr_event_t *event)
249{
250 if (!event || event->type != MMR_EVENT_STATE)
251 return;
252
253 switch (event->state) {
255 case MMR_STATE_IDLE:
258 break;
261 break;
262 }
263}
264
265void QQnxAudioRecorder::handleMmEventError(const mmr_event_t *event)
266{
267 if (!event)
268 return;
269
270 // When playback is explicitly stopped using mmr_stop(), mm-renderer
271 // generates a STATE event. When the end of media is reached, an ERROR
272 // event is generated and the error code contained in the event information
273 // is set to MMR_ERROR_NONE. When an error causes playback to stop,
274 // the error code is set to something else.
275 if (event->details.error.info.error_code == MMR_ERROR_NONE) {
276 //TODO add error
278 detach();
279 }
280}
281
283
284#include "moc_qqnxaudiorecorder_p.cpp"
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
static qint64 applicationPid() Q_DECL_CONST_FUNCTION
QString preferredSuffix
the preferred suffix for the MIME type
Definition qmimetype.h:38
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
void setInputDeviceId(const QByteArray &id)
void durationChanged(qint64 durationMs)
void setOutputUrl(const QUrl &url)
void stateChanged(QMediaRecorder::RecorderState state)
QQnxAudioRecorder(QObject *parent=nullptr)
void setMediaEncoderSettings(const QMediaEncoderSettings &settings)
void actualLocationChanged(const QUrl &location)
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
\inmodule QtCore
Definition qurl.h:94
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
Definition qurl.cpp:3425
@ MMR_STATE_DESTROYED
@ MMR_STATE_PLAYING
@ MMR_STATE_STOPPED
@ MMR_STATE_IDLE
@ MMR_EVENT_STATE
@ MMR_EVENT_OVERFLOW
@ MMR_EVENT_INPUT
@ MMR_EVENT_ERROR
@ MMR_EVENT_STATUS
@ MMR_EVENT_TRKPAR
@ MMR_EVENT_PLAYLIST
@ MMR_EVENT_CTXTPAR
@ MMR_EVENT_NONE
@ MMR_EVENT_OTHER
@ MMR_EVENT_OUTPUT
@ MMR_EVENT_METADATA
@ MMR_EVENT_WARNING
const mmr_event_t * mmr_event_get(mmr_context_t *ctxt)
Q_MULTIMEDIA_EXPORT QString generateFileName(const QString &requestedName, QStandardPaths::StandardLocation type, const QString &extension)
Combined button and popup list for selecting options.
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define qCritical
Definition qlogging.h:167
#define qWarning
Definition qlogging.h:166
GLint location
GLenum GLuint id
[7]
GLenum GLuint GLenum GLsizei const GLchar * buf
struct _cl_event * event
static QByteArray buildDevicePath(const QByteArray &deviceId, const QMediaEncoderSettings &settings)
struct strm_dict strm_dict_t
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
#define Q_EMIT
long long qint64
Definition qtypes.h:60
QSettings settings("MySoft", "Star Runner")
[0]
QUrl url("example.com")
[constructor-url-reference]