ExtAudioFileRead crash with code -40 - core-audio

My app plays music in background. I have audio key on in Background modes, my audio session looks like:
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *err = NULL;
[audioSession setCategory:AVAudioSessionCategoryPlayback error:&err];
if( err ){
NSLog(#"There was an error creating the audio session");
}
[audioSession setMode:AVAudioSessionModeDefault error:&err];
if( err ){
NSLog(#"There was an error setting mote to the audio session");
}
[[AVAudioSession sharedInstance] setActive:YES error:&err];
if( err ){
NSLog(#"There was an error setting mote to the audio session");
}
I'm playing via AUGraph which is configured with 2 nodes: Remote I/O and Mixer:
AudioComponentDescription outputcd;
outputcd.componentFlags = 0;
outputcd.componentFlagsMask = 0;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
outputcd.componentSubType = kAudioUnitSubType_RemoteIO;
outputcd.componentType = kAudioUnitType_Output;
// Multichannel mixer unit
AudioComponentDescription MixerUnitDescription;
MixerUnitDescription.componentType = kAudioUnitType_Mixer;
MixerUnitDescription.componentSubType = kAudioUnitSubType_AU3DMixerEmbedded;
MixerUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
MixerUnitDescription.componentFlags = 0;
MixerUnitDescription.componentFlagsMask = 0;
Also according to Technical QA I added
UInt32 maxFPS = 4096;
AudioUnitSetProperty(_mixerUnit, kAudioUnitProperty_MaximumFramesPerSlice,kAudioUnitScope_Global, 0, &maxFPS,sizeof(maxFPS));
But still no luck, my app keeps crashing on ExtAudioFileRead in Render callback function approx 10 seconds as i lock iPhone. Any suggestions?
Important to mention this bug is not reproduced on ios 7.

The issue was with Data Protection enabled in app capabilities. So as device was locked, files got encrypted and could not be played in background. Hence the crash.
Changing encryption properties for audio files fixes this issue.

Related

Monitor changes on Thunderbolt port connection

I am working on a requirement where i need to monitor changes in Thunderbolt port connection. (When Thunderbolt cable is connected or disconnected).
I tried to use IOServiceMatching(kIOUSBInterfaceClassName) from IOKit framework but i cannot monitor changes on Thunderbolt port.
Is there any way i can achieve it? Any help is appreciated.
Thunderbolt devices (except displays that use the DisplayPort portion of the Thunderbolt port) are PCI devices, not USB, so they will show up in the IOService registry as IOPCIDevices. They will however also show up as IOThunderboltPort objects in the Thunderbolt subtree, where the "PCI Path" property will indicate the IOService path to the relevant IOPCIDevice. By monitoring the appearance and disappearance of IOThunderboltPort services, and checking their PCI Path property, you can avoid matching other kinds of PCI devices.
To illustrate what I'm talking about, open up IORegistryExplorer or IOJones and hotplug a Thunderbolt device; you should see both the IOThunderboltPort (and a bunch of other types of related object, such as AppleThunderboltPCIUpAdapter etc.) and the IOPCIDevice (as well as the PCI2PCI bridges via which the Thunderbolt bus works) appear. (Alternatively you can use ioreg to take snapshots before and after the hotplug.)
So in summary, I would match IOThunderboltPort services, ignore any without a PCI path property, and look up the corresponding IOPCIDevice in the IO Registry for the ones that have it to get to the actual device.
Finally i figured out a way indeed to monitor Thunderbolt Connection. Thanks to the apple tech guy who pointed me out in a right direction.
Monitoring the I/O Registry for IOEthernetInterface entries.  It’s relatively easy to filter out Thunderbolt networking (I’m not sure what the best option is, but an easy option is to look for “ThunderboltIP” in the “IOModel” property of the parent IOEthernetController). This was the response from one of the Tech guys from apple on Apple forum. Using the above info i wrote a piece of code which will return you the status of Thunderbolt port.
#include <IOKit/network/IOEthernetController.h>
- (void) monitorThunderboltConnection
{
CFMutableDictionaryRef matchingDict;
io_iterator_t iter;
io_object_t controllerService;
kern_return_t kr;
UInt8 MACAddress[kIOEthernetAddressSize];
QNInterfaceModel *interfaceModel = [[QNInterfaceModel alloc] initWithInterfaceModel];
/* set up a matching dictionary for the class */
matchingDict = IOServiceMatching(kIOEthernetInterfaceClass);
if (matchingDict == NULL)
{
NSLog(#"Failed");
return;
}
/* Now we have a dictionary, get an iterator.*/
kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
if (kr == kIOReturnSuccess)
{
// Actually iterate through the found devices.
io_registry_entry_t serviceObject;
while ((serviceObject = IOIteratorNext(iter)))
{
// Put this services object into a dictionary object.
kr = IORegistryEntryGetParentEntry(serviceObject,
kIOServicePlane,
&controllerService);
if (KERN_SUCCESS != kr)
{
printf("IORegistryEntryGetParentEntry returned 0x%08x\n", kr);
}
else
{
CFMutableDictionaryRef serviceDictionary;
CFTypeRef networkType;
CFTypeRef MACAddressAsCFData;
NSNumber *linkStatus;
if (IORegistryEntryCreateCFProperties(serviceObject,
&serviceDictionary,
kCFAllocatorDefault,
kNilOptions) == kIOReturnSuccess)
{
networkType = IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOModel),
kCFAllocatorDefault,
0);
if(networkType)
{
if (CFGetTypeID(networkType) == CFStringGetTypeID())
{
CFStringRef networkName = networkType;
interfaceModel.interfaceName = (__bridge NSString *)networkName;
}
CFRelease(networkType);
}
if([interfaceModel.interfaceName isEqualToString:#"ThunderboltIP"])
{
MACAddressAsCFData = IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOMACAddress),
kCFAllocatorDefault,
0);
if (MACAddressAsCFData)
{
CFShow(MACAddressAsCFData); // for display purposes only; output goes to stderr
// Get the raw bytes of the MAC address from the CFData
CFDataGetBytes(MACAddressAsCFData, CFRangeMake(0, kIOEthernetAddressSize), MACAddress);
if (KERN_SUCCESS != kr)
{
printf("GetMACAddress returned 0x%08x\n", kr);
}
else
{
interfaceModel.macAddress = [[NSString stringWithFormat:#"%02x:%02x:%02x:%02x:%02x:%02x",MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3], MACAddress[4], MACAddress[5]] uppercaseString];
}
CFRelease(MACAddressAsCFData);
}
linkStatus = (__bridge NSNumber *)(IORegistryEntryCreateCFProperty(controllerService,
CFSTR(kIOLinkStatus),
kCFAllocatorDefault,
0));
if (linkStatus)
{
NSLog(#"%#", [linkStatus stringValue]);
if([linkStatus integerValue] == 3) // Thunderbolt IP is Connnected
{
interfaceModel.connectedStatus = YES;
}
else
{
interfaceModel.connectedStatus = NO;
}
}
CFStringRef bsdName = ( CFStringRef ) IORegistryEntrySearchCFProperty (controllerService,
kIOServicePlane,
CFSTR ( kIOBSDNameKey ),
kCFAllocatorDefault,
kIORegistryIterateRecursively);
interfaceModel.interfaceName = (__bridge NSString *) bsdName;
if(interfaceModel.connectedStatus == YES)
{
NSLog(#"Connected");
}
else
{
NSLog(#"DisConnected");
}
}
// Failed to create a service dictionary, release and go on.
IOObjectRelease(serviceObject);
// Done with the parent Ethernet controller object so we release it.
(void) IOObjectRelease(controllerService);
continue;
}
}
}
}
/* Done, release the iterator */
IOObjectRelease(iter);
}
NOTE: I am using Interface model to collect all the thunderbolt info like Hardware Address, BSD Name, Link Status etc. You also need add I/O Kit framework to your project.

Merge video is not working in iOS app

I have working on merge video functionality.
In my application I have one video with multiple tracks (total 10 tracks 9 video tracks and one audio track is common ).
Now I want to get 3 video from this multiple Tracks.
First video is combine with 1,4,7 track and
Second video is combine with 2,5,8 track and
Third video is combine with 3,6,9 track and
and Audio track is common for this three video.
I want to do this using following code.
AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:urlSubItem.path]];
NSLog(#"%#",playerItem);
NSArray* arrTracks = [playerItem.asset tracksWithMediaType:AVMediaTypeVideo];
NSLog(#"%#",arrTracks);
NSArray* arrTracksText = [playerItem.asset tracksWithMediaType:AVMediaTypeText];
NSArray* arrTracksAudio = [playerItem.asset tracksWithMediaType:AVMediaTypeAudio];
NSLog(#"%#:%#",arrTracks,arrTracksAudio);
for (int i=0; i<3; i++) {
AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionCommentaryTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, playerItem.asset.duration) ofTrack:[[playerItem.asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
CMTime currentTime = kCMTimeZero;
for (int k=0;k<[arrTracks count];k++) {
NSLog(#"%d",k%3);
if(k%3==i){
AVAssetTrack* trackCombineVideo = [arrTracks objectAtIndex:k];
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
NSError* errors;
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(currentTime, trackCombineVideo.timeRange.duration) ofTrack:[arrTracks objectAtIndex:k] atTime:currentTime error:&errors];
if (errors) {
NSLog(#"wait error:%#",errors);
}
currentTime = trackCombineVideo.timeRange.duration;
}
}
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetPassthrough];
_assetExport.outputFileType = #"com.apple.quicktime-movie";
NSLog(#"file type %#",_assetExport.outputFileType);
_assetExport.outputURL = exportUrl // Document Directory Path;
_assetExport.shouldOptimizeForNetworkUse = YES;
Using this code 3 separate video is create but each video have a 3 different track.
Now, my question is how to create video with only one track ?
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition
addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
for (int k=0;k<[arrTracks count];k++) {
NSLog(#"%d",k%3);
if(k%3==i){
AVAssetTrack* trackCombineVideo = [arrTracks objectAtIndex:k];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(currentTime, trackCombineVideo.timeRange.duration) ofTrack:[arrTracks objectAtIndex:k] atTime:currentTime error:&errors];
if (errors) {
NSLog(#"wait error:%#",errors);
}
currentTime = trackCombineVideo.timeRange.duration;
}
}
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPreset1280x720];
_assetExport.outputFileType = #"com.apple.quicktime-movie";
NSLog(#"file type %#",_assetExport.outputFileType);
_assetExport.outputURL = exportUrl // Document Directory Path;
_assetExport.shouldOptimizeForNetworkUse = YES;
_assetExport.timeRange = CMTimeRangeMake(kCMTimeZero, playerItem.asset.duration);

Audio Units: getting generated audio into a render callback

I've been trying without success to manipulate the samples produced by kAudioUnitType_Generator audio units by attaching an AURenderCallbackStruct to the input of the audio unit right after. I managed to get this working on OS X using the following simple graph:
(input callback) -> multichannel mixer -> (intput callback) -> default output
But I've failed with the following (even simpler) graphs that start with a generator unit:
speech synthesis -> (intput callback) -> default output | fails in render callback with kAudioUnitErr_Uninitialized
audiofile player -> (intput callback) -> default output | fails when scheduling file region with kAudioUnitErr_Uninitialized
I've tried just about everything I can think of, from setting ASBD format to sample rates, but I always get these errors. Does anyone know how to setup a graph where we can manipulate samples from these nice generator units?
Below is the failing render callback function and graph instantiation method for the attempt using speech synthesis. The audiofile player is almost identical for this, except setting up the file playback, of course. Both of these setups work if I remove the callback and add an AUGraphConnectNodeInput in it's place...
static OSStatus RenderCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
AppDelegate *app = (AppDelegate *)inRefCon;
AudioUnit inputUnit = app->_speechUnit;
OSStatus status = noErr;
status = AudioUnitRender(inputUnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);
// *** ERROR *** kAudioUnitErr_Uninitialized, code: -10867
// ... insert processing code here...
return status;
}
- (int)createSynthGraph {
AUGRAPH_CHECK( NewAUGraph( &_graph ) );
AUNode speechNode, outputNode;
// speech synthesizer
AudioComponentDescription speechCD = {0};
speechCD.componentType = kAudioUnitType_Generator;
speechCD.componentSubType = kAudioUnitSubType_SpeechSynthesis;
speechCD.componentManufacturer = kAudioUnitManufacturer_Apple;
// output device (speakers)
AudioComponentDescription outputCD = {0};
outputCD.componentType = kAudioUnitType_Output;
outputCD.componentSubType = kAudioUnitSubType_DefaultOutput;
outputCD.componentManufacturer = kAudioUnitManufacturer_Apple;
AUGRAPH_CHECK( AUGraphAddNode( _graph, &outputCD, &outputNode ) );
AUGRAPH_CHECK( AUGraphAddNode( _graph, &speechCD, &speechNode ) );
AUGRAPH_CHECK( AUGraphOpen( _graph ) );
AUGRAPH_CHECK( AUGraphNodeInfo( _graph, outputNode, NULL, &_outputUnit ) );
AUGRAPH_CHECK( AUGraphNodeInfo( _graph, speechNode, NULL, &_speechUnit ) );
// setup stream formats:
AudioStreamBasicDescription streamFormat = [self streamFormat];
AU_CHECK( AudioUnitSetProperty( _speechUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, sizeof(streamFormat) ) );
// setup callback:
AURenderCallbackStruct callback;
callback.inputProc = RenderCallback;
callback.inputProcRefCon = self;
AUGRAPH_CHECK( AUGraphSetNodeInputCallback ( _graph, outputNode, 0, &callback ) );
// init and start
AUGRAPH_CHECK( AUGraphInitialize( _graph ) );
AUGRAPH_CHECK( AUGraphStart( _graph ) );
return 0;
}
You must connect these nodes together with AUGraphConnectNodeInput. The AUGraph will not initialize AudioUnits within it unless they are connected. Units in a graph that are not connected to other units will not be initialized.
You could also try manually initing them before starting the graph.
kAudioUnitErr_Uninitialized error appears when your audio unit is not initialized. Just initialize your graph before setting problem properties. This will initialize all opened audio units in graph. From AUGraphInitialize discussion in AUGraph.h:
AudioUnitInitialize() is called on each opened node/AudioUnit
(get ready to render) and SubGraph that are involved in a
interaction.

Getting the position of my application's dock icon using Cocoa's Accessibility API

How can I get the position of my application's dock icon using the Accessibility API?
Found it! Using this forum post as reference, I was able to shape the given sample code to what I needed:
- (NSArray *)subelementsFromElement:(AXUIElementRef)element forAttribute:(NSString *)attribute
{
NSArray *subElements = nil;
CFIndex count = 0;
AXError result;
result = AXUIElementGetAttributeValueCount(element, (CFStringRef)attribute, &count);
if (result != kAXErrorSuccess) return nil;
result = AXUIElementCopyAttributeValues(element, (CFStringRef)attribute, 0, count, (CFArrayRef *)&subElements);
if (result != kAXErrorSuccess) return nil;
return [subElements autorelease];
}
- (AXUIElementRef)appDockIconByName:(NSString *)appName
{
AXUIElementRef appElement = NULL;
appElement = AXUIElementCreateApplication([[[NSRunningApplication runningApplicationsWithBundleIdentifier:#"com.apple.dock"] lastObject] processIdentifier]);
if (appElement != NULL)
{
AXUIElementRef firstChild = (__bridge AXUIElementRef)[[self subelementsFromElement:appElement forAttribute:#"AXChildren"] objectAtIndex:0];
NSArray *children = [self subelementsFromElement:firstChild forAttribute:#"AXChildren"];
NSEnumerator *e = [children objectEnumerator];
AXUIElementRef axElement;
while (axElement = (__bridge AXUIElementRef)[e nextObject])
{
CFTypeRef value;
id titleValue;
AXError result = AXUIElementCopyAttributeValue(axElement, kAXTitleAttribute, &value);
if (result == kAXErrorSuccess)
{
if (AXValueGetType(value) != kAXValueIllegalType)
titleValue = [NSValue valueWithPointer:value];
else
titleValue = (__bridge id)value; // assume toll-free bridging
if ([titleValue isEqual:appName]) {
return axElement;
}
}
}
}
return nil;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
AXUIElementRef dockIcon = [self appDockIconByName:#"MYAPPNAME"];
if (dockIcon) {
CFTypeRef value;
CGPoint iconPosition;
AXError result = AXUIElementCopyAttributeValue(dockIcon, kAXPositionAttribute, &value);
if (result == kAXErrorSuccess)
{
if (AXValueGetValue(value, kAXValueCGPointType, &iconPosition)) {
NSLog(#"position: (%f, %f)", iconPosition.x, iconPosition.y);
}
}
}
}
As for Mac OS El Capitan, looks like you aren't supposed to get the position of the icon using Accessibility API. The matter is that the icon isn't located in accessibility objects hierarchy of the app—it can be found in the hierarchy of the system Dock application. A sandboxed app isn't supposed to access the accessibility objects of other apps.
The code in approved answer doesn't yield any warnings of the sandboxd daemon in the console, looks like it doesn't violate any rules. It creates the top-level accessibility object with the function AXUIElementCreateApplication. The documentation states, that it:
Creates and returns the top-level accessibility object for the
application with the specified process ID.
Unfortunately, this top-level object is not the ancestor of the Dock icon.
I've tried to run the code, and it calculates the position of the first app's main menu item (which has the same title as the app itself). The comparison takes place in this line:
if ([titleValue isEqual:appName]) {
So the output was always the same for my app:
position: (45.000000, 0.000000)
An attempt to access the other app's accessibility object yielded a warning in console. I guess another way to calculate the position of the icon has to be found.

Can't edit IORegistryEntry

I am creating a software on Mac and I would like to change the value of an IORegistryEntry. I can view it on the IORegistryExplorer, but I can't edit it. So it's my understanding that I have to edit it via code. Here is my code:
CFMutableDictionaryRef matchingDict = IOServiceNameMatching("AppleUSBMultitouchDriver");
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
if(service) {
CFStringRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("Manufacturer"), kCFAllocatorDefault,0);
NSLog(#"%#", (NSString*)manufacturer);
kern_return_t err = IORegistryEntrySetCFProperty(service, CFSTR("Manufacturer"), CFSTR("test"));
NSLog(#"error = %d", err);
}
This will output
2010-04-10 16:09:09.015 Test[41548:a0f] Apple Inc.
2010-04-10 16:09:09.015 Test[41548:a0f] error = 0
But after I check the value in the IORegistryExplorer, it still doesn't change. Does anybody have any suggestions?
Thank you
In order for this to be possible, usually the driver for the particular hardware you're changing has to implement setProperties() (in IOKit) that makes this change for you.
It's unlikely that Apple will implement setProperty() in their AppleUSBMultitouchDriver in a way that allows you to change the manufacturer name. They want to specify what kind of fruit they are. ;)
Use IOConnectSetCFProperties instead of IORegistryEntrySetCFProperty. Pass it a dictionary with the settings you want to set.
For example to turn off three finger swipe to navigate, call it with a dictionary containing { TrackpadThreeFingerSwipe = 0; }
This is example how to change trackpad settings properly. Trackpad.prefpane do exactly this, but also save this setting somewhere in defaults (if you will not find out where exactly, ask here about it).
P.S. getEVSHandle() may be found in MachineSettings.framework.
P.P.S. Checked only on 10.5 & 10.6.
NSInteger zero = 0, one = 1;
CFNumberRef _numberWith0 = CFNumberCreate(kCFAllocatorDefault, kCFNumberNSIntegerType, &zero);
CFNumberRef _numberWith1 = CFNumberCreate(kCFAllocatorDefault, kCFNumberNSIntegerType, &one);
CFMutableDictionaryRef propertyDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, NULL, NULL);
CFDictionarySetValue(propertyDict, #"TrackpadThreeFingerSwipe", flag ? _numberWith1 : _numberWith0);
io_connect_t connect = getEVSHandle();
if (!connect)
{
// error
}
kern_return_t status = IOConnectSetCFProperties(connect, propertyDict);
if (status != KERN_SUCCESS)
{
//error
}
CFRelease(propertyDict);

Resources