| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include <QtCore/qmetaobject.h> |
| #include <QtCore/qdebug.h> |
| |
| #include "qmediaobject_p.h" |
| |
| #include <qmediaservice.h> |
| #include <qmetadatareadercontrol.h> |
| #include <qmediabindableinterface.h> |
| #include <qmediaavailabilitycontrol.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| void QMediaObjectPrivate::_q_notify() |
| { |
| Q_Q(QMediaObject); |
| |
| const QMetaObject* m = q->metaObject(); |
| |
| // QTBUG-57045 |
| // we create a copy of notifyProperties container to ensure that if a property is removed |
| // from the original container as a result of invoking propertyChanged signal, the iterator |
| // won't become invalidated |
| QSet<int> properties = notifyProperties; |
| |
| for (int pi : qAsConst(properties)) { |
| QMetaProperty p = m->property(pi); |
| p.notifySignal().invoke( |
| q, QGenericArgument(QMetaType::typeName(p.userType()), p.read(q).data())); |
| } |
| } |
| |
| void QMediaObjectPrivate::_q_availabilityChanged() |
| { |
| Q_Q(QMediaObject); |
| |
| // Really this should not always emit, but |
| // we can't really tell from here (isAvailable |
| // may not have changed, or the mediaobject's overridden |
| // availability() may not have changed). |
| q->availabilityChanged(q->availability()); |
| q->availabilityChanged(q->isAvailable()); |
| } |
| |
| /*! |
| \class QMediaObject |
| |
| \brief The QMediaObject class provides a common base for multimedia objects. |
| \inmodule QtMultimedia |
| |
| \ingroup multimedia |
| \ingroup multimedia_core |
| |
| It provides some basic functionality that is common to other high level classes |
| like \l QMediaPlayer, \l QAudioDecoder and \l QCamera, including availability |
| and meta-data functionality, as well as functionality to connect media objects |
| with support classes like QMediaPlaylist. |
| |
| The higher level QMediaObject derived classes provide the actual multimedia |
| functionality, by internally using a QMediaService. Each media object |
| hosts a QMediaService and uses the QMediaControl interfaces implemented by the service to implement its |
| API. These controls can be accessed from the media object if necessary, but in general |
| the useful functionality can be accessed from the higher level classes. |
| |
| Most media objects when constructed will request a new |
| QMediaService instance, but some like |
| QMediaRecorder and QAudioRecorder will share a service with another object. |
| |
| \sa QMediaService, QMediaControl |
| */ |
| |
| /*! |
| Destroys this media object. |
| */ |
| |
| QMediaObject::~QMediaObject() |
| { |
| } |
| |
| /*! |
| Returns the availability of the functionality offered by this object. |
| |
| In some cases the functionality may not be available (for example, if |
| the current operating system or platform does not provide the required |
| functionality), or it may be temporarily unavailable (for example, |
| audio playback during a phone call or similar). |
| */ |
| |
| QMultimedia::AvailabilityStatus QMediaObject::availability() const |
| { |
| if (d_func()->service == nullptr) |
| return QMultimedia::ServiceMissing; |
| |
| if (d_func()->availabilityControl) |
| return d_func()->availabilityControl->availability(); |
| |
| return QMultimedia::Available; |
| } |
| |
| /*! |
| Returns true if the service is available for use. |
| */ |
| |
| bool QMediaObject::isAvailable() const |
| { |
| return availability() == QMultimedia::Available; |
| } |
| |
| /*! |
| Returns the media service that provides the functionality of this multimedia object. |
| */ |
| |
| QMediaService* QMediaObject::service() const |
| { |
| return d_func()->service; |
| } |
| |
| int QMediaObject::notifyInterval() const |
| { |
| return d_func()->notifyTimer->interval(); |
| } |
| |
| void QMediaObject::setNotifyInterval(int milliSeconds) |
| { |
| Q_D(QMediaObject); |
| |
| if (d->notifyTimer->interval() != milliSeconds) { |
| d->notifyTimer->setInterval(milliSeconds); |
| |
| emit notifyIntervalChanged(milliSeconds); |
| } |
| } |
| |
| /*! |
| Bind \a object to this QMediaObject instance. |
| |
| This method establishes a relationship between this media object and a |
| helper object. The nature of the relationship depends on both parties. This |
| methods returns true if the helper was successfully bound, false otherwise. |
| |
| Most subclasses of QMediaObject provide more convenient functions |
| that wrap this functionality, so this function rarely needs to be |
| called directly. |
| |
| The object passed must implement the QMediaBindableInterface interface. |
| |
| \sa QMediaBindableInterface |
| */ |
| bool QMediaObject::bind(QObject *object) |
| { |
| QMediaBindableInterface *helper = qobject_cast<QMediaBindableInterface*>(object); |
| if (!helper) |
| return false; |
| |
| QMediaObject *currentObject = helper->mediaObject(); |
| |
| if (currentObject == this) |
| return true; |
| |
| if (currentObject) |
| currentObject->unbind(object); |
| |
| return helper->setMediaObject(this); |
| } |
| |
| /*! |
| Detach \a object from the QMediaObject instance. |
| |
| Unbind the helper object from this media object. A warning |
| will be generated if the object was not previously bound to this |
| object. |
| |
| \sa QMediaBindableInterface |
| */ |
| void QMediaObject::unbind(QObject *object) |
| { |
| QMediaBindableInterface *helper = qobject_cast<QMediaBindableInterface*>(object); |
| |
| if (helper && helper->mediaObject() == this) |
| helper->setMediaObject(nullptr); |
| else |
| qWarning() << "QMediaObject: Trying to unbind not connected helper object"; |
| } |
| |
| /*! |
| Constructs a media object which uses the functionality provided by a media \a service. |
| |
| The \a parent is passed to QObject. |
| |
| This class is meant as a base class for multimedia objects so this |
| constructor is protected. |
| */ |
| |
| QMediaObject::QMediaObject(QObject *parent, QMediaService *service) |
| : QObject(*new QMediaObjectPrivate, parent) |
| { |
| Q_D(QMediaObject); |
| |
| d->notifyTimer = new QTimer(this); |
| d->notifyTimer->setInterval(1000); |
| connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); |
| |
| d->service = service; |
| |
| setupControls(); |
| } |
| |
| /*! |
| \internal |
| */ |
| |
| QMediaObject::QMediaObject(QMediaObjectPrivate &dd, QObject *parent, QMediaService *service) |
| : QObject(dd, parent) |
| { |
| Q_D(QMediaObject); |
| |
| d->notifyTimer = new QTimer(this); |
| d->notifyTimer->setInterval(1000); |
| connect(d->notifyTimer, SIGNAL(timeout()), SLOT(_q_notify())); |
| |
| d->service = service; |
| |
| setupControls(); |
| } |
| |
| /*! |
| Watch the property \a name. The property's notify signal will be emitted |
| once every \c notifyInterval milliseconds. |
| |
| \sa notifyInterval |
| */ |
| |
| void QMediaObject::addPropertyWatch(QByteArray const &name) |
| { |
| Q_D(QMediaObject); |
| |
| const QMetaObject* m = metaObject(); |
| |
| int index = m->indexOfProperty(name.constData()); |
| |
| if (index != -1 && m->property(index).hasNotifySignal()) { |
| d->notifyProperties.insert(index); |
| |
| if (!d->notifyTimer->isActive()) |
| d->notifyTimer->start(); |
| } |
| } |
| |
| /*! |
| Remove property \a name from the list of properties whose changes are |
| regularly signaled. |
| |
| \sa notifyInterval |
| */ |
| |
| void QMediaObject::removePropertyWatch(QByteArray const &name) |
| { |
| Q_D(QMediaObject); |
| |
| int index = metaObject()->indexOfProperty(name.constData()); |
| |
| if (index != -1) { |
| d->notifyProperties.remove(index); |
| |
| if (d->notifyProperties.isEmpty()) |
| d->notifyTimer->stop(); |
| } |
| } |
| |
| /*! |
| \property QMediaObject::notifyInterval |
| |
| The interval at which notifiable properties will update. |
| |
| The interval is expressed in milliseconds, the default value is 1000. |
| |
| \sa addPropertyWatch(), removePropertyWatch() |
| */ |
| |
| /*! |
| \fn void QMediaObject::notifyIntervalChanged(int milliseconds) |
| |
| Signal a change in the notify interval period to \a milliseconds. |
| */ |
| |
| /*! |
| Returns true if there is meta-data associated with this media object, else false. |
| */ |
| |
| bool QMediaObject::isMetaDataAvailable() const |
| { |
| Q_D(const QMediaObject); |
| |
| return d->metaDataControl |
| ? d->metaDataControl->isMetaDataAvailable() |
| : false; |
| } |
| |
| /*! |
| \fn QMediaObject::metaDataAvailableChanged(bool available) |
| |
| Signals that the \a available state of a media object's meta-data has changed. |
| */ |
| |
| /*! |
| Returns the value associated with a meta-data \a key. |
| |
| See the list of predefined \l {QMediaMetaData}{meta-data keys}. |
| */ |
| QVariant QMediaObject::metaData(const QString &key) const |
| { |
| Q_D(const QMediaObject); |
| |
| return d->metaDataControl |
| ? d->metaDataControl->metaData(key) |
| : QVariant(); |
| } |
| |
| /*! |
| Returns a list of keys there is meta-data available for. |
| */ |
| QStringList QMediaObject::availableMetaData() const |
| { |
| Q_D(const QMediaObject); |
| |
| return d->metaDataControl |
| ? d->metaDataControl->availableMetaData() |
| : QStringList(); |
| } |
| |
| /*! |
| \fn QMediaObject::metaDataChanged() |
| |
| Signals that this media object's meta-data has changed. |
| |
| If multiple meta-data elements are changed, |
| metaDataChanged(const QString &key, const QVariant &value) signal is emitted |
| for each of them with metaDataChanged() changed emitted once. |
| */ |
| |
| /*! |
| \fn QMediaObject::metaDataChanged(const QString &key, const QVariant &value) |
| |
| Signal the changes of one meta-data element \a value with the given \a key. |
| */ |
| |
| |
| void QMediaObject::setupControls() |
| { |
| Q_D(QMediaObject); |
| |
| if (d->service != nullptr) { |
| d->metaDataControl = qobject_cast<QMetaDataReaderControl*>( |
| d->service->requestControl(QMetaDataReaderControl_iid)); |
| |
| if (d->metaDataControl) { |
| connect(d->metaDataControl, SIGNAL(metaDataChanged()), SIGNAL(metaDataChanged())); |
| connect(d->metaDataControl, |
| SIGNAL(metaDataChanged(QString,QVariant)), |
| SIGNAL(metaDataChanged(QString,QVariant))); |
| connect(d->metaDataControl, |
| SIGNAL(metaDataAvailableChanged(bool)), |
| SIGNAL(metaDataAvailableChanged(bool))); |
| } |
| |
| d->availabilityControl = d->service->requestControl<QMediaAvailabilityControl*>(); |
| if (d->availabilityControl) { |
| connect(d->availabilityControl, |
| SIGNAL(availabilityChanged(QMultimedia::AvailabilityStatus)), |
| SLOT(_q_availabilityChanged())); |
| } |
| } |
| } |
| |
| /*! |
| \fn QMediaObject::availabilityChanged(bool available) |
| |
| Signal emitted when the availability state has changed to \a available. |
| */ |
| |
| /*! |
| \fn QMediaObject::availabilityChanged(QMultimedia::AvailabilityStatus availability) |
| |
| Signal emitted when the availability of the service has changed to \a availability. |
| */ |
| |
| QT_END_NAMESPACE |
| |
| #include "moc_qmediaobject.cpp" |