# examples/Multimedia/MmfExFormatPlugin/mmfrawformat.cpp

    00001 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
    00002 // All rights reserved.
    00003 // This component and the accompanying materials are made available
    00004 // under the terms of "Eclipse Public License v1.0"
    00005 // which accompanies this distribution, and is available
    00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
    00007 //
    00008 // Initial Contributors:
    00009 // Nokia Corporation - initial contribution.
    00010 //
    00011 // Contributors:
    00012 //
    00013 // Description:
    00014 //
    00015
    00016 // MMF framework headers
    00017 #include <mmffile.h>
    00018 #include <ecom.h>
    00019 #include <mmfformatimplementationuids.hrh>
    00020 #include <mmffourcc.h>
    00021
    00022 #include "mmfrawformat.h"
    00023 #include "UIDs.hrh"
    00024
    00025 const TUint KFormatDefaultFrameSize(0x1000); //Set default frame size to 4 K
    00026 const TUint KDefineIOBufferSize(0x0200); //easy to read clip buffer size
    00027 const TUint KOneSecondInMicroSeconds(1000000); //1 Second
    00028 const TUint KMono(1);
    00029 const TUint KStereo(2);
    00030 //this defines the valid sample rates for RAW
    00031 const TUint KRawSampleRates[] = { 8000, 11025, 22050, 44100 };
    00032
    00033
    00034 //
    00035 // CMMFRawFormatRead
    00036 //
    00037
    00038 // Factory function
    00039 CMMFFormatDecode* CMMFRawFormatRead::NewL(MDataSource* aSource)
    00040         {
    00041         if ((aSource->DataSourceType()==KUidMmfDescriptorSource)||
    00042                         (aSource->DataSourceType()==KUidMmfFileSource))
    00043                 {//currently only files and descriptor MDataSources are supported
    00044                 CMMFRawFormatRead* self = new(ELeave)CMMFRawFormatRead;
    00045                 CleanupStack::PushL(self);
    00046                 self->ConstructL(aSource);
    00047                 CleanupStack::Pop();
    00048                 return self;
    00049                 }
    00050         else return NULL;
    00051         }
    00052
    00053 // Destructor
    00054 CMMFRawFormatRead::~CMMFRawFormatRead()
    00055         {
    00056         delete iBuffer;
    00057         }
    00058
    00059 // Second-phase constructor
    00060 void CMMFRawFormatRead::ConstructL(MDataSource* aSource)
    00061         {
    00062         // tell clip we're using it
    00063         iClip = aSource;
    00064         User::LeaveIfError(iClip->SourceThreadLogon(*this));
    00065         iClip->SourcePrimeL();
    00066         iFrameSize = KFormatDefaultFrameSize;
    00067         iClipLength = (static_cast<CMMFClip*>(iClip))->Size();
    00068         }
    00069
    00070 // Implementing MDataSource
    00071
    00072 // Handle request to fill buffer with data from clip
    00073 void CMMFRawFormatRead::FillBufferL(CMMFBuffer* aBuffer, MDataSink* aConsumer, TMediaId aMediaId )
    00074         {
    00075         // check media id & pass onto the clip
    00076         if (aMediaId.iMediaType != KUidMediaTypeAudio) User::Leave(KErrNotSupported);
    00077         iDataPath = aConsumer;
    00078         //assumes first frame is frame 1
    00079         TUint position = ((aBuffer->FrameNumber()-1)*iFrameSize)+iStartPosition;
    00080         (static_cast<CMMFClip*>(iClip))->ReadBufferL(aBuffer, position, this);
    00081         // notified of when buffer is full by BufferFilledL
    00082         }
    00083
    00084 // creates the buffer for the source
    00085 // This overload supplies the sink buffer, as optimal source buffer size creation may depend on this
    00086 CMMFBuffer* CMMFRawFormatRead::CreateSourceBufferL(TMediaId aMediaId, CMMFBuffer& aSinkBuffer, TBool &aReference)
    00087         {
    00088         if (aMediaId.iMediaType == KUidMediaTypeAudio)
    00089                 {
    00090                 NegotiateSourceBufferL(aSinkBuffer); //sets frame size to match sink buffer
    00091                 return CreateSourceBufferL(aMediaId, aReference);
    00092                 }
    00093         else User::Leave(KErrNotSupported);
    00094         return NULL;
    00095         }
    00096
    00097 // creates the buffer for the source
    00098 CMMFBuffer* CMMFRawFormatRead::CreateSourceBufferL(TMediaId aMediaId, TBool &aReference)
    00099         {
    00100         if (aMediaId.iMediaType == KUidMediaTypeAudio)
    00101                 {
    00102                 // assume default frame size if haven't determined a better one
    00103                 if (!iFrameSize) iFrameSize = KFormatDefaultFrameSize;
    00104                 // sets aReference to false if a new CMMFBuffer is returned
    00105                 aReference = EFalse;
    00106                 return CreateSourceBufferOfSizeL(iFrameSize);
    00107                 }
    00108         else User::Leave(KErrNotSupported);
    00109         return NULL;
    00110         }
    00111
    00112 // Helper function to create and zero fill a buffer of specified size
    00113 CMMFDataBuffer* CMMFRawFormatRead::CreateSourceBufferOfSizeL(TUint aSize)
    00114         {
    00115         //needs to create source buffer
    00116         CMMFDataBuffer* buffer = CMMFDataBuffer::NewL(aSize);
    00117         buffer->Data().FillZ(aSize);
    00118         return buffer;
    00119         }
    00120
    00121 // Helper function to determine best source buffer size
    00122 void CMMFRawFormatRead::NegotiateSourceBufferL(CMMFBuffer& aSinkBuffer)
    00123         {
    00124         // if sink buffer has a fixed size use this to determine source buffer size
    00125         if (aSinkBuffer.Type() == KUidMmfDataBuffer)
    00126                 {
    00127                 // RAW is linear data, so can set target buffer to sink buffer size
    00128                 TUint sinkBufferLength = (static_cast<CMMFDataBuffer&>(aSinkBuffer)).Data().MaxLength();
    00129                 if (sinkBufferLength == 0) sinkBufferLength = KFormatDefaultFrameSize;
    00130                 iFrameSize = sinkBufferLength;
    00131                 CalculateFrameTimeInterval();
    00132                 }
    00133         else
    00134                 User::Leave(KErrNotSupported);
    00135         }
    00136
    00137 // returns the codec FourCC code for the mediaId
    00138 TFourCC CMMFRawFormatRead::SourceDataTypeCode(TMediaId aMediaId)
    00139         {
    00140         if (aMediaId.iMediaType == KUidMediaTypeAudio) return iFourCC;
    00141         else return TFourCC(); //defaults to 'NULL' fourCC
    00142         }
    00143
    00144 // sets the codec FourCC code for the mediaId
    00145 TInt CMMFRawFormatRead::SetSourceDataTypeCode(TFourCC aSinkFourCC, TMediaId aMediaId)
    00146         {
    00147         if (aMediaId.iMediaType != KUidMediaTypeAudio) return KErrNotSupported;
    00148         else iFourCC = aSinkFourCC;
    00149
    00150         if ((iFourCC == KMMFFourCCCodePCM16) ||
    00151                 (iFourCC == KMMFFourCCCodePCM16B) ||
    00152                 (iFourCC == KMMFFourCCCodePCMU16))
    00153                         iBitsPerSample = 16;
    00154         else if ((iFourCC == KMMFFourCCCodeIMAD) ||
    00155                 (iFourCC == KMMFFourCCCodeIMAS))
    00156                         iBitsPerSample = 4;
    00157         else
    00158                         iBitsPerSample = 8; //default to 8
    00159         return KErrNone;
    00160         }
    00161
    00162 // Initiate use of the interface
    00163 TInt CMMFRawFormatRead::SourceThreadLogon(MAsyncEventHandler& aEventHandler)
    00164         {//pass through to source clip
    00165         return(iClip->SourceThreadLogon(aEventHandler));
    00166         }
    00167
    00168 // Prepare clip
    00169 void CMMFRawFormatRead::SourcePrimeL()
    00170         {
    00171         iClip->SourcePrimeL();
    00172         CalculateFrameTimeInterval();
    00173         }
    00174
    00175 // Play clip
    00176 void CMMFRawFormatRead::SourcePlayL()
    00177         {
    00178         iClip->SourcePlayL();
    00179         }
    00180
    00181 // Pause clip
    00182 void CMMFRawFormatRead::SourcePauseL()
    00183         {
    00184         iClip->SourcePauseL(); //propagate state change down to clip
    00185         }
    00186
    00187 // Stop clip
    00188 void CMMFRawFormatRead::SourceStopL()
    00189         {
    00190         iClip->SourceStopL();
    00191         }
    00192
    00193 // End use of the interface
    00194 void CMMFRawFormatRead::SourceThreadLogoff()
    00195         {
    00196         iClip->SourceThreadLogoff();
    00197         }
    00198
    00199 // from MDataSink
    00200
    00201 // called by MDataSource to pass back full buffer to the sink
    00202 void CMMFRawFormatRead::BufferFilledL(CMMFBuffer* aBuffer)
    00203         {
    00204         //set position
    00205         TTimeIntervalMicroSeconds position = //assumes frame numbers begin at frame 1
    00206                 TTimeIntervalMicroSeconds(TInt64(aBuffer->FrameNumber()-1)*iFrameTimeInterval.Int64());
    00207         aBuffer->SetTimeToPlay(position);
    00208         iDataPath->BufferFilledL(aBuffer);
    00209         }
    00210
    00211
    00212 // from CMMFFormatDecode
    00213
    00214 // returns number of streams
    00215 TUint CMMFRawFormatRead::Streams(TUid aMediaType) const
    00216         {
    00217         //need to check aMediaType for audio
    00218         if (aMediaType == KUidMediaTypeAudio) return 1; //raw files can only have 1 audio stream
    00219         else return 0;
    00220         }
    00221
    00222 // returns the time interval for one frame
    00223 TTimeIntervalMicroSeconds CMMFRawFormatRead::FrameTimeInterval(TMediaId aMediaId) const
    00224         {
    00225         if (aMediaId.iMediaType == KUidMediaTypeAudio) return iFrameTimeInterval;
    00226         else return TTimeIntervalMicroSeconds(0);
    00227         }
    00228
    00229 // returns the duration of the source clip
    00230 TTimeIntervalMicroSeconds CMMFRawFormatRead::Duration(TMediaId aMediaId) const
    00231         {
    00232         if ((aMediaId.iMediaType == KUidMediaTypeAudio) &&
    00233                 (iClipLength) && (iSampleRate) && (iBitsPerSample) && (iChannels))
    00234                 {//we have enough values to calculate the duration
    00235                 TInt64 clipLength(iClipLength);
    00236                 clipLength*=KOneSecondInMicroSeconds;
    00237                 TTimeIntervalMicroSeconds duration = TTimeIntervalMicroSeconds(clipLength/iSampleRate);
    00238                 duration = TTimeIntervalMicroSeconds(duration.Int64()/(iBitsPerSample*iChannels));
    00239                 duration = TTimeIntervalMicroSeconds(duration.Int64()*8);
    00240                 return duration;
    00241                 }
    00242         else return TTimeIntervalMicroSeconds(0);
    00243         }
    00244
    00245 // helper function: calculates time between frames
    00246 void CMMFRawFormatRead::CalculateFrameTimeInterval()
    00247         {
    00248         if ((iFrameSize) && (iSampleRate) && (iBitsPerSample) && (iChannels))
    00249                 {
    00250                 iFrameTimeInterval = TTimeIntervalMicroSeconds((iFrameSize*KOneSecondInMicroSeconds)/iSampleRate);
    00251                 iFrameTimeInterval =
    00252                         TTimeIntervalMicroSeconds(iFrameTimeInterval.Int64()/(iBitsPerSample*iChannels));
    00253                 iFrameTimeInterval = TTimeIntervalMicroSeconds(iFrameTimeInterval.Int64()*8);
    00254                 }
    00255         }
    00256
    00257 // called by sink to suggest a source buffer size
    00258 void CMMFRawFormatRead::SuggestSourceBufferSize(TUint aSuggestedBufferSize)
    00259         {
    00260         iFrameSize = aSuggestedBufferSize; //set source format frame size to buffer size suggested by sink
    00261         CalculateFrameTimeInterval();
    00262         }
    00263
    00264 // set the number of channels
    00265 TInt CMMFRawFormatRead::SetNumChannels(TUint aChannels)
    00266         {
    00267         TInt error = KErrNone;
    00268         if ((aChannels ==  KMono)||(aChannels == KStereo)) iChannels = aChannels;
    00269         else error = KErrNotSupported; //only alow one or two channels
    00270         return error;
    00271         }
    00272
    00273 // set the sample rate
    00274 TInt CMMFRawFormatRead::SetSampleRate(TUint aSampleRate)
    00275         {
    00276         TInt status = KErrNotSupported;
    00277         //we'll iterate through the valid sample table
    00278         TInt i = sizeof(KRawSampleRates) / sizeof(TUint);
    00279
    00280         while ((i--) && (status != KErrNone))
    00281                 {
    00282                 if (aSampleRate == KRawSampleRates[i])
    00283                         {
    00284                         iSampleRate = aSampleRate;
    00285                         status = KErrNone;
    00286                         }
    00287                 }
    00288         return status;
    00289         }
    00290
    00291 // helper function to read from clip
    00292 void CMMFRawFormatRead::DoReadL(TInt aReadPosition)
    00293         {
    00294         STATIC_CAST(CMMFClip*,iClip)->ReadBufferL(iBuffer,aReadPosition);
    00295         }
    00296
    00297 // get the supported sample rates
    00298 void CMMFRawFormatRead::GetSupportedSampleRatesL(RArray<TUint>& aSampleRates)
    00299         {
    00300         aSampleRates.Reset();
    00301
    00302         // Iterate through the valid sample table and append each value to aSampleRates
    00303         TInt i = sizeof(KRawSampleRates) / sizeof(TUint);
    00304
    00305         while (i--)
    00306                 {
    00307                 User::LeaveIfError(aSampleRates.Append(KRawSampleRates[i]));
    00308                 }
    00309         }
    00310
    00311 // get the supported channel number options
    00312 void CMMFRawFormatRead::GetSupportedNumChannelsL(RArray<TUint>& aNumChannels)
    00313         {
    00314         aNumChannels.Reset();
    00315         User::LeaveIfError(aNumChannels.Append(KMono));
    00316         User::LeaveIfError(aNumChannels.Append(KStereo));
    00317         }
    00318
    00319 // get the supported codecs
    00320 void CMMFRawFormatRead::GetSupportedDataTypesL(TMediaId aMediaId, RArray<TFourCC>& aDataTypes)
    00321         {
    00322         if (aMediaId.iMediaType != KUidMediaTypeAudio)
    00323                 User::Leave(KErrNotSupported);
    00324         aDataTypes.Reset();
    00325         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodePCM16));
    00326         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodePCM16B));
    00327         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodePCMU16));
    00328         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodeIMAD));
    00329         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodeIMAS));
    00330         }
    00331
    00332
    00333 //
    00334 // CMMFRawFormatWrite
    00335 //
    00336
    00337 // Factory function
    00338 CMMFFormatEncode* CMMFRawFormatWrite::NewL(MDataSink* aSink)
    00339         {
    00340         if ((aSink->DataSinkType()==KUidMmfDescriptorSink)||
    00341                         (aSink->DataSinkType()==KUidMmfFileSink))
    00342                 {//currently only files and descriptor MDataSources are supported
    00343                 CMMFRawFormatWrite* self = new(ELeave)CMMFRawFormatWrite;
    00344                 CleanupStack::PushL(self);
    00345                 self->ConstructL(aSink);
    00346                 CleanupStack::Pop();
    00347                 return STATIC_CAST(CMMFFormatEncode*, self);
    00348                 }
    00349         else return NULL;
    00350         }
    00351
    00352 // destructor
    00353 CMMFRawFormatWrite::~CMMFRawFormatWrite()
    00354         {
    00355         delete iBuffer;
    00356         delete iConvertBuffer;
    00357         delete iChannelAndSampleRateConverterFactory;
    00358         }
    00359
    00360 // second-phase construction
    00361 void CMMFRawFormatWrite::ConstructL(MDataSink* aSink)
    00362         {
    00363         iClip = aSink;
    00364         //first need to check if sink clip already exists to get settings.
    00365         User::LeaveIfError(iClip->SinkThreadLogon(*this));
    00366         iClip->SinkPrimeL();
    00367         iBuffer = CreateSinkBufferOfSizeL(KDefineIOBufferSize); //512 easiest file size to read
    00368         DoReadL(0);//read from beginning of clip
    00369         if (iBuffer->Data().Size()> 0)
    00370                 {
    00371                 iClipAlreadyExists = ETrue;
    00372                 //There is no header, so data size is the same as the clip size in this case.
    00373                 iDataSize = iClipLength = STATIC_CAST(CMMFClip*,iClip)->Size();
    00374                 }
    00375         iFrameSize = KFormatDefaultFrameSize;
    00376         }
    00377
    00378 // from MDataSink
    00379
    00380 // sink thread attaches
    00381 TInt CMMFRawFormatWrite::SinkThreadLogon(MAsyncEventHandler& aEventHandler)
    00382         {//pass through to sink clip
    00383         return(iClip->SinkThreadLogon(aEventHandler));
    00384         }
    00385
    00386 // helper function: calculates time between frames
    00387 void CMMFRawFormatWrite::CalculateFrameTimeInterval()
    00388         {
    00389         if ((iFrameSize) && (iSampleRate) && (iBitsPerSample) && (iChannels))
    00390                 {
    00391                 iFrameTimeInterval = TTimeIntervalMicroSeconds((iFrameSize*KOneSecondInMicroSeconds)/iSampleRate);
    00392                 iFrameTimeInterval =
    00393                         TTimeIntervalMicroSeconds((iFrameTimeInterval.Int64())/(iBitsPerSample*iChannels));
    00394                 iFrameTimeInterval = TTimeIntervalMicroSeconds(iFrameTimeInterval.Int64()*8);
    00395                 }
    00396         }
    00397
    00398 // called if sink setup depends on source
    00399 void CMMFRawFormatWrite::Negotiate(MDataSource& aSource)
    00400         {
    00401         if (aSource.DataSourceType() == KUidMmfAudioInput)
    00402                 {
    00403                 // could query the audio capabilities from DevSound for the settings below
    00404                 iSourceSampleRate = 8000; // assume 8KHz for now
    00405                 iSourceChannels = 1; //assume mono
    00406                 iSourceFourCC.Set(KMMFFourCCCodePCM16); //16 bit PCM
    00407                 }
    00408         else if (aSource.DataSourceType() == KUidMmfFormatDecode)
    00409                 {//source is a clip so for now set sink settings to match source
    00410                 iSourceSampleRate = ((CMMFFormatDecode&)aSource).SampleRate();
    00411                 iSourceChannels = ((CMMFFormatDecode&)aSource).NumChannels();
    00412                 iSourceFourCC.Set(aSource.SourceDataTypeCode(TMediaId(KUidMediaTypeAudio)));
    00413                 iSourceWillSampleConvert = STATIC_CAST(CMMFFormatDecode&, aSource).SourceSampleConvert();
    00414                 ((CMMFFormatDecode&)aSource).SuggestSourceBufferSize(iFrameSize); //for now suggest format src takes same buf size as sink??
    00415                 //make the start position the end of the clip
    00416                 }
    00417         else return;
    00418         //set default sink parameters to be the same as the source
    00419         if (iClipAlreadyExists) iStartPosition = iClipLength;
    00420         if (!iSampleRate) iSampleRate = iSourceSampleRate; //might have already been set by custom command
    00421         if (!iChannels) iChannels = iSourceChannels;
    00422         if (!iBitsPerSample)
    00423                 {
    00424                 iFourCC.Set(iSourceFourCC);
    00425                 if ((iFourCC == KMMFFourCCCodePCM16) ||
    00426                         (iFourCC == KMMFFourCCCodePCM16B) ||
    00427                         (iFourCC == KMMFFourCCCodePCMU16))
    00428                                 iBitsPerSample = 16;
    00429                 else if ((iFourCC == KMMFFourCCCodeIMAD) ||
    00430                         (iFourCC == KMMFFourCCCodeIMAS))
    00431                                 iBitsPerSample = 4;
    00432                 else
    00433                                 iBitsPerSample = 8; //default to 8
    00434                 }
    00435         CalculateFrameTimeInterval();
    00436         }
    00437
    00438 // Prime the sink to be accessed
    00439 void CMMFRawFormatWrite::SinkPrimeL()
    00440         {
    00441         iClip->SinkPrimeL(); //propagate state change down to clip
    00442         CalculateFrameTimeInterval();
    00443         }
    00444
    00445 // Play the sink
    00446 void CMMFRawFormatWrite::SinkPlayL()
    00447         {
    00448         iClip->SinkPlayL(); //propagate state change down to clip
    00449         if ((iChannels != iSourceChannels) || (iSampleRate != iSourceSampleRate) && (!iSourceWillSampleConvert))
    00450                 {//the source channels & sample rate don't match the formats - therefore need to do a conversion
    00451                 //currently only pcm16 is supported so return with an error if format not pcm16
    00452                 if (iFourCC != KMMFFourCCCodePCM16) User::Leave(KErrNotSupported);
    00453                 iChannelAndSampleRateConverterFactory
    00454                         = new(ELeave)CMMFChannelAndSampleRateConverterFactory;
    00455                 iChannelAndSampleRateConverter =
    00456                         iChannelAndSampleRateConverterFactory->CreateConverterL( iSourceSampleRate, iSourceChannels,
    00457                                                                                                                                         iSampleRate, iChannels);
    00458                 //need to create an intermediate buffer in which to place the converted data
    00459                 TUint convertedBufferFrameSize = (iFrameSize*iChannels)/iSourceChannels;
    00460                 iConvertBuffer = CreateSinkBufferOfSizeL(convertedBufferFrameSize);
    00461                 }
    00462         iFileHasChanged = ETrue; //file will change if we start playing to it
    00463         }
    00464
    00465 // Pause the sink
    00466 void CMMFRawFormatWrite::SinkPauseL()
    00467         {
    00468         iClip->SinkPauseL(); //propagate state change down to clip
    00469         }
    00470
    00471 // Stop the sink
    00472 void CMMFRawFormatWrite::SinkStopL()
    00473         {
    00474         iClip->SinkStopL(); //propagate state change down to clip
    00475         }
    00476
    00477 // Detach from the sink
    00478 void CMMFRawFormatWrite::SinkThreadLogoff()
    00479         {
    00480         iClip->SinkThreadLogoff(); //propagate down to clip
    00481         }
    00482
    00483 // Called by the CMMFDataPath to add a buffer to a clip
    00484 void CMMFRawFormatWrite::EmptyBufferL(CMMFBuffer* aBuffer, MDataSource* aSupplier, TMediaId aMediaId)
    00485         {
    00486         //since raw always contains linear audio the sink buffer size can set the source buffer size
    00487
    00488         //check media id &pass onto clip
    00489         if (aMediaId.iMediaType!=KUidMediaTypeAudio) User::Leave(KErrNotSupported);
    00490         iDataPath = aSupplier;
    00491
    00492         // Check we haven't exceeded any set maximum on our clip length
    00493         if (iMaximumClipSize > 0)
    00494                 {
    00495                 // Find the current clip size
    00496                 TInt currentClipLength = STATIC_CAST(CMMFClip*, iClip)->Size();
    00497                 TInt bufferSize = aBuffer->BufferSize();
    00498                 if ((currentClipLength + bufferSize) >= iMaximumClipSize)
    00499                         User::Leave(KErrEof);
    00500                 }
    00501
    00502         //assumes first frame is frame 1
    00503         iBufferToEmpty = aBuffer; //save this so it can be returned to datapath
    00504         TInt position = ((aBuffer->FrameNumber()-1)*iFrameSize)+iStartPosition;
    00505         if (position < (TInt)iStartPosition) position = iStartPosition; //can't write before start of header
    00506         if ((iChannelAndSampleRateConverter) && (!iSourceWillSampleConvert))
    00507                 {//need to perform channel & sample rate conversion before writing to clip
    00508                 iFrameSize = iChannelAndSampleRateConverter->Convert(*(CMMFDataBuffer*)aBuffer,*iConvertBuffer);
    00509                 STATIC_CAST(CMMFClip*,iClip)->WriteBufferL(iConvertBuffer, position, this);
    00510                 }
    00511         else
    00512                 {//no need to convert the data
    00513                 STATIC_CAST(CMMFClip*,iClip)->WriteBufferL(aBuffer, position, this);
    00514                 }
    00515         iPos = position; //save current write position
    00516         }
    00517
    00518 // helper function to create buffer of specficed size
    00519 CMMFDataBuffer* CMMFRawFormatWrite::CreateSinkBufferOfSizeL(TUint aSize)
    00520         {
    00521         //needs to create source buffer
    00522         CMMFDataBuffer* buffer = CMMFDataBuffer::NewL(aSize);
    00523         buffer->Data().FillZ(aSize);
    00524         iBufferCreated = ETrue;
    00525         return buffer;
    00526         }
    00527
    00528 // create buffer to receive data
    00529 CMMFBuffer* CMMFRawFormatWrite::CreateSinkBufferL(TMediaId aMediaId, TBool &aReference)
    00530         {
    00531         if (aMediaId.iMediaType == KUidMediaTypeAudio)
    00532                 {
    00533                 if (!iFrameSize) iFrameSize = KFormatDefaultFrameSize;
    00534                 aReference = EFalse;
    00535                 return CreateSinkBufferOfSizeL(iFrameSize);
    00536                 }
    00537         else User::Leave(KErrNotSupported);
    00538         return NULL;
    00539         }
    00540
    00541 // gets the codec type
    00542 TFourCC CMMFRawFormatWrite::SinkDataTypeCode(TMediaId aMediaId)
    00543         {
    00544         if (aMediaId.iMediaType == KUidMediaTypeAudio) return iFourCC;
    00545         else return TFourCC(); //defaults to 'NULL' fourCC
    00546         }
    00547
    00548 // sets the codec type
    00549 TInt CMMFRawFormatWrite::SetSinkDataTypeCode(TFourCC aSinkFourCC, TMediaId aMediaId)
    00550         {
    00551         if (aMediaId.iMediaType != KUidMediaTypeAudio) return KErrNotSupported;
    00552         else iFourCC = aSinkFourCC;
    00553
    00554         if ((iFourCC == KMMFFourCCCodePCM16) ||
    00555                 (iFourCC == KMMFFourCCCodePCM16B) ||
    00556                 (iFourCC == KMMFFourCCCodePCMU16))
    00557                         iBitsPerSample = 16;
    00558         else if ((iFourCC == KMMFFourCCCodeIMAD) ||
    00559                 (iFourCC == KMMFFourCCCodeIMAS))
    00560                         iBitsPerSample = 4;
    00561         else
    00562                         iBitsPerSample = 8; //default to 8
    00563
    00564         return KErrNone;
    00565         }
    00566
    00567 // helper function to read data from clip
    00568 void CMMFRawFormatWrite::DoReadL(TInt aReadPosition)
    00569         {
    00570         STATIC_CAST(CMMFClip*,iClip)->ReadBufferL(iBuffer,aReadPosition);
    00571         }
    00572
    00573 // helper function to write data to clip
    00574 void CMMFRawFormatWrite::DoWriteL(TInt aWritePosition)
    00575         {
    00576         STATIC_CAST(CMMFClip*,iClip)->WriteBufferL(iBuffer,aWritePosition);
    00577         }
    00578
    00579
    00580 // from MDataSource
    00581
    00582 // called by MDataSink to pass back emptied buffer to the source
    00583 void CMMFRawFormatWrite::BufferEmptiedL(CMMFBuffer* aBuffer)
    00584         {
    00585         iDataSize+=aBuffer->BufferSize(); //total bytes written
    00586         iPos += aBuffer->BufferSize(); //total bytes written so far - iPos is not always = iDataSize due to repositions
    00587         if (iMaxPos < iPos) iMaxPos = iPos; //need iMaxPos incase we write data then repos to an earlier pos in the clip
    00588         if (iBufferToEmpty != aBuffer) iDataPath->BufferEmptiedL(iBufferToEmpty); //need to return same buffer
    00589         else iDataPath->BufferEmptiedL(aBuffer);
    00590         }
    00591
    00592
    00593 // from CMMFFormatEncode
    00594
    00595 // set the number of channels
    00596 TInt CMMFRawFormatWrite::SetNumChannels(TUint aChannels)
    00597         {
    00598         TInt error = KErrNone;
    00599         if ((aChannels ==  KMono)||(aChannels == KStereo)) iChannels = aChannels;
    00600         else error = KErrNotSupported; //only alow one or two channels
    00601         return error;
    00602         }
    00603
    00604 // set the sample rate
    00605 TInt CMMFRawFormatWrite::SetSampleRate(TUint aSampleRate)
    00606         {
    00607         TInt status = KErrNotSupported;
    00608         //we'll iterate through the valid sample table
    00609         TInt i = sizeof(KRawSampleRates) / sizeof(TUint);
    00610
    00611         while ((i--) && (status != KErrNone))
    00612                 {
    00613                 if (aSampleRate == KRawSampleRates[i])
    00614                         {
    00615                         iSampleRate = aSampleRate;
    00616                         status = KErrNone;
    00617                         }
    00618                 }
    00619         return status;
    00620         }
    00621
    00622 // get the frame interval
    00623 TTimeIntervalMicroSeconds CMMFRawFormatWrite::FrameTimeInterval(TMediaId aMediaId) const
    00624         {
    00625         if (aMediaId.iMediaType == KUidMediaTypeAudio) return iFrameTimeInterval;
    00626         else return TTimeIntervalMicroSeconds(0);
    00627         }
    00628
    00629 // returns the duration of the source clip
    00630 TTimeIntervalMicroSeconds CMMFRawFormatWrite::Duration(TMediaId aMediaId) const
    00631         {
    00632         if ((aMediaId.iMediaType == KUidMediaTypeAudio)
    00633                 && (iDataSize) && (iSampleRate) && (iBitsPerSample) && (iChannels))
    00634                 {
    00635                 TInt64 clipLength(iDataSize);
    00636                 clipLength*=KOneSecondInMicroSeconds;
    00637                 TTimeIntervalMicroSeconds duration = TTimeIntervalMicroSeconds(clipLength/iSampleRate);
    00638                 duration =
    00639                         TTimeIntervalMicroSeconds(duration.Int64()/(iBitsPerSample*iChannels));
    00640                 duration = TTimeIntervalMicroSeconds(duration.Int64()*8);
    00641                 return duration;
    00642                 }
    00643         else return TTimeIntervalMicroSeconds(0);
    00644         }
    00645
    00646 // Calculate and return the number of bytes used for on second of audio.
    00647 TInt64 CMMFRawFormatWrite::BytesPerSecond()
    00648         {
    00649         TInt64 bitsPerSecond = iSampleRate * iBitsPerSample * iChannels ;
    00650         TInt64 bytesPerSecond = bitsPerSecond/8;
    00651         return bytesPerSecond ;
    00652         }
    00653
    00654 // Shortens the clip from the position specified to the end specified.
    00655 void CMMFRawFormatWrite::CropL(TTimeIntervalMicroSeconds aPosition, TBool aToEnd )
    00656         {
    00657         // Does clip have any size to crop
    00658         if (!(STATIC_CAST(CMMFClip*,iClip)->Size())) User::Leave(KErrNotFound); //no clip to crop or clip is 0 bytes.
    00659
    00660
    00661         // Is aPosition between the start and the end?
    00662         if ( ( aPosition < TTimeIntervalMicroSeconds(0) ) || ( aPosition >= Duration( KUidMediaTypeAudio) ) )
    00663                 User::Leave( KErrArgument ) ;
    00664
    00665         // Convert aPostion to cropPosition in bytes
    00666
    00667         TInt64 cropPosition64 =
    00668                 TInt64( ( aPosition.Int64() * iSampleRate * (iBitsPerSample/8) * iChannels ) /KOneSecondInMicroSeconds);
    00669         TUint cropPosition = I64INT(cropPosition64);
    00670
    00671         // Does cropPosition need adjustment to retain integrity?  (assume not)
    00672
    00673         TUint dataSize ;  // This will be the size of the data left after cropping.
    00674
    00675         if ( !aToEnd )
    00676                 {
    00677                 // Shift the data physically
    00678                 // move the data in blocks
    00679                 // Create a CMMFDataBuffer and use CMMFClip to shift the data
    00680                 dataSize = iMaxPos - cropPosition ;
    00681                 if (( dataSize > 0 ) && (aPosition != TTimeIntervalMicroSeconds(0)))
    00682                         {
    00683                         TUint bufSize = ( dataSize < KDefineIOBufferSize ? dataSize : KDefineIOBufferSize ) ; //max bufSize 512
    00684                         CMMFDataBuffer* buffer = CMMFDataBuffer::NewL(bufSize) ;
    00685                         CleanupStack::PushL( buffer ) ;
    00686
    00687                         TUint rPos = cropPosition ; // read position
    00688                         TUint wPos = 0;
    00689                         TInt dataToShift = ETrue ;
    00690                         while ( dataToShift )
    00691                                 {
    00692                                 STATIC_CAST( CMMFClip*, iClip )->ReadBufferL( buffer, rPos ) ;  // synchronous calls
    00693                                 STATIC_CAST( CMMFClip*, iClip )->WriteBufferL( buffer, wPos ) ;
    00694                                 if ( rPos > iMaxPos )
    00695                                         dataToShift = EFalse ;  // past the end:  Done
    00696                                 else
    00697                                         { // shift the pointers
    00698                                         rPos += bufSize ;
    00699                                         wPos += bufSize ;
    00700                                         }
    00701                                 }// while data to shift
    00702                         CleanupStack::PopAndDestroy( ) ; // buffer
    00703                         }// if data to shift
    00704                 }// crop to start
    00705         else // crop to end
    00706                 dataSize = cropPosition ;
    00707
    00708         iDataSize = dataSize ;
    00709         iMaxPos = dataSize ;
    00710
    00711         // Do the physical chop
    00712         if ( iClip->DataSinkType() == KUidMmfFileSink )
    00713                 {
    00714                 STATIC_CAST( CMMFFile*, iClip )->FileL().SetSize( iMaxPos ) ;
    00715                 iClipLength = iMaxPos;
    00716                 }
    00717         }
    00718
    00719 // get the supported sample rates
    00720 void CMMFRawFormatWrite::GetSupportedSampleRatesL(RArray<TUint>& aSampleRates)
    00721         {
    00722         aSampleRates.Reset();
    00723
    00724         // Iterate through the valid sample table and append each value to aSampleRates
    00725         TInt i = sizeof(KRawSampleRates) / sizeof(TUint);
    00726
    00727         while (i--)
    00728                 {
    00729                 User::LeaveIfError(aSampleRates.Append(KRawSampleRates[i]));
    00730                 }
    00731         }
    00732
    00733 // get the supported channel number options
    00734 void CMMFRawFormatWrite::GetSupportedNumChannelsL(RArray<TUint>& aNumChannels)
    00735         {
    00736         aNumChannels.Reset();
    00737         User::LeaveIfError(aNumChannels.Append(KMono));
    00738         User::LeaveIfError(aNumChannels.Append(KStereo));
    00739         }
    00740
    00741 // set maximum clip size
    00742 void CMMFRawFormatWrite::SetMaximumClipSize(TInt aBytes)
    00743         {
    00744         iMaximumClipSize = aBytes;
    00745         }
    00746
    00747 // get the supported codecs
    00748 void CMMFRawFormatWrite::GetSupportedDataTypesL(TMediaId aMediaId, RArray<TFourCC>& aDataTypes)
    00749         {
    00750         if (aMediaId.iMediaType != KUidMediaTypeAudio)
    00751                 User::Leave(KErrNotSupported);
    00752         aDataTypes.Reset();
    00753         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodePCM16));
    00754         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodePCM16B));
    00755         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodePCMU16));
    00756         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodeIMAD));
    00757         User::LeaveIfError(aDataTypes.Append(KMMFFourCCCodeIMAS));
    00758         }
    00759
    00760
    00761 // __________________________________________________________________________
    00762 // Exported proxy for instantiation method resolution
    00763 // Define the interface UIDs
    00764
    00765 const TImplementationProxy ImplementationTable[] =
    00766         {
    00767                 IMPLEMENTATION_PROXY_ENTRY(KRawDecoder, CMMFRawFormatRead::NewL),
    00768                 IMPLEMENTATION_PROXY_ENTRY(KRawEncoder, CMMFRawFormatWrite::NewL)
    00769         };
    00770
    00771 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
    00772         {
    00773         aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
    00774
    00775         return ImplementationTable;
    00776         }