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 }
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.