/*============================================================================= CAChannelMappingPlayer.cpp $Log: CAChannelMappingPlayer.cpp,v $ Revision 1.1 2004/01/14 00:08:09 dwyatt moved from Source/Tests/AudioFileUtility/Utility Revision 1.2 2003/08/23 04:51:19 dwyatt track changes to CAAudioFile Revision 1.1 2003/08/04 23:40:00 dwyatt initial checkin created Thu Jul 31 2003, Doug Wyatt Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved $NoKeywords: $ =============================================================================*/ #include "CAChannelMappingPlayer.h" #include "CAXException.h" #if DEBUG #define VERBOSE 1 #endif CAChannelMappingPlayer::CAChannelMappingPlayer(int nBuffers, UInt32 ioBufferSizeBytes) : CAAudioFilePlayer(nBuffers, ioBufferSizeBytes), mMapper(NULL) { } CAChannelMappingPlayer::~CAChannelMappingPlayer() { delete mMapper; } void CAChannelMappingPlayer::SetupChannelMapping() { delete mMapper; mMapper = NULL; const CAStreamBasicDescription &fileFormat = GetFile().GetClientDataFormat(); CAStreamBasicDescription deviceFormat; UInt32 propertySize = sizeof(AudioStreamBasicDescription); XThrowIfError(AudioUnitGetProperty( GetOutputUnit(), kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, (void *)&deviceFormat, &propertySize), "get output device's format"); #if VERBOSE printf("CAChannelMappingPlayer::SetupChannelMapping: %ld-ch file, %ld-ch device\n", fileFormat.mChannelsPerFrame, deviceFormat.mChannelsPerFrame); #endif if (fileFormat.mChannelsPerFrame <= deviceFormat.mChannelsPerFrame) { // no mapping needed, use output unit's default behavior // (default stereo pair and speaker config from AMS) #if VERBOSE printf(" using output unit's channel mapping\n"); #endif CAAudioFilePlayer::SetupChannelMapping(); } else { // fewer device than file channels, mapping needed CAAudioChannelLayout fileLayout, deviceLayout; #if VERBOSE printf(" using our own channel mapping\n"); #endif deviceFormat.mSampleRate = fileFormat.mSampleRate; deviceFormat.SetCanonical(deviceFormat.mChannelsPerFrame, false); // force deinterleaved fileLayout = GetFile().GetFileChannelLayout(); UInt32 layoutSize; Boolean writable; OSStatus err = AudioUnitGetPropertyInfo( GetOutputUnit(), kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Input, 0, &layoutSize, &writable); if (!err) { char *buf = (char *)malloc(layoutSize); err = AudioUnitGetProperty( GetOutputUnit(), kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Input, 0, buf, &layoutSize); deviceLayout = CAAudioChannelLayout(reinterpret_cast(buf)); free(buf); } mMapper = new CAChannelMapper(fileFormat, deviceFormat, &fileLayout, &deviceLayout); // give the output unit the same number of channels as in the device, // since we'll be doing the mapping ourselves XThrowIfError(AudioUnitSetProperty( GetOutputUnit(), kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, (void *)&deviceFormat, sizeof(AudioStreamBasicDescription)), "set audio output format"); XThrowIfError(mMapper->OpenMixer(fileFormat.mSampleRate), "open mixer"); XThrowIfError(mMapper->ConfigureDownmix(), "configure downmix"); AudioUnitConnection conn; conn.sourceAudioUnit = mMapper->GetMixer(); conn.sourceOutputNumber = 0; conn.destInputNumber = 0; XThrowIfError(AudioUnitSetProperty( GetOutputUnit(), kAudioUnitProperty_MakeConnection, kAudioUnitScope_Global, 0, (void *)&conn, sizeof(AudioUnitConnection)), "connect mixer to output unit"); AURenderCallbackStruct input; input.inputProc = InputProc; input.inputProcRefCon = this; XThrowIfError(AudioUnitSetProperty( conn.sourceAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, 0, &input, sizeof(input)), "connect input proc to mixer"); // provide NO channel layout // mReadBuf = CABufferList::New("", fileFormat); // mReadBuf->AllocateBuffers( } }