diff -r 2b40d63a9c3d -r 90517678cc4f qtmobility/plugins/multimedia/symbian/openmaxal/mediarecorder/qxarecordsession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qtmobility/plugins/multimedia/symbian/openmaxal/mediarecorder/qxarecordsession.cpp Mon May 03 13:18:40 2010 +0300 @@ -0,0 +1,647 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Mobility Components. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include "qxarecordsession.h" +#include "xarecordsessionimpl.h" +#include "qxacommon.h" + +/* The following declaration is required to allow QList to be added to + * QVariant + */ +Q_DECLARE_METATYPE(QList) + +/* This macro checks for m_impl null pointer. If it is, emits an error signal + * error(QMediaRecorder::ResourceError, tr("Service has not been started")); + * and returns from function immediately with value 's'. + */ + +#define RETURN_s_IF_m_impl_IS_NULL(s) \ + if (!m_impl) { \ + emit error(QMediaRecorder::ResourceError, tr("Service has not been started")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Service has not been started\"))"); \ + return s; \ + } + +/* This macro checks for m_impl null pointer. If it is, emits an error signal + * error(QMediaRecorder::ResourceError, tr("Service has not been started")); + * and returns from function immediately. + */ +#define RETURN_IF_m_impl_IS_NULL \ + if (!m_impl) { \ + emit error(QMediaRecorder::ResourceError, tr("Service has not been started")); \ + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Service has not been started\"))"); \ + return; \ + } + +QXARecordSession::QXARecordSession(QObject *parent) +:QObject(parent), +m_state(QMediaRecorder::StoppedState) +{ + QT_TRACE_FUNCTION_ENTRY; + m_impl = NULL; + m_impl = new XARecordSessionImpl(*this); + if (m_impl) { + if (m_impl->postConstruct() == KErrNone) { + initCodecsList(); + initContainersList(); + m_containerMimeType = QString(); + m_audioencodersettings.setBitRate(0); + m_audioencodersettings.setChannelCount(-1); + m_audioencodersettings.setEncodingMode(QtMedia::ConstantQualityEncoding); + m_audioencodersettings.setQuality(QtMedia::NormalQuality); + m_audioencodersettings.setSampleRate(-1); + QT_TRACE1("Initialized implementation"); + } + else { + delete m_impl; + m_impl = NULL; + QT_TRACE1("Error initializing implementation"); + } + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to start Service")); + } + QT_TRACE_FUNCTION_EXIT; +} + +QXARecordSession::~QXARecordSession() +{ + QT_TRACE_FUNCTION_ENTRY; + delete m_impl; + QT_TRACE_FUNCTION_EXIT; +} + +QUrl QXARecordSession::outputLocation() +{ + return m_outputLocation; +} + +bool QXARecordSession::setOutputLocation(const QUrl &location) +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(false); + + // Location can be set only when recorder is in stopped state. + if (state() != QMediaRecorder::StoppedState ) + return false; + + // Validate URL + if (!location.isValid()) + return false; + + // If old and new locations are same, do nothing. + QString newUrlStr = (QUrl::fromUserInput(location.toString().toLower())).toString(); + QString curUrlStr = (QUrl::fromUserInput(m_outputLocation.toString().toLower())).toString(); + if (curUrlStr.compare(newUrlStr) == KErrNone) + return true; + + bool retVal = false; + TPtrC16 tempPtr(reinterpret_cast(newUrlStr.utf16())); + if (m_impl->setURI(tempPtr) == 0) { + m_outputLocation = location; + retVal = true; + } + else { + emit error(QMediaRecorder::ResourceError, tr("Generic error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Generic error\"))"); + } + + QT_TRACE_FUNCTION_EXIT; + return retVal; +} + +QMediaRecorder::State QXARecordSession::state() +{ + return m_state; +} + +qint64 QXARecordSession::duration() +{ + TInt64 dur(0); + + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(dur); + + m_impl->duration(dur); + + QT_TRACE_FUNCTION_EXIT; + return (qint64)dur; +} + +void QXARecordSession::applySettings() +{ + if (m_appliedaudioencodersettings != m_audioencodersettings) + setEncoderSettingsToImpl(); +} + +void QXARecordSession::record() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + /* 1. Set encoder settings here */ + if (m_appliedaudioencodersettings != m_audioencodersettings) + RET_IF_FALSE(setEncoderSettingsToImpl()); + + /* 2. Start recording... + * If successful, setRecorderState(QMediaRecorder::RecordingState); + * will be called from the callback cbRecordingStarted() + */ + if (m_impl->record() != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Generic error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Generic error\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::pause() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + if (m_impl->pause() == KErrNone) { + setRecorderState(QMediaRecorder::PausedState); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to pause")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Unable to pause\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::stop() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + if ((m_impl->stop() == KErrNone)) { + setRecorderState(QMediaRecorder::StoppedState); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Unable to stop")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Unable to stop\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::cbDurationChanged(TInt64 new_pos) +{ + emit durationChanged((qint64)new_pos); + SIGNAL_EMIT_TRACE1("emit durationChanged((qint64)new_pos);"); +} + +void QXARecordSession::cbAvailableAudioInputsChanged() +{ + emit availableAudioInputsChanged(); + SIGNAL_EMIT_TRACE1("emit availableAudioInputsChanged();"); +} + +void QXARecordSession::cbRecordingStarted() +{ + setRecorderState(QMediaRecorder::RecordingState); +} + +void QXARecordSession::cbRecordingStopped() +{ + emit error(QMediaRecorder::ResourceError, tr("Resources Unavailable")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Resources Unavailable\"))"); + setRecorderState(QMediaRecorder::StoppedState); +} + +/* For QAudioEndpointSelector begin */ +QList QXARecordSession::availableEndpoints() +{ + QT_TRACE_FUNCTION_ENTRY; + + QList strList; + + RETURN_s_IF_m_impl_IS_NULL(strList); + + QString str; + RArray names; + m_impl->getAudioInputDeviceNames(names); + for (TInt index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + strList.append(str); + } + + QT_TRACE_FUNCTION_EXIT; + return strList; +} + +QString QXARecordSession::endpointDescription(const QString &name) +{ + /* From AL we get only device name */ + return name; +} + +QString QXARecordSession::defaultEndpoint() +{ + QT_TRACE_FUNCTION_ENTRY; + + QString str; + + RETURN_s_IF_m_impl_IS_NULL(str); + + TPtrC name; + if(m_impl->defaultAudioInputDevice(name) == KErrNone) + str = QString((QChar*)name.Ptr(), name.Length()); + + QT_TRACE_FUNCTION_EXIT; + return str; +} + +QString QXARecordSession::activeEndpoint() +{ + QT_TRACE_FUNCTION_ENTRY; + + QString str; + + RETURN_s_IF_m_impl_IS_NULL(str); + + TPtrC name; + if(m_impl->activeAudioInputDevice(name) == KErrNone) + str = QString((QChar*)name.Ptr(), name.Length()); + + QT_TRACE_FUNCTION_EXIT; + return str; +} + +void QXARecordSession::setActiveEndpoint(const QString &name) +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + TPtrC16 tempPtr(reinterpret_cast(name.utf16())); + if (m_impl->setAudioInputDevice(tempPtr) == true) { + emit activeEndpointChanged(name); + SIGNAL_EMIT_TRACE1("emit activeEndpointChanged(name)"); + } + else { + emit error(QMediaRecorder::ResourceError, tr("Invalid endpoint")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Invalid endpoint\"))"); + } + + QT_TRACE_FUNCTION_EXIT; +} +/* For QAudioEndpointSelector end */ + +/* For QAudioEncoderControl begin */ +QStringList QXARecordSession::supportedAudioCodecs() +{ + return m_codecs; +} + +QString QXARecordSession::codecDescription(const QString &codecName) +{ + if (m_codecs.contains(codecName.toLower())) + return QString(codecName); + return QString(); +} + +QList QXARecordSession::supportedSampleRates( + const QAudioEncoderSettings &settings, + bool *continuous) +{ + QT_TRACE_FUNCTION_ENTRY; + + QList srList; + + RETURN_s_IF_m_impl_IS_NULL(srList); + + QString selectedCodec = settings.codec().toLower(); + + if (m_codecs.indexOf(selectedCodec) >= 0) { + RArray sampleRates; + TBool isContinuous; + TPtrC16 tempPtr(reinterpret_cast(selectedCodec.utf16())); + if (m_impl->getSampleRates(tempPtr, sampleRates, isContinuous) == KErrNone) { + for (TInt index = 0; index < sampleRates.Count(); index++) + srList.append(sampleRates[index]); + sampleRates.Close(); + *continuous = false; + if (isContinuous == true) + *continuous = true; + } + } + + QT_TRACE_FUNCTION_EXIT; + return srList; +} + +QAudioEncoderSettings QXARecordSession::audioSettings() +{ + return m_audioencodersettings; +} + +void QXARecordSession::setAudioSettings(const QAudioEncoderSettings &settings) +{ + m_audioencodersettings = settings; +} + +QStringList QXARecordSession::supportedEncodingOptions(const QString &codec) +{ + QT_TRACE_FUNCTION_ENTRY; + Q_UNUSED(codec); + QStringList options; + options << "bitrate"; + + QT_TRACE_FUNCTION_EXIT; + return options; +} + +QVariant QXARecordSession::encodingOption(const QString &codec, const QString &name) +{ + QT_TRACE_FUNCTION_ENTRY; + + QVariant encodingOption; + + RETURN_s_IF_m_impl_IS_NULL(encodingOption); + + if (name.toLower().compare("bitrate") == 0) { + TPtrC16 tempPtr(reinterpret_cast(codec.toLower().utf16())); + QList bitrateList; + RArray bitrates; + if (m_impl->getBitrates(tempPtr, bitrates) == KErrNone) { + for (TInt index = 0; index < bitrates.Count(); index++) + bitrateList.append(bitrates[index]); + bitrates.Close(); + } + encodingOption.setValue(bitrateList); + } + + QT_TRACE_FUNCTION_EXIT; + return encodingOption; +} + +void QXARecordSession::setEncodingOption( + const QString &codec, + const QString &name, + const QVariant &value) +{ + /* + * Currently nothing can be set via this function. + * Bitrate is set via QAudioEncoderSettings::setBitrate(). + */ + Q_UNUSED(codec); + Q_UNUSED(name); + Q_UNUSED(value); +} +/* For QAudioEncoderControl end */ + +QStringList QXARecordSession::supportedContainers() +{ + return m_containers; +} + +QString QXARecordSession::containerMimeType() +{ + return m_containerMimeType; +} + +void QXARecordSession::setContainerMimeType(const QString &formatMimeType) +{ + if (m_containers.indexOf(formatMimeType.toLower()) >= 0 ) + m_containerMimeType = formatMimeType; + else { + emit error(QMediaRecorder::FormatError, tr("Invalid container")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid container\"))"); + } +} + +QString QXARecordSession::containerDescription(const QString &formatMimeType) +{ + int index = m_containers.indexOf(formatMimeType.toLower()); + if (index >= 0) { + return m_containersDesc.at(index); + } + else { + emit error(QMediaRecorder::FormatError, tr("Invalid container")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid container\"))"); + } + return QString(); +} + +void QXARecordSession::setRecorderState(QMediaRecorder::State state) +{ + if (state != m_state) { + m_state = state; + emit stateChanged(m_state); + SIGNAL_EMIT_TRACE1("emit stateChanged(m_state);"); + } +} + +void QXARecordSession::initCodecsList() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + m_codecs.clear(); + + const RArray& names = m_impl->getAudioEncoderNames(); + QString str; + + for (TInt index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + m_codecs.append(str); + } + QT_TRACE_FUNCTION_EXIT; +} + +void QXARecordSession::initContainersList() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_IF_m_impl_IS_NULL; + + m_containers.clear(); + m_containersDesc.clear(); + + const RArray& names = m_impl->getContainerNames(); + const RArray& descs = m_impl->getContainerDescs(); + QString str; + + for (TInt32 index = 0; index < names.Count(); index++) { + str = QString((QChar*)names[index].Ptr(), names[index].Length()); + m_containers.append(str); + str = QString((QChar*)descs[index].Ptr(), descs[index].Length()); + m_containersDesc.append(str); + } + QT_TRACE_FUNCTION_EXIT; +} + +bool QXARecordSession::setEncoderSettingsToImpl() +{ + QT_TRACE_FUNCTION_ENTRY; + + RETURN_s_IF_m_impl_IS_NULL(false); + + m_impl->resetEncoderAttributes(); + + QString tempStr = m_containerMimeType.toLower(); + TPtrC16 tempPtr(reinterpret_cast(tempStr.utf16())); + m_impl->setContainerType(tempPtr); + + /* Validate and set bitrate only if encoding mode is other than quality encoding */ + if (m_audioencodersettings.encodingMode() != QtMedia::ConstantQualityEncoding) { + if (m_audioencodersettings.bitRate() < 0 ) { + emit error(QMediaRecorder::FormatError, tr("Invalid bitrate")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid bitrate\"))"); + return false; + } + else { + m_impl->setBitRate(m_audioencodersettings.bitRate()); + } + } + + if (m_audioencodersettings.channelCount() == -1) { + m_impl->setOptimalChannelCount(); + } + else if (m_audioencodersettings.channelCount() <= 0) { + emit error(QMediaRecorder::FormatError, tr("Invalid channel count")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid channel count\"));"); + return false; + } + else { + m_impl->setChannels(m_audioencodersettings.channelCount()); + } + + tempStr = m_audioencodersettings.codec().toLower(); + if (m_codecs.indexOf(tempStr) >= 0) { + tempPtr.Set(reinterpret_cast(tempStr.utf16())); + /* We already did validation above, so function always returns true */ + m_impl->setCodec(tempPtr); + } + else { + emit error(QMediaRecorder::FormatError, tr("Invalid codec")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid codec\"));"); + return false; + } + + switch (m_audioencodersettings.encodingMode()) { + case QtMedia::ConstantQualityEncoding: { + switch (m_audioencodersettings.quality()) { + case QtMedia::VeryLowQuality: + m_impl->setVeryLowQuality(); + break; + case QtMedia::LowQuality: + m_impl->setLowQuality(); + break; + case QtMedia::NormalQuality: + m_impl->setNormalQuality(); + break; + case QtMedia::HighQuality: + m_impl->setHighQuality(); + break; + case QtMedia::VeryHighQuality: + m_impl->setVeryHighQuality(); + break; + default: + emit error(QMediaRecorder::FormatError, tr("Invalid encoding quality setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding quality setting\"));"); + return false; + }; /* end of switch (m_audioencodersettings.quality())*/ + } + break; + case QtMedia::ConstantBitRateEncoding: { + TInt32 status = m_impl->setCBRMode(); + if (status == KErrNotSupported) { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + else if (status != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Internal error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Internal error\"));"); + return false; + } + } + break; + case QtMedia::AverageBitRateEncoding: { + TInt32 status = m_impl->setVBRMode(); + if (status == KErrNotSupported) { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + else if (status != KErrNone) { + emit error(QMediaRecorder::ResourceError, tr("Internal error")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::ResourceError, tr(\"Internal error\"));"); + return false; + } + } + break; + case QtMedia::TwoPassEncoding: + // fall through + default: { + emit error(QMediaRecorder::FormatError, tr("Invalid encoding mode setting")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid encoding mode setting\"));"); + return false; + } + }; /* switch (m_audioencodersettings.encodingMode()) */ + + if (m_audioencodersettings.sampleRate() == -1) { + m_impl->setOptimalSampleRate(); + } + else if (m_audioencodersettings.sampleRate() <= 0) { + emit error(QMediaRecorder::FormatError, tr("Invalid sample rate")); + SIGNAL_EMIT_TRACE1("emit error(QMediaRecorder::FormatError, tr(\"Invalid sample rate\"));"); + return false; + } + else { + m_impl->setSampleRate(m_audioencodersettings.sampleRate()); + } + m_appliedaudioencodersettings = m_audioencodersettings; + QT_TRACE_FUNCTION_EXIT; + return true; +}