• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Output Channel Selection Redux
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Output Channel Selection Redux


  • Subject: Output Channel Selection Redux
  • From: Bob Ingraham <email@hidden>
  • Date: Tue, 24 Feb 2009 15:38:48 -0700 (MST)

Hey All,

Thanks for the help thus far!

But I am just hitting a brick wall here. I think I'm on the right track with the SimpleSDK PlayFile example I've been modifying, but I just can't past the channel select problem using kAudioOutputUnitProperty_ChannelMap.

Any help would be most appreciated...



Scenario:
- Mac Pro with OS X 10.5.6 and XCode 3.1.2
- PCI device with 16 output channels (the "MOTU")
- Tried AudioQueue Services, but hit dead-end
- Using modified /Developer/Examples/CoreAudio/SimpleSDK/PlayFile code



Goal:
- Get PlayFile.cpp to play mono audio on a specific channel of the 16-channel MOTU

So far, I've modified the code to use the AUHAL audio unit as the output unit, and I've set it's Current Device to point to my 16-channel MOTU device.

The PlayFile app now plays my mono file (as stereo,) on channel 1 & 2 on the MOTU.



Failures:
- Trying to change the AUHAL channel layout to mono.
- Trying to change the AUHAL ChannelMap property to map mono channel 0 to AUHAL channel 3 (or whatever.)


The problem is, I don't the order of operations or when it's appropriate to issue the Layout and Channel Map prpoerty modification requests. My current order of ops is:

1. AUGraphAddNode (AUHAL) --> OK
2. AUGraphAddNode (Audio File Player) --> OK
3. AUGraphOpen --> OK
4. AUGraphNodeInfo (AUHAL Node) --> Done to get AudioUnit handle to AUHAL --> OK
5. AudioUnitSetProperty (AUHAL, CurrentDevice, MOTU-Audio-Device-ID) --> OK
6. AudioUnitGetProperty (AUHAL, SupportedNumChannels, Scope-Output, Element-0) -- > Fails with kAudioUnitErr_InvalidScope. Tried with Scope-Global and fails with kAudioUnitErr_InvalidProperty.
7. AudioUnitGetProperty (AUHAL, SupportedChannelLayoutTags, Scope-Output) --> Fails with kAudioUnitErr_InvalidElement or kAudioUnitErr_InvalidProperty depending on which element/scope I try.
8. AudioUnitSetProperty (AUHAL, AudioChannelLayout, Scope-Output, Element-1) --> Fails with kAudioUnitErr_InvalidProperty - guess it doesn't take bitmaps.
9. AudioUnitSetProperty (AUHAL, ChannelMap, Scope-Output, Element-1) --> OK, but doesn't work like I expect it to. I ask for audiochannel 0 to be mapped to device-channel 1, but it still plays on device-channel 0...




Code (modified MakeSimpleGraph subroutine from PlayFile.cpp):

void MakeSimpleGraph (AUGraph &theGraph, CAAudioUnit &fileAU, CAStreamBasicDescription &fileFormat, AudioFileID audioFile)
{
	XThrowIfError (NewAUGraph (&theGraph), "NewAUGraph");

	AudioUnit auOutput;
	AudioDeviceID adiMOTU;
	OSStatus err;
	ComponentDescription myCd;
	char fred[5];
	AudioChannelLayoutTag tags[8];
	UInt32 numTags, outSize, numElements, numChannels;
	int i;
	AudioChannelLayout chanLayout;

	CAComponentDescription cd;

	// output node
	cd.componentType = kAudioUnitType_Output;
	cd.componentSubType = kAudioUnitSubType_HALOutput;
	cd.componentManufacturer = kAudioUnitManufacturer_Apple;

	AUNode outputNode;
	XThrowIfError (AUGraphAddNode (theGraph, &cd, &outputNode), "AUGraphAddNode");

	// Get the Audio Device ID of the MOTU device
	if ((err = GetMOTUDevice(&adiMOTU)) != noErr)
	{
		printf("Unable to locate MOTU Audio Device ID: %d\n", err);
		return;
	}

	// file AU node
	AUNode fileNode;
	cd.componentType = kAudioUnitType_Generator;
	cd.componentSubType = kAudioUnitSubType_AudioFilePlayer;

	XThrowIfError (AUGraphAddNode (theGraph, &cd, &fileNode), "AUGraphAddNode");

	// connect & setup
	XThrowIfError (AUGraphOpen (theGraph), "AUGraphOpen");

	// Get Audio Device of output node
	err = AUGraphNodeInfo(theGraph, outputNode, &myCd, &auOutput);
	if (err != noErr)
	{
		printf("Failed to obtain Graph Node Info: %d\n", err);
		return;
	}
	printf("AUGraphNodeInfo: err = %d\n", err);
	printf("Output Audio Unit: %x\n", auOutput);
	printf("componentType: %s\n", ost2str(myCd.componentType, fred));
	printf("componentSubType: %s\n", ost2str(myCd.componentSubType, fred));
	printf("componentManufacturer: %s\n", ost2str(myCd.componentManufacturer, fred));

	err = AudioUnitSetProperty(auOutput, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &adiMOTU, sizeof(adiMOTU));
	if (err != noErr)
	{
		printf("Failed to set CurrentDevice of the output node: 0x%x\n", err);
		//return;
	}

	// Get output element count
	outSize = sizeof(numElements);
	err = AudioUnitGetProperty(auOutput, kAudioUnitProperty_ElementCount, kAudioUnitScope_Output, 1, &numElements, &outSize);
	if (err != noErr)
	{
		printf("Failed to get output scope element count: %d\n", err);
		//return;
	}
	else
	{
		printf("Output Scope Elements = %u\n", numElements);
	}

	// Get Output Unit stream format
	AudioStreamBasicDescription sFormat;
	outSize = sizeof(sFormat);
	err = AudioUnitGetProperty(auOutput, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &sFormat, &outSize);
	if (err != noErr)
	{
		printf("Failed to get Audio Stream Format: %d\n", err);
	}
	else
	{
		printf("Audio Stream Format:\n");
		printf("mSampleRate      : %f\n", sFormat.mSampleRate);
		printf("mFormatID        : %s\n", ost2str(sFormat.mFormatID, fred));
		printf("mFormatFlags     : 0x%x\n", sFormat.mFormatFlags);
		printf("mBytesPerPacket  : %u\n", sFormat.mBytesPerPacket);
		printf("mFramesPerPacket : %u\n", sFormat.mFramesPerPacket);
		printf("mBytesPerFrame   : %u\n", sFormat.mBytesPerFrame);
		printf("mChannelsPerFrame: %u\n", sFormat.mChannelsPerFrame);
		printf("mBitsPerChannel  : %u\n", sFormat.mBitsPerChannel);

	}

	// Get output channel count
	outSize = sizeof(numElements);
	err = AudioUnitGetProperty(auOutput, kAudioUnitProperty_SupportedNumChannels, kAudioUnitScope_Output, 0, &numChannels, &outSize);
	if (err != noErr)
	{
		printf("Failed to get output scope channel count: %d\n", err);
		//return;
	}
	else
	{
		printf("Output Scope Channels = %u\n", numChannels);
	}

	// Get property size of LayoutTags
	outSize = 0;
	err = AudioUnitGetProperty(auOutput, kAudioUnitProperty_SupportedChannelLayoutTags, kAudioUnitScope_Global, 0, NULL, &outSize);
	if (err != noErr)
	{
		printf("Failed to get size  of supported Channel Layout Tags: %d\n", err);
		//return;
	}
	else
	{
		printf("LayoutTags size = %u\n", outSize);
	}
	outSize = sizeof(tags);
	memset(tags, 0, sizeof(tags));
	err = AudioUnitGetProperty(auOutput, kAudioUnitProperty_SupportedChannelLayoutTags, kAudioUnitScope_Output, 1, &tags, &outSize);
	if (err != noErr)
	{
		printf("Failed to get supported Channel Layout Tags: %d\n", err);
		//return;
	}
	else
	{
		numTags = outSize/sizeof(AudioChannelLayoutTag);
		printf("Number of Layout Tags: %d\n", numTags);
		for (i=0; i < numTags; i++)
		{
			printf("Tag %d: %d\n", i, tags[i]);
		}
	}

	// Set channel layout
	memset(&chanLayout, 0, sizeof(chanLayout));
	chanLayout.mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelBitmap | kAudioChannelLayoutTag_Mono;
	chanLayout.mChannelBitmap = kAudioChannelBit_Left;

	err = AudioUnitSetProperty(auOutput, kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Output, 1, &chanLayout, sizeof(chanLayout));
	if (err != noErr)
	{
		printf("Failed to set Audio Channel Layout: %d\n", err);
	}

	SInt32 *channelMap = NULL;
	UInt32 numOfChannels = fileFormat.NumberChannels();
	UInt32 mapSize = numOfChannels * sizeof(SInt32);
	channelMap = (SInt32 *)malloc(mapSize);
	for (i=0; i < numOfChannels; i++)
	{
		channelMap[i] = i+1;
	}
	//channelMap[desiredInputChannel] = deviceOutputChannel;
	//channelMap[0] = 2;
	//channelMap[1] = 3;
	err = AudioUnitSetProperty(auOutput, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 1, channelMap, mapSize);
	if (err != noErr)
	{
		printf("Failed to set Audio Channel Map: %d\n", err);
	}
	else
	{
		printf("Set Audio Channel Map OK!\n");
	}

	// install overload listener to detect when something is wrong
	AudioUnit anAU;
	XThrowIfError (AUGraphNodeInfo(theGraph, fileNode, NULL, &anAU), "AUGraphNodeInfo");

	fileAU = CAAudioUnit (fileNode, anAU);
...



Debug Output:

bobis-mac-pro:Development bobi$ ./PlayFile ~/Downloads/English\ Small\ Business\ 3.mp3
playing file: /Users/bobi/Downloads/English Small Business 3.mp3
format: AudioStreamBasicDescription:  1 ch,  44100 Hz, '.mp3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1152 frames/packet, 0 bytes/frame
Device: Built-in Line Input
Device: Built-in Digital Input
Device: Built-in Output
Device: Built-in Line Output
Device: Built-in Digital Output
Device: PCI-424
Found the MOTU Audio Device ID
AUGraphNodeInfo: err = 0
Output Audio Unit: 810000
componentType: auou
componentSubType: ahal
componentManufacturer: appl
Output Scope Elements = 2
Audio Stream Format:
mSampleRate      : 44100.000000
mFormatID        : lpcm
mFormatFlags     : 0x29
mBytesPerPacket  : 4
mFramesPerPacket : 1
mBytesPerFrame   : 4
mChannelsPerFrame: 2
mBitsPerChannel  : 32
Failed to get output scope channel count: -10866
Failed to get size  of supported Channel Layout Tags: -10877
Failed to get supported Channel Layout Tags: -10879
Failed to set Audio Channel Layout: -10851
Set Audio Channel Map OK!
file duration: 672.208980 secs


Help!

Bob
 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Coreaudio-api mailing list      (email@hidden)
Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden

  • Follow-Ups:
    • Re: Output Channel Selection Redux
      • From: William Stewart <email@hidden>
  • Prev by Date: Re: Advice on audio file media protection?
  • Next by Date: 16 bit audio
  • Previous by thread: Re: how to unregister interuptListener registered in AudioSessionInitialize() on iPhone
  • Next by thread: Re: Output Channel Selection Redux
  • Index(es):
    • Date
    • Thread