diff options
author | axis <qt-info@nokia.com> | 2010-01-21 12:20:33 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2010-01-21 12:20:33 (GMT) |
commit | 833bea1f71ed685e5f371d93f6f5c2da7be546e5 (patch) | |
tree | 09e3f60311ebf8af123a9e61f27908dd87118109 /src/3rdparty/phonon | |
parent | d609f7d1963e06d05fa6f7e4a098a304a177bc68 (diff) | |
parent | d83e82e5c8a7fa0f6b1dcc4b1ab56f22afd942f6 (diff) | |
download | Qt-833bea1f71ed685e5f371d93f6f5c2da7be546e5.zip Qt-833bea1f71ed685e5f371d93f6f5c2da7be546e5.tar.gz Qt-833bea1f71ed685e5f371d93f6f5c2da7be546e5.tar.bz2 |
Merge branch '4.6' of scm.dev.nokia.troll.no:qt/qt-s60-public
Conflicts:
mkspecs/features/symbian/platform_paths.prf
Diffstat (limited to 'src/3rdparty/phonon')
41 files changed, 1924 insertions, 678 deletions
diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp index a559249..132eb79 100644 --- a/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.cpp @@ -19,6 +19,8 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include "mediaobject.h" #include "abstractaudioeffect.h" +#include "audioplayer.h" +#include "mmf_videoplayer.h" QT_BEGIN_NAMESPACE @@ -34,24 +36,25 @@ using namespace Phonon::MMF; */ AbstractAudioEffect::AbstractAudioEffect(QObject *parent, - const QList<EffectParameter> ¶ms) : MediaNode::MediaNode(parent) - , m_params(params) + const QList<EffectParameter> ¶ms) + : MediaNode(parent) + , m_params(params) + , m_player(0) { -} -bool AbstractAudioEffect::disconnectMediaNode(MediaNode *target) -{ - MediaNode::disconnectMediaNode(target); - m_effect.reset(); - return true; } -QList<EffectParameter> AbstractAudioEffect::parameters() const +QList<Phonon::EffectParameter> AbstractAudioEffect::parameters() const { - return m_params; + // Convert from QList<MMF::EffectParameter> to QList<Phonon::EffectParameter> + QList<Phonon::EffectParameter> result; + EffectParameter param; + foreach (param, m_params) + result += param; + return result; } -QVariant AbstractAudioEffect::parameterValue(const EffectParameter &queriedParam) const +QVariant AbstractAudioEffect::parameterValue(const Phonon::EffectParameter &queriedParam) const { const QVariant &val = m_values.value(queriedParam.id()); @@ -61,22 +64,131 @@ QVariant AbstractAudioEffect::parameterValue(const EffectParameter &queriedParam return val; } -bool AbstractAudioEffect::activateOnMediaObject(MediaObject *mo) +void AbstractAudioEffect::setParameterValue(const Phonon::EffectParameter ¶m, + const QVariant &newValue) +{ + m_values.insert(param.id(), newValue); + + if (m_effect.data()) { + const EffectParameter& internalParam = internalParameter(param.id()); + int err = parameterChanged(internalParam, newValue); + // TODO: handle audio effect errors + Q_UNUSED(err); + } +} + +void AbstractAudioEffect::abstractPlayerChanged(AbstractPlayer *player) +{ + m_player = qobject_cast<AbstractMediaPlayer *>(player); + m_effect.reset(); +} + +void AbstractAudioEffect::stateChanged(Phonon::State newState, + Phonon::State oldState) +{ + if (Phonon::LoadingState == oldState + && Phonon::LoadingState != newState) + createEffect(); +} + +void AbstractAudioEffect::connectMediaObject(MediaObject *mediaObject) { - AudioPlayer *const ap = qobject_cast<AudioPlayer *>(mo->abstractPlayer()); + Q_ASSERT_X(!m_player, Q_FUNC_INFO, "Player already connected"); + Q_ASSERT_X(!m_effect.data(), Q_FUNC_INFO, "Effect already created"); + + abstractPlayerChanged(mediaObject->abstractPlayer()); + + connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), + SLOT(stateChanged(Phonon::State, Phonon::State))); - if (ap) - return activateOn(ap->player()); + connect(mediaObject, SIGNAL(abstractPlayerChanged(AbstractPlayer *)), + SLOT(abstractPlayerChanged(AbstractPlayer *))); + + if (mediaObject->state() != Phonon::LoadingState) + createEffect(); +} + +void AbstractAudioEffect::disconnectMediaObject(MediaObject *mediaObject) +{ + mediaObject->disconnect(this); + abstractPlayerChanged(0); +} + +void AbstractAudioEffect::setEnabled(bool enabled) +{ + TInt err = KErrNone; + + if (enabled) + // TODO: handle audio effect errors + TRAP(err, m_effect->EnableL()) else - return true; + // TODO: handle audio effect errors + TRAP(err, m_effect->DisableL()) + + Q_UNUSED(err); } -void AbstractAudioEffect::setParameterValue(const EffectParameter ¶m, - const QVariant &newValue) +void AbstractAudioEffect::createEffect() { - m_values.insert(param.id(), newValue); - parameterChanged(param.id(), newValue); + Q_ASSERT_X(m_player, Q_FUNC_INFO, "Invalid media player pointer"); + + if (AudioPlayer *audioPlayer = qobject_cast<AudioPlayer *>(m_player)) { + createEffect(audioPlayer->nativePlayer()); + } + + if (m_effect.data()) { + EffectParameter param; + int err = 0; + foreach (param, m_params) { + const QVariant value = parameterValue(param); + err = parameterChanged(param, value); + } + Q_UNUSED(err) + } } +const MMF::EffectParameter& AbstractAudioEffect::internalParameter(int id) const +{ + const EffectParameter *result = 0; + for (int i=0; i<m_params.count() && !result; ++i) { + if (m_params[i].id() == id) + result = &m_params[i]; + } + Q_ASSERT_X(result, Q_FUNC_INFO, "Parameter not found"); + return *result; +} + +int AbstractAudioEffect::parameterChanged(const EffectParameter ¶m, + const QVariant &value) +{ + int err = 0; + + switch (param.id()) { + case ParameterEnable: + setEnabled(value.toBool()); + break; + default: + { + const EffectParameter& internalParam = internalParameter(param.id()); + err = effectParameterChanged(internalParam, value); + } + break; + } + + if (!err) + TRAP(err, m_effect->ApplyL()); + + return err; +} + +int AbstractAudioEffect::effectParameterChanged( + const EffectParameter ¶m, const QVariant &value) +{ + // Default implementation + Q_ASSERT_X(false, Q_FUNC_INFO, "Effect has no parameters"); + return 0; +} + + QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/abstractaudioeffect.h b/src/3rdparty/phonon/mmf/abstractaudioeffect.h index 01542c9..436e8e4 100644 --- a/src/3rdparty/phonon/mmf/abstractaudioeffect.h +++ b/src/3rdparty/phonon/mmf/abstractaudioeffect.h @@ -19,15 +19,18 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_ABSTRACTEFFECT_H #define PHONON_MMF_ABSTRACTEFFECT_H -#include "mmf_medianode.h" - #include <QScopedPointer> #include <AudioEffectBase.h> -#include <Phonon/EffectInterface> -#include <Phonon/EffectParameter> +#include <phonon/effectinterface.h> + #include "audioplayer.h" +#include "effectparameter.h" +#include "mmf_medianode.h" +#include "mmf_videoplayer.h" + +class CMdaAudioOutputStream; QT_BEGIN_NAMESPACE @@ -35,6 +38,8 @@ namespace Phonon { namespace MMF { +class AbstractPlayer; +class AbstractMediaPlayer; /** * @short Base class for all effects for MMF. @@ -61,42 +66,71 @@ public: AbstractAudioEffect(QObject *parent, const QList<EffectParameter> ¶ms); - virtual QList<EffectParameter> parameters() const; - virtual QVariant parameterValue(const EffectParameter ¶m) const; - virtual void setParameterValue(const EffectParameter &, + // Phonon::EffectInterface + virtual QList<Phonon::EffectParameter> parameters() const; + virtual QVariant parameterValue(const Phonon::EffectParameter ¶m) const; + virtual void setParameterValue(const Phonon::EffectParameter &, const QVariant &newValue); - virtual bool disconnectMediaNode(MediaNode *target); - - enum Type + // Parameters which are shared by all effects + enum CommonParameters { - EffectAudioEqualizer = 1, - EffectBassBoost, - EffectDistanceAttenuation, - EffectEnvironmentalReverb, - EffectListenerOrientation, - EffectLoudness, - EffectSourceOrientation, - EffectStereoWidening + ParameterEnable = 0, + ParameterBase // must be last entry in enum }; +public Q_SLOTS: + void abstractPlayerChanged(AbstractPlayer *player); + void stateChanged(Phonon::State newState, + Phonon::State oldState); + protected: - virtual bool activateOn(CPlayerType *player) = 0; - virtual void parameterChanged(const int id, - const QVariant &value) = 0; + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); + + virtual void createEffect(AudioPlayer::NativePlayer *player) = 0; - /** - * Part of the implementation of AbstractAudioEffect. Forwards the call to - * activateOn(), essentially. - */ - virtual bool activateOnMediaObject(MediaObject *mo); + // Effect-specific parameter changed + virtual int effectParameterChanged(const EffectParameter ¶m, + const QVariant &value); +private: + void createEffect(); + void setEnabled(bool enabled); + const EffectParameter& internalParameter(int id) const; + int parameterChanged(const EffectParameter ¶m, + const QVariant &value); + +protected: QScopedPointer<CAudioEffect> m_effect; + private: const QList<EffectParameter> m_params; + AbstractMediaPlayer * m_player; QHash<int, QVariant> m_values; }; + +} } + + +// Macro for defining functions which depend on the native class name +// for each of the effects. Using this reduces repetition of boilerplate +// in the implementations of the backend effect nodes. + +#define PHONON_MMF_DEFINE_EFFECT_FUNCTIONS(Effect) \ + \ +void Effect##::createEffect(AudioPlayer::NativePlayer *player) \ +{ \ + C##Effect *ptr = 0; \ + QT_TRAP_THROWING(ptr = C##Effect::NewL(*player)); \ + m_effect.reset(ptr); \ +} \ + \ +C##Effect* Effect::concreteEffect() \ +{ \ + return static_cast<C##Effect *>(m_effect.data()); \ } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp index 99e96cd..544762a 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.cpp @@ -20,6 +20,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include "abstractmediaplayer.h" #include "defs.h" +#include "mediaobject.h" #include "utils.h" QT_BEGIN_NAMESPACE @@ -36,27 +37,26 @@ using namespace Phonon::MMF; //----------------------------------------------------------------------------- const int NullMaxVolume = -1; +const int BufferStatusTimerInterval = 100; // ms //----------------------------------------------------------------------------- // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AbstractMediaPlayer::AbstractMediaPlayer() : - m_playPending(false) - , m_tickTimer(new QTimer(this)) - , m_mmfMaxVolume(NullMaxVolume) -{ - connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick())); -} - -MMF::AbstractMediaPlayer::AbstractMediaPlayer(const AbstractPlayer& player) : - AbstractPlayer(player) +MMF::AbstractMediaPlayer::AbstractMediaPlayer + (MediaObject *parent, const AbstractPlayer *player) + : AbstractPlayer(player) + , m_parent(parent) , m_playPending(false) - , m_tickTimer(new QTimer(this)) + , m_positionTimer(new QTimer(this)) + , m_bufferStatusTimer(new QTimer(this)) , m_mmfMaxVolume(NullMaxVolume) + , m_prefinishMarkSent(false) + , m_aboutToFinishSent(false) { - connect(m_tickTimer.data(), SIGNAL(timeout()), this, SLOT(tick())); + connect(m_positionTimer.data(), SIGNAL(timeout()), this, SLOT(positionTick())); + connect(m_bufferStatusTimer.data(), SIGNAL(timeout()), this, SLOT(bufferStatusTick())); } //----------------------------------------------------------------------------- @@ -70,7 +70,7 @@ void MMF::AbstractMediaPlayer::play() switch (privateState()) { case GroundState: - setError(NormalError); + setError(tr("Not ready to play")); break; case LoadingState: @@ -80,7 +80,7 @@ void MMF::AbstractMediaPlayer::play() case StoppedState: case PausedState: doPlay(); - startTickTimer(); + startPositionTimer(); changeState(PlayingState); break; @@ -104,21 +104,22 @@ void MMF::AbstractMediaPlayer::pause() TRACE_ENTRY("state %d", privateState()); m_playPending = false; + stopTimers(); switch (privateState()) { case GroundState: case LoadingState: case PausedState: + case StoppedState: // Do nothing break; - case StoppedState: case PlayingState: - case ErrorState: case BufferingState: - doPause(); - stopTickTimer(); changeState(PausedState); + // Fall through + case ErrorState: + doPause(); break; // Protection against adding new states and forgetting to update this switch @@ -135,6 +136,7 @@ void MMF::AbstractMediaPlayer::stop() TRACE_ENTRY("state %d", privateState()); m_playPending = false; + stopTimers(); switch (privateState()) { case GroundState: @@ -148,7 +150,6 @@ void MMF::AbstractMediaPlayer::stop() case BufferingState: case PausedState: doStop(); - stopTickTimer(); changeState(StoppedState); break; @@ -173,14 +174,21 @@ void MMF::AbstractMediaPlayer::seek(qint64 ms) case PlayingState: case LoadingState: { - const bool tickTimerWasRunning = m_tickTimer->isActive(); - stopTickTimer(); + bool wasPlaying = false; + if (state() == PlayingState) { + stopPositionTimer(); + doPause(); + wasPlaying = true; + } doSeek(ms); + resetMarksIfRewound(); - if (tickTimerWasRunning) { - startTickTimer(); + if(wasPlaying && state() != ErrorState) { + doPlay(); + startPositionTimer(); } + break; } case BufferingState: @@ -203,17 +211,12 @@ void MMF::AbstractMediaPlayer::doSetTickInterval(qint32 interval) TRACE_CONTEXT(AbstractMediaPlayer::doSetTickInterval, EAudioApi); TRACE_ENTRY("state %d m_interval %d interval %d", privateState(), tickInterval(), interval); - m_tickTimer->setInterval(interval); + m_positionTimer->setInterval(interval); TRACE_EXIT_0(); } -MediaSource MMF::AbstractMediaPlayer::source() const -{ - return m_source; -} - -void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& file) +void MMF::AbstractMediaPlayer::open(const MediaSource &source, RFile& file) { TRACE_CONTEXT(AbstractMediaPlayer::setFileSource, EAudioApi); TRACE_ENTRY("state %d source.type %d", privateState(), source.type()); @@ -221,15 +224,14 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f close(); changeState(GroundState); - // TODO: is it correct to assign even if the media type is not supported in - // the switch statement below? - m_source = source; - TInt symbianErr = KErrNone; + QString errorMessage; - switch (m_source.type()) { + switch (source.type()) { case MediaSource::LocalFile: { symbianErr = openFile(file); + if (KErrNone != symbianErr) + errorMessage = tr("Error opening file"); break; } @@ -238,68 +240,76 @@ void MMF::AbstractMediaPlayer::setFileSource(const MediaSource &source, RFile& f if (url.scheme() == QLatin1String("file")) { symbianErr = openFile(file); - } - else { - TRACE_0("Source type not supported"); - // TODO: support network URLs - symbianErr = KErrNotSupported; + if (KErrNone != symbianErr) + errorMessage = tr("Error opening file"); + } else { + symbianErr = openUrl(url.toString()); + if (KErrNone != symbianErr) + errorMessage = tr("Error opening URL"); } break; } - case MediaSource::Invalid: - case MediaSource::Disc: - case MediaSource::Stream: - TRACE_0("Source type not supported"); - symbianErr = KErrNotSupported; - break; - - case MediaSource::Empty: - TRACE_0("Empty source - doing nothing"); - TRACE_EXIT_0(); - return; + // Other source types are handled in MediaObject::createPlayer - // Protection against adding new media types and forgetting to update this switch + // Protection against adding new media types and forgetting to update this switch default: TRACE_PANIC(InvalidMediaTypePanic); } - if (KErrNone == symbianErr) { + if (errorMessage.isEmpty()) { changeState(LoadingState); } else { - TRACE("error %d", symbianErr) - setError(NormalError); + if (symbianErr) + setError(errorMessage, symbianErr); + else + setError(errorMessage); } TRACE_EXIT_0(); } -void MMF::AbstractMediaPlayer::setNextSource(const MediaSource &source) +void MMF::AbstractMediaPlayer::volumeChanged(qreal volume) { - TRACE_CONTEXT(AbstractMediaPlayer::setNextSource, EAudioApi); + TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal); TRACE_ENTRY("state %d", privateState()); - // TODO: handle 'next source' - - m_nextSource = source; - Q_UNUSED(source); + AbstractPlayer::volumeChanged(volume); + doVolumeChanged(); TRACE_EXIT_0(); } +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- -void MMF::AbstractMediaPlayer::volumeChanged(qreal volume) +void MMF::AbstractMediaPlayer::startPositionTimer() { - TRACE_CONTEXT(AbstractMediaPlayer::volumeChanged, EAudioInternal); - TRACE_ENTRY("state %d", privateState()); + m_positionTimer->start(tickInterval()); +} - AbstractPlayer::volumeChanged(volume); - doVolumeChanged(); +void MMF::AbstractMediaPlayer::stopPositionTimer() +{ + m_positionTimer->stop(); +} - TRACE_EXIT_0(); +void MMF::AbstractMediaPlayer::startBufferStatusTimer() +{ + m_bufferStatusTimer->start(BufferStatusTimerInterval); } +void MMF::AbstractMediaPlayer::stopBufferStatusTimer() +{ + m_bufferStatusTimer->stop(); +} + +void MMF::AbstractMediaPlayer::stopTimers() +{ + stopPositionTimer(); + stopBufferStatusTimer(); +} void MMF::AbstractMediaPlayer::doVolumeChanged() { @@ -318,7 +328,7 @@ void MMF::AbstractMediaPlayer::doVolumeChanged() const int err = setDeviceVolume(volume); if (KErrNone != err) { - setError(NormalError); + setError(tr("Setting volume failed"), err); } break; } @@ -330,19 +340,23 @@ void MMF::AbstractMediaPlayer::doVolumeChanged() } } - //----------------------------------------------------------------------------- // Protected functions //----------------------------------------------------------------------------- -void MMF::AbstractMediaPlayer::startTickTimer() +void MMF::AbstractMediaPlayer::bufferingStarted() { - m_tickTimer->start(tickInterval()); + m_stateBeforeBuffering = privateState(); + changeState(BufferingState); + bufferStatusTick(); + startBufferStatusTimer(); } -void MMF::AbstractMediaPlayer::stopTickTimer() +void MMF::AbstractMediaPlayer::bufferingComplete() { - m_tickTimer->stop(); + stopBufferStatusTimer(); + emit MMF::AbstractPlayer::bufferStatus(100); + changeState(m_stateBeforeBuffering); } void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) @@ -351,6 +365,23 @@ void MMF::AbstractMediaPlayer::maxVolumeChanged(int mmfMaxVolume) doVolumeChanged(); } +void MMF::AbstractMediaPlayer::playbackComplete(int error) +{ + stopTimers(); + + if (KErrNone == error) { + changeState(StoppedState); + + // MediaObject::switchToNextSource deletes the current player, so we + // call it via delayed slot invokation to ensure that this object does + // not get deleted during execution of a member function. + QMetaObject::invokeMethod(m_parent, "switchToNextSource", Qt::QueuedConnection); + } + else { + setError(tr("Playback complete"), error); + } +} + qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds &in) { return in.Int64() / 1000; @@ -360,10 +391,53 @@ qint64 MMF::AbstractMediaPlayer::toMilliSeconds(const TTimeIntervalMicroSeconds // Slots //----------------------------------------------------------------------------- -void MMF::AbstractMediaPlayer::tick() +void MMF::AbstractMediaPlayer::positionTick() +{ + emitMarksIfReached(); + + const qint64 current = currentTime(); + emit MMF::AbstractPlayer::tick(current); +} + +void MMF::AbstractMediaPlayer::emitMarksIfReached() +{ + const qint64 current = currentTime(); + const qint64 total = totalTime(); + const qint64 remaining = total - current; + + if (prefinishMark() && !m_prefinishMarkSent) { + if (remaining < (prefinishMark() + tickInterval()/2)) { + m_prefinishMarkSent = true; + emit prefinishMarkReached(remaining); + } + } + + if (!m_aboutToFinishSent) { + if (remaining < tickInterval()) { + m_aboutToFinishSent = true; + emit aboutToFinish(); + } + } +} + +void MMF::AbstractMediaPlayer::resetMarksIfRewound() +{ + const qint64 current = currentTime(); + const qint64 total = totalTime(); + const qint64 remaining = total - current; + + if (prefinishMark() && m_prefinishMarkSent) + if (remaining >= (prefinishMark() + tickInterval()/2)) + m_prefinishMarkSent = false; + + if (m_aboutToFinishSent) + if (remaining >= tickInterval()) + m_aboutToFinishSent = false; +} + +void MMF::AbstractMediaPlayer::bufferStatusTick() { - // For the MWC compiler, we need to qualify the base class. - emit MMF::AbstractPlayer::tick(currentTime()); + emit MMF::AbstractPlayer::bufferStatus(bufferStatus()); } void MMF::AbstractMediaPlayer::changeState(PrivateState newState) diff --git a/src/3rdparty/phonon/mmf/abstractmediaplayer.h b/src/3rdparty/phonon/mmf/abstractmediaplayer.h index cb6e437..abd6bff 100644 --- a/src/3rdparty/phonon/mmf/abstractmediaplayer.h +++ b/src/3rdparty/phonon/mmf/abstractmediaplayer.h @@ -33,6 +33,7 @@ namespace Phonon namespace MMF { class AudioOutput; +class MediaObject; /** * Interface via which MMF client APIs for both audio and video can be @@ -43,19 +44,17 @@ class AbstractMediaPlayer : public AbstractPlayer Q_OBJECT protected: - AbstractMediaPlayer(); - explicit AbstractMediaPlayer(const AbstractPlayer& player); + AbstractMediaPlayer(MediaObject *parent, const AbstractPlayer *player); public: + virtual void open(const Phonon::MediaSource&, RFile&); + // MediaObjectInterface virtual void play(); virtual void pause(); virtual void stop(); virtual void seek(qint64 milliseconds); virtual bool isSeekable() const; - virtual MediaSource source() const; - virtual void setFileSource(const Phonon::MediaSource&, RFile&); - virtual void setNextSource(const MediaSource &source); virtual void volumeChanged(qreal volume); protected: @@ -68,6 +67,8 @@ protected: virtual void doSeek(qint64 pos) = 0; virtual int setDeviceVolume(int mmfVolume) = 0; virtual int openFile(RFile& file) = 0; + virtual int openUrl(const QString& url) = 0; + virtual int bufferStatus() const = 0; virtual void close() = 0; virtual void changeState(PrivateState newState); @@ -76,23 +77,30 @@ protected: virtual QPair<QString, QString> metaDataEntry(int index) const = 0; protected: - bool tickTimerRunning() const; - void startTickTimer(); - void stopTickTimer(); + void bufferingStarted(); + void bufferingComplete(); void maxVolumeChanged(int maxVolume); + void playbackComplete(int error); static qint64 toMilliSeconds(const TTimeIntervalMicroSeconds &); private: + void startPositionTimer(); + void stopPositionTimer(); + void startBufferStatusTimer(); + void stopBufferStatusTimer(); + void stopTimers(); void doVolumeChanged(); + void emitMarksIfReached(); + void resetMarksIfRewound(); private Q_SLOTS: - /** - * Receives signal from m_tickTimer - */ - void tick(); + void positionTick(); + void bufferStatusTick(); private: + MediaObject *const m_parent; + /** * This flag is set to true if play is called when the object is * in a Loading state. Once loading is complete, playback will @@ -100,12 +108,15 @@ private: */ bool m_playPending; - QScopedPointer<QTimer> m_tickTimer; + QScopedPointer<QTimer> m_positionTimer; + + QScopedPointer<QTimer> m_bufferStatusTimer; + PrivateState m_stateBeforeBuffering; int m_mmfMaxVolume; - MediaSource m_source; - MediaSource m_nextSource; + bool m_prefinishMarkSent; + bool m_aboutToFinishSent; QMultiMap<QString, QString> m_metaData; diff --git a/src/3rdparty/phonon/mmf/abstractplayer.cpp b/src/3rdparty/phonon/mmf/abstractplayer.cpp index caf4092..53973eb 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.cpp +++ b/src/3rdparty/phonon/mmf/abstractplayer.cpp @@ -33,7 +33,7 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AbstractPlayer::AbstractPlayer() +MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer *player) : m_videoOutput(0) , m_volume(InitialVolume) , m_state(GroundState) @@ -42,19 +42,13 @@ MMF::AbstractPlayer::AbstractPlayer() , m_transitionTime(0) , m_prefinishMark(0) { - -} - -MMF::AbstractPlayer::AbstractPlayer(const AbstractPlayer& player) - : m_videoOutput(player.m_videoOutput) - , m_volume(player.m_volume) - , m_state(GroundState) - , m_error(NoError) - , m_tickInterval(player.tickInterval()) - , m_transitionTime(player.transitionTime()) - , m_prefinishMark(player.prefinishMark()) -{ - + if(player) { + m_videoOutput = player->m_videoOutput; + m_volume = player->m_volume; + m_tickInterval = player->m_tickInterval; + m_transitionTime = player->m_transitionTime; + m_prefinishMark = player->m_prefinishMark; + } } //----------------------------------------------------------------------------- @@ -113,19 +107,23 @@ void MMF::AbstractPlayer::videoOutputChanged() // Default behaviour is empty - overridden by VideoPlayer } -void MMF::AbstractPlayer::setError(Phonon::ErrorType error, - const QString &errorMessage) +void MMF::AbstractPlayer::setError(const QString &errorMessage) { TRACE_CONTEXT(AbstractPlayer::setError, EAudioInternal); - TRACE_ENTRY("state %d error %d", m_state, error); + TRACE_ENTRY("state %d", m_state); - m_error = error; + m_error = Phonon::NormalError; m_errorString = errorMessage; changeState(ErrorState); TRACE_EXIT_0(); } +void MMF::AbstractPlayer::setError(const QString &errorMessage, int symbianError) +{ + setError(errorMessage + ": " + Utils::symbianErrorToString(symbianError)); +} + Phonon::ErrorType MMF::AbstractPlayer::errorType() const { const Phonon::ErrorType result = (ErrorState == m_state) diff --git a/src/3rdparty/phonon/mmf/abstractplayer.h b/src/3rdparty/phonon/mmf/abstractplayer.h index 2e9cfa0..cec5568 100644 --- a/src/3rdparty/phonon/mmf/abstractplayer.h +++ b/src/3rdparty/phonon/mmf/abstractplayer.h @@ -19,8 +19,8 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_ABSTRACTPLAYER_H #define PHONON_MMF_ABSTRACTPLAYER_H -#include <Phonon/phononnamespace.h> -#include <Phonon/MediaSource.h> +#include <phonon/phononnamespace.h> +#include <phonon/mediasource.h> #include <QObject> @@ -53,8 +53,9 @@ class AbstractPlayer : public QObject Q_OBJECT public: - AbstractPlayer(); - explicit AbstractPlayer(const AbstractPlayer& player); + AbstractPlayer(const AbstractPlayer *player); + + virtual void open(const Phonon::MediaSource&, RFile&) = 0; // MediaObjectInterface (implemented) qint32 tickInterval() const; @@ -75,22 +76,28 @@ public: virtual Phonon::ErrorType errorType() const; virtual QString errorString() const; virtual qint64 totalTime() const = 0; - virtual Phonon::MediaSource source() const = 0; - // 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 setNextSource(const Phonon::MediaSource &) = 0; virtual void volumeChanged(qreal volume); void setVideoOutput(VideoOutput* videoOutput); /** - * Records error and changes state to ErrorState + * Records error message and changes state to ErrorState + */ + void setError(const QString &errorMessage); + + /** + * Records error message and changes state to ErrorState + * + * Appends a human-readable version of symbianErrorCode to the error message, + * e.g. + * @code + * setError("Opening file failed", KErrPermissionDenied) + * @endcode + * results in the following error message: + * "Opening file failed: permission denied" */ - void setError(Phonon::ErrorType error, - const QString &errorMessage = QString()); + void setError(const QString &errorMessage, int symbianErrorCode); Phonon::State state() const; @@ -98,9 +105,12 @@ Q_SIGNALS: void totalTimeChanged(qint64 length); void finished(); void tick(qint64 time); - void stateChanged(Phonon::State oldState, - Phonon::State newState); + void bufferStatus(int percentFilled); + void stateChanged(Phonon::State newState, + Phonon::State oldState); void metaDataChanged(const QMultiMap<QString, QString>& metaData); + void aboutToFinish(); + void prefinishMarkReached(qint32 remaining); protected: /** diff --git a/src/3rdparty/phonon/mmf/audioequalizer.cpp b/src/3rdparty/phonon/mmf/audioequalizer.cpp index 7cc9bc7..1d2bbd4 100644 --- a/src/3rdparty/phonon/mmf/audioequalizer.cpp +++ b/src/3rdparty/phonon/mmf/audioequalizer.cpp @@ -16,6 +16,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. */ +#include <AudioEqualizerBase.h> #include "audioequalizer.h" QT_BEGIN_NAMESPACE @@ -27,61 +28,79 @@ using namespace Phonon::MMF; \internal */ -AudioEqualizer::AudioEqualizer(QObject *parent) : AbstractAudioEffect::AbstractAudioEffect(parent, createParams()) -{ -} - -void AudioEqualizer::parameterChanged(const int pid, - const QVariant &value) -{ - // There is no way to return an error from this function, so we just - // have to trap and ignore exceptions. - TRAP_IGNORE(static_cast<CAudioEqualizer *>(m_effect.data())->SetBandLevelL(pid, value.toInt())); -} +// Define functions which depend on concrete native effect class name +PHONON_MMF_DEFINE_EFFECT_FUNCTIONS(AudioEqualizer) -bool AudioEqualizer::activateOn(CPlayerType *player) +AudioEqualizer::AudioEqualizer(QObject *parent, const QList<EffectParameter>& parameters) + : AbstractAudioEffect::AbstractAudioEffect(parent, parameters) { - CAudioEqualizer *ptr = 0; - QT_TRAP_THROWING(ptr = CAudioEqualizer::NewL(*player)); - m_effect.reset(ptr); - return true; } -QList<EffectParameter> AudioEqualizer::createParams() +int AudioEqualizer::effectParameterChanged(const EffectParameter ¶m, + const QVariant &value) { - QList<EffectParameter> retval; - - // We temporarily create an AudioPlayer, and run the effect on it, so - // we can extract the readonly data we need. - AudioPlayer dummyPlayer; + const int band = param.id() - ParameterBase + 1; - CAudioEqualizer *eqPtr = 0; - QT_TRAP_THROWING(eqPtr = CAudioEqualizer::NewL(*dummyPlayer.player());) - QScopedPointer<CAudioEqualizer> e(eqPtr); + const qreal externalLevel = value.toReal(); + const int internalLevel = param.toInternalValue(externalLevel); - TInt32 dbMin; - TInt32 dbMax; - e->DbLevelLimits(dbMin, dbMax); + TRAPD(err, concreteEffect()->SetBandLevelL(band, internalLevel)); + return err; +} - const int bandCount = e->NumberOfBands(); - for (int i = 0; i < bandCount; ++i) { - const qint32 hz = e->CenterFrequency(i); +//----------------------------------------------------------------------------- +// Static functions +//----------------------------------------------------------------------------- - const qint32 defVol = e->BandLevel(i); +const char* AudioEqualizer::description() +{ + return "Audio equalizer"; +} - retval.append(EffectParameter(i, - tr("Frequency band, %1 Hz").arg(hz), - EffectParameter::LogarithmicHint, - QVariant(qint32(defVol)), - QVariant(qint32(dbMin)), - QVariant(qint32(dbMax)), - QVariantList(), - QString())); +bool AudioEqualizer::getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter>& parameters) +{ + bool supported = false; + + QScopedPointer<CAudioEqualizer> effect; + TRAPD(err, effect.reset(CAudioEqualizer::NewL(*stream))); + + if (KErrNone == err) { + supported = true; + + TInt32 dbMin; + TInt32 dbMax; + effect->DbLevelLimits(dbMin, dbMax); + + const int bandCount = effect->NumberOfBands(); + + for (int i = 0; i < bandCount; ++i) { + // For some reason, band IDs are 1-based, as opposed to the + // 0-based indices used in just about other Symbian API...! + const int band = i + 1; + + const qint32 hz = effect->CenterFrequency(band); + + // We pass a floating-point parameter range of -1.0 to +1.0 for + // each band in order to work around a limitation in + // Phonon::EffectWidget. See documentation of EffectParameter + // for more details. + EffectParameter param( + /* parameterId */ ParameterBase + i, + /* name */ tr("%1 Hz").arg(hz), + /* hints */ EffectParameter::LogarithmicHint, + /* defaultValue */ QVariant(qreal(0.0)), + /* minimumValue */ QVariant(qreal(-1.0)), + /* maximumValue */ QVariant(qreal(+1.0))); + + param.setInternalRange(dbMin, dbMax); + parameters.append(param); + } } - return retval; + return supported; } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/audioequalizer.h b/src/3rdparty/phonon/mmf/audioequalizer.h index d4c8165..9c3770a 100644 --- a/src/3rdparty/phonon/mmf/audioequalizer.h +++ b/src/3rdparty/phonon/mmf/audioequalizer.h @@ -19,9 +19,10 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_AUDIOEQUALIZER_H #define PHONON_MMF_AUDIOEQUALIZER_H -#include <AudioEqualizerBase.h> #include "abstractaudioeffect.h" +class CAudioEqualizer; + QT_BEGIN_NAMESPACE namespace Phonon @@ -40,17 +41,22 @@ class AudioEqualizer : public AbstractAudioEffect { Q_OBJECT public: - AudioEqualizer(QObject *parent); + AudioEqualizer(QObject *parent, const QList<EffectParameter> ¶meters); -protected: - virtual void parameterChanged(const int id, - const QVariant &value); + // Static interface required by EffectFactory + static const char* description(); + static bool getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter>& parameters); - virtual bool activateOn(CPlayerType *player); +protected: + // AbstractAudioEffect + virtual void createEffect(AudioPlayer::NativePlayer *player); + virtual int effectParameterChanged(const EffectParameter ¶m, + const QVariant &value); private: - static QList<EffectParameter> createParams(); - QScopedPointer<CAudioEqualizer> m_bassBoost; + CAudioEqualizer *concreteEffect(); + }; } } diff --git a/src/3rdparty/phonon/mmf/audiooutput.cpp b/src/3rdparty/phonon/mmf/audiooutput.cpp index d6e0c13..c6be20b 100644 --- a/src/3rdparty/phonon/mmf/audiooutput.cpp +++ b/src/3rdparty/phonon/mmf/audiooutput.cpp @@ -81,13 +81,18 @@ bool MMF::AudioOutput::setOutputDevice(int index) return true; } -bool MMF::AudioOutput::activateOnMediaObject(MediaObject *mo) +void MMF::AudioOutput::connectMediaObject(MediaObject *mediaObject) { // Ensure that the MediaObject has the correct initial volume - mo->volumeChanged(m_volume); + mediaObject->volumeChanged(m_volume); // Connect MediaObject to receive future volume changes - connect(this, SIGNAL(volumeChanged(qreal)), mo, SLOT(volumeChanged(qreal))); - return true; + connect(this, SIGNAL(volumeChanged(qreal)), mediaObject, SLOT(volumeChanged(qreal))); +} + +void MMF::AudioOutput::disconnectMediaObject(MediaObject *mediaObject) +{ + // Disconnect all signal-slot connections + disconnect(this, 0, mediaObject, 0); } QHash<QByteArray, QVariant> MMF::AudioOutput::audioOutputDescription(int index) diff --git a/src/3rdparty/phonon/mmf/audiooutput.h b/src/3rdparty/phonon/mmf/audiooutput.h index 1e1e134..67aaa38 100644 --- a/src/3rdparty/phonon/mmf/audiooutput.h +++ b/src/3rdparty/phonon/mmf/audiooutput.h @@ -74,7 +74,9 @@ public: }; protected: - virtual bool activateOnMediaObject(MediaObject *mo); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); Q_SIGNALS: void volumeChanged(qreal volume); diff --git a/src/3rdparty/phonon/mmf/audioplayer.cpp b/src/3rdparty/phonon/mmf/audioplayer.cpp index 8fccfe6..ee07229 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.cpp +++ b/src/3rdparty/phonon/mmf/audioplayer.cpp @@ -34,13 +34,9 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::AudioPlayer::AudioPlayer() -{ - construct(); -} - -MMF::AudioPlayer::AudioPlayer(const AbstractPlayer& player) - : AbstractMediaPlayer(player) +MMF::AudioPlayer::AudioPlayer(MediaObject *parent, const AbstractPlayer *player) + : AbstractMediaPlayer(parent, player) + , m_totalTime(0) { construct(); } @@ -50,10 +46,10 @@ void MMF::AudioPlayer::construct() TRACE_CONTEXT(AudioPlayer::AudioPlayer, EAudioApi); TRACE_ENTRY_0(); - TRAPD(err, m_player.reset(CPlayerType::NewL(*this, 0, EMdaPriorityPreferenceNone))); - if (KErrNone != err) { - changeState(ErrorState); - } + NativePlayer *player = 0; + QT_TRAP_THROWING(player = NativePlayer::NewL(*this, 0, EMdaPriorityPreferenceNone)); + m_player.reset(player); + m_player->RegisterForAudioLoadingNotification(*this); TRACE_EXIT_0(); } @@ -66,6 +62,11 @@ MMF::AudioPlayer::~AudioPlayer() TRACE_EXIT_0(); } +MMF::AudioPlayer::NativePlayer *MMF::AudioPlayer::nativePlayer() const +{ + return m_player.data(); +} + //----------------------------------------------------------------------------- // Public API //----------------------------------------------------------------------------- @@ -125,6 +126,24 @@ int MMF::AudioPlayer::openFile(RFile& file) return err; } +int MMF::AudioPlayer::openUrl(const QString& /*url*/) +{ + // Streaming playback is generally not supported by the implementation + // of the audio player API, so we use CVideoPlayerUtility for both + // audio and video streaming. + Utils::panic(AudioUtilityUrlNotSupported); + + // Silence warning + return 0; +} + +int MMF::AudioPlayer::bufferStatus() const +{ + int result = 0; + TRAP_IGNORE(m_player->GetAudioLoadingProgressL(result)); + return result; +} + void MMF::AudioPlayer::close() { m_player->Close(); @@ -151,7 +170,7 @@ qint64 MMF::AudioPlayer::currentTime() const // If we don't cast away constness here, we simply have to ignore // the error. - const_cast<AudioPlayer*>(this)->setError(NormalError); + const_cast<AudioPlayer*>(this)->setError(tr("Getting position failed"), err); } return result; @@ -159,7 +178,7 @@ qint64 MMF::AudioPlayer::currentTime() const qint64 MMF::AudioPlayer::totalTime() const { - return toMilliSeconds(m_player->Duration()); + return m_totalTime; } @@ -182,12 +201,12 @@ void MMF::AudioPlayer::MapcInitComplete(TInt aError, if (KErrNone == aError) { maxVolumeChanged(m_player->MaxVolume()); - emit totalTimeChanged(totalTime()); + m_totalTime = toMilliSeconds(m_player->Duration()); + emit totalTimeChanged(m_totalTime); updateMetaData(); changeState(StoppedState); } else { - // TODO: set different error states according to value of aError? - setError(NormalError); + setError(tr("Opening clip failed"), aError); } TRACE_EXIT_0(); @@ -202,53 +221,39 @@ void MMF::AudioPlayer::MapcPlayComplete(TInt aError) TRACE_CONTEXT(AudioPlayer::MapcPlayComplete, EAudioInternal); TRACE_ENTRY("state %d error %d", state(), aError); - stopTickTimer(); + // Call base class function which handles end of playback for both + // audio and video clips. + playbackComplete(aError); - if (KErrNone == aError) { - changeState(StoppedState); - // TODO: move on to m_nextSource - } else { - // TODO: do something with aError? - setError(NormalError); - } + TRACE_EXIT_0(); +} - /* - if (aError == KErrNone) { - if (m_nextSource.type() == MediaSource::Empty) { - emit finished(); - } else { - setSource(m_nextSource); - m_nextSource = MediaSource(); - } - - changeState(StoppedState); - } - else { - m_error = NormalError; - changeState(ErrorState); - } - */ +#ifdef QT_PHONON_MMF_AUDIO_DRM +void MMF::AudioPlayer::MaloLoadingStarted() +{ - TRACE_EXIT_0(); } -CPlayerType *MMF::AudioPlayer::player() const +void MMF::AudioPlayer::MaloLoadingComplete() { - return m_player.data(); + } +#endif // QT_PHONON_MMF_AUDIO_DRM -#ifdef QT_PHONON_MMF_AUDIO_DRM +//----------------------------------------------------------------------------- +// MAudioLoadingObserver callbacks +//----------------------------------------------------------------------------- + void MMF::AudioPlayer::MaloLoadingStarted() { - + bufferingStarted(); } void MMF::AudioPlayer::MaloLoadingComplete() { - + bufferingComplete(); } -#endif // QT_PHONON_MMF_AUDIO_DRM //----------------------------------------------------------------------------- diff --git a/src/3rdparty/phonon/mmf/audioplayer.h b/src/3rdparty/phonon/mmf/audioplayer.h index bc60076..0eb8bb7 100644 --- a/src/3rdparty/phonon/mmf/audioplayer.h +++ b/src/3rdparty/phonon/mmf/audioplayer.h @@ -26,12 +26,10 @@ class TTimeIntervalMicroSeconds; #ifdef QT_PHONON_MMF_AUDIO_DRM #include <drmaudiosampleplayer.h> -typedef CDrmPlayerUtility CPlayerType; -typedef MDrmAudioPlayerCallback MPlayerObserverType; +typedef MDrmAudioPlayerCallback NativePlayerObserver; #else #include <mdaaudiosampleplayer.h> -typedef CMdaAudioPlayerUtility CPlayerType; -typedef MMdaAudioPlayerCallback MPlayerObserverType; +typedef MMdaAudioPlayerCallback NativePlayerObserver; #endif QT_BEGIN_NAMESPACE @@ -44,18 +42,23 @@ namespace MMF * @short Wrapper over MMF audio client utility */ class AudioPlayer : public AbstractMediaPlayer - , public MPlayerObserverType // typedef -#ifdef QT_PHONON_MMF_AUDIO_DRM + , public NativePlayerObserver , public MAudioLoadingObserver -#endif { Q_OBJECT public: - AudioPlayer(); - explicit AudioPlayer(const AbstractPlayer& player); + AudioPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~AudioPlayer(); +#ifdef QT_PHONON_MMF_AUDIO_DRM +typedef CDrmPlayerUtility NativePlayer; +#else +typedef CMdaAudioPlayerUtility NativePlayer; +#endif + + NativePlayer *nativePlayer() const; + // AbstractMediaPlayer virtual void doPlay(); virtual void doPause(); @@ -63,6 +66,8 @@ public: virtual void doSeek(qint64 milliseconds); virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); + virtual int openUrl(const QString& url); + virtual int bufferStatus() const; virtual void close(); // MediaObjectInterface @@ -70,15 +75,24 @@ public: virtual qint64 currentTime() const; virtual qint64 totalTime() const; + // AbstractMediaPlayer + virtual int numberOfMetaDataEntries() const; + virtual QPair<QString, QString> metaDataEntry(int index) const; + + /** + * This class owns the pointer. + */ + NativePlayer *player() const; + +private: + void construct(); + +private: #ifdef QT_PHONON_MMF_AUDIO_DRM // MDrmAudioPlayerCallback virtual void MdapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds &aDuration); virtual void MdapcPlayComplete(TInt aError); - - // MAudioLoadingObserver - virtual void MaloLoadingStarted(); - virtual void MaloLoadingComplete(); #else // MMdaAudioPlayerCallback virtual void MapcInitComplete(TInt aError, @@ -86,24 +100,19 @@ public: virtual void MapcPlayComplete(TInt aError); #endif - /** - * This class owns the pointer. - */ - CPlayerType *player() const; - -private: - void construct(); - - // AbstractMediaPlayer - virtual int numberOfMetaDataEntries() const; - virtual QPair<QString, QString> metaDataEntry(int index) const; + // MAudioLoadingObserver + virtual void MaloLoadingStarted(); + virtual void MaloLoadingComplete(); private: /** * Using CPlayerType typedef in order to be able to easily switch between * CMdaAudioPlayerUtility and CDrmPlayerUtility */ - QScopedPointer<CPlayerType> m_player; + QScopedPointer<NativePlayer> m_player; + + qint64 m_totalTime; + }; } } diff --git a/src/3rdparty/phonon/mmf/backend.cpp b/src/3rdparty/phonon/mmf/backend.cpp index 7e3a67f..3568a49 100644 --- a/src/3rdparty/phonon/mmf/backend.cpp +++ b/src/3rdparty/phonon/mmf/backend.cpp @@ -45,6 +45,7 @@ using namespace Phonon::MMF; Backend::Backend(QObject *parent) : QObject(parent) , m_ancestorMoveMonitor(new AncestorMoveMonitor(this)) + , m_effectFactory(new EffectFactory(this)) { TRACE_CONTEXT(Backend::Backend, EBackend); TRACE_ENTRY_0(); @@ -81,9 +82,9 @@ QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const { Q_ASSERT(args.count() == 1); Q_ASSERT(args.first().type() == QVariant::Int); - const AbstractAudioEffect::Type effect = AbstractAudioEffect::Type(args.first().toInt()); - - return EffectFactory::createAudioEffect(effect, parent); + const EffectFactory::Type type = + static_cast<EffectFactory::Type>(args.first().toInt()); + return m_effectFactory->createAudioEffect(type, parent); } case VideoWidgetClass: result = new VideoWidget(m_ancestorMoveMonitor.data(), qobject_cast<QWidget *>(parent)); @@ -105,7 +106,7 @@ QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const switch(type) { case EffectType: - retval.append(EffectFactory::effectIndexes()); + retval.append(m_effectFactory->effectIndexes()); break; case AudioOutputDeviceType: // We only have one possible output device, but we need at least @@ -126,7 +127,7 @@ QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescripti switch (type) { case EffectType: - return EffectFactory::audioEffectDescriptions(AbstractAudioEffect::Type(index)); + return m_effectFactory->audioEffectDescriptions(EffectFactory::Type(index)); case AudioOutputDeviceType: return AudioOutput::audioOutputDescription(index); default: @@ -139,29 +140,32 @@ bool Backend::startConnectionChange(QSet<QObject *>) return true; } -bool Backend::connectNodes(QObject *source, QObject *target) +bool Backend::connectNodes(QObject *sourceObject, QObject *targetObject) { TRACE_CONTEXT(Backend::connectNodes, EBackend); - TRACE_ENTRY("source 0x%08x target 0x%08x", source, target); - Q_ASSERT(qobject_cast<MediaNode *>(source)); - Q_ASSERT(qobject_cast<MediaNode *>(target)); + TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject); + + MediaNode *const source = qobject_cast<MediaNode *>(sourceObject); + MediaNode *const target = qobject_cast<MediaNode *>(targetObject); - MediaNode *const mediaSource = static_cast<MediaNode *>(source); - MediaNode *const mediaTarget = static_cast<MediaNode *>(target); + Q_ASSERT_X(source, Q_FUNC_INFO, "source is not a MediaNode"); + Q_ASSERT_X(target, Q_FUNC_INFO, "target is not a MediaNode"); - return mediaSource->connectMediaNode(mediaTarget); + return source->connectOutput(target); } -bool Backend::disconnectNodes(QObject *source, QObject *target) +bool Backend::disconnectNodes(QObject *sourceObject, QObject *targetObject) { TRACE_CONTEXT(Backend::disconnectNodes, EBackend); - TRACE_ENTRY("source 0x%08x target 0x%08x", source, target); - Q_ASSERT(qobject_cast<MediaNode *>(source)); - Q_ASSERT(qobject_cast<MediaNode *>(target)); + TRACE_ENTRY("source 0x%08x target 0x%08x", sourceObject, targetObject); + + MediaNode *const source = qobject_cast<MediaNode *>(sourceObject); + MediaNode *const target = qobject_cast<MediaNode *>(targetObject); - const bool result = static_cast<MediaNode *>(source)->disconnectMediaNode(static_cast<MediaNode *>(target)); + Q_ASSERT_X(source, Q_FUNC_INFO, "source is not a MediaNode"); + Q_ASSERT_X(target, Q_FUNC_INFO, "target is not a MediaNode"); - TRACE_RETURN("%d", result); + return source->disconnectOutput(target); } bool Backend::endConnectionChange(QSet<QObject *>) diff --git a/src/3rdparty/phonon/mmf/backend.h b/src/3rdparty/phonon/mmf/backend.h index 9e3d3b3..9361544 100644 --- a/src/3rdparty/phonon/mmf/backend.h +++ b/src/3rdparty/phonon/mmf/backend.h @@ -20,9 +20,10 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #define PHONON_MMF_BACKEND_H #include "ancestormovemonitor.h" +#include "effectfactory.h" -#include <Phonon/MediaSource> -#include <Phonon/BackendInterface> +#include <phonon/mediasource.h> +#include <phonon/backendinterface.h> #include <QScopedPointer> QT_BEGIN_NAMESPACE @@ -53,6 +54,7 @@ Q_SIGNALS: private: QScopedPointer<AncestorMoveMonitor> m_ancestorMoveMonitor; + QScopedPointer<EffectFactory> m_effectFactory; }; } diff --git a/src/3rdparty/phonon/mmf/bassboost.cpp b/src/3rdparty/phonon/mmf/bassboost.cpp index e34f9e7..c7af939 100644 --- a/src/3rdparty/phonon/mmf/bassboost.cpp +++ b/src/3rdparty/phonon/mmf/bassboost.cpp @@ -16,6 +16,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. */ +#include <BassBoostBase.h> #include "bassboost.h" QT_BEGIN_NAMESPACE @@ -23,25 +24,34 @@ QT_BEGIN_NAMESPACE using namespace Phonon; using namespace Phonon::MMF; +// Define functions which depend on concrete native effect class name +PHONON_MMF_DEFINE_EFFECT_FUNCTIONS(BassBoost) + /*! \class MMF::BassBoost \internal */ -BassBoost::BassBoost(QObject *parent) : AbstractAudioEffect::AbstractAudioEffect(parent, - QList<EffectParameter>()) +BassBoost::BassBoost(QObject *parent, const QList<EffectParameter> ¶meters) + : AbstractAudioEffect::AbstractAudioEffect(parent, parameters) { + } -void BassBoost::parameterChanged(const int, - const QVariant &) +//----------------------------------------------------------------------------- +// Static functions +//----------------------------------------------------------------------------- + +const char* BassBoost::description() { - // We should never be called, because we have no parameters. + return "Bass boost"; } -bool BassBoost::activateOn(CPlayerType *player) +bool BassBoost::getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter> ¶meters) { - m_effect.reset(CBassBoost::NewL(*player, true)); - return true; + QScopedPointer<CBassBoost> effect; + TRAPD(err, effect.reset(CBassBoost::NewL(*stream))); + return (KErrNone == err); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/bassboost.h b/src/3rdparty/phonon/mmf/bassboost.h index c16393a..fc40e21 100644 --- a/src/3rdparty/phonon/mmf/bassboost.h +++ b/src/3rdparty/phonon/mmf/bassboost.h @@ -19,9 +19,10 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_BASSBOOST_H #define PHONON_MMF_BASSBOOST_H -#include <BassBoostBase.h> #include "abstractaudioeffect.h" +class CBassBoost; + QT_BEGIN_NAMESPACE namespace Phonon @@ -29,25 +30,26 @@ namespace Phonon namespace MMF { /** - * @short An "bass boost" effect. - * - * The documentation does not say what "bass boost" is, neither has it anykind - * of setting. It's an on or off thing. + * @short A "bass boost" effect. */ class BassBoost : public AbstractAudioEffect { Q_OBJECT public: - BassBoost(QObject *parent); + BassBoost(QObject *parent, const QList<EffectParameter> ¶meters); -protected: - virtual void parameterChanged(const int id, - const QVariant &value); + // Static interface required by EffectFactory + static const char* description(); + static bool getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter>& parameters); - virtual bool activateOn(CPlayerType *player); +protected: + // AbstractAudioEffect + virtual void createEffect(AudioPlayer::NativePlayer *player); private: - QScopedPointer<CBassBoost> m_bassBoost; + CBassBoost *concreteEffect(); + }; } } diff --git a/src/3rdparty/phonon/mmf/dummyplayer.cpp b/src/3rdparty/phonon/mmf/dummyplayer.cpp index e6f3855..6970088 100644 --- a/src/3rdparty/phonon/mmf/dummyplayer.cpp +++ b/src/3rdparty/phonon/mmf/dummyplayer.cpp @@ -31,12 +31,7 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::DummyPlayer::DummyPlayer() -{ - -} - -MMF::DummyPlayer::DummyPlayer(const AbstractPlayer& player) +MMF::DummyPlayer::DummyPlayer(const AbstractPlayer *player) : AbstractPlayer(player) { @@ -97,17 +92,7 @@ qint64 MMF::DummyPlayer::totalTime() const return 0; } -MediaSource MMF::DummyPlayer::source() const -{ - return MediaSource(); -} - -void MMF::DummyPlayer::setFileSource(const Phonon::MediaSource &, RFile &) -{ - -} - -void MMF::DummyPlayer::setNextSource(const MediaSource &) +void MMF::DummyPlayer::open(const Phonon::MediaSource &, RFile &) { } diff --git a/src/3rdparty/phonon/mmf/dummyplayer.h b/src/3rdparty/phonon/mmf/dummyplayer.h index c6270c9..6841b5d 100644 --- a/src/3rdparty/phonon/mmf/dummyplayer.h +++ b/src/3rdparty/phonon/mmf/dummyplayer.h @@ -42,8 +42,7 @@ class AudioOutput; class DummyPlayer : public AbstractPlayer { public: - DummyPlayer(); - DummyPlayer(const AbstractPlayer& player); + DummyPlayer(const AbstractPlayer *player = 0); // MediaObjectInterface virtual void play(); @@ -56,12 +55,9 @@ public: virtual Phonon::State state() const; virtual Phonon::ErrorType errorType() const; virtual qint64 totalTime() const; - virtual MediaSource source() const; - // virtual void setSource(const MediaSource &); - virtual void setFileSource(const Phonon::MediaSource&, RFile&); - virtual void setNextSource(const MediaSource &source); // AbstractPlayer + virtual void open(const Phonon::MediaSource&, RFile&); virtual void doSetTickInterval(qint32 interval); }; } diff --git a/src/3rdparty/phonon/mmf/effectfactory.cpp b/src/3rdparty/phonon/mmf/effectfactory.cpp index e9c5e27..c5e33d5 100644 --- a/src/3rdparty/phonon/mmf/effectfactory.cpp +++ b/src/3rdparty/phonon/mmf/effectfactory.cpp @@ -19,19 +19,13 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include <QObject> #include <QCoreApplication> -#include <AudioEqualizerBase.h> -#include <BassBoostBase.h> -#include <DistanceAttenuationBase.h> -#include <DopplerBase.h> -#include <EnvironmentalReverbBase.h> -#include <ListenerOrientationBase.h> -#include <LocationBase.h> -#include <LoudnessBase.h> -#include <SourceOrientationBase.h> -#include <StereoWideningBase.h> +#include <mdaaudiooutputstream.h> #include "audioequalizer.h" #include "bassboost.h" +#include "environmentalreverb.h" +#include "loudness.h" +#include "stereowidening.h" #include "effectfactory.h" @@ -44,111 +38,176 @@ using namespace Phonon::MMF; \internal */ -QHash<QByteArray, QVariant> EffectFactory::constructEffectDescription(const QString &name, - const QString &description) +EffectFactory::EffectFactory(QObject *parent) + : QObject(parent) + , m_initialized(false) { - QHash<QByteArray, QVariant> retval; - retval.insert("name", name); - retval.insert("description", description); - retval.insert("available", true); - - return retval; } - -QHash<QByteArray, QVariant> EffectFactory::audioEffectDescriptions(AbstractAudioEffect::Type type) +EffectFactory::~EffectFactory() { - switch (type) - { - case AbstractAudioEffect::EffectAudioEqualizer: - return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Audio Equalizer"), "Audio equalizer."); - case AbstractAudioEffect::EffectBassBoost: - return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Bass Boost"), "Bass boost."); - case AbstractAudioEffect::EffectDistanceAttenuation: - return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Distance Attenuation"), "Distance Attenuation."); - case AbstractAudioEffect::EffectEnvironmentalReverb: - return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Environmental Reverb"), "Environmental Reverb."); - case AbstractAudioEffect::EffectListenerOrientation: - return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Environmental Reverb"), "Environmental Reverb."); - case AbstractAudioEffect::EffectLoudness: - return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Loudness"), "Loudness."); - case AbstractAudioEffect::EffectSourceOrientation: - return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Source Orientation"), "Source Orientation."); - case AbstractAudioEffect::EffectStereoWidening: - return constructEffectDescription(QCoreApplication::translate("Phonon::MMF::EffectFactory", "Stereo Widening"), "Stereo Widening."); - } - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect type."); - return QHash<QByteArray, QVariant>(); } -AbstractAudioEffect *EffectFactory::createAudioEffect(AbstractAudioEffect::Type type, +//----------------------------------------------------------------------------- +// Public functions +//----------------------------------------------------------------------------- + +AbstractAudioEffect *EffectFactory::createAudioEffect(Type type, QObject *parent) { + // Lazily initialize + if (!m_initialized) + initialize(); + Q_ASSERT(parent); + const QList<EffectParameter>& parameters = data(type).m_parameters; + + AbstractAudioEffect *effect = 0; + switch (type) { - case AbstractAudioEffect::EffectBassBoost: - return new BassBoost(parent); - case AbstractAudioEffect::EffectAudioEqualizer: - return new AudioEqualizer(parent); - case AbstractAudioEffect::EffectDistanceAttenuation: - case AbstractAudioEffect::EffectEnvironmentalReverb: - case AbstractAudioEffect::EffectListenerOrientation: - case AbstractAudioEffect::EffectLoudness: - case AbstractAudioEffect::EffectSourceOrientation: - case AbstractAudioEffect::EffectStereoWidening: - ; + case TypeBassBoost: + effect = new BassBoost(parent, parameters); + break; + case TypeAudioEqualizer: + effect = new AudioEqualizer(parent, parameters); + break; + case TypeEnvironmentalReverb: + effect = new EnvironmentalReverb(parent, parameters); + break; + case TypeLoudness: + effect = new Loudness(parent, parameters); + break; + case TypeStereoWidening: + effect = new StereoWidening(parent, parameters); + break; + + // Not implemented + case TypeDistanceAttenuation: + case TypeListenerOrientation: + case TypeSourceOrientation: + // Fall through + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect"); } - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown effect."); - return 0; + return effect; } -template<typename TEffect> -bool isEffectSupported() +QHash<QByteArray, QVariant> EffectFactory::audioEffectDescriptions(Type type) { - AudioPlayer audioPlayer; - - QScopedPointer<TEffect> eff; - TRAPD(errorCode, eff.reset(TEffect::NewL(*audioPlayer.player()))); + // Lazily initialize + if (!m_initialized) + initialize(); - return errorCode != KErrNone; + return data(type).m_descriptions; } QList<int> EffectFactory::effectIndexes() { - QList<int> retval; + // Lazily initialize + if (!m_initialized) + initialize(); - if (isEffectSupported<CAudioEqualizer>()) - retval.append(AbstractAudioEffect::EffectAudioEqualizer); + QList<int> result; - if (isEffectSupported<CBassBoost>()) - retval.append(AbstractAudioEffect::EffectBassBoost); + QHash<Type, EffectData>::const_iterator i = m_effectData.begin(); + for ( ; i != m_effectData.end(); ++i) + if (i.value().m_supported) + result.append(i.key()); - /* We haven't implemented these yet. - if (isEffectSupported<CDistanceAttenuation>()) - retval.append(AbstractAudioEffect::EffectDistanceAttenuation); + return result; +} - if (isEffectSupported<CEnvironmentalReverb>()) - retval.append(AbstractAudioEffect::EffectEnvironmentalReverb); +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- - if (isEffectSupported<CLoudness>()) - retval.append(AbstractAudioEffect::EffectLoudness); +#define INITIALIZE_EFFECT(Effect) \ + { \ + EffectData data = getData<Effect>(); \ + m_effectData.insert(Type##Effect, data); \ + } - if (isEffectSupported<CListenerOrientation>()) - retval.append(AbstractAudioEffect::EffectListenerOrientation); +void EffectFactory::initialize() +{ + Q_ASSERT_X(!m_initialized, Q_FUNC_INFO, "Already initialized"); - if (isEffectSupported<CSourceOrientation>()) - retval.append(AbstractAudioEffect::EffectSourceOrientation); + INITIALIZE_EFFECT(AudioEqualizer) + INITIALIZE_EFFECT(BassBoost) + INITIALIZE_EFFECT(EnvironmentalReverb) + INITIALIZE_EFFECT(Loudness) + INITIALIZE_EFFECT(StereoWidening) - if (isEffectSupported<CStereoWidening>()) - retval.append(AbstractAudioEffect::EffectStereoWidening); - */ + m_initialized = true; +} + +// This class is just a wrapper which allows us to instantiate a +// CMdaAudioOutputStream object. This is done in order to allow the +// effects API to query the DevSound implementation, to discover +// which effects are supported and what parameters they take. +// Ideally, we would use CMMFDevSound directly, but this class is not +// available in the public S60 SDK. +class OutputStreamFactory : public MMdaAudioOutputStreamCallback +{ +public: + CMdaAudioOutputStream* create() + { + CMdaAudioOutputStream* stream = 0; + QT_TRAP_THROWING(stream = CMdaAudioOutputStream::NewL(*this)); + return stream; + } +private: + void MaoscOpenComplete(TInt /*aError*/) { } + void MaoscBufferCopied(TInt /*aError*/, const TDesC8& /*aBuffer*/) { } + void MaoscPlayComplete(TInt /*aError*/) { } +}; + +template<typename BackendNode> +EffectFactory::EffectData EffectFactory::getData() +{ + EffectData data; + + // Create a temporary CMdaAudioOutputStream object, so that the effects + // API can query DevSound to discover which effects are supported. + OutputStreamFactory streamFactory; + QScopedPointer<CMdaAudioOutputStream> stream(streamFactory.create()); + + EffectParameter param( + /* parameterId */ AbstractAudioEffect::ParameterEnable, + /* name */ tr("Enabled"), + /* hints */ EffectParameter::ToggledHint, + /* defaultValue */ QVariant(bool(true))); + data.m_parameters.append(param); + + if (data.m_supported = BackendNode::getParameters + (stream.data(), data.m_parameters)) { + const QString description = QCoreApplication::translate + ("Phonon::MMF::EffectFactory", BackendNode::description()); + data.m_descriptions.insert("name", description); + data.m_descriptions.insert("description", description); + data.m_descriptions.insert("available", true); + } + + // Sanity check to ensure that all parameter IDs are unique + QSet<int> ids; + foreach (param, data.m_parameters) { + Q_ASSERT_X(ids.find(param.id()) == ids.end(), Q_FUNC_INFO, + "Parameter list contains duplicates"); + ids.insert(param.id()); + } - return retval; + return data; +} + +const EffectFactory::EffectData& EffectFactory::data(Type type) const +{ + QHash<Type, EffectData>::const_iterator i = m_effectData.find(type); + Q_ASSERT_X(i != m_effectData.end(), Q_FUNC_INFO, "Effect data not found"); + return i.value(); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/effectfactory.h b/src/3rdparty/phonon/mmf/effectfactory.h index e83ad15..dd4b58d 100644 --- a/src/3rdparty/phonon/mmf/effectfactory.h +++ b/src/3rdparty/phonon/mmf/effectfactory.h @@ -20,6 +20,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #define PHONON_MMF_EFFECTFACTORY_H #include "abstractaudioeffect.h" +#include "effectparameter.h" QT_BEGIN_NAMESPACE @@ -31,14 +32,30 @@ namespace MMF /** * @short Contains utility functions related to effects. */ -class EffectFactory +class EffectFactory : public QObject { + Q_OBJECT + public: + EffectFactory(QObject *parent); + ~EffectFactory(); + + enum Type + { + TypeAudioEqualizer = 0 + , TypeBassBoost + , TypeDistanceAttenuation + , TypeEnvironmentalReverb + , TypeListenerOrientation + , TypeLoudness + , TypeSourceOrientation + , TypeStereoWidening + }; + /** * @short Creates an audio effect of type @p type. */ - static AbstractAudioEffect *createAudioEffect(AbstractAudioEffect::Type type, - QObject *parent); + AbstractAudioEffect *createAudioEffect(Type type, QObject *parent); /** * @short Return the properties for effect @p type. @@ -46,7 +63,7 @@ public: * This handles the effects for * BackendInterface::objectDescriptionProperties(). */ - static QHash<QByteArray, QVariant> audioEffectDescriptions(AbstractAudioEffect::Type type); + QHash<QByteArray, QVariant> audioEffectDescriptions(Type type); /** * @short Returns the indexes for the supported effects. @@ -54,19 +71,27 @@ public: * This handles the effects for * BackendInterface::objectDescriptionIndexes(). */ - static QList<int> effectIndexes(); + QList<int> effectIndexes(); private: - static inline QHash<QByteArray, QVariant> constructEffectDescription(const QString &name, - const QString &description); + void initialize(); + + struct EffectData + { + bool m_supported; + QHash<QByteArray, QVariant> m_descriptions; + QList<EffectParameter> m_parameters; + }; + + template<typename BackendNode> EffectData getData(); + const EffectData& data(Type type) const; + +private: + bool m_initialized; + QHash<Type, EffectData> m_effectData; - /** - * This class is not supposed to be instantiated, so disable - * the default constructor. - */ - inline EffectFactory(); - Q_DISABLE_COPY(EffectFactory) }; + } } diff --git a/src/3rdparty/phonon/mmf/effectparameter.cpp b/src/3rdparty/phonon/mmf/effectparameter.cpp new file mode 100644 index 0000000..17c1315 --- /dev/null +++ b/src/3rdparty/phonon/mmf/effectparameter.cpp @@ -0,0 +1,71 @@ +/* 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 "effectparameter.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +/*! \class MMF::EffectParameter + \internal +*/ + +MMF::EffectParameter::EffectParameter() + : m_hasInternalRange(false) +{ + +} + +MMF::EffectParameter::EffectParameter( + int parameterId, const QString &name, Hints hints, + const QVariant &defaultValue, const QVariant &min, + const QVariant &max, const QVariantList &values, + const QString &description) + : Phonon::EffectParameter(parameterId, name, hints, defaultValue, + min, max, values, description) + , m_hasInternalRange(false) +{ + +} + +void MMF::EffectParameter::setInternalRange(qint32 min, qint32 max) +{ + Q_ASSERT_X(max >= min, Q_FUNC_INFO, "Invalid range"); + m_internalRange = QPair<qint32, qint32>(min, max); + m_hasInternalRange = true; +} + +qint32 MMF::EffectParameter::toInternalValue(qreal external) const +{ + Q_ASSERT_X(m_hasInternalRange, Q_FUNC_INFO, "Does not have internal range"); + const qint32 range = m_internalRange.second - m_internalRange.first; + return m_internalRange.first + ((1.0 + external) / 2) * range; +} + +qreal MMF::EffectParameter::toExternalValue + (qint32 value, qint32 min, qint32 max) +{ + Q_ASSERT_X(max >= min, Q_FUNC_INFO, "Invalid range"); + const qint32 range = max - min; + return range == 0 ? 0.0 : ((2.0 * value - min) / range) - 1.0; +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/effectparameter.h b/src/3rdparty/phonon/mmf/effectparameter.h new file mode 100644 index 0000000..892ed4d --- /dev/null +++ b/src/3rdparty/phonon/mmf/effectparameter.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_EFFECTPARAMETER_H +#define PHONON_MMF_EFFECTPARAMETER_H + +#include <phonon/effectparameter.h> + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ + +/** + * @short Parameter value for an audio effect + * + * The base class is extended in order to work around a shortcoming + * in Phonon::EffectWidget. This widget only displays sliders for + * parameters with numeric values if the variant type of the parameter + * is QReal and the range is exactly -1.0 to +1.0; otherwise, a + * spinbox is used to set numeric parameters. This is rather + * inconvenient for many effects, such as the audio equalizer, for + * which a slider is a much more natural UI control. + * + * For many such parameters, we therefore report the type to be QReal + * and the range to be -1.0 to +1.0. This class stores the actual + * integer range for the parameter, and provides the toInternalValue + * function for converting between the client-side floating point + * value and the internal integer value. + */ +class EffectParameter : public Phonon::EffectParameter +{ +public: + EffectParameter(); + EffectParameter(int parameterId, const QString &name, Hints hints, + const QVariant &defaultValue, const QVariant &min = QVariant(), + const QVariant &max = QVariant(), const QVariantList &values = QVariantList(), + const QString &description = QString()); + + void setInternalRange(qint32 min, qint32 max); + qint32 toInternalValue(qreal external) const; + + static qreal toExternalValue(qint32 value, qint32 min, qint32 max); + +private: + bool m_hasInternalRange; + QPair<qint32, qint32> m_internalRange; + +}; + +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/environmentalreverb.cpp b/src/3rdparty/phonon/mmf/environmentalreverb.cpp new file mode 100644 index 0000000..89f8d60 --- /dev/null +++ b/src/3rdparty/phonon/mmf/environmentalreverb.cpp @@ -0,0 +1,201 @@ +/* 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 <EnvironmentalReverbBase.h> +#include "environmentalreverb.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +/*! \class MMF::EnvironmentalReverb + \internal +*/ + +// Define functions which depend on concrete native effect class name +PHONON_MMF_DEFINE_EFFECT_FUNCTIONS(EnvironmentalReverb) + +enum Parameters +{ + DecayHFRatio = AbstractAudioEffect::ParameterBase, + DecayTime, + Density, + Diffusion, + ReflectionsDelay, + ReflectionsLevel, + ReverbDelay, + ReverbLevel, + RoomHFLevel, + RoomLevel +}; + +EnvironmentalReverb::EnvironmentalReverb(QObject *parent, const QList<EffectParameter>& parameters) + : AbstractAudioEffect::AbstractAudioEffect(parent, parameters) +{ + +} + +int EnvironmentalReverb::effectParameterChanged(const EffectParameter ¶m, + const QVariant &value) +{ + const qreal externalLevel = value.toReal(); + const int internalLevel = param.toInternalValue(externalLevel); + + TInt err = 0; + + switch(param.id()) { + case DecayHFRatio: + TRAP(err, concreteEffect()->SetDecayHFRatioL(internalLevel)); + break; + case DecayTime: + TRAP(err, concreteEffect()->SetDecayTimeL(internalLevel)); + break; + case Density: + TRAP(err, concreteEffect()->SetDensityL(internalLevel)); + break; + case Diffusion: + TRAP(err, concreteEffect()->SetDiffusionL(internalLevel)); + break; + case ReflectionsDelay: + TRAP(err, concreteEffect()->SetReflectionsDelayL(internalLevel)); + break; + case ReflectionsLevel: + TRAP(err, concreteEffect()->SetReflectionsLevelL(internalLevel)); + break; + case ReverbDelay: + TRAP(err, concreteEffect()->SetReverbDelayL(internalLevel)); + break; + case ReverbLevel: + TRAP(err, concreteEffect()->SetReverbLevelL(internalLevel)); + break; + case RoomHFLevel: + TRAP(err, concreteEffect()->SetRoomHFLevelL(internalLevel)); + break; + case RoomLevel: + TRAP(err, concreteEffect()->SetRoomLevelL(internalLevel)); + break; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown parameter"); + } + + return err; +} + + +//----------------------------------------------------------------------------- +// Static functions +//----------------------------------------------------------------------------- + +const char* EnvironmentalReverb::description() +{ + return "Reverb"; +} + +// Internal helper function +Phonon::MMF::EffectParameter createParameter(int id, const QString &name, + int defaultValue, int minValue, int maxValue, + Phonon::EffectParameter::Hint hint = Phonon::EffectParameter::IntegerHint) +{ + const qreal externalDefaultValue = + Phonon::MMF::EffectParameter::toExternalValue + (defaultValue, minValue, maxValue); + + Phonon::MMF::EffectParameter param(id, name, hint, + /* defaultValue */ QVariant(externalDefaultValue), + /* minimumValue */ QVariant(qreal(-1.0)), + /* maximumValue */ QVariant(qreal(+1.0))); + + param.setInternalRange(minValue, maxValue); + return param; +} + +bool EnvironmentalReverb::getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter>& parameters) +{ + bool supported = false; + + QScopedPointer<CEnvironmentalReverb> effect; + TRAPD(err, effect.reset(CEnvironmentalReverb::NewL(*stream))); + + if (KErrNone == err) { + supported = true; + + TInt32 min, max; + TUint32 umin, umax; + + // DecayHFRatio + effect->DecayHFRatioRange(umin, umax); + parameters.append(createParameter( + DecayHFRatio, tr("Decay HF ratio (%)"), effect->DecayHFRatio(), + umin, umax)); + + // DecayTime + effect->DecayTimeRange(umin, umax); + parameters.append(createParameter( + DecayTime, tr("Decay time (ms)"), effect->DecayTime(), + umin, umax)); + + // Density + parameters.append(createParameter( + Density, tr("Density (%)"), effect->Density(), 0, 100)); + + // Diffusion + parameters.append(createParameter( + Diffusion, tr("Diffusion (%)"), effect->Diffusion(), 0, 100)); + + // ReflectionsDelay + parameters.append(createParameter( + ReflectionsDelay, tr("Reflections delay (ms)"), + effect->ReflectionsDelay(), 0, effect->ReflectionsDelayMax())); + + // ReflectionsLevel + effect->ReflectionLevelRange(min, max); + parameters.append(createParameter( + ReflectionsLevel, tr("Reflections level (mB)"), + effect->ReflectionsLevel(), + min, max, EffectParameter::LogarithmicHint)); + + // ReverbDelay + parameters.append(createParameter( + ReverbDelay, tr("Reverb delay (ms)"), effect->ReverbDelay(), + 0, effect->ReverbDelayMax())); + + // ReverbLevel + effect->ReverbLevelRange(min, max); + parameters.append(createParameter( + ReverbLevel, tr("Reverb level (mB)"), effect->ReverbLevel(), + min, max, EffectParameter::LogarithmicHint)); + + // RoomHFLevel + effect->RoomHFLevelRange(min, max); + parameters.append(createParameter( + RoomHFLevel, tr("Room HF level"), effect->RoomHFLevel(), + min, max)); + + // RoomLevel + effect->RoomLevelRange(min, max); + parameters.append(createParameter( + RoomLevel, tr("Room level (mB)"), effect->RoomLevel(), + min, max, EffectParameter::LogarithmicHint)); + } + + return supported; +} + +QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/environmentalreverb.h b/src/3rdparty/phonon/mmf/environmentalreverb.h new file mode 100644 index 0000000..eab68c6 --- /dev/null +++ b/src/3rdparty/phonon/mmf/environmentalreverb.h @@ -0,0 +1,62 @@ +/* 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_ENVIRONMENTALREVERB_H +#define PHONON_MMF_ENVIRONMENTALREVERB_H + +#include "abstractaudioeffect.h" + +class CEnvironmentalReverb; + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * @short A reverb effect. + */ +class EnvironmentalReverb : public AbstractAudioEffect +{ + Q_OBJECT +public: + EnvironmentalReverb(QObject *parent, const QList<EffectParameter>& parameters); + + // Static interface required by EffectFactory + static const char* description(); + static bool getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter>& parameters); + +protected: + // AbstractAudioEffect + virtual void createEffect(AudioPlayer::NativePlayer *player); + virtual int effectParameterChanged(const EffectParameter ¶m, + const QVariant &value); + +private: + CEnvironmentalReverb *concreteEffect(); + +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/loudness.cpp b/src/3rdparty/phonon/mmf/loudness.cpp new file mode 100644 index 0000000..1079a35 --- /dev/null +++ b/src/3rdparty/phonon/mmf/loudness.cpp @@ -0,0 +1,58 @@ +/* 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 <LoudnessBase.h> +#include "loudness.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +// Define functions which depend on concrete native effect class name +PHONON_MMF_DEFINE_EFFECT_FUNCTIONS(Loudness) + +/*! \class MMF::Loudness + \internal +*/ + +Loudness::Loudness(QObject *parent, const QList<EffectParameter>& parameters) + : AbstractAudioEffect::AbstractAudioEffect(parent, parameters) +{ + +} + +//----------------------------------------------------------------------------- +// Static functions +//----------------------------------------------------------------------------- + +const char* Loudness::description() +{ + return "Loudness"; +} + +bool Loudness::getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter> ¶meters) +{ + QScopedPointer<CLoudness> effect; + TRAPD(err, effect.reset(CLoudness::NewL(*stream))); + return (KErrNone == err); +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/loudness.h b/src/3rdparty/phonon/mmf/loudness.h new file mode 100644 index 0000000..a688a67 --- /dev/null +++ b/src/3rdparty/phonon/mmf/loudness.h @@ -0,0 +1,60 @@ +/* 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_LOUDNESS_H +#define PHONON_MMF_LOUDNESS_H + +#include "abstractaudioeffect.h" + +class CLoudness; + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * @short A "loudness" effect. + */ +class Loudness : public AbstractAudioEffect +{ + Q_OBJECT +public: + Loudness(QObject *parent, const QList<EffectParameter>& parameters); + + // Static interface required by EffectFactory + static const char* description(); + static bool getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter>& parameters); + +protected: + // AbstractAudioEffect + virtual void createEffect(AudioPlayer::NativePlayer *player); + +private: + CLoudness *concreteEffect(); + +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/mediaobject.cpp b/src/3rdparty/phonon/mmf/mediaobject.cpp index 21dcfe1..9744774 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.cpp +++ b/src/3rdparty/phonon/mmf/mediaobject.cpp @@ -45,6 +45,7 @@ using namespace Phonon::MMF; MMF::MediaObject::MediaObject(QObject *parent) : MMF::MediaNode::MediaNode(parent) , m_recognizerOpened(false) + , m_nextSourceSet(false) { m_player.reset(new DummyPlayer()); @@ -211,18 +212,20 @@ qint64 MMF::MediaObject::totalTime() const MediaSource MMF::MediaObject::source() const { - return m_player->source(); + return m_source; } void MMF::MediaObject::setSource(const MediaSource &source) { - createPlayer(source); - - // This is a hack to work around KErrInUse from MMF client utility - // OpenFileL calls - m_player->setFileSource(source, m_file); + switchToSource(source); +} - emit currentSourceChanged(source); +void MMF::MediaObject::switchToSource(const MediaSource &source) +{ + createPlayer(source); + m_source = source; + m_player->open(m_source, m_file); + emit currentSourceChanged(m_source); } void MMF::MediaObject::createPlayer(const MediaSource &source) @@ -238,7 +241,6 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) const bool oldPlayerHasVideo = oldPlayer->hasVideo(); const bool oldPlayerSeekable = oldPlayer->isSeekable(); - Phonon::ErrorType error = NoError; QString errorMessage; // Determine media type @@ -254,8 +256,10 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) mediaType = fileMediaType(url.toLocalFile()); } else { - errorMessage = QLatin1String("Network streaming not supported yet"); - error = NormalError; + // Streaming playback is generally not supported by the implementation + // of the audio player API, so we use CVideoPlayerUtility for both + // audio and video streaming. + mediaType = MediaTypeVideo; } } break; @@ -263,8 +267,7 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) case MediaSource::Invalid: case MediaSource::Disc: case MediaSource::Stream: - TRACE_0("Unsupported media type"); - error = NormalError; + errorMessage = tr("Error opening source: type not supported"); break; case MediaSource::Empty: @@ -281,34 +284,23 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) switch (mediaType) { case MediaTypeUnknown: TRACE_0("Media type could not be determined"); - if (oldPlayer) { - newPlayer = new DummyPlayer(*oldPlayer); - } else { - newPlayer = new DummyPlayer(); - } - - error = NormalError; - errorMessage = tr("Media type could not be determined"); + newPlayer = new DummyPlayer(oldPlayer); + errorMessage = tr("Error opening source: media type could not be determined"); break; case MediaTypeAudio: - if (oldPlayer) { - newPlayer = new AudioPlayer(*oldPlayer); - } else { - newPlayer = new AudioPlayer(); - } + newPlayer = new AudioPlayer(this, oldPlayer); break; case MediaTypeVideo: - if (oldPlayer) { - newPlayer = new VideoPlayer(*oldPlayer); - } else { - newPlayer = new VideoPlayer(); - } + newPlayer = new VideoPlayer(this, oldPlayer); break; } + if (oldPlayer) + emit abstractPlayerChanged(0); m_player.reset(newPlayer); + emit abstractPlayerChanged(newPlayer); if (oldPlayerHasVideo != hasVideo()) { emit hasVideoChanged(hasVideo()); @@ -322,13 +314,16 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) 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(bufferStatus(int)), SIGNAL(bufferStatus(int))); connect(m_player.data(), SIGNAL(metaDataChanged(QMultiMap<QString,QString>)), SIGNAL(metaDataChanged(QMultiMap<QString,QString>))); + connect(m_player.data(), SIGNAL(aboutToFinish()), SIGNAL(aboutToFinish())); + connect(m_player.data(), SIGNAL(prefinishMarkReached(qint32)), SIGNAL(tick(qint32))); // We need to call setError() after doing the connects, otherwise the // error won't be received. - if (error != NoError) { + if (!errorMessage.isEmpty()) { Q_ASSERT(m_player); - m_player->setError(error, errorMessage); + m_player->setError(errorMessage); } TRACE_EXIT_0(); @@ -336,7 +331,8 @@ void MMF::MediaObject::createPlayer(const MediaSource &source) void MMF::MediaObject::setNextSource(const MediaSource &source) { - m_player->setNextSource(source); + m_nextSource = source; + m_nextSourceSet = true; } qint32 MMF::MediaObject::prefinishMark() const @@ -365,6 +361,25 @@ void MMF::MediaObject::volumeChanged(qreal volume) } //----------------------------------------------------------------------------- +// MediaNode +//----------------------------------------------------------------------------- + +void MMF::MediaObject::connectMediaObject(MediaObject * /*mediaObject*/) +{ + // This function should never be called - see MediaNode::setMediaObject() + Q_ASSERT_X(false, Q_FUNC_INFO, + "Connection of MediaObject to MediaObject"); +} + +void MMF::MediaObject::disconnectMediaObject(MediaObject * /*mediaObject*/) +{ + // This function should never be called - see MediaNode::setMediaObject() + Q_ASSERT_X(false, Q_FUNC_INFO, + "Disconnection of MediaObject from MediaObject"); +} + + +//----------------------------------------------------------------------------- // Video output //----------------------------------------------------------------------------- @@ -379,10 +394,17 @@ AbstractPlayer *MMF::MediaObject::abstractPlayer() const return m_player.data(); } -bool MMF::MediaObject::activateOnMediaObject(MediaObject *) +//----------------------------------------------------------------------------- +// Playlist support +//----------------------------------------------------------------------------- + +void MMF::MediaObject::switchToNextSource() { - // Guess what, we do nothing. - return true; + if (m_nextSourceSet) { + m_nextSourceSet = false; + switchToSource(m_nextSource); + play(); + } } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/mediaobject.h b/src/3rdparty/phonon/mmf/mediaobject.h index ee94ea2..d6248e2 100644 --- a/src/3rdparty/phonon/mmf/mediaobject.h +++ b/src/3rdparty/phonon/mmf/mediaobject.h @@ -19,8 +19,8 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_MEDIAOBJECT_H #define PHONON_MMF_MEDIAOBJECT_H -#include <Phonon/MediaSource> -#include <Phonon/MediaObjectInterface> +#include <phonon/mediasource.h> +#include <phonon/mediaobjectinterface.h> #include <QScopedPointer> #include <QTimer> @@ -75,6 +75,10 @@ public: virtual qint32 transitionTime() const; virtual void setTransitionTime(qint32); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); + /** * This class owns the AbstractPlayer, and will delete it upon * destruction. @@ -83,30 +87,28 @@ public: void setVideoOutput(VideoOutput* videoOutput); - virtual bool activateOnMediaObject(MediaObject *); - public Q_SLOTS: void volumeChanged(qreal volume); + void switchToNextSource(); Q_SIGNALS: + void abstractPlayerChanged(AbstractPlayer *player); void totalTimeChanged(qint64 length); void hasVideoChanged(bool hasVideo); void seekableChanged(bool seekable); - // TODO: emit bufferStatus from MediaObject void bufferStatus(int); - // TODO: emit aboutToFinish from MediaObject void aboutToFinish(); - // TODO: emit prefinishMarkReached from MediaObject - void prefinishMarkReached(qint32); + void prefinishMarkReached(qint32 remaining); // TODO: emit metaDataChanged from MediaObject void metaDataChanged(const QMultiMap<QString, QString>& metaData); void currentSourceChanged(const MediaSource& source); - void stateChanged(Phonon::State oldState, - Phonon::State newState); + void stateChanged(Phonon::State newState, + Phonon::State oldState); void finished(); void tick(qint64 time); private: + void switchToSource(const MediaSource &source); void createPlayer(const MediaSource &source); bool openRecognizer(); @@ -123,6 +125,10 @@ private: RApaLsSession m_recognizer; RFs m_fileServer; + MediaSource m_source; + MediaSource m_nextSource; + bool m_nextSourceSet; + // Storing the file handle here to work around KErrInUse error // from MMF player utility OpenFileL functions RFile m_file; diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.cpp b/src/3rdparty/phonon/mmf/mmf_medianode.cpp index 253c5e7..ca413d9 100644 --- a/src/3rdparty/phonon/mmf/mmf_medianode.cpp +++ b/src/3rdparty/phonon/mmf/mmf_medianode.cpp @@ -29,92 +29,123 @@ using namespace Phonon::MMF; \internal */ -MMF::MediaNode::MediaNode(QObject *parent) : QObject::QObject(parent) - , m_source(0) - , m_target(0) - , m_isApplied(false) +MMF::MediaNode::MediaNode(QObject *parent) + : QObject(parent) + , m_mediaObject(qobject_cast<MediaObject *>(this)) + , m_input(0) { -} - -bool MMF::MediaNode::connectMediaNode(MediaNode *target) -{ - m_target = target; - m_target->setSource(this); - return applyNodesOnMediaObject(target); } -bool MMF::MediaNode::disconnectMediaNode(MediaNode *target) +MMF::MediaNode::~MediaNode() { - Q_UNUSED(target); - m_target = 0; - m_isApplied = false; - return true; + // Phonon framework ensures nodes are disconnected before being destroyed. + Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, + "Media node not disconnected before destruction"); } -void MMF::MediaNode::setSource(MediaNode *source) +bool MMF::MediaNode::connectOutput(MediaNode *output) { - m_source = source; + Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer"); + + bool connected = false; + + // Check that this connection will not result in a graph which + // containing more than one MediaObject + const bool mediaObjectMisMatch = + m_mediaObject + && output->m_mediaObject + && m_mediaObject != output->m_mediaObject; + + const bool canConnect = + !output->isMediaObject() + && !output->m_input + && !m_outputs.contains(output); + + if (canConnect && !mediaObjectMisMatch) { + output->m_input = this; + m_outputs += output; + updateMediaObject(); + connected = true; + } + + return connected; } -MMF::MediaNode *MMF::MediaNode::source() const +bool MMF::MediaNode::disconnectOutput(MediaNode *output) { - return m_source; + Q_ASSERT_X(output, Q_FUNC_INFO, "Null output pointer"); + + bool disconnected = false; + + if (m_outputs.contains(output) && this == output->m_input) { + output->m_input = 0; + const bool removed = m_outputs.removeOne(output); + Q_ASSERT_X(removed, Q_FUNC_INFO, "Output removal failed"); + + Q_ASSERT_X(!m_outputs.contains(output), Q_FUNC_INFO, + "Output list contains duplicate entries"); + + // Perform traversal across each of the two graphs separately + updateMediaObject(); + output->updateMediaObject(); + + disconnected = true; + } + + return disconnected; } -MMF::MediaNode *MMF::MediaNode::target() const +bool MMF::MediaNode::isMediaObject() const { - return m_target; + return (qobject_cast<const MediaObject *>(this) != 0); } -bool MMF::MediaNode::applyNodesOnMediaObject(MediaNode *) +void MMF::MediaNode::updateMediaObject() { - // Algorithmically, this can be expressed in a more efficient way by - // exercising available assumptions, but it complicates code for input - // data(length of the graph) which typically is very small. - - // First, we go to the very beginning of the graph. - MMF::MediaNode *current = this; - do { - MediaNode *const candidate = current->source(); - if (candidate) - current = candidate; - else - break; - } - while (current); - - // Now we do two things, while walking to the other end: - // 1. Find the MediaObject, if present - // 2. Collect a list of all unapplied MediaNodes - - QList<MediaNode *> unapplied; - MMF::MediaObject *mo = 0; + QList<MediaNode *> nodes; + MediaObject *mediaObject = 0; - do { - if (!current->m_isApplied) - unapplied.append(current); + // Traverse the graph, collecting a list of nodes, and locating + // the MediaObject node, if present + visit(nodes, mediaObject); - if (!mo) - mo = qobject_cast<MMF::MediaObject *>(current); + MediaNode *node = 0; + foreach(node, nodes) + node->setMediaObject(mediaObject); +} - current = current->target(); +void MMF::MediaNode::setMediaObject(MediaObject *mediaObject) +{ + if(!isMediaObject() && m_mediaObject != mediaObject) { + if (!mediaObject) + disconnectMediaObject(m_mediaObject); + else { + Q_ASSERT_X(!m_mediaObject, Q_FUNC_INFO, "MediaObject already set"); + connectMediaObject(mediaObject); + } + m_mediaObject = mediaObject; } - while (current); +} - // Now, lets activate all the objects, if we found the MediaObject. +void MMF::MediaNode::visit(QList<MediaNode *>& visited, MediaObject*& mediaObject) +{ + if (isMediaObject()) { + // There can never be more than one MediaObject per graph, due to the + // mediaObjectMisMatch test in connectOutput(). + Q_ASSERT_X(!mediaObject, Q_FUNC_INFO, "MediaObject already found"); + mediaObject = static_cast<MediaObject *>(this); + } - if (mo) { - for (int i = 0; i < unapplied.count(); ++i) { - MediaNode *const at = unapplied.at(i); + visited += this; - // We don't want to apply MediaObject on itself. - if (at != mo) - at->activateOnMediaObject(mo); - } - } + if (m_input && !visited.contains(m_input)) + m_input->visit(visited, mediaObject); - return true; + MediaNode *output = 0; + foreach (output, m_outputs) + if (!visited.contains(output)) + output->visit(visited, mediaObject); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/mmf_medianode.h b/src/3rdparty/phonon/mmf/mmf_medianode.h index 4616ff1..f2f64e0 100644 --- a/src/3rdparty/phonon/mmf/mmf_medianode.h +++ b/src/3rdparty/phonon/mmf/mmf_medianode.h @@ -20,7 +20,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #define PHONON_MMF_MEDIANODE_H #include <QObject> -#include <Phonon/EffectInterface> +#include <phonon/effectinterface.h> #include "audioplayer.h" QT_BEGIN_NAMESPACE @@ -43,54 +43,62 @@ class MediaObject; /** * @short Base class for all nodes in the MMF backend. * - * MediaNode is the base class for all nodes in the chain for MMF. Currently - * they are: + * MediaNode is the base class for all nodes created by the MMF + * backend. * - * - MediaObject: a source of media - * - AbstractEffect: supplying audio effects - * - AudioOutput: pretty much a dummy interface, but is also MediaNode in order - * to simplify connection/disconnection. + * These nodes may be one of the following types: * - * MediaNode provides spectatability into the chain, and also allows the - * connection code to be written in a polymorphic manner, instead of putting it - * all in the Backend class. Due to that MMF has no concept of chaining, the - * order of the nodes in the graph has no meaning. + * - MediaObject + * This represents the source of media data. It encapsulates the + * appropriate MMF client API for playing audio or video. + * - AudioOutput + * This represents the audio output device. Since the MMF client API + * does not expose the output device directly, this backend node + * simply forwards volume control commands to the MediaObject. + * - VideoWidget + * A native widget on which video will be rendered. + * - An audio effect, derived form AbstractAudioEffect + * + * Because the MMF API does not support the concept of a media filter graph, + * this class must ensure the following: + * + * - Each media graph contains at most one MediaObject instance. + * - Every non-MediaObject node holds a reference to the MediaObject. This + * allows commands to be sent through the graph to the encapsulated MMF client + * API. */ class MediaNode : public QObject { Q_OBJECT public: MediaNode(QObject *parent); + ~MediaNode(); + + bool connectOutput(MediaNode *output); + bool disconnectOutput(MediaNode *output); + + virtual void connectMediaObject(MediaObject *mediaObject) = 0; + virtual void disconnectMediaObject(MediaObject *mediaObject) = 0; - virtual bool connectMediaNode(MediaNode *target); - virtual bool disconnectMediaNode(MediaNode *target); - void setSource(MediaNode *source); +private: + bool isMediaObject() const; - MediaNode *source() const; - MediaNode *target() const; + void updateMediaObject(); + void setMediaObject(MediaObject *mediaObject); -protected: - /** - * When connectMediaNode() is called and a MediaObject is part of - * the its graph, this function will be called for each MediaNode in the - * graph for which it hasn't been called yet. - * - * The caller guarantees that @p mo is always non-null. - */ - virtual bool activateOnMediaObject(MediaObject *mo) = 0; + typedef QList<const MediaNode *> NodeList; + void visit(QList<MediaNode *>& visited, MediaObject*& mediaObject); private: - /** - * Finds a MediaObject anywhere in the graph @p target is apart of, and - * calls activateOnMediaObject() for all MediaNodes in the graph for which - * it hasn't been applied to already. - */ - bool applyNodesOnMediaObject(MediaNode *target); - - MediaNode * m_source; - MediaNode * m_target; - bool m_isApplied; + MediaObject * m_mediaObject; + + // All nodes except MediaObject may have an input + MediaNode * m_input; + + // Only MediaObject can have more than one output + QList<MediaNode *> m_outputs; }; + } } diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp index b6f53ae..127edb4 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.cpp @@ -44,20 +44,8 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::VideoPlayer::VideoPlayer() - : m_wsSession(CCoeEnv::Static()->WsSession()) - , m_screenDevice(*CCoeEnv::Static()->ScreenDevice()) - , m_window(0) - , m_totalTime(0) - , m_pendingChanges(false) - , m_dsaActive(false) - , m_dsaWasActive(false) -{ - construct(); -} - -MMF::VideoPlayer::VideoPlayer(const AbstractPlayer& player) - : AbstractMediaPlayer(player) +MMF::VideoPlayer::VideoPlayer(MediaObject *parent, const AbstractPlayer *player) + : AbstractMediaPlayer(parent, player) , m_wsSession(CCoeEnv::Static()->WsSession()) , m_screenDevice(*CCoeEnv::Static()->ScreenDevice()) , m_window(0) @@ -78,22 +66,22 @@ void MMF::VideoPlayer::construct() const TInt priority = 0; const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone; - TRAPD(err, - m_player.reset(CVideoPlayerUtility::NewL + CVideoPlayerUtility *player = 0; + QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL ( *this, priority, preference, m_wsSession, m_screenDevice, *m_window, m_videoRect, m_videoRect - )) + ) ); + m_player.reset(player); // CVideoPlayerUtility::NewL starts DSA m_dsaActive = true; - if (KErrNone != err) - changeState(ErrorState); + m_player->RegisterForVideoLoadingNotification(*this); TRACE_EXIT_0(); } @@ -109,6 +97,11 @@ MMF::VideoPlayer::~VideoPlayer() TRACE_EXIT_0(); } +CVideoPlayerUtility* MMF::VideoPlayer::nativePlayer() const +{ + return m_player.data(); +} + //----------------------------------------------------------------------------- // Public API //----------------------------------------------------------------------------- @@ -127,9 +120,9 @@ void MMF::VideoPlayer::doPause() TRACE_CONTEXT(VideoPlayer::doPause, EVideoApi); TRAPD(err, m_player->PauseL()); - if (KErrNone != err) { + if (KErrNone != err && state() != ErrorState) { TRACE("PauseL error %d", err); - setError(NormalError); + setError(tr("Pause failed"), err); } } @@ -142,24 +135,10 @@ void MMF::VideoPlayer::doSeek(qint64 ms) { TRACE_CONTEXT(VideoPlayer::doSeek, EVideoApi); - bool wasPlaying = false; - if (state() == PlayingState) { - // The call to SetPositionL does not have any effect if playback is - // ongoing, so we pause before seeking. - doPause(); - wasPlaying = true; - } - TRAPD(err, m_player->SetPositionL(TTimeIntervalMicroSeconds(ms * 1000))); - if (KErrNone == err) { - if (wasPlaying) - doPlay(); - } - else { - TRACE("SetPositionL error %d", err); - setError(NormalError); - } + if(KErrNone != err) + setError(tr("Seek failed"), err); } int MMF::VideoPlayer::setDeviceVolume(int mmfVolume) @@ -174,6 +153,19 @@ int MMF::VideoPlayer::openFile(RFile& file) return err; } +int MMF::VideoPlayer::openUrl(const QString& url) +{ + TRAPD(err, m_player->OpenUrlL(qt_QString2TPtrC(url))); + return err; +} + +int MMF::VideoPlayer::bufferStatus() const +{ + int result = 0; + TRAP_IGNORE(m_player->GetVideoLoadingProgressL(result)); + return result; +} + void MMF::VideoPlayer::close() { m_player->Close(); @@ -200,7 +192,7 @@ qint64 MMF::VideoPlayer::currentTime() const // If we don't cast away constness here, we simply have to ignore // the error. - const_cast<VideoPlayer*>(this)->setError(NormalError); + const_cast<VideoPlayer*>(this)->setError(tr("Getting position failed"), err); } return result; @@ -226,7 +218,7 @@ void MMF::VideoPlayer::MvpuoOpenComplete(TInt aError) if (KErrNone == aError) m_player->Prepare(); else - setError(NormalError); + setError(tr("Opening clip failed"), aError); TRACE_EXIT_0(); } @@ -252,7 +244,7 @@ void MMF::VideoPlayer::MvpuoPrepareComplete(TInt aError) emit totalTimeChanged(totalTime()); changeState(StoppedState); } else { - setError(NormalError); + setError(tr("Buffering clip failed"), err); } TRACE_EXIT_0(); @@ -277,7 +269,6 @@ void MMF::VideoPlayer::MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError) TRACE_CONTEXT(VideoPlayer::MvpuoFrameReady, EVideoApi); TRACE_ENTRY("state %d error %d", state(), aError); - // TODO Q_UNUSED(aFrame); Q_UNUSED(aError); // suppress warnings in release builds @@ -289,8 +280,9 @@ void MMF::VideoPlayer::MvpuoPlayComplete(TInt aError) TRACE_CONTEXT(VideoPlayer::MvpuoPlayComplete, EVideoApi) TRACE_ENTRY("state %d error %d", state(), aError); - Q_UNUSED(aError); // suppress warnings in release builds - changeState(StoppedState); + // Call base class function which handles end of playback for both + // audio and video clips. + playbackComplete(aError); TRACE_EXIT_0(); } @@ -300,7 +292,6 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent) TRACE_CONTEXT(VideoPlayer::MvpuoEvent, EVideoApi); TRACE_ENTRY("state %d", state()); - // TODO Q_UNUSED(aEvent); TRACE_EXIT_0(); @@ -308,6 +299,21 @@ void MMF::VideoPlayer::MvpuoEvent(const TMMFEvent &aEvent) //----------------------------------------------------------------------------- +// MVideoLoadingObserver callbacks +//----------------------------------------------------------------------------- + +void MMF::VideoPlayer::MvloLoadingStarted() +{ + bufferingStarted(); +} + +void MMF::VideoPlayer::MvloLoadingComplete() +{ + bufferingComplete(); +} + + +//----------------------------------------------------------------------------- // Video window updates //----------------------------------------------------------------------------- @@ -412,7 +418,7 @@ void MMF::VideoPlayer::startDirectScreenAccess() if(KErrNone == err) m_dsaActive = true; else - setError(NormalError); + setError(tr("Video display error"), err); } } @@ -424,7 +430,7 @@ bool MMF::VideoPlayer::stopDirectScreenAccess() if(KErrNone == err) m_dsaActive = false; else - setError(NormalError); + setError(tr("Video display error"), err); } return dsaWasActive; } @@ -600,7 +606,7 @@ void MMF::VideoPlayer::applyVideoWindowChange() TRAPD(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight, antialias)); if(KErrNone != err) { TRACE("SetScaleFactorL (1) err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } if(KErrNone == err) { @@ -615,13 +621,13 @@ void MMF::VideoPlayer::applyVideoWindowChange() if (KErrNone != err) { TRACE("SetDisplayWindowL err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } else { m_dsaActive = true; TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight, antialias)); if(KErrNone != err) { TRACE("SetScaleFactorL (2) err %d", err); - setError(NormalError); + setError(tr("Video display error"), err); } } } diff --git a/src/3rdparty/phonon/mmf/mmf_videoplayer.h b/src/3rdparty/phonon/mmf/mmf_videoplayer.h index abb1da8..0253ab9 100644 --- a/src/3rdparty/phonon/mmf/mmf_videoplayer.h +++ b/src/3rdparty/phonon/mmf/mmf_videoplayer.h @@ -39,14 +39,17 @@ namespace MMF */ class VideoPlayer : public AbstractMediaPlayer , public MVideoPlayerUtilityObserver + , public MVideoLoadingObserver { Q_OBJECT public: - VideoPlayer(); - explicit VideoPlayer(const AbstractPlayer& player); + VideoPlayer(MediaObject *parent = 0, const AbstractPlayer *player = 0); virtual ~VideoPlayer(); + typedef CVideoPlayerUtility NativePlayer; + NativePlayer *nativePlayer() const; + // AbstractPlayer virtual void doPlay(); virtual void doPause(); @@ -54,6 +57,8 @@ public: virtual void doSeek(qint64 milliseconds); virtual int setDeviceVolume(int mmfVolume); virtual int openFile(RFile& file); + virtual int openUrl(const QString& url); + virtual int bufferStatus() const; virtual void close(); // MediaObjectInterface @@ -61,12 +66,12 @@ public: virtual qint64 currentTime() const; virtual qint64 totalTime() const; - // MVideoPlayerUtilityObserver - virtual void MvpuoOpenComplete(TInt aError); - virtual void MvpuoPrepareComplete(TInt aError); - virtual void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError); - virtual void MvpuoPlayComplete(TInt aError); - virtual void MvpuoEvent(const TMMFEvent &aEvent); + // AbstractPlayer + virtual void videoOutputChanged(); + + // AbstractMediaPlayer + virtual int numberOfMetaDataEntries() const; + virtual QPair<QString, QString> metaDataEntry(int index) const; public Q_SLOTS: void videoWindowChanged(); @@ -80,12 +85,8 @@ private: void doPrepareCompleteL(TInt aError); - // AbstractPlayer - virtual void videoOutputChanged(); - void getVideoWindow(); void initVideoOutput(); - void updateVideoRect(); void applyPendingChanges(); @@ -94,12 +95,20 @@ private: void startDirectScreenAccess(); bool stopDirectScreenAccess(); - // AbstractMediaPlayer - virtual int numberOfMetaDataEntries() const; - virtual QPair<QString, QString> metaDataEntry(int index) const; +private: + // MVideoPlayerUtilityObserver + virtual void MvpuoOpenComplete(TInt aError); + virtual void MvpuoPrepareComplete(TInt aError); + virtual void MvpuoFrameReady(CFbsBitmap &aFrame, TInt aError); + virtual void MvpuoPlayComplete(TInt aError); + virtual void MvpuoEvent(const TMMFEvent &aEvent); + + // MVideoLoadingObserver + virtual void MvloLoadingStarted(); + virtual void MvloLoadingComplete(); private: - QScopedPointer<CVideoPlayerUtility> m_player; + QScopedPointer<NativePlayer> m_player; // Not owned RWsSession& m_wsSession; diff --git a/src/3rdparty/phonon/mmf/objectdump.cpp b/src/3rdparty/phonon/mmf/objectdump.cpp index 3d10be4..778cde9 100644 --- a/src/3rdparty/phonon/mmf/objectdump.cpp +++ b/src/3rdparty/phonon/mmf/objectdump.cpp @@ -390,7 +390,7 @@ void QVisitorPrivate::dumpNode // No annotations - just dump the object pointer const bool isNodeLine = true; QByteArray buffer = branchBuffer(branches, isNodeLine, isLastChild); - qDebug() << 0; // TODO + qDebug() << 0; } else { // Dump annotations diff --git a/src/3rdparty/phonon/mmf/stereowidening.cpp b/src/3rdparty/phonon/mmf/stereowidening.cpp new file mode 100644 index 0000000..f90651b --- /dev/null +++ b/src/3rdparty/phonon/mmf/stereowidening.cpp @@ -0,0 +1,93 @@ +/* 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 <StereoWideningBase.h> +#include "stereowidening.h" + +QT_BEGIN_NAMESPACE + +using namespace Phonon; +using namespace Phonon::MMF; + +// Define functions which depend on concrete native effect class name +PHONON_MMF_DEFINE_EFFECT_FUNCTIONS(StereoWidening) + +/*! \class MMF::StereoWidening + \internal +*/ + +StereoWidening::StereoWidening(QObject *parent, const QList<EffectParameter>& parameters) + : AbstractAudioEffect::AbstractAudioEffect(parent, parameters) +{ + +} + +int StereoWidening::parameterChanged(const EffectParameter ¶m, + const QVariant &value) +{ + Q_ASSERT_X(param.id() == ParameterBase, Q_FUNC_INFO, "Invalid parameter ID"); + + const qreal externalLevel = value.toReal(); + const int internalLevel = param.toInternalValue(externalLevel); + + TRAPD(err, concreteEffect()->SetStereoWideningLevelL(internalLevel)); + + return err; +} + +//----------------------------------------------------------------------------- +// Static functions +//----------------------------------------------------------------------------- + +const char* StereoWidening::description() +{ + return "Stereo widening"; +} + +bool StereoWidening::getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter> ¶meters) +{ + bool supported = false; + + QScopedPointer<CStereoWidening> effect; + TRAPD(err, effect.reset(CStereoWidening::NewL(*stream))); + + if (KErrNone == err) { + supported = true; + + const qreal defaultValue = + Phonon::MMF::EffectParameter::toExternalValue + (effect->StereoWideningLevel(), 0, 100); + + EffectParameter param( + /* parameterId */ ParameterBase, + /* name */ tr("Level (%)"), + /* hints */ EffectParameter::IntegerHint, + /* defaultValue */ QVariant(defaultValue), + /* minimumValue */ QVariant(qreal(-1.0)), + /* maximumValue */ QVariant(qreal(+1.0))); + + param.setInternalRange(0, 100); + parameters.append(param); + } + + return supported; +} + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/stereowidening.h b/src/3rdparty/phonon/mmf/stereowidening.h new file mode 100644 index 0000000..c967e37 --- /dev/null +++ b/src/3rdparty/phonon/mmf/stereowidening.h @@ -0,0 +1,62 @@ +/* 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_STEREOWIDENING_H +#define PHONON_MMF_STEREOWIDENING_H + +#include "abstractaudioeffect.h" + +class CStereoWidening; + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +/** + * @short A "bass boost" effect. + */ +class StereoWidening : public AbstractAudioEffect +{ + Q_OBJECT +public: + StereoWidening(QObject *parent, const QList<EffectParameter>& parameters); + + // Static interface required by EffectFactory + static const char* description(); + static bool getParameters(CMdaAudioOutputStream *stream, + QList<EffectParameter>& parameters); + +protected: + // AbstractAudioEffect + virtual void createEffect(AudioPlayer::NativePlayer *player); + virtual int parameterChanged(const EffectParameter ¶m, + const QVariant &value); + +private: + CStereoWidening *concreteEffect(); + +}; +} +} + +QT_END_NAMESPACE + +#endif + diff --git a/src/3rdparty/phonon/mmf/utils.cpp b/src/3rdparty/phonon/mmf/utils.cpp index d728fcf..2d17bd2 100644 --- a/src/3rdparty/phonon/mmf/utils.cpp +++ b/src/3rdparty/phonon/mmf/utils.cpp @@ -18,6 +18,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include "utils.h" #include <e32std.h> +#include <mmf/common/mmferrors.h> QT_BEGIN_NAMESPACE @@ -69,6 +70,101 @@ MMF::MediaType MMF::Utils::mimeTypeToMediaType(const TDesC& mimeType) return result; } +QString MMF::Utils::symbianErrorToString(int errorCode) +{ + /** + * Here we translate only the error codes which are likely to be + * meaningful to the user. For example, when an error occurs + * during opening of a media file, displaying "not found" or + * "permission denied" is informative. On the other hand, + * differentiating between KErrGeneral and KErrArgument at the UI + * level does not make sense. + */ + switch (errorCode) + { + // System-wide errors + case KErrNone: + return tr("No error"); + case KErrNotFound: + return tr("Not found"); + case KErrNoMemory: + return tr("Out of memory"); + case KErrNotSupported: + return tr("Not supported"); + case KErrOverflow: + return tr("Overflow"); + case KErrUnderflow: + return tr("Underflow"); + case KErrAlreadyExists: + return tr("Already exists"); + case KErrPathNotFound: + return tr("Path not found"); + case KErrInUse: + return tr("In use"); + case KErrNotReady: + return tr("Not ready"); + case KErrAccessDenied: + return tr("Access denied"); + case KErrCouldNotConnect: + return tr("Could not connect"); + case KErrDisconnected: + return tr("Disconnected"); + case KErrPermissionDenied: + return tr("Permission denied"); + + // Multimedia framework errors + case KErrMMNotEnoughBandwidth: + return tr("Insufficient bandwidth"); + case KErrMMSocketServiceNotFound: + case KErrMMServerSocket: + return tr("Network unavailable"); + case KErrMMNetworkRead: + case KErrMMNetworkWrite: + case KErrMMUDPReceive: + return tr("Network communication error"); + case KErrMMServerNotSupported: + return tr("Streaming not supported"); + case KErrMMServerAlert: + return tr("Server alert"); + case KErrMMInvalidProtocol: + return tr("Invalid protocol"); + case KErrMMInvalidURL: + return tr("Invalid URL"); + case KErrMMMulticast: + return tr("Multicast error"); + case KErrMMProxyServer: + case KErrMMProxyServerConnect: + return tr("Proxy server error"); + case KErrMMProxyServerNotSupported: + return tr("Proxy server not supported"); + case KErrMMAudioDevice: + return tr("Audio output error"); + case KErrMMVideoDevice: + return tr("Video output error"); + case KErrMMDecoder: + return tr("Decoder error"); + case KErrMMPartialPlayback: + return tr("Audio or video components could not be played"); + case KErrMMDRMNotAuthorized: + return tr("DRM error"); + + /* + // We don't use QoS settings + case KErrMMQosLowBandwidth: + case KErrMMQosUnsupportedTrafficClass: + case KErrMMQosPoorTrafficClass: + case KErrMMQosUnsupportedParameters: + case KErrMMQosPoorParameters: + case KErrMMQosNotSupported: + */ + + // Catch-all for errors other than those above + default: + { + return tr("Unknown error (%1)").arg(errorCode); + } + } +} #ifndef QT_NO_DEBUG diff --git a/src/3rdparty/phonon/mmf/utils.h b/src/3rdparty/phonon/mmf/utils.h index 7e363e8..56ccafc 100644 --- a/src/3rdparty/phonon/mmf/utils.h +++ b/src/3rdparty/phonon/mmf/utils.h @@ -21,7 +21,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include <private/qcore_symbian_p.h> #include <e32debug.h> // for RDebug - +#include <QtCore/QCoreApplication> // for Q_DECLARE_TR_FUNCTIONS #include <QColor> #include "defs.h" @@ -38,35 +38,44 @@ namespace MMF enum PanicCode { InvalidStatePanic = 1, InvalidMediaTypePanic = 2, - InvalidBackendInterfaceClass = 3 + InvalidBackendInterfaceClass = 3, + AudioUtilityUrlNotSupported = 4 }; -namespace Utils +class Utils { + Q_DECLARE_TR_FUNCTIONS(Utils) + +public: /** * Raise a fatal exception */ -void panic(PanicCode code); +static void panic(PanicCode code); /** * Determines whether the provided MIME type is an audio or video * type. If it is neither, the function returns MediaTypeUnknown. */ -MediaType mimeTypeToMediaType(const TDesC& mimeType); +static MediaType mimeTypeToMediaType(const TDesC& mimeType); + +/** + * Translates a Symbian error code into a user-readable string. + */ +static QString symbianErrorToString(int errorCode); #ifndef QT_NO_DEBUG /** * Retrieve color of specified pixel from the screen. */ -QColor getScreenPixel(const QPoint& pos); +static QColor getScreenPixel(const QPoint& pos); /** * Samples a small number of pixels from the screen, and dumps their * colors to the debug log. */ -void dumpScreenPixelSample(); +static void dumpScreenPixelSample(); #endif -} +}; /** * Available trace categories; diff --git a/src/3rdparty/phonon/mmf/videooutput.h b/src/3rdparty/phonon/mmf/videooutput.h index 2788401..3e9c036 100644 --- a/src/3rdparty/phonon/mmf/videooutput.h +++ b/src/3rdparty/phonon/mmf/videooutput.h @@ -24,7 +24,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include <QRect> #include "defs.h" -#include <Phonon/VideoWidget> +#include <phonon/videowidget.h> #include <e32std.h> class RWindowBase; diff --git a/src/3rdparty/phonon/mmf/videowidget.cpp b/src/3rdparty/phonon/mmf/videowidget.cpp index bd22307..bc9acfd 100644 --- a/src/3rdparty/phonon/mmf/videowidget.cpp +++ b/src/3rdparty/phonon/mmf/videowidget.cpp @@ -157,10 +157,18 @@ QWidget* MMF::VideoWidget::widget() return m_videoOutput.data(); } -bool MMF::VideoWidget::activateOnMediaObject(MediaObject *mo) +//----------------------------------------------------------------------------- +// MediaNode +//----------------------------------------------------------------------------- + +void MMF::VideoWidget::connectMediaObject(MediaObject *mediaObject) +{ + mediaObject->setVideoOutput(m_videoOutput.data()); +} + +void MMF::VideoWidget::disconnectMediaObject(MediaObject *mediaObject) { - mo->setVideoOutput(m_videoOutput.data()); - return true; + mediaObject->setVideoOutput(0); } QT_END_NAMESPACE diff --git a/src/3rdparty/phonon/mmf/videowidget.h b/src/3rdparty/phonon/mmf/videowidget.h index 2f0978b..899dca6 100644 --- a/src/3rdparty/phonon/mmf/videowidget.h +++ b/src/3rdparty/phonon/mmf/videowidget.h @@ -23,8 +23,8 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include "videooutput.h" #include <QtGui/QWidget> -#include <Phonon/VideoWidget> -#include <Phonon/VideoWidgetInterface> +#include <phonon/videowidget.h> +#include <phonon/videowidgetinterface.h> QT_BEGIN_NAMESPACE @@ -61,7 +61,9 @@ public: virtual QWidget *widget(); protected: - virtual bool activateOnMediaObject(MediaObject *mo); + // MediaNode + void connectMediaObject(MediaObject *mediaObject); + void disconnectMediaObject(MediaObject *mediaObject); private: QScopedPointer<VideoOutput> m_videoOutput; diff --git a/src/3rdparty/phonon/phonon/effectwidget.cpp b/src/3rdparty/phonon/phonon/effectwidget.cpp index 2334d7f..a2fe50f 100644 --- a/src/3rdparty/phonon/phonon/effectwidget.cpp +++ b/src/3rdparty/phonon/phonon/effectwidget.cpp @@ -15,7 +15,7 @@ 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 + 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/>. */ @@ -151,7 +151,7 @@ void EffectWidgetPrivate::autogenerateUi() bool minValueOk = false; bool maxValueOk = false; const int minValue = para.minimumValue().toInt(&minValueOk); - const int maxValue = para.minimumValue().toInt(&maxValueOk); + const int maxValue = para.maximumValue().toInt(&maxValueOk); sb->setRange(minValueOk ? minValue : DEFAULT_MIN_INT, maxValueOk ? maxValue : DEFAULT_MAX_INT); sb->setValue(value.toInt()); |