I'm trying to use AudioUnit to play an ac3 stream in passthrough mode, but am getting kAudioFormatUnsupportedDataFormatError from AudioUnitInitialize().
Is kAudioFormatAC3 supported with AudioUnit on tvOS?
I'm trying to use AudioUnit to play an ac3 stream in passthrough mode, but am getting kAudioFormatUnsupportedDataFormatError from AudioUnitInitialize().
Is kAudioFormatAC3 supported with AudioUnit on tvOS?
Here is my code:
#define STREAM_FORMAT_MSG(pre, sfm) \
pre "[%f][%4.4s][%u][%u][%u][%u][%u][%u]", \
sfm.mSampleRate, (char *)&sfm.mFormatID, \
(unsigned int)sfm.mFormatFlags, (unsigned int)sfm.mBytesPerPacket, \
(unsigned int)sfm.mFramesPerPacket, (unsigned int)sfm.mBytesPerFrame, \
(unsigned int)sfm.mChannelsPerFrame, (unsigned int)sfm.mBitsPerChannel
static OSStatus RenderCallback(void *ref,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
return noErr;
}
- (BOOL)startAU{
AudioComponent au_component;
AudioUnit au_unit;
AudioComponentDescription desc;
AURenderCallbackStruct callback;
UInt32 i_param_size = 0;
OSStatus status;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_RemoteIO;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
au_component = AudioComponentFindNext(NULL, &desc);
if (au_component == NULL) {
NSLog(@"we cannot find our audio component");
return false;
}
status = AudioComponentInstanceNew(au_component, &au_unit);
if (status != noErr) {
NSLog(@"we cannot open our audio component (%i)", (int)status);
return false;
}
UInt32 flag = 1;
status = AudioUnitSetProperty(au_unit,
kAudioOutputUnitProperty_EnableIO,
kAudioUnitScope_Output,
0,
&flag,
sizeof(flag));
if (status != noErr)
NSLog(@"failed to set IO mode (%i)", (int)status);
AudioStreamBasicDescription streamDescription;
streamDescription.mFormatID = kAudioFormatAC3;
streamDescription.mSampleRate = 48000.0;
streamDescription.mFormatFlags = 0;
streamDescription.mChannelsPerFrame = 6;
streamDescription.mBytesPerFrame = 6144;
streamDescription.mFramesPerPacket = 1;
streamDescription.mBytesPerPacket = 0;
streamDescription.mBitsPerChannel = 0;
status = AudioUnitSetProperty(au_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&streamDescription,
sizeof(AudioStreamBasicDescription));
if (status != noErr) {
NSLog(@"failed to set stream format (%i)", (int)status);
return false;
}
NSLog(STREAM_FORMAT_MSG(@"we set the AU format: ", streamDescription));
i_param_size = sizeof(streamDescription);
status = AudioUnitGetProperty(au_unit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&streamDescription,
&i_param_size);
if (status != noErr)
NSLog(@"failed to verify stream format (%i)", (int)status);
NSLog(STREAM_FORMAT_MSG(@"the actual set AU format is " , streamDescription));
callback.inputProc = (AURenderCallback) RenderCallback;
callback.inputProcRefCon = NULL;
status = AudioUnitSetProperty(au_unit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0, &callback, sizeof(callback));
if (status != noErr) {
NSLog(@"render callback setup failed (%i)", (int)status);
return false;
}
status = AudioUnitInitialize(au_unit);
if (status != noErr) {
NSLog(@"failed to init AudioUnit (%@)", [[NSError errorWithDomain:NSOSStatusErrorDomain code:status userInfo:nil] description]);
return false;
}
return true;
}
}and the output:
2015-11-13 11:23:45.093 audiotest[51217:6038451] we set the AU format: [48000.000000][3-ca][0][0][1][6144][6][0]
2015-11-13 11:23:45.093 audiotest[51217:6038451] the actual set AU format is [48000.000000][3-ca][0][0][1][6144][6][0]
2015-11-13 11:23:45.156 audiotest[51217:6038451] failed to init AudioUnit (Error Domain=NSOSStatusErrorDomain Code=1718449215 "(null)")
Looks like that error is kAudioFormatUnsupportedDataFormatError.
See this for more info on your error.
http://stackoverflow.com/questions/4259078/osstatus-error-1718449215
Google is your friend. I googled your error and got many suggestions, like this one on hinting AC3:
I mentioned kAudioFormatUnsupportedDataFormatError in my original post and have googled it extensively. Most of the posts are from devs trying this on an iPhone, where AC3 is unimplemented and the error is expected.
However, the ATV4 supports AC3 so I'm trying to figure out the correct way to play an ac3 bitstream on this device.
Thanks. I would like to do this too. I'll take a hammer to it this weekend and see how far I can get.
I also tried kAudioFormat60958AC3 but got the same error. Did you have any luck?
I also tried to use AVAudioEngine to play an ac3 file, but am getting the same errors. I also found that setPreferredOutputNumberOfChannels on AVAudioSession does not work.
NSError *error = nil;
AVAudioSession *instance = [AVAudioSession sharedInstance];
[instance setCategory:AVAudioSessionCategoryPlayback error:&error];
[instance setActive:YES error:&error];
NSLog(@"output channels: %ld", (long)instance.outputNumberOfChannels);
NSLog(@"max channels: %ld", (long)instance.maximumOutputNumberOfChannels);
[instance setPreferredOutputNumberOfChannels:instance.maximumOutputNumberOfChannels error:&error];
NSLog(@"set preferred channels error: %@", error);
NSLog(@"output channels: %ld", (long)instance.outputNumberOfChannels);
NSURL *ac3URL = [NSBundle.mainBundle URLForResource:@"out" withExtension:@"ac3"];
AVAudioFile *file = [[AVAudioFile alloc] initForReading:ac3URL error:nil];
NSLog(@"file format: %@", file.fileFormat);
NSLog(@"processing format: %@", file.processingFormat);
AVAudioEngine *engine = [AVAudioEngine new];
AVAudioPlayerNode *player = [AVAudioPlayerNode new];
[engine attachNode:player];
AVAudioMixerNode *mixer = engine.mainMixerNode;
NSLog(@"mixer format: %@", [mixer outputFormatForBus:0]);
AVAudioOutputNode *output = engine.outputNode;
NSLog(@"output format: %@", [output outputFormatForBus:0]);
[engine connect:player to:mixer format:file.processingFormat];
[engine startAndReturnError:&error];
if (error) {
NSLog(@"engine could not start: %@", error);
return;
}
[player scheduleFile:file atTime:nil completionHandler:nil];
[player play];2015-11-18 20:52:01.958 audiotest[13537:1258644] output channels: 2
2015-11-18 20:52:01.959 audiotest[13537:1258644] max channels: 6
2015-11-18 20:52:01.959 audiotest[13537:1258644] set preferred channels error: (null)
2015-11-18 20:52:01.960 audiotest[13537:1258644] output channels: 2
2015-11-18 20:52:02.023 audiotest[13537:1258644] file format: <AVAudioFormat 0x7fafb3c1afb0: 6 ch, 48000 Hz, 'ac-3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1536 frames/packet, 0 bytes/frame>
2015-11-18 20:52:02.023 audiotest[13537:1258644] processing format: <AVAudioFormat 0x7fafb3c1b050: 6 ch, 48000 Hz, Float32, non-inter>
2015-11-18 20:52:02.099 audiotest[13537:1258644] mixer format: <AVAudioFormat 0x7fafb3e10200: 2 ch, 44100 Hz, Float32, non-inter>
2015-11-18 20:52:02.632 audiotest[13537:1258644] output format: <AVAudioFormat 0x7fafb3e10780: 2 ch, 44100 Hz, Float32, non-inter>
2015-11-18 20:52:02.665 audiotest[13537:1258644] 20:52:02.638 ERROR: AVAudioFile.mm:86: AVAudioFileImpl: error 1718449215
So far the only thing that works is using AVPlayer or AVAudioPlayer directly, which must be using some sort of new private/internal api that's different than AudioUnit and AVAudioEngine.
NSURL *ac3URL = [NSBundle.mainBundle URLForResource:@"out" withExtension:@"ac3"];
AVPlayer *player = [[AVPlayer alloc] initWithURL:ac3URL];
[player play];