diff options
author | Gareth Stockwell <gareth.stockwell@sosco.com> | 2009-08-19 12:57:27 +0100 |
---|---|---|
committer | Gareth Stockwell <gareth.stockwell@sosco.com> | 2009-08-19 12:57:27 +0100 |
commit | d9e03376f9f82e5664dfd2446ff4c05e35ffb535 (patch) | |
tree | 711f77f7d307c05a3ae310b1fd59bbce74bd8eab /src/3rdparty/phonon | |
parent | 98d4c657803d5f1956560bd9b62e73f15c05e8fd (diff) | |
parent | ca0b5b503e8865c0eedeea86aa132291281fc49f (diff) |
Merged in DummyPlayer changes
Diffstat (limited to 'src/3rdparty/phonon')
-rw-r--r-- | src/3rdparty/phonon/ds9/effect.cpp | 3 | ||||
-rw-r--r-- | src/3rdparty/phonon/ds9/mediaobject.cpp | 62 | ||||
-rw-r--r-- | src/3rdparty/phonon/ds9/mediaobject.h | 4 | ||||
-rw-r--r-- | src/3rdparty/phonon/ds9/videowidget.cpp | 17 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/abstractplayer.h | 3 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/dummyplayer.cpp | 137 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/dummyplayer.h | 74 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/mediaobject.cpp | 180 | ||||
-rw-r--r-- | src/3rdparty/phonon/phonon/effectwidget.cpp | 11 | ||||
-rw-r--r-- | src/3rdparty/phonon/phonon/mediasource.cpp | 8 |
10 files changed, 315 insertions, 184 deletions
diff --git a/src/3rdparty/phonon/ds9/effect.cpp b/src/3rdparty/phonon/ds9/effect.cpp index dc4ac3d603..104a3c144f 100644 --- a/src/3rdparty/phonon/ds9/effect.cpp +++ b/src/3rdparty/phonon/ds9/effect.cpp @@ -138,8 +138,7 @@ namespace Phonon ComPointer<IMediaParams> params(filter, IID_IMediaParams); Q_ASSERT(params); - MP_DATA data = float(v.toDouble()); - params->SetParam(p.id(), data); + params->SetParam(p.id(), v.toFloat()); } } diff --git a/src/3rdparty/phonon/ds9/mediaobject.cpp b/src/3rdparty/phonon/ds9/mediaobject.cpp index 10782c2519..de2078ab3e 100644 --- a/src/3rdparty/phonon/ds9/mediaobject.cpp +++ b/src/3rdparty/phonon/ds9/mediaobject.cpp @@ -57,24 +57,6 @@ namespace Phonon { } - WorkerThread::Work WorkerThread::dequeueWork() - { - QMutexLocker locker(&m_mutex); - if (m_finished) { - return Work(); - } - Work ret = m_queue.dequeue(); - - //we ensure to have the wait condition in the right state - if (m_queue.isEmpty()) { - m_waitCondition.reset(); - } else { - m_waitCondition.set(); - } - - return ret; - } - void WorkerThread::run() { while (m_finished == false) { @@ -88,11 +70,6 @@ namespace Phonon } DWORD result = ::WaitForMultipleObjects(count, handles, FALSE, INFINITE); if (result == WAIT_OBJECT_0) { - if (m_finished) { - //that's the end of the thread execution - return; - } - handleTask(); } else { //this is the event management @@ -199,22 +176,28 @@ namespace Phonon void WorkerThread::handleTask() { - const Work w = dequeueWork(); - - if (m_finished) { + QMutexLocker locker(&m_mutex); + if (m_finished || m_queue.isEmpty()) { return; } + const Work w = m_queue.dequeue(); + + //we ensure to have the wait condition in the right state + if (m_queue.isEmpty()) { + m_waitCondition.reset(); + } else { + m_waitCondition.set(); + } + HRESULT hr = S_OK; { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_currentMutex); m_currentRender = w.graph; - m_currentRenderId = w.id; + m_currentRenderId = w.id; } - if (w.task == ReplaceGraph) { - QMutexLocker locker(&m_mutex); int index = -1; for(int i = 0; i < FILTER_COUNT; ++i) { if (m_graphHandle[i].graph == w.oldGraph) { @@ -328,7 +311,7 @@ namespace Phonon } { - QMutexLocker locker(&m_mutex); + QMutexLocker locker(&m_currentMutex); m_currentRender = Graph(); m_currentRenderId = 0; } @@ -336,6 +319,13 @@ namespace Phonon void WorkerThread::abortCurrentRender(qint16 renderId) { + { + QMutexLocker locker(&m_currentMutex); + if (m_currentRender && m_currentRenderId == renderId) { + m_currentRender->Abort(); + } + } + QMutexLocker locker(&m_mutex); bool found = false; for(int i = 0; !found && i < m_queue.size(); ++i) { @@ -343,12 +333,11 @@ namespace Phonon if (w.id == renderId) { found = true; m_queue.removeAt(i); + if (m_queue.isEmpty()) { + m_waitCondition.reset(); + } } } - - if (m_currentRender && m_currentRenderId == renderId) { - m_currentRender->Abort(); - } } //tells the thread to stop processing @@ -523,6 +512,9 @@ namespace Phonon qSwap(m_graphs[0], m_graphs[1]); //swap the graphs + if (m_transitionTime >= 0) + m_graphs[1]->stop(); //make sure we stop the previous graph + if (currentGraph()->mediaSource().type() != Phonon::MediaSource::Invalid && catchComError(currentGraph()->renderResult())) { setState(Phonon::ErrorState); diff --git a/src/3rdparty/phonon/ds9/mediaobject.h b/src/3rdparty/phonon/ds9/mediaobject.h index 2c34ffc35b..a6beb5f593 100644 --- a/src/3rdparty/phonon/ds9/mediaobject.h +++ b/src/3rdparty/phonon/ds9/mediaobject.h @@ -135,7 +135,6 @@ namespace Phonon }; QList<Filter> decoders; //for the state change requests }; - Work dequeueWork(); void handleTask(); Graph m_currentRender; @@ -144,7 +143,8 @@ namespace Phonon bool m_finished; quint16 m_currentWorkId; QWinWaitCondition m_waitCondition; - QMutex m_mutex; + QMutex m_mutex; // mutex for the m_queue, m_finished and m_currentWorkId + QMutex m_currentMutex; //mutex for current renderer and id //this is for WaitForMultipleObjects struct diff --git a/src/3rdparty/phonon/ds9/videowidget.cpp b/src/3rdparty/phonon/ds9/videowidget.cpp index 34ff8cbb8c..091be16d94 100644 --- a/src/3rdparty/phonon/ds9/videowidget.cpp +++ b/src/3rdparty/phonon/ds9/videowidget.cpp @@ -84,7 +84,19 @@ namespace Phonon void setCurrentRenderer(AbstractVideoRenderer *renderer) { m_currentRenderer = renderer; - update(); + //we disallow repaint on that widget for just a fraction of second + //this allows better transition between videos + setUpdatesEnabled(false); + m_flickerFreeTimer.start(20, this); + } + + void timerEvent(QTimerEvent *e) + { + if (e->timerId() == m_flickerFreeTimer.timerId()) { + m_flickerFreeTimer.stop(); + setUpdatesEnabled(true); + } + QWidget::timerEvent(e); } QSize sizeHint() const @@ -106,6 +118,8 @@ namespace Phonon void paintEvent(QPaintEvent *e) { + if (!updatesEnabled()) + return; //this avoids repaint from native events checkCurrentRenderingMode(); m_currentRenderer->repaintCurrentFrame(this, e->rect()); } @@ -160,6 +174,7 @@ namespace Phonon VideoWidget *m_node; AbstractVideoRenderer *m_currentRenderer; QVariant m_restoreScreenSaverActive; + QBasicTimer m_flickerFreeTimer; }; VideoWidget::VideoWidget(QWidget *parent) diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index 97527ff3ab..02c08079d6 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -56,8 +56,7 @@ namespace Phonon // This is a temporary hack to work around KErrInUse from MMF // client utility OpenFileL calls //virtual void setSource(const Phonon::MediaSource &) = 0; - virtual void setFileSource - (const Phonon::MediaSource&, RFile&) = 0; + virtual void setFileSource(const Phonon::MediaSource&, RFile&) = 0; virtual void setNextSource(const Phonon::MediaSource &) = 0; diff --git a/src/3rdparty/phonon/mmf/dummyplayer.cpp b/src/3rdparty/phonon/mmf/dummyplayer.cpp new file mode 100644 index 0000000000..ecd68159c1 --- /dev/null +++ b/src/3rdparty/phonon/mmf/dummyplayer.cpp @@ -0,0 +1,137 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "dummyplayer.h" + +using namespace Phonon; +using namespace Phonon::MMF; + +void MMF::DummyPlayer::play() +{ +} + +void MMF::DummyPlayer::pause() +{ +} + +void MMF::DummyPlayer::stop() +{ +} + +void MMF::DummyPlayer::seek(qint64) +{ +} + +qint32 MMF::DummyPlayer::tickInterval() const +{ + return 0; +} + +void MMF::DummyPlayer::setTickInterval(qint32) +{ +} + +bool MMF::DummyPlayer::hasVideo() const +{ + return false; +} + +bool MMF::DummyPlayer::isSeekable() const +{ + return false; +} + +Phonon::State MMF::DummyPlayer::state() const +{ + return Phonon::StoppedState; +} + +qint64 MMF::DummyPlayer::currentTime() const +{ + return 0; +} + +QString MMF::DummyPlayer::errorString() const +{ + return QString(); +} + +Phonon::ErrorType MMF::DummyPlayer::errorType() const +{ + return Phonon::NoError; +} + +qint64 MMF::DummyPlayer::totalTime() const +{ + return 0; +} + +MediaSource MMF::DummyPlayer::source() const +{ + return MediaSource(); +} + +void MMF::DummyPlayer::setSource(const MediaSource &) +{ +} + +void MMF::DummyPlayer::setNextSource(const MediaSource &) +{ +} + +qint32 MMF::DummyPlayer::prefinishMark() const +{ + return 0; +} + +void MMF::DummyPlayer::setPrefinishMark(qint32) +{ +} + +qint32 MMF::DummyPlayer::transitionTime() const +{ + return 0; +} + +void MMF::DummyPlayer::setTransitionTime(qint32) +{ +} + +void MMF::DummyPlayer::setFileSource(const Phonon::MediaSource &, RFile &) +{ +} + +//----------------------------------------------------------------------------- +// Volume +//----------------------------------------------------------------------------- + +qreal MMF::DummyPlayer::volume() const +{ + return 0; +} + +bool MMF::DummyPlayer::setVolume(qreal) +{ + return true; +} + +void MMF::DummyPlayer::setAudioOutput(AudioOutput *) +{ +} + + diff --git a/src/3rdparty/phonon/mmf/dummyplayer.h b/src/3rdparty/phonon/mmf/dummyplayer.h new file mode 100644 index 0000000000..263a013178 --- /dev/null +++ b/src/3rdparty/phonon/mmf/dummyplayer.h @@ -0,0 +1,74 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_DUMMYPLAYER_H +#define PHONON_MMF_DUMMYPLAYER_H + +#include "abstractplayer.h" + +namespace Phonon +{ + namespace MMF + { + class AudioOutput; + + /** + * @short In order to make the implementation of MediaObject simpler, + * we have this class. + */ + class DummyPlayer : public AbstractPlayer + { + public: + // AbstractPlayer + virtual void play(); + virtual void pause(); + virtual void stop(); + virtual void seek(qint64 milliseconds); + virtual qint32 tickInterval() const; + virtual void setTickInterval(qint32 interval); + virtual bool hasVideo() const; + virtual bool isSeekable() const; + virtual qint64 currentTime() const; + virtual Phonon::State state() const; + virtual QString errorString() const; + virtual Phonon::ErrorType errorType() const; + virtual qint64 totalTime() const; + virtual MediaSource source() const; + virtual void setSource(const MediaSource &); + virtual void setNextSource(const MediaSource &source); + virtual qint32 prefinishMark() const; + virtual void setPrefinishMark(qint32); + virtual qint32 transitionTime() const; + virtual void setTransitionTime(qint32); + virtual qreal volume() const; + virtual bool setVolume(qreal volume); + + virtual void setAudioOutput(AudioOutput* audioOutput); + virtual void setFileSource(const Phonon::MediaSource&, RFile&); + + Q_SIGNALS: + void totalTimeChanged(); + void stateChanged(Phonon::State oldState, + Phonon::State newState); + void finished(); + void tick(qint64 time); + }; + } +} + +#endif diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 5b0ac3693f..c5310a53d5 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -17,6 +17,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. */ #include "audioplayer.h" +#include "dummyplayer.h" #include "mediaobject.h" #include "utils.h" #include "videoplayer.h" @@ -32,6 +33,8 @@ using namespace Phonon::MMF; MMF::MediaObject::MediaObject(QObject *parent) : QObject::QObject(parent) , m_recognizerOpened(false) { + m_player.reset(new DummyPlayer()); + TRACE_CONTEXT(MediaObject::MediaObject, EAudioApi); TRACE_ENTRY_0(); @@ -142,145 +145,81 @@ MMF::MediaObject::MediaType MMF::MediaObject::fileMediaType void MMF::MediaObject::play() { - if(!m_player.isNull()) - { - m_player->play(); - } + m_player->play(); } void MMF::MediaObject::pause() { - if(!m_player.isNull()) - { - m_player->pause(); - } + m_player->pause(); } void MMF::MediaObject::stop() { - if(!m_player.isNull()) - { - m_player->stop(); - } + m_player->stop(); } void MMF::MediaObject::seek(qint64 ms) { - if(!m_player.isNull()) - { - m_player->seek(ms); - } + m_player->seek(ms); } qint32 MMF::MediaObject::tickInterval() const { - qint32 result = 0; - if(!m_player.isNull()) - { - result = m_player->tickInterval(); - } - return result; + return m_player->tickInterval(); } void MMF::MediaObject::setTickInterval(qint32 interval) { - if(!m_player.isNull()) - { - m_player->setTickInterval(interval); - } + m_player->setTickInterval(interval); } bool MMF::MediaObject::hasVideo() const { - bool result = false; - if(!m_player.isNull()) - { - result = m_player->hasVideo(); - } - return result; + return m_player->hasVideo(); } bool MMF::MediaObject::isSeekable() const { - bool result = false; - if(!m_player.isNull()) - { - result = m_player->isSeekable(); - } - return result; + return m_player->isSeekable(); } Phonon::State MMF::MediaObject::state() const { - Phonon::State result = Phonon::StoppedState; - if(!m_player.isNull()) - { - result = m_player->state(); - } - return result; + return m_player->state(); } qint64 MMF::MediaObject::currentTime() const { - qint64 result = 0; - if(!m_player.isNull()) - { - result = m_player->currentTime(); - } - return result; + return m_player->currentTime(); } QString MMF::MediaObject::errorString() const { - QString result; - if(!m_player.isNull()) - { - result = m_player->errorString(); - } - return result; + return m_player->errorString(); } Phonon::ErrorType MMF::MediaObject::errorType() const { - Phonon::ErrorType result = Phonon::NoError; - if(!m_player.isNull()) - { - result = m_player->errorType(); - } - return result; + return m_player->errorType(); } qint64 MMF::MediaObject::totalTime() const { - qint64 result = 0; - if(!m_player.isNull()) - { - result = m_player->totalTime(); - } - return result; + return m_player->totalTime(); } MediaSource MMF::MediaObject::source() const { - MediaSource result; - if(!m_player.isNull()) - { - result = m_player->source(); - } - return result; + return m_player->source(); } void MMF::MediaObject::setSource(const MediaSource &source) { - createPlayer(source); - if(!m_player.isNull()) - { - //m_player->setSource(source); - - // This is a hack to work around KErrInUse from MMF client utility - // OpenFileL calls - m_player->setFileSource(source, m_file); - } + createPlayer(source); + + // This is a hack to work around KErrInUse from MMF client utility + // OpenFileL calls + m_player->setFileSource(source, m_file); } void MMF::MediaObject::createPlayer(const MediaSource &source) @@ -289,12 +228,18 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) TRACE_ENTRY("state %d source.type %d", state(), source.type()); TRACE_ENTRY("source.type %d", source.type()); + // Store old player object +/* + AbstractPlayer* oldPlayer = m_player.take(); + + // Destroy old player object if(!m_player.isNull()) { disconnect(m_player.data(), 0, this, 0); - m_player.reset(NULL); + m_player.reset(); } +*/ MediaType mediaType = MediaTypeUnknown; @@ -308,14 +253,13 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) case MediaSource::Url: // TODO: support detection of media type from HTTP streams TRACE_0("Network streaming not supported yet"); - /* * TODO: handle error * m_error = NormalError; changeState(ErrorState); - break; */ + break; case MediaSource::Invalid: case MediaSource::Disc: @@ -330,14 +274,15 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) break; case MediaSource::Empty: - TRACE_EXIT_0(); - return; + TRACE_0("Empty media source"); + break; } switch(mediaType) { case MediaTypeUnknown: TRACE_0("Media type could not be determined"); + m_player.reset(new DummyPlayer()); /* * TODO: handle error * @@ -355,57 +300,35 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) break; } - if(!m_player.isNull()) - { - connect(m_player.data(), SIGNAL(totalTimeChanged()), SIGNAL(totalTimeChanged())); - connect(m_player.data(), SIGNAL(stateChanged(Phonon::State, Phonon::State)), SIGNAL(stateChanged(Phonon::State, Phonon::State))); - connect(m_player.data(), SIGNAL(finished()), SIGNAL(finished())); - connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64))); - } + connect(m_player.data(), SIGNAL(totalTimeChanged()), SIGNAL(totalTimeChanged())); + connect(m_player.data(), SIGNAL(stateChanged(Phonon::State, Phonon::State)), SIGNAL(stateChanged(Phonon::State, Phonon::State))); + connect(m_player.data(), SIGNAL(finished()), SIGNAL(finished())); + connect(m_player.data(), SIGNAL(tick(qint64)), SIGNAL(tick(qint64))); } void MMF::MediaObject::setNextSource(const MediaSource &source) { - if(!m_player.isNull()) - { - m_player->setNextSource(source); - } + m_player->setNextSource(source); } qint32 MMF::MediaObject::prefinishMark() const { - qint32 result = 0; - if(!m_player.isNull()) - { - result = m_player->prefinishMark(); - } - return result; + return m_player->prefinishMark(); } void MMF::MediaObject::setPrefinishMark(qint32 mark) { - if(!m_player.isNull()) - { - m_player->setPrefinishMark(mark); - } + m_player->setPrefinishMark(mark); } qint32 MMF::MediaObject::transitionTime() const { - qint32 result = 0; - if(!m_player.isNull()) - { - result = m_player->transitionTime(); - } - return result; + return m_player->transitionTime(); } void MMF::MediaObject::setTransitionTime(qint32 time) { - if(!m_player.isNull()) - { - m_player->setTransitionTime(time); - } + m_player->setTransitionTime(time); } //----------------------------------------------------------------------------- @@ -414,29 +337,16 @@ void MMF::MediaObject::setTransitionTime(qint32 time) qreal MMF::MediaObject::volume() const { - qreal result = 0.0; - if(!m_player.isNull()) - { - m_player->volume(); - } - return result; + return m_player->volume(); } bool MMF::MediaObject::setVolume(qreal volume) { - bool result = false; - if(!m_player.isNull()) - { - result = m_player->setVolume(volume); - } - return result; + return m_player->setVolume(volume); } void MMF::MediaObject::setAudioOutput(AudioOutput* audioOutput) { - if(!m_player.isNull()) - { - m_player->setAudioOutput(audioOutput); - } + m_player->setAudioOutput(audioOutput); } diff --git a/src/3rdparty/phonon/phonon/effectwidget.cpp b/src/3rdparty/phonon/phonon/effectwidget.cpp index 99478f7c09..fb9cf6e631 100644 --- a/src/3rdparty/phonon/phonon/effectwidget.cpp +++ b/src/3rdparty/phonon/phonon/effectwidget.cpp @@ -157,19 +157,20 @@ void EffectWidgetPrivate::autogenerateUi() QObject::connect(sb, SIGNAL(valueChanged(int)), q, SLOT(_k_setIntParameter(int))); } break; + case QMetaType::Float: case QVariant::Double: { - const double minValue = (para.minimumValue().type() == QVariant::Double ? - para.minimumValue().toDouble() : DEFAULT_MIN); - const double maxValue = (para.maximumValue().type() == QVariant::Double ? - para.maximumValue().toDouble() : DEFAULT_MAX); + const qreal minValue = para.minimumValue().canConvert(QVariant::Double) ? + para.minimumValue().toReal() : DEFAULT_MIN; + const qreal maxValue = para.maximumValue().canConvert(QVariant::Double) ? + para.maximumValue().toReal() : DEFAULT_MAX; if (minValue == -1. && maxValue == 1.) { //Special case values between -1 and 1.0 to use a slider for improved usability QSlider *slider = new QSlider(Qt::Horizontal, q); control = slider; slider->setRange(-SLIDER_RANGE, +SLIDER_RANGE); - slider->setValue(int(SLIDER_RANGE * value.toDouble())); + slider->setValue(int(SLIDER_RANGE * value.toReal())); slider->setTickPosition(QSlider::TicksBelow); slider->setTickInterval(TICKINTERVAL); QObject::connect(slider, SIGNAL(valueChanged(int)), q, SLOT(_k_setSliderParameter(int))); diff --git a/src/3rdparty/phonon/phonon/mediasource.cpp b/src/3rdparty/phonon/phonon/mediasource.cpp index 0a21c87664..c003af9884 100644 --- a/src/3rdparty/phonon/phonon/mediasource.cpp +++ b/src/3rdparty/phonon/phonon/mediasource.cpp @@ -140,8 +140,12 @@ MediaSourcePrivate::~MediaSourcePrivate() { #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM if (autoDelete) { - delete stream; - delete ioDevice; + //here we use deleteLater because this object + //might be destroyed from another thread + if (stream) + stream->deleteLater(); + if (ioDevice) + ioDevice->deleteLater(); } #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM } |