sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "A2dpCodecUtilities.h" sl@0: sl@0: sl@0: /** sl@0: A2dp codec utilities Panics sl@0: **/ sl@0: enum TA2dpCodecUtilitiesPanic sl@0: { sl@0: EA2dpCodecUtilNoRemoteCodecConfig, //0 sl@0: EA2dpCodecUtilUnexpectedDataType, //1 sl@0: EA2dpCodecUtilUnsupportedDataType, //2 sl@0: EA2dpCodecUtilUnexpectedConfiguration, //3 sl@0: EA2dpCodecUtilDataMemberNotSet //4 sl@0: }; sl@0: sl@0: sl@0: static void Panic(TA2dpCodecUtilitiesPanic aPanic) sl@0: // Panic client sl@0: { sl@0: _LIT(KA2dpCodecUtilitiesPanicName, "A2DP Codec Util Panic"); sl@0: User::Panic(KA2dpCodecUtilitiesPanicName, aPanic); sl@0: } sl@0: sl@0: sl@0: TInt TA2dpCodecCapabilityParser::GetSupportedSBCSampleRates(const TSBCCodecCapabilities& aCodecCaps, RArray& aSupportedDiscreteRates) sl@0: { sl@0: TInt err = KErrNone; sl@0: TSBCSamplingFrequencyBitmask samplingRatesBitMask = aCodecCaps.SamplingFrequencies(); sl@0: if (samplingRatesBitMask & E16kHz) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(16000); sl@0: } sl@0: if (!err && (samplingRatesBitMask & E32kHz)) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(32000); sl@0: } sl@0: if (!err && (samplingRatesBitMask & E44100Hz)) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(44100); sl@0: } sl@0: if (!err && (samplingRatesBitMask & E48kHz)) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(48000); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: TInt TA2dpCodecCapabilityParser::GetSupportedMPEG12SampleRates(const TNonSBCCodecCapabilities& aCodecCaps, RArray& aSupportedDiscreteRates) sl@0: { sl@0: TInt err = KErrNone; sl@0: sl@0: TPtrC8 codecCapsData(aCodecCaps.CodecData()); sl@0: sl@0: TMPEG12SamplingFrequencyBitmask samplingRatesBitMask = codecCapsData[1] & KA2dpMPEG12SamplingFrequencyMask; sl@0: sl@0: if (samplingRatesBitMask & EMPEG12_16kHz) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(16000); sl@0: } sl@0: if (!err && samplingRatesBitMask & EMPEG12_22050Hz) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(22050); sl@0: } sl@0: if (!err && samplingRatesBitMask & EMPEG12_24kHz) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(24000); sl@0: } sl@0: if (!err && samplingRatesBitMask & EMPEG12_32kHz) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(32000); sl@0: } sl@0: if (!err && samplingRatesBitMask & EMPEG12_44100Hz) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(44100); sl@0: } sl@0: if (!err && samplingRatesBitMask & EMPEG12_48kHz) sl@0: { sl@0: err = aSupportedDiscreteRates.Append(48000); sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: TInt TA2dpCodecCapabilityParser::GetSupportedSampleRates(const TAvdtpMediaCodecCapabilities& aCodecCaps, RArray& aSupportedDiscreteRates) sl@0: { sl@0: TInt err = KErrNotSupported; sl@0: switch(aCodecCaps.MediaCodecType()) sl@0: { sl@0: case EAudioCodecSBC: sl@0: err = GetSupportedSBCSampleRates(static_cast(aCodecCaps), aSupportedDiscreteRates); sl@0: break; sl@0: case EAudioCodecMPEG12Audio: sl@0: err = GetSupportedMPEG12SampleRates(static_cast(aCodecCaps), aSupportedDiscreteRates); sl@0: break; sl@0: case EAudioCodecMPEG24AAC: sl@0: break; sl@0: case EAudioCodecATRAC: sl@0: break; sl@0: default: sl@0: Panic(EA2dpCodecUtilUnexpectedDataType); sl@0: break; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: TInt TA2dpCodecCapabilityParser::GetSupportedSBCChannels(const TSBCCodecCapabilities& aCodecCaps, RArray& aSupportedChannels, TMMFStereoSupport& aStereoSupport) sl@0: { sl@0: TInt err = KErrNotSupported; sl@0: sl@0: TSBCChannelModeBitmask channelModesBitMask = aCodecCaps.ChannelModes(); sl@0: sl@0: err = GetSupportedChannelsCommonCode(channelModesBitMask, aSupportedChannels, aStereoSupport); sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: TInt TA2dpCodecCapabilityParser::GetSupportedMPEG12Channels(const TNonSBCCodecCapabilities& aCodecCaps, RArray& aSupportedChannels, TMMFStereoSupport& aStereoSupport) sl@0: { sl@0: TInt err = KErrNotSupported; sl@0: sl@0: TPtrC8 codecCapsData(aCodecCaps.CodecData()); sl@0: TSBCChannelModeBitmask channelModesBitMask = codecCapsData[0] & KA2dpMPEG12AudioChannelModeMask; sl@0: sl@0: err = GetSupportedChannelsCommonCode(channelModesBitMask, aSupportedChannels, aStereoSupport); sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: MPEG12 uses the same channel mode bit mask as SBC so we'll factor out the common code sl@0: and reuse the TSBCChannelModeBitmask for mp3 as well sl@0: */ sl@0: TInt TA2dpCodecCapabilityParser::GetSupportedChannelsCommonCode(TSBCChannelModeBitmask aChannelModesBitMask, RArray& aSupportedChannels, TMMFStereoSupport& aStereoSupport) sl@0: { sl@0: TInt err = KErrNotSupported; sl@0: sl@0: if (aChannelModesBitMask & EMono) sl@0: { sl@0: err = aSupportedChannels.Append(EMMFMono); sl@0: } sl@0: if (!err) sl@0: { sl@0: if ((aChannelModesBitMask & EStereo) || (aChannelModesBitMask & EJointStereo)) sl@0: { sl@0: err = aSupportedChannels.Append(EMMFStereo); sl@0: aStereoSupport = EMMFInterleavedOnly; sl@0: } sl@0: } sl@0: if (!err && (aChannelModesBitMask & EJointStereo)) sl@0: { sl@0: //we have to cast as the TMMFStereoSupport is an enumeration sl@0: //but is really should be a bitmap sl@0: //but don't want to change it in order to preserve BC sl@0: TUint aStereoSupportInt = static_cast(aStereoSupport); sl@0: aStereoSupportInt |= static_cast(EMMFJoint); sl@0: aStereoSupport = static_cast(aStereoSupportInt); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: TInt TA2dpCodecCapabilityParser::GetSupportedChannels(const TAvdtpMediaCodecCapabilities& aCodecCaps, RArray& aSupportedChannels, TMMFStereoSupport& aStereoSupport) sl@0: { sl@0: TInt err = KErrNotSupported; sl@0: switch(aCodecCaps.MediaCodecType()) sl@0: { sl@0: case EAudioCodecSBC: sl@0: err = GetSupportedSBCChannels(static_cast(aCodecCaps), aSupportedChannels, aStereoSupport); sl@0: break; sl@0: case EAudioCodecMPEG12Audio: sl@0: err = GetSupportedMPEG12Channels(static_cast(aCodecCaps), aSupportedChannels, aStereoSupport); sl@0: break; sl@0: case EAudioCodecMPEG24AAC: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: case EAudioCodecATRAC: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: default: sl@0: Panic(EA2dpCodecUtilUnexpectedDataType); sl@0: break; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: static sl@0: */ sl@0: TUint8 TRTPa2dpCodecSpecificUtils::PayloadType(const TFourCC& aCodecDataType) sl@0: { sl@0: TUint8 payloadType = 0; sl@0: switch(const_cast(aCodecDataType).FourCC()) sl@0: { sl@0: case KMMFFourCCCodeSBC: sl@0: payloadType = KSbcRTPPayloadType; sl@0: break; sl@0: case KMMFFourCCCodeMP3: sl@0: payloadType = KMPEG12RTPAudioPayloadType; sl@0: break; sl@0: case KMMFFourCCCodeAAC: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: case KMMFFourCCCodeATRAC3: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: default: sl@0: Panic(EA2dpCodecUtilUnexpectedDataType); sl@0: break; sl@0: } sl@0: return payloadType; sl@0: } sl@0: sl@0: sl@0: TUint TRTPa2dpCodecSpecificUtils::MediaPayloadHeaderLength(const TFourCC& aCodecDataType) sl@0: { sl@0: TUint mediaPayloadHeaderLength = 0; sl@0: switch(const_cast(aCodecDataType).FourCC()) sl@0: { sl@0: case KMMFFourCCCodeSBC: sl@0: mediaPayloadHeaderLength = KSbcRTPMediaPayloadHeaderLength; sl@0: break; sl@0: case KMMFFourCCCodeMP3: sl@0: mediaPayloadHeaderLength = KMPEG12RTPMediaPayloadHeaderLength; sl@0: break; sl@0: case KMMFFourCCCodeAAC: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: case KMMFFourCCCodeATRAC3: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: default: sl@0: Panic(EA2dpCodecUtilUnexpectedDataType); sl@0: break; sl@0: } sl@0: return mediaPayloadHeaderLength; sl@0: } sl@0: sl@0: sl@0: sl@0: TTimeIntervalMicroSeconds32 TFrameTimingUtils::FrameDuration(TUint aFrameLength, TUint aBitRate) sl@0: { sl@0: TUint frameDurationuS = (aFrameLength*8*1000000)/aBitRate; sl@0: return TTimeIntervalMicroSeconds32(frameDurationuS); sl@0: } sl@0: sl@0: sl@0: TUint TFrameTimingUtils::CalculateSBCTimeStampIncrementPerFrame(TUint aFrameLength, TUint aBitRate, TUint aSampleRate) sl@0: { sl@0: //SBC uses the sampleRate clock as the timestamp clock A2DP spec 4.3.3.1 sl@0: TUint frameDurationuS = FrameDuration(aFrameLength, aBitRate).Int(); sl@0: sl@0: return (frameDurationuS*aSampleRate)/1000000; sl@0: } sl@0: sl@0: sl@0: TUint TFrameTimingUtils::CalculateMPEG12TimeStampIncrementPerFrame(TUint aFrameLength, TUint aBitRate) sl@0: { sl@0: //MPEG12 uses a 90Khz clock as the timestamp clock RFC3551 section 4.5.13 sl@0: TUint frameDurationuS = FrameDuration(aFrameLength, aBitRate).Int(); sl@0: sl@0: //div 1000000 as frame duration is in microseconds sl@0: return (frameDurationuS*KMPEG12RTPTimeStampClock)/1000000; sl@0: } sl@0: sl@0: sl@0: TUint TFrameTimingUtils::TimeStampIncrementPerFrame(const TFourCC& aCodecDataType, TUint aFrameLength, TUint aBitRate, TUint aSampleRate) sl@0: { sl@0: TInt timeStampIncrement = 0; sl@0: switch (const_cast(aCodecDataType).FourCC()) sl@0: { sl@0: case KMMFFourCCCodeSBC: sl@0: timeStampIncrement = CalculateSBCTimeStampIncrementPerFrame(aFrameLength, aBitRate, aSampleRate); sl@0: break; sl@0: case KMMFFourCCCodeMP3: sl@0: timeStampIncrement = CalculateMPEG12TimeStampIncrementPerFrame(aFrameLength, aBitRate); sl@0: break; sl@0: case KMMFFourCCCodeAAC: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: case KMMFFourCCCodeATRAC3: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: default: sl@0: //the datatype is a non A2DP datatype sl@0: //which is not supported so panic sl@0: Panic(EA2dpCodecUtilUnexpectedDataType); sl@0: break; sl@0: } sl@0: return timeStampIncrement; sl@0: } sl@0: sl@0: sl@0: CA2dpLocalCodecCapabilities* CA2dpLocalCodecCapabilities::NewL() sl@0: { sl@0: return new(ELeave) CA2dpLocalCodecCapabilities(); sl@0: } sl@0: sl@0: sl@0: CA2dpLocalCodecCapabilities::CA2dpLocalCodecCapabilities() sl@0: { sl@0: sl@0: } sl@0: sl@0: sl@0: CA2dpLocalCodecCapabilities::~CA2dpLocalCodecCapabilities() sl@0: { sl@0: delete iLocalCodecCapabilities; sl@0: } sl@0: sl@0: sl@0: TAvdtpMediaCodecCapabilities* CA2dpLocalCodecCapabilities::LocalCodecCapabilities(const TFourCC& aCodecDataType) sl@0: { sl@0: switch(const_cast(aCodecDataType).FourCC()) sl@0: { sl@0: case KMMFFourCCCodeSBC: sl@0: iLocalCodecCapabilities = LocalSBCCodecCapabilities(); sl@0: break; sl@0: case KMMFFourCCCodeMP3: sl@0: iLocalCodecCapabilities = LocalMPEG12CodecCapabilities(); sl@0: break; sl@0: case KMMFFourCCCodeAAC: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: case KMMFFourCCCodeATRAC3: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: default: sl@0: Panic(EA2dpCodecUtilUnexpectedDataType); sl@0: break; sl@0: } sl@0: return iLocalCodecCapabilities; sl@0: } sl@0: sl@0: sl@0: TSBCCodecCapabilities* CA2dpLocalCodecCapabilities::LocalSBCCodecCapabilities() sl@0: { sl@0: delete iLocalCodecCapabilities; sl@0: iLocalCodecCapabilities = NULL; sl@0: TSBCCodecCapabilities* localSbcCodecCapabilities = new TSBCCodecCapabilities(); sl@0: if (localSbcCodecCapabilities) sl@0: { sl@0: localSbcCodecCapabilities->SetSamplingFrequencies(E16kHz|E32kHz|E44100Hz|E48kHz); sl@0: localSbcCodecCapabilities->SetChannelModes(EMono|EStereo|EJointStereo); sl@0: localSbcCodecCapabilities->SetBlockLengths(EBlockLenFour|EBlockLenEight|EBlockLenTwelve|EBlockLenSixteen); sl@0: localSbcCodecCapabilities->SetSubbands(EFourSubbands|EEightSubbands); sl@0: localSbcCodecCapabilities->SetAllocationMethods(ELoudness|ESNR); sl@0: localSbcCodecCapabilities->SetMinBitpoolValue(KMinBitPoolValue); sl@0: localSbcCodecCapabilities->SetMaxBitpoolValue(KMaxBitPoolValue); sl@0: } sl@0: return localSbcCodecCapabilities; sl@0: } sl@0: sl@0: sl@0: TNonSBCCodecCapabilities* CA2dpLocalCodecCapabilities::LocalMPEG12CodecCapabilities() sl@0: { sl@0: delete iLocalCodecCapabilities; sl@0: iLocalCodecCapabilities = NULL; sl@0: TNonSBCCodecCapabilities* localSEPmpeg12CodecCapabilities = new TNonSBCCodecCapabilities(EAvdtpMediaTypeAudio, EAudioCodecMPEG12Audio); sl@0: if (localSEPmpeg12CodecCapabilities) sl@0: { sl@0: TBuf8<4> mpeg12CodecCapabilitiesData; sl@0: sl@0: //MPEG12 channel modes are the same as SBC so we'll use SBC structure sl@0: TSBCChannelModeBitmask channelModes = (EMono|EStereo); sl@0: mpeg12CodecCapabilitiesData.Append(KA2dpMPEG12LayerMP3Supported | channelModes); sl@0: sl@0: //no MPF-2 support, will support 16-44100khz sample sl@0: TInt8 samplingFrequencySupport = EMPEG12_16kHz|EMPEG12_22050Hz|EMPEG12_24kHz|EMPEG12_32kHz|EMPEG12_44100Hz; sl@0: mpeg12CodecCapabilitiesData.Append(samplingFrequencySupport); sl@0: sl@0: //no VBR all bitrates <= 96kbs-1 except free format sl@0: mpeg12CodecCapabilitiesData.Append(0); sl@0: mpeg12CodecCapabilitiesData.Append(KA2dpMPEG12SupportedBitRateIndex);//all bit rates <= 96kbs-1 sl@0: localSEPmpeg12CodecCapabilities->SetCodecData(mpeg12CodecCapabilitiesData); sl@0: } sl@0: return localSEPmpeg12CodecCapabilities; sl@0: } sl@0: sl@0: sl@0: sl@0: CA2dpAudioCodecConfiguration* CA2dpAudioCodecConfiguration::NewL() sl@0: { sl@0: return new(ELeave)CA2dpAudioCodecConfiguration(); sl@0: } sl@0: sl@0: sl@0: CA2dpAudioCodecConfiguration::CA2dpAudioCodecConfiguration() : iHeadsetCodecDataType(KMMFFourCCCodeSBC), iSampleRate(KDefaultSampleRate), iChannels(KDefaultChannels), iStereoSupport(KDefaultStereoSupport) sl@0: { sl@0: } sl@0: sl@0: CA2dpAudioCodecConfiguration::~CA2dpAudioCodecConfiguration() sl@0: { sl@0: delete iRemoteCodecConfiguration; sl@0: } sl@0: sl@0: sl@0: void CA2dpAudioCodecConfiguration::Reset() sl@0: { sl@0: delete iRemoteCodecConfiguration; sl@0: iRemoteCodecConfiguration = NULL; sl@0: iHeadsetCodecDataType = KMMFFourCCCodeSBC; sl@0: iSampleRate = KDefaultSampleRate; sl@0: iChannels = KDefaultChannels; sl@0: iStereoSupport = KDefaultStereoSupport; sl@0: iLocalSBCCodecConfiguration.Reset(); sl@0: } sl@0: sl@0: /** sl@0: Function used to return a TAvdtpMediaCodecCapabilities structure sl@0: that can be used to configure the SEP at the remote end ie on the headset sl@0: The capabilities are used to determine the configuration sl@0: need to return by pointer rather than by ref as TAvdtpMediaCodecCapabilities is abstract sl@0: Note that this parameter passed in treats the TAvdtpMediaCodecCapabilities as sl@0: the capabilities of the code, whereas the returned TAvdtpMediaCodecCapabilities is a sl@0: configuration ie a specific set of values that can be used to configure the remote codec sl@0: sl@0: @param aCodecCapabilities This is the capabilities supported by the remote codec sl@0: @return The configuration for the remote codec sl@0: */ sl@0: //void CA2dpAudioCodecConfiguration::GetRemoteCodecConfiguration(const TAvdtpMediaCodecCapabilities& aRemoteCodecCapabilities, TAvdtpMediaCodecCapabilities& aRemoteCodecConfiguration) sl@0: TAvdtpMediaCodecCapabilities* CA2dpAudioCodecConfiguration::UpdateRemoteCodecConfiguration(const TAvdtpMediaCodecCapabilities& aRemoteCodecCapabilities) sl@0: { sl@0: delete iRemoteCodecConfiguration; sl@0: iRemoteCodecConfiguration = NULL; sl@0: { sl@0: //this hasn't been set yet so set it sl@0: //first find out the capabilities of the codec sl@0: switch (aRemoteCodecCapabilities.MediaCodecType()) sl@0: { sl@0: case EAudioCodecSBC: sl@0: iRemoteCodecConfiguration = GetRemoteSBCCodecConfiguration(static_cast(aRemoteCodecCapabilities)); sl@0: iHeadsetCodecDataType = KMMFFourCCCodeSBC; sl@0: break; sl@0: case EAudioCodecMPEG12Audio: sl@0: iRemoteCodecConfiguration = GetRemoteMPEG12CodecConfiguration(static_cast(aRemoteCodecCapabilities)); sl@0: iHeadsetCodecDataType = KMMFFourCCCodeMP3; sl@0: break; sl@0: case EAudioCodecMPEG24AAC: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: case EAudioCodecATRAC: sl@0: Panic(EA2dpCodecUtilUnsupportedDataType); sl@0: break; sl@0: default: sl@0: //the datatype is a non A2DP datatype sl@0: //which is not supported so panic sl@0: Panic(EA2dpCodecUtilUnexpectedDataType); sl@0: break; sl@0: } sl@0: } sl@0: return iRemoteCodecConfiguration; sl@0: } sl@0: sl@0: sl@0: /** sl@0: sl@0: */ sl@0: TSBCCodecCapabilities* CA2dpAudioCodecConfiguration::GetRemoteSBCCodecConfiguration(const TSBCCodecCapabilities& aCodecCaps) sl@0: { sl@0: TSBCCodecCapabilities* sbcCodecConfiguration = new TSBCCodecCapabilities(); sl@0: sl@0: if (sbcCodecConfiguration) sl@0: { sl@0: //--sampling frequency-- sl@0: TSBCSamplingFrequencyBitmask freqs; sl@0: switch(iSampleRate) sl@0: { sl@0: case 16000: sl@0: freqs = E16kHz; sl@0: break; sl@0: case 32000: sl@0: freqs = E32kHz; sl@0: break; sl@0: case 44100: sl@0: freqs = E44100Hz; sl@0: break; sl@0: case 48000: sl@0: freqs = E48kHz; sl@0: break; sl@0: default: sl@0: freqs = E16kHz; sl@0: break; sl@0: } sl@0: //check we really can support this sampling frequency sl@0: //since we may be using the default which may not be supported sl@0: //by the headset (even if the A2DP spec says it is mandatory) sl@0: TSBCSamplingFrequencyBitmask samplingFreqsSupportedByHeadset = aCodecCaps.SamplingFrequencies(); sl@0: if (iForcedRemoteSBCCodecConfiguration) sl@0: { sl@0: samplingFreqsSupportedByHeadset = iForcedRemoteSBCCodecConfiguration->SamplingFrequencies(); sl@0: } sl@0: if (!(freqs & samplingFreqsSupportedByHeadset)) sl@0: {//then the headset doesn't support the sampling frequency sl@0: //this could happen if iSampleRate is a default that the headset doesn't support sl@0: //note that evenif the default is a mandatory sample rate eg 44100 sl@0: //we still do not make any assumptions about what is supported sl@0: if (samplingFreqsSupportedByHeadset & E16kHz) sl@0: { sl@0: iSampleRate = 16000; sl@0: freqs = E16kHz; sl@0: } sl@0: else if (samplingFreqsSupportedByHeadset & E32kHz) sl@0: { sl@0: iSampleRate = 32000; sl@0: freqs = E32kHz; sl@0: } sl@0: else if (samplingFreqsSupportedByHeadset & E44100Hz) sl@0: { sl@0: iSampleRate = 44100; sl@0: freqs = E44100Hz; sl@0: } sl@0: else if (samplingFreqsSupportedByHeadset & E48kHz) sl@0: { sl@0: iSampleRate = 48000; sl@0: freqs = E48kHz; sl@0: } sl@0: //else just keep as is sl@0: } sl@0: sbcCodecConfiguration->SetSamplingFrequencies(freqs); sl@0: sl@0: //--channels-- sl@0: TSBCChannelModeBitmask channelMode = EMono; sl@0: TSBCChannelModeBitmask channelModesSupportedByHeadset = EMono; sl@0: channelModesSupportedByHeadset = aCodecCaps.ChannelModes(); sl@0: if (iChannels == EMMFMono) sl@0: { sl@0: channelMode = EMono; sl@0: } sl@0: else if ((iChannels == EMMFStereo) && (iStereoSupport == EMMFInterleavedOnly)) sl@0: { sl@0: channelMode = EStereo; sl@0: } sl@0: else if ((iChannels == EMMFStereo) && (iStereoSupport == EMMFJoint)) sl@0: { sl@0: channelMode = EJointStereo; sl@0: } sl@0: if (!(channelMode & channelModesSupportedByHeadset)) sl@0: { sl@0: //then we don't support the selected channel mode sl@0: if (channelModesSupportedByHeadset & EMono) sl@0: { sl@0: iChannels = EMMFMono; sl@0: iStereoSupport = EMMFNone; sl@0: channelMode = EMono; sl@0: } sl@0: else if (channelModesSupportedByHeadset & EJointStereo) sl@0: { sl@0: iChannels = EMMFStereo; sl@0: iStereoSupport = EMMFJoint; sl@0: channelMode = EJointStereo; sl@0: } sl@0: else if (channelModesSupportedByHeadset & EStereo) sl@0: { sl@0: iChannels = EMMFStereo; sl@0: iStereoSupport = EMMFInterleavedOnly; sl@0: channelMode = EStereo; sl@0: } sl@0: } sl@0: sbcCodecConfiguration->SetChannelModes(channelMode); sl@0: sl@0: //--block mode-- sl@0: //we'll choose a preference order of 16,12, 8,4 sl@0: //although there may be a more intelligent way of doing this sl@0: //based on the other parameters. sl@0: TSBCBlockLengthBitmask blockLength = EBlockLenSixteen; sl@0: TSBCBlockLengthBitmask blockLengthsSupportedByHeadset = aCodecCaps.BlockLengths(); sl@0: if (iForcedRemoteSBCCodecConfiguration) sl@0: { sl@0: blockLengthsSupportedByHeadset = iForcedRemoteSBCCodecConfiguration->BlockLengths(); sl@0: } sl@0: if (blockLengthsSupportedByHeadset & EBlockLenSixteen) sl@0: { sl@0: blockLength = EBlockLenSixteen; sl@0: } sl@0: else if (blockLengthsSupportedByHeadset & EBlockLenTwelve) sl@0: { sl@0: blockLength = EBlockLenTwelve; sl@0: } sl@0: else if (blockLengthsSupportedByHeadset & EBlockLenEight) sl@0: { sl@0: blockLength = EBlockLenEight; sl@0: } sl@0: else if (blockLengthsSupportedByHeadset & EBlockLenFour) sl@0: { sl@0: blockLength = EBlockLenFour; sl@0: } sl@0: sbcCodecConfiguration->SetBlockLengths(blockLength); sl@0: sl@0: //--subbands-- sl@0: //Subbands currently have a preference of 8 over 4 sl@0: TUint numberOfSubbands = 8; //used later for max bit pool value calculation sl@0: TSBCSubbandsBitmask subbands = EEightSubbands; sl@0: TSBCSubbandsBitmask subbandsSupportedByHeadset = aCodecCaps.Subbands(); sl@0: if (iForcedRemoteSBCCodecConfiguration) sl@0: { sl@0: subbandsSupportedByHeadset = iForcedRemoteSBCCodecConfiguration->Subbands(); sl@0: } sl@0: if (subbandsSupportedByHeadset & EEightSubbands) sl@0: { sl@0: subbands = EEightSubbands; sl@0: } sl@0: else if (subbandsSupportedByHeadset & EFourSubbands) sl@0: { sl@0: subbands = EFourSubbands; sl@0: numberOfSubbands = 4; sl@0: } sl@0: sbcCodecConfiguration->SetSubbands(subbands); sl@0: sl@0: //--Allocation-- sl@0: //although allocation support of SNR and loudness are mandatory the headset sl@0: //may have reconfigured to use a particular allocation method sl@0: //If both allocation methods are available we have to choose which one sl@0: //so we'll choose a preference order of loudness over SNR sl@0: TSBCAllocationMethodBitmask allocationMethod = ELoudness; sl@0: TSBCAllocationMethodBitmask allocationMethodsSupportedByHeadset = aCodecCaps.AllocationMethods(); sl@0: if (iForcedRemoteSBCCodecConfiguration) sl@0: { sl@0: allocationMethodsSupportedByHeadset = iForcedRemoteSBCCodecConfiguration->AllocationMethods(); sl@0: } sl@0: if (allocationMethodsSupportedByHeadset & ELoudness) sl@0: { sl@0: allocationMethod = ELoudness; sl@0: } sl@0: else if (allocationMethodsSupportedByHeadset & ESNR) sl@0: { sl@0: allocationMethod = ESNR; sl@0: } sl@0: sbcCodecConfiguration->SetAllocationMethods(allocationMethod); sl@0: sl@0: //--bitpool sl@0: // The bitpool value must be in the range of 2-250 and must not exceed sl@0: // 16*numberOfSubbands*channels sl@0: // note that we don't normally play SBC directly, except for test purposes sl@0: // in order to arbitary play any SBC file extra code would be required sl@0: // to parse the SBC frame header to get the bitpool value sl@0: // since for unit testing the the SBC test file is known to have a sl@0: // bit pool value of 20, this shall be the default value sl@0: // This code could be made more more intelligent and base the sl@0: // bitpool value around table 4.7 in the A2DP specification sl@0: TUint minBitPoolValue = KMinBitPoolValue; sl@0: TUint maxBitPoolValue = KMaxBitPoolValue; sl@0: if (KMinBitPoolValue < aCodecCaps.MinBitpoolValue()) sl@0: { sl@0: minBitPoolValue = aCodecCaps.MinBitpoolValue(); sl@0: } sl@0: if (KMaxBitPoolValue > aCodecCaps.MaxBitpoolValue()) sl@0: { sl@0: TUint maxAllowableBitPoolValueForCurrentConfiguration = 16*iChannels*numberOfSubbands; sl@0: maxBitPoolValue = aCodecCaps.MaxBitpoolValue(); sl@0: if (maxBitPoolValue > maxAllowableBitPoolValueForCurrentConfiguration) sl@0: { sl@0: maxBitPoolValue = maxAllowableBitPoolValueForCurrentConfiguration; sl@0: } sl@0: } sl@0: sbcCodecConfiguration->SetMinBitpoolValue(minBitPoolValue); sl@0: sbcCodecConfiguration->SetMaxBitpoolValue(maxBitPoolValue); sl@0: }//if (sbcCodecConfiguration) sl@0: sl@0: return sbcCodecConfiguration; sl@0: } sl@0: sl@0: sl@0: /** sl@0: internal function to get a remote codec configuration from the capabilities sl@0: Note technically speaking MPEG12 refers to MPEG 1 & MPEG 2 audio layers 1,2 and 3 sl@0: however since mp1 & mp2 is rarely used in practice this sl@0: will be MPEG 1 layer 3 ie mp3 in most case sl@0: */ sl@0: TNonSBCCodecCapabilities* CA2dpAudioCodecConfiguration::GetRemoteMPEG12CodecConfiguration(const TNonSBCCodecCapabilities& aCodecCaps) sl@0: { sl@0: TNonSBCCodecCapabilities* mpeg12CodecConfiguration = new TNonSBCCodecCapabilities(EAvdtpMediaTypeAudio, EAudioCodecMPEG12Audio); sl@0: TBuf8<4> mpeg12CodecConfigurationData;//should be 4 make 6 for bug?? sl@0: if (mpeg12CodecConfiguration) sl@0: {//codecData should contain data conformant to A2DP profile sl@0: // codec specific information elements section A2DP 4.4.2 sl@0: TPtrC8 codecCapsData(aCodecCaps.CodecData()); sl@0: TInt8 mpegLayerSupport = codecCapsData[0] & KA2dpMPEG12LayerMask; sl@0: if (!(mpegLayerSupport & KA2dpMPEG12LayerMP3Supported)) sl@0: { sl@0: //then mp3 is not supported must be mp1 or mp2 which we don't support sl@0: delete mpeg12CodecConfiguration; sl@0: mpeg12CodecConfiguration = NULL; sl@0: return mpeg12CodecConfiguration; sl@0: } sl@0: mpegLayerSupport = KA2dpMPEG12LayerMP3Supported; //mp3 sl@0: //we don't bother with CRC protection so don't check sl@0: sl@0: //the MPEG12 channel support structure is identical to sl@0: //SBC so we'll use the SBC structure sl@0: //--channels-- sl@0: TSBCChannelModeBitmask channelMode = EMono; sl@0: TSBCChannelModeBitmask channelModesSupportedByHeadset = EMono; sl@0: channelModesSupportedByHeadset = codecCapsData[0] & KA2dpMPEG12AudioChannelModeMask; sl@0: if (iChannels == EMMFMono) sl@0: { sl@0: channelMode = EMono; sl@0: } sl@0: else if ((iChannels == EMMFStereo) && (iStereoSupport == EMMFInterleavedOnly)) sl@0: { sl@0: channelMode = EStereo; sl@0: } sl@0: else if ((iChannels == EMMFStereo) && (iStereoSupport == EMMFJoint)) sl@0: { sl@0: channelMode = EJointStereo; sl@0: } sl@0: if (!(channelMode & channelModesSupportedByHeadset)) sl@0: { sl@0: //then we don't support the selected channel mode sl@0: if (channelModesSupportedByHeadset & EMono) sl@0: { sl@0: iChannels = EMMFMono; sl@0: iStereoSupport = EMMFNone; sl@0: channelMode = EMono; sl@0: } sl@0: else if (channelModesSupportedByHeadset & EJointStereo) sl@0: { sl@0: iChannels = EMMFStereo; sl@0: iStereoSupport = EMMFJoint; sl@0: channelMode = EJointStereo; sl@0: } sl@0: else if (channelModesSupportedByHeadset & EStereo) sl@0: { sl@0: iChannels = EMMFStereo; sl@0: iStereoSupport = EMMFInterleavedOnly; sl@0: channelMode = EStereo; sl@0: } sl@0: } sl@0: mpeg12CodecConfigurationData.Append(mpegLayerSupport | channelMode); sl@0: sl@0: //Media Payload Format sl@0: //this ref implementation shall only support the media payload format sl@0: //defined in RFC2250, RFC3119 is not supported sl@0: //therefore there is no need to check this since MPF-1/RFC2250 is mandatory sl@0: sl@0: //--sampling frequency-- sl@0: //the mp3 sampling frequency mask is not the same as SBC so can't use TSBCSamplingFrequencyBitmask sl@0: TMPEG12SamplingFrequencyBitmask freqs; sl@0: switch(iSampleRate) sl@0: { sl@0: case 16000: sl@0: freqs = EMPEG12_16kHz; sl@0: break; sl@0: case 22050: sl@0: freqs = EMPEG12_22050Hz; sl@0: break; sl@0: case 24000: sl@0: freqs = EMPEG12_24kHz; sl@0: break; sl@0: case 32000: sl@0: freqs = EMPEG12_32kHz; sl@0: break; sl@0: case 44100: sl@0: freqs = EMPEG12_44100Hz; sl@0: break; sl@0: case 48000: sl@0: freqs = EMPEG12_48kHz; sl@0: break; sl@0: default: sl@0: freqs = EMPEG12_16kHz; sl@0: break; sl@0: } sl@0: //check we really can support this sampling frequency sl@0: //since we may be using the default which may not be supported sl@0: //by the headset (even if the A2DP spec says it is mandatory) sl@0: TMPEG12SamplingFrequencyBitmask samplingFreqsSupportedByHeadset = codecCapsData[1] & KA2dpMPEG12SamplingFrequencyMask; sl@0: if (!(freqs & samplingFreqsSupportedByHeadset)) sl@0: {//then the headset doesn't support the sampling frequency sl@0: //this could happen if iSampleRate is a default that the headset doesn't support sl@0: //note that evenif the default is a mandatory sample rate eg 44100 sl@0: //we still do not make any assumptions about what is supported sl@0: if (samplingFreqsSupportedByHeadset & EMPEG12_16kHz) sl@0: { sl@0: iSampleRate = 16000; sl@0: freqs = EMPEG12_16kHz; sl@0: } sl@0: else if (samplingFreqsSupportedByHeadset & EMPEG12_22050Hz) sl@0: { sl@0: iSampleRate = 22050; sl@0: freqs = EMPEG12_22050Hz; sl@0: } sl@0: else if (samplingFreqsSupportedByHeadset & EMPEG12_24kHz) sl@0: { sl@0: iSampleRate = 24000; sl@0: freqs = EMPEG12_24kHz; sl@0: } sl@0: else if (samplingFreqsSupportedByHeadset & EMPEG12_32kHz) sl@0: { sl@0: iSampleRate = 32000; sl@0: freqs = EMPEG12_32kHz; sl@0: } sl@0: else if (samplingFreqsSupportedByHeadset & EMPEG12_44100Hz) sl@0: { sl@0: iSampleRate = 44100; sl@0: freqs = EMPEG12_44100Hz; sl@0: } sl@0: else if (samplingFreqsSupportedByHeadset & EMPEG12_48kHz) sl@0: { sl@0: iSampleRate = 48000; sl@0: freqs = EMPEG12_48kHz; sl@0: } sl@0: //else just keep as is sl@0: } sl@0: //set frequency, MPF-1 sl@0: mpeg12CodecConfigurationData.Append(freqs); sl@0: sl@0: sl@0: //The casira pod only supports bit rates up to 96kbs-1 sl@0: //so check the headset supports these as well sl@0: //we'll just mask with all the lower bit rates sl@0: //all the lower bit rate support up to 96kbs-1are in octet 3 sl@0: //so just make out octet 2 bit rate support sl@0: //also VBR = 0 as no VBR support sl@0: mpeg12CodecConfigurationData.Append(0); sl@0: sl@0: //all bitrates <= 96kbs-1 except free format sl@0: mpeg12CodecConfigurationData.Append(KA2dpMPEG12SupportedBitRateIndex & codecCapsData[3]); sl@0: mpeg12CodecConfiguration->SetCodecData(mpeg12CodecConfigurationData); sl@0: } sl@0: return mpeg12CodecConfiguration; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Utility function get the codec capabilities used by Gavdp into the SBC codec paramerers sl@0: used by the SBC codec sl@0: The function uses the TSBCCodecCapabilities to generate a set of TSBCFrameParameters sl@0: which can be used to configure the codec sl@0: the remote codec configuration must have already been updated before calling sl@0: this function sl@0: sl@0: @param aSBCFrameParameters These are set to the current configuration settings sl@0: */ sl@0: TSBCFrameParameters& CA2dpAudioCodecConfiguration::UpdateLocalSBCCodecConfiguration() sl@0: { sl@0: __ASSERT_DEBUG(iRemoteCodecConfiguration, Panic(EA2dpCodecUtilNoRemoteCodecConfig)); sl@0: __ASSERT_DEBUG((iHeadsetCodecDataType == KMMFFourCCCodeSBC) && (iRemoteCodecConfiguration->MediaCodecType() == EAudioCodecSBC), Panic(EA2dpCodecUtilUnexpectedDataType)); sl@0: TSBCCodecCapabilities* remoteSBCCodecConfiguration = static_cast(iRemoteCodecConfiguration); sl@0: sl@0: //note that for sampling frequency and channels the capabilites sl@0: //have already been checked in SetSampleRate and SetChannels sl@0: //and once set we don't allow these to be reconfigured sl@0: //so no need to check these again with the codecCaps sl@0: //if set the iSampleRate should always be in agreement with sl@0: //the settings on the remote codec sl@0: TSBCFrameParameters::TSamplingFrequency SBCSamplingFrequency; sl@0: switch(iSampleRate) sl@0: { sl@0: case 32000: sl@0: SBCSamplingFrequency = TSBCFrameParameters::E32000Hz; sl@0: break; sl@0: case 44100: sl@0: SBCSamplingFrequency = TSBCFrameParameters::E44100Hz; sl@0: break; sl@0: case 48000: sl@0: SBCSamplingFrequency = TSBCFrameParameters::E48000Hz; sl@0: break; sl@0: default://[TODO] change default to 44100 when hardware sl@0: //(ie BT support H2 or higher bandwidth support on Casira) supports it sl@0: SBCSamplingFrequency = TSBCFrameParameters::E16000Hz; sl@0: break; sl@0: } sl@0: sl@0: iLocalSBCCodecConfiguration.SetSamplingFrequency(SBCSamplingFrequency); sl@0: sl@0: //although a block length of 4,8,12,16 are mandatory the headset sl@0: //may have reconfigured to use a particular block length sl@0: //If all block lengths are available we have to choose which one sl@0: //For now we'll choose a preference order of 12,16,8,4 sl@0: //although there may be a more intelligent way of doing this sl@0: //based on the other parameters. sl@0: switch(remoteSBCCodecConfiguration->BlockLengths()) sl@0: { sl@0: case EBlockLenTwelve: sl@0: iLocalSBCCodecConfiguration.SetBlockLength(TSBCFrameParameters::E12Blocks); sl@0: break; sl@0: case EBlockLenSixteen: sl@0: iLocalSBCCodecConfiguration.SetBlockLength(TSBCFrameParameters::E16Blocks); sl@0: break; sl@0: case EBlockLenEight: sl@0: iLocalSBCCodecConfiguration.SetBlockLength(TSBCFrameParameters::E8Blocks); sl@0: break; sl@0: case EBlockLenFour: sl@0: iLocalSBCCodecConfiguration.SetBlockLength(TSBCFrameParameters::E4Blocks); sl@0: break; sl@0: default: sl@0: Panic(EA2dpCodecUtilUnexpectedConfiguration); sl@0: break; sl@0: } sl@0: sl@0: sl@0: //channel mode sl@0: //although the number of channels can't be changed on the fly sl@0: //switching between stereo and joint stereo is supported sl@0: //note different namespaces for EStereo & EJointStereo ! sl@0: TSBCFrameParameters::TChannelMode channelMode = TSBCFrameParameters::EMono;//default sl@0: if (iChannels == EMMFStereo) sl@0: { sl@0: if (iStereoSupport & EMMFJoint) sl@0: { sl@0: channelMode = TSBCFrameParameters::EJointStereo; sl@0: } sl@0: else if (iStereoSupport & EMMFInterleavedOnly) sl@0: { sl@0: channelMode = TSBCFrameParameters::EStereo; sl@0: } sl@0: else sl@0: { sl@0: Panic(EA2dpCodecUtilUnexpectedConfiguration); sl@0: } sl@0: } sl@0: sl@0: iLocalSBCCodecConfiguration.SetChannelMode(channelMode); sl@0: sl@0: //Allocation sl@0: //although allocation support of SNR and loudness are mandatory the headset sl@0: //may have reconfigured to use a particular allocation method sl@0: //If both allocation methods are available we have to choose which one sl@0: //For now we'll choose a preference order of loudness followed by SNR sl@0: sl@0: switch(remoteSBCCodecConfiguration->AllocationMethods()) sl@0: { sl@0: case ELoudness: sl@0: iLocalSBCCodecConfiguration.SetAllocationMethod(TSBCFrameParameters::ELoudness); sl@0: break; sl@0: case ESNR: sl@0: iLocalSBCCodecConfiguration.SetAllocationMethod(TSBCFrameParameters::ESNR); sl@0: break; sl@0: default: sl@0: Panic(EA2dpCodecUtilUnexpectedConfiguration); sl@0: break; sl@0: } sl@0: sl@0: sl@0: //Subbands currently have a preference of four over 8, but change to 8 later sl@0: //when hardware is available to support higher bandwidth sl@0: switch(remoteSBCCodecConfiguration->Subbands()) sl@0: { sl@0: case EFourSubbands: sl@0: iLocalSBCCodecConfiguration.SetSubbands(TSBCFrameParameters::E4Subbands); sl@0: break; sl@0: case EEightSubbands: sl@0: iLocalSBCCodecConfiguration.SetSubbands(TSBCFrameParameters::E8Subbands); sl@0: break; sl@0: default: sl@0: Panic(EA2dpCodecUtilUnexpectedConfiguration); sl@0: break; sl@0: } sl@0: sl@0: // note that we don't normally play SBC directly, except for test purposes sl@0: // in order to arbitary play any SBC file extra code would be required sl@0: // to parse the SBC frame header to get the bitpool value sl@0: // since for unit testing the the SBC test file is known to have a sl@0: // bit pool value of 20, this shall be the default value sl@0: // This code could be made more more intelligent and base the sl@0: // bitpool value around table 4.7 in the A2DP specification sl@0: TUint bitPoolValue = KDefaultBitPoolValue; //default is 20 sl@0: if (KDefaultBitPoolValue < remoteSBCCodecConfiguration->MinBitpoolValue()) sl@0: { sl@0: bitPoolValue = remoteSBCCodecConfiguration->MinBitpoolValue(); sl@0: } sl@0: else if (KDefaultBitPoolValue > remoteSBCCodecConfiguration->MaxBitpoolValue()) sl@0: { sl@0: bitPoolValue = remoteSBCCodecConfiguration->MaxBitpoolValue(); sl@0: } sl@0: iLocalSBCCodecConfiguration.SetBitpool(bitPoolValue); sl@0: sl@0: return iLocalSBCCodecConfiguration; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Internal function to calculate the SBC buffer length required from the SBC frame parameters sl@0: using the given pcm16 buffer length sl@0: */ sl@0: TUint CA2dpAudioCodecConfiguration::CalculateSBCBufferLength(TUint aPCM16BufferLength) const sl@0: { sl@0: //ASSERT data type = SBC sl@0: sl@0: //first calculate the number of PCM16 samples in one SBC frame sl@0: TUint numberOfSamplesPerSBCFrame = iLocalSBCCodecConfiguration.BlockLength()*iLocalSBCCodecConfiguration.Subbands(); sl@0: sl@0: //calculate the number of bytes in one sample sl@0: TUint numberOfPCM16BytesPerSample = 2*iLocalSBCCodecConfiguration.Channels(); sl@0: sl@0: TUint numberOfPCM16BytesPerSBCFrame = numberOfSamplesPerSBCFrame*numberOfPCM16BytesPerSample; sl@0: sl@0: TUint numberOfFrames = aPCM16BufferLength/numberOfPCM16BytesPerSBCFrame; sl@0: sl@0: TUint lengthOfSBCFrame = iLocalSBCCodecConfiguration.CalcFrameLength(); sl@0: sl@0: return numberOfFrames*lengthOfSBCFrame; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Test function to force the remote SBC codec configuration to that set in aRemoteCodecConfiguration sl@0: This function is just used for test purposes to set the SBC settings for sl@0: playing SBC data direct to the a2dpBTHeadsetAudioIf ie when the Data type is sl@0: set to SBC sl@0: It is up to the user to ensure that the headset supports the configuration sl@0: since this will bypass the normal capability check sl@0: */ sl@0: void CA2dpAudioCodecConfiguration::TEST_ForceRemoteSBCCodecConfiguration(const TSBCCodecCapabilities& aRemoteCodecConfiguration) sl@0: { sl@0: iForcedRemoteSBCCodecConfiguration = const_cast(&aRemoteCodecConfiguration); sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: CA2dpCodecFrameHeaderParser* CA2dpCodecFrameHeaderParser::NewL(const TFourCC& aCodecDataType, const TDesC8& aHeader) sl@0: { sl@0: CA2dpCodecFrameHeaderParser* self = new (ELeave) CA2dpCodecFrameHeaderParser(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aCodecDataType, aHeader); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: sl@0: CA2dpCodecFrameHeaderParser::CA2dpCodecFrameHeaderParser() sl@0: { sl@0: sl@0: } sl@0: sl@0: sl@0: CA2dpCodecFrameHeaderParser::~CA2dpCodecFrameHeaderParser() sl@0: { sl@0: sl@0: } sl@0: sl@0: sl@0: /** sl@0: Only used for playing SBC test files sl@0: */ sl@0: void CA2dpCodecFrameHeaderParser::ParseSBCHeaderL(const TDesC8& aHeader) sl@0: { sl@0: if (aHeader[0] != KSbcFrameHeaderSyncWord) sl@0: { sl@0: User::Leave(KErrCorrupt); //not a valid sbc frame sl@0: } sl@0: sl@0: TUint samplingFrequency = (aHeader[1] & KSbcFrameHeaderSamplingFrequencyMask)>>6; sl@0: switch(samplingFrequency) sl@0: { sl@0: case TSBCFrameParameters::E16000Hz: sl@0: iSampleRate = 16000; sl@0: break; sl@0: case TSBCFrameParameters::E32000Hz: sl@0: iSampleRate = 32000; sl@0: break; sl@0: case TSBCFrameParameters::E44100Hz: sl@0: iSampleRate = 44100; sl@0: break; sl@0: case TSBCFrameParameters::E48000Hz: sl@0: iSampleRate = 48000; sl@0: break; sl@0: default: sl@0: User::Leave(KErrCorrupt);//not a valid header sl@0: break; sl@0: } sl@0: sl@0: TUint8 blocks = (aHeader[1] & KSbcFrameHeaderBlocksMask)>>4; sl@0: switch(blocks) sl@0: { sl@0: case TSBCFrameParameters::E4Blocks: sl@0: blocks = 4; sl@0: break; sl@0: case TSBCFrameParameters::E8Blocks: sl@0: blocks = 8; sl@0: break; sl@0: case TSBCFrameParameters::E12Blocks: sl@0: blocks = 12; sl@0: break; sl@0: case TSBCFrameParameters::E16Blocks: sl@0: blocks = 16; sl@0: break; sl@0: default: sl@0: User::Leave(KErrCorrupt);//not a valid header sl@0: break; sl@0: } sl@0: TUint8 channelMode = (aHeader[1] & KSbcFrameHeaderChannelModeMask)>>2; sl@0: TUint8 channels = 1; sl@0: sl@0: if (channelMode != TSBCFrameParameters::EMono) sl@0: { sl@0: channels = 2; sl@0: } sl@0: sl@0: TUint8 subbands = 4; sl@0: if (aHeader[1] & KSbcFrameHeaderSubbandsMask) sl@0: { sl@0: subbands = 8; sl@0: } sl@0: sl@0: TUint8 bitpool = aHeader[2]; sl@0: sl@0: TUint temp = 0; sl@0: switch (channelMode) sl@0: { sl@0: case TSBCFrameParameters::EMono: sl@0: temp = blocks * bitpool; // blocks * bitpool sl@0: break; sl@0: case TSBCFrameParameters::EDualChannel: sl@0: temp = (blocks * bitpool) << 1; // blocks * bitpool * 2 sl@0: break; sl@0: case TSBCFrameParameters::EStereo: sl@0: temp = blocks * bitpool; // blocks * bitpool sl@0: break; sl@0: case TSBCFrameParameters::EJointStereo: sl@0: temp = subbands + blocks * bitpool; // subbands + blocks * bitpool sl@0: break; sl@0: } sl@0: sl@0: iFrameLength = 4 + ( (subbands * channels) >> 1) + (temp >> 3); sl@0: if (temp & 0x7) sl@0: { sl@0: iFrameLength++; sl@0: } sl@0: sl@0: iBitRate = (8*iFrameLength*iSampleRate)/(subbands*blocks); sl@0: } sl@0: sl@0: sl@0: void CA2dpCodecFrameHeaderParser::ParseMPEG12HeaderL(const TDesC8& aHeader) sl@0: { sl@0: if (aHeader[0] != KMPEGAudioFrameHeaderSyncWord ) sl@0: { sl@0: User::Leave(KErrCorrupt); //not a valid MPEG audio frame sl@0: } sl@0: sl@0: //check it's really mp3 as opposed to mp1 or mp2 sl@0: if ((aHeader[1] & KMp3AudioFrameHeaderIdMask) != KMp3AudioFrameHeaderId) sl@0: { sl@0: User::Leave(KErrNotSupported); //either corrupt or mp1/mp2 sl@0: } sl@0: sl@0: TUint8 sampleRateIndex = (aHeader[2] & KMp3FrameHeaderSamplingFrequencyMask)>>2; sl@0: switch(sampleRateIndex) sl@0: { sl@0: case 0x00: sl@0: iSampleRate = 44100; sl@0: break; sl@0: case 0x01: sl@0: iSampleRate = 48000; sl@0: break; sl@0: case 0x02: sl@0: iSampleRate = 32000; sl@0: break; sl@0: default: sl@0: User::Leave(KErrCorrupt); //invalid mp3 header? sl@0: break; sl@0: } sl@0: TUint8 bitRateIndex = (aHeader[2] & KMp3FrameHeaderBitRateIndexMask)>>4; sl@0: switch(bitRateIndex) sl@0: { sl@0: case EMp3BitRateIndex32000: sl@0: iBitRate = 32000; sl@0: break; sl@0: case EMp3BitRateIndex40000: sl@0: iBitRate = 40000; sl@0: break; sl@0: case EMp3BitRateIndex48000: sl@0: iBitRate = 48000; sl@0: break; sl@0: case EMp3BitRateIndex56000: sl@0: iBitRate = 56000; sl@0: break; sl@0: case EMp3BitRateIndex64000: sl@0: iBitRate = 64000; sl@0: break; sl@0: case EMp3BitRateIndex80000: sl@0: iBitRate = 80000; sl@0: break; sl@0: case EMp3BitRateIndex96000: sl@0: iBitRate = 96000; sl@0: break; sl@0: default: sl@0: User::Leave(KErrNotSupported);//don't support more than 96kbs-1 sl@0: break; sl@0: } sl@0: sl@0: //this code should really be made more clever to take allowance for any padding sl@0: //and use a frame length such that if padding is used then take the lowest sl@0: //common multiple of frames tht gives a common frame length eg if the frames sl@0: //alternate between 100 and 101 bytes due to an extra padding byte everyother sl@0: //frame then set the frame length to 201; sl@0: TUint bitRateX144 = iBitRate*144; sl@0: iFrameLength = bitRateX144/iSampleRate; sl@0: } sl@0: sl@0: sl@0: /** sl@0: static sl@0: */ sl@0: void CA2dpCodecFrameHeaderParser::ConstructL(const TFourCC& aCodecDataType, const TDesC8& aHeader) sl@0: { sl@0: switch(const_cast(aCodecDataType).FourCC()) sl@0: { sl@0: case KMMFFourCCCodeSBC: sl@0: ParseSBCHeaderL(aHeader); sl@0: break; sl@0: case KMMFFourCCCodeMP3: sl@0: ParseMPEG12HeaderL(aHeader); sl@0: break; sl@0: case KMMFFourCCCodeAAC: sl@0: User::Leave(KErrNotSupported); sl@0: break; sl@0: case KMMFFourCCCodeATRAC3: sl@0: User::Leave(KErrNotSupported); sl@0: break; sl@0: default: sl@0: User::Leave(KErrNotSupported); sl@0: break; sl@0: } sl@0: } sl@0: