1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtCore/qmetaobject.h>
41#include <QtCore/qdebug.h>
42
43#include "qmediaobject_p.h"
44
45#include <qmediaservice.h>
46#include <qmetadatareadercontrol.h>
47#include <qmediabindableinterface.h>
48#include <qmediaavailabilitycontrol.h>
49
50QT_BEGIN_NAMESPACE
51
52void QMediaObjectPrivate::_q_notify()
53{
54 Q_Q(QMediaObject);
55
56 const QMetaObject* m = q->metaObject();
57
58 // QTBUG-57045
59 // we create a copy of notifyProperties container to ensure that if a property is removed
60 // from the original container as a result of invoking propertyChanged signal, the iterator
61 // won't become invalidated
62 QSet<int> properties = notifyProperties;
63
64 for (int pi : qAsConst(t&: properties)) {
65 QMetaProperty p = m->property(index: pi);
66 p.notifySignal().invoke(
67 object: q, val0: QGenericArgument(QMetaType::typeName(type: p.userType()), p.read(obj: q).data()));
68 }
69}
70
71void QMediaObjectPrivate::_q_availabilityChanged()
72{
73 Q_Q(QMediaObject);
74
75 // Really this should not always emit, but
76 // we can't really tell from here (isAvailable
77 // may not have changed, or the mediaobject's overridden
78 // availability() may not have changed).
79 q->availabilityChanged(availability: q->availability());
80 q->availabilityChanged(available: q->isAvailable());
81}
82
83/*!
84 \class QMediaObject
85
86 \brief The QMediaObject class provides a common base for multimedia objects.
87 \inmodule QtMultimedia
88
89 \ingroup multimedia
90 \ingroup multimedia_core
91
92 It provides some basic functionality that is common to other high level classes
93 like \l QMediaPlayer, \l QAudioDecoder and \l QCamera, including availability
94 and meta-data functionality, as well as functionality to connect media objects
95 with support classes like QMediaPlaylist.
96
97 The higher level QMediaObject derived classes provide the actual multimedia
98 functionality, by internally using a QMediaService. Each media object
99 hosts a QMediaService and uses the QMediaControl interfaces implemented by the service to implement its
100 API. These controls can be accessed from the media object if necessary, but in general
101 the useful functionality can be accessed from the higher level classes.
102
103 Most media objects when constructed will request a new
104 QMediaService instance, but some like
105 QMediaRecorder and QAudioRecorder will share a service with another object.
106
107 \sa QMediaService, QMediaControl
108*/
109
110/*!
111 Destroys this media object.
112*/
113
114QMediaObject::~QMediaObject()
115{
116}
117
118/*!
119 Returns the availability of the functionality offered by this object.
120
121 In some cases the functionality may not be available (for example, if
122 the current operating system or platform does not provide the required
123 functionality), or it may be temporarily unavailable (for example,
124 audio playback during a phone call or similar).
125*/
126
127QMultimedia::AvailabilityStatus QMediaObject::availability() const
128{
129 if (d_func()->service == nullptr)
130 return QMultimedia::ServiceMissing;
131
132 if (d_func()->availabilityControl)
133 return d_func()->availabilityControl->availability();
134
135 return QMultimedia::Available;
136}
137
138/*!
139 Returns true if the service is available for use.
140*/
141
142bool QMediaObject::isAvailable() const
143{
144 return availability() == QMultimedia::Available;
145}
146
147/*!
148 Returns the media service that provides the functionality of this multimedia object.
149*/
150
151QMediaService* QMediaObject::service() const
152{
153 return d_func()->service;
154}
155
156int QMediaObject::notifyInterval() const
157{
158 return d_func()->notifyTimer->interval();
159}
160
161void QMediaObject::setNotifyInterval(int milliSeconds)
162{
163 Q_D(QMediaObject);
164
165 if (d->notifyTimer->interval() != milliSeconds) {
166 d->notifyTimer->setInterval(milliSeconds);
167
168 emit notifyIntervalChanged(milliSeconds);
169 }
170}
171
172/*!
173 Bind \a object to this QMediaObject instance.
174
175 This method establishes a relationship between this media object and a
176 helper object. The nature of the relationship depends on both parties. This
177 methods returns true if the helper was successfully bound, false otherwise.
178
179 Most subclasses of QMediaObject provide more convenient functions
180 that wrap this functionality, so this function rarely needs to be
181 called directly.
182
183 The object passed must implement the QMediaBindableInterface interface.
184
185 \sa QMediaBindableInterface
186*/
187bool QMediaObject::bind(QObject *object)
188{
189 QMediaBindableInterface *helper = qobject_cast<QMediaBindableInterface*>(object);
190 if (!helper)
191 return false;
192
193 QMediaObject *currentObject = helper->mediaObject();
194
195 if (currentObject == this)
196 return true;
197
198 if (currentObject)
199 currentObject->unbind(object);
200
201 return helper->setMediaObject(this);
202}
203
204/*!
205 Detach \a object from the QMediaObject instance.
206
207 Unbind the helper object from this media object. A warning
208 will be generated if the object was not previously bound to this
209 object.
210
211 \sa QMediaBindableInterface
212*/
213void QMediaObject::unbind(QObject *object)
214{
215 QMediaBindableInterface *helper = qobject_cast<QMediaBindableInterface*>(object);
216
217 if (helper && helper->mediaObject() == this)
218 helper->setMediaObject(nullptr);
219 else
220 qWarning() << "QMediaObject: Trying to unbind not connected helper object";
221}
222
223/*!
224 Constructs a media object which uses the functionality provided by a media \a service.
225
226 The \a parent is passed to QObject.
227
228 This class is meant as a base class for multimedia objects so this
229 constructor is protected.
230*/
231
232QMediaObject::QMediaObject(QObject *parent, QMediaService *service)
233 : QObject(*new QMediaObjectPrivate, parent)
234{
235 Q_D(QMediaObject);
236
237 d->notifyTimer = new QTimer(this);
238 d->notifyTimer->setInterval(1000);
239 connect(asender: d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify()));
240
241 d->service = service;
242
243 setupControls();
244}
245
246/*!
247 \internal
248*/
249
250QMediaObject::QMediaObject(QMediaObjectPrivate &dd, QObject *parent, QMediaService *service)
251 : QObject(dd, parent)
252{
253 Q_D(QMediaObject);
254
255 d->notifyTimer = new QTimer(this);
256 d->notifyTimer->setInterval(1000);
257 connect(asender: d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify()));
258
259 d->service = service;
260
261 setupControls();
262}
263
264/*!
265 Watch the property \a name. The property's notify signal will be emitted
266 once every \c notifyInterval milliseconds.
267
268 \sa notifyInterval
269*/
270
271void QMediaObject::addPropertyWatch(QByteArray const &name)
272{
273 Q_D(QMediaObject);
274
275 const QMetaObject* m = metaObject();
276
277 int index = m->indexOfProperty(name: name.constData());
278
279 if (index != -1 && m->property(index).hasNotifySignal()) {
280 d->notifyProperties.insert(value: index);
281
282 if (!d->notifyTimer->isActive())
283 d->notifyTimer->start();
284 }
285}
286
287/*!
288 Remove property \a name from the list of properties whose changes are
289 regularly signaled.
290
291 \sa notifyInterval
292*/
293
294void QMediaObject::removePropertyWatch(QByteArray const &name)
295{
296 Q_D(QMediaObject);
297
298 int index = metaObject()->indexOfProperty(name: name.constData());
299
300 if (index != -1) {
301 d->notifyProperties.remove(value: index);
302
303 if (d->notifyProperties.isEmpty())
304 d->notifyTimer->stop();
305 }
306}
307
308/*!
309 \property QMediaObject::notifyInterval
310
311 The interval at which notifiable properties will update.
312
313 The interval is expressed in milliseconds, the default value is 1000.
314
315 \sa addPropertyWatch(), removePropertyWatch()
316*/
317
318/*!
319 \fn void QMediaObject::notifyIntervalChanged(int milliseconds)
320
321 Signal a change in the notify interval period to \a milliseconds.
322*/
323
324/*!
325 Returns true if there is meta-data associated with this media object, else false.
326*/
327
328bool QMediaObject::isMetaDataAvailable() const
329{
330 Q_D(const QMediaObject);
331
332 return d->metaDataControl
333 ? d->metaDataControl->isMetaDataAvailable()
334 : false;
335}
336
337/*!
338 \fn QMediaObject::metaDataAvailableChanged(bool available)
339
340 Signals that the \a available state of a media object's meta-data has changed.
341*/
342
343/*!
344 Returns the value associated with a meta-data \a key.
345
346 See the list of predefined \l {QMediaMetaData}{meta-data keys}.
347*/
348QVariant QMediaObject::metaData(const QString &key) const
349{
350 Q_D(const QMediaObject);
351
352 return d->metaDataControl
353 ? d->metaDataControl->metaData(key)
354 : QVariant();
355}
356
357/*!
358 Returns a list of keys there is meta-data available for.
359*/
360QStringList QMediaObject::availableMetaData() const
361{
362 Q_D(const QMediaObject);
363
364 return d->metaDataControl
365 ? d->metaDataControl->availableMetaData()
366 : QStringList();
367}
368
369/*!
370 \fn QMediaObject::metaDataChanged()
371
372 Signals that this media object's meta-data has changed.
373
374 If multiple meta-data elements are changed,
375 metaDataChanged(const QString &key, const QVariant &value) signal is emitted
376 for each of them with metaDataChanged() changed emitted once.
377*/
378
379/*!
380 \fn QMediaObject::metaDataChanged(const QString &key, const QVariant &value)
381
382 Signal the changes of one meta-data element \a value with the given \a key.
383*/
384
385
386void QMediaObject::setupControls()
387{
388 Q_D(QMediaObject);
389
390 if (d->service != nullptr) {
391 d->metaDataControl = qobject_cast<QMetaDataReaderControl*>(
392 object: d->service->requestControl(QMetaDataReaderControl_iid));
393
394 if (d->metaDataControl) {
395 connect(asender: d->metaDataControl, SIGNAL(metaDataChanged()), SIGNAL(metaDataChanged()));
396 connect(asender: d->metaDataControl,
397 SIGNAL(metaDataChanged(QString,QVariant)),
398 SIGNAL(metaDataChanged(QString,QVariant)));
399 connect(asender: d->metaDataControl,
400 SIGNAL(metaDataAvailableChanged(bool)),
401 SIGNAL(metaDataAvailableChanged(bool)));
402 }
403
404 d->availabilityControl = d->service->requestControl<QMediaAvailabilityControl*>();
405 if (d->availabilityControl) {
406 connect(asender: d->availabilityControl,
407 SIGNAL(availabilityChanged(QMultimedia::AvailabilityStatus)),
408 SLOT(_q_availabilityChanged()));
409 }
410 }
411}
412
413/*!
414 \fn QMediaObject::availabilityChanged(bool available)
415
416 Signal emitted when the availability state has changed to \a available.
417*/
418
419/*!
420 \fn QMediaObject::availabilityChanged(QMultimedia::AvailabilityStatus availability)
421
422 Signal emitted when the availability of the service has changed to \a availability.
423*/
424
425QT_END_NAMESPACE
426
427#include "moc_qmediaobject.cpp"
428

source code of qtmultimedia/src/multimedia/qmediaobject.cpp