How to use the CoreAudio API in Swift - ios

I am in the process of migrating my streaming audio engine to swift. i am finding it difficult to use the C Audio API in swift.
I have a problem with AudioFileStreamOpen api where it takes 2 C functions as a parameter. I don't know how to use this API is swift.
AudioFileStreamOpen(self as UnsafePointer<()>, propertyProc, packetProc, kAudioFileMP3Type, audioStreamId)
I have defined the callback method as below for this API. But i am getting the compilation error.
func propertyProc(inClientData: UnsafePointer<()>,inFileStreamId: AudioFileStreamID,inPropertyId: AudioFileStreamPropertyID,ioFlags: UnsafePointer<UInt32>) -> Void {
.....
}
func packetProc(inClientData: UnsafePointer<()>,inNumberOfBytes: UInt32,inNumberOfPackets: UInt32, ConstUnsafePointer<()>, inPacketDescriptions: UnsafePointer<AudioStreamPacketDescription>) -> Void {
.....
}
Any help is appreciated to correctly define this C API in swift

You can't (currently) use an API requiring a C callback pointer from pure Swift code. Calling Swift functions or methods using a C function pointer is not supported by the current beta 4 language implementation, according to replies in the Swift forum at devforums.apple.com
UPDATE: The above answer is obsolete as of Swift 2.0
One alternative is to put some small trampoline C callback functions in an Objective C file, which can interoperate with Swift, and have those C functions in turn call a block or closure, which can be in Swift code. Configure the C callbacks with your Swift closures, and then pass those C callbacks to the CoreAudio functions.

I don't know much about Audio API, however, you should replace UnsafePointer by a pointer to an Object. for example:
var clientData : AnyObject?
var listenerProc : AudioFileStream_PropertyListenerProc = AudioFileStream_PropertyListenerProc.convertFromNilLiteral()
var packetsProc : AudioFileStream_PacketsProc = AudioFileStream_PacketsProc.convertFromNilLiteral()
var audioFileTypyeId : AudioFileTypeID = 0
AudioFileStreamOpen(&clientData, listenerProc, packetsProc, audioFileTypyeId, &streamId)
the initialization code for listenerProc, packetsProc or other variables is just to by-pass the compiler error.
To your situation, try to replace 'self as UnsafePointer<>' by '&self'. However 'self' must be something that can be converted to compatible data type.
https://developer.apple.com/library/prerelease/ios/documentation/MusicAudio/Reference/AudioStreamReference/index.html#//apple_ref/c/func/AudioFileStreamOpen

Related

How to call a swift method which parameter is a protocol from Objective-C

How to call a swift method which parameter is a protocol from Objective-C.
Class A
{
func sendMessage<Serializable: Encodable>(message:Serializable){
let jsonData = try! JSONEncoder().encode(message)
}
}
Objective-C code
A a = [[A alloc] init];
[a sendMessage] ;// Not Available
How can I call this method from Objective-C.
I don't think sendMessage will ever appear in compiled TargetName-Swift.h because Generics and Encodable protocol is not available in Objective-C.
Clearly when you use
sendMessage<Serializable: Encodable>(message:Serializable)
You employ Generics as well as Encodable protocol which is only available in Swift not in Objective-C
When you try to access the Swift functions in your Objective-C files, compiler creates a Objective-C equivalent/ counterpart of your Swift functions hence you see the signature for those methods in your TargetName-Swift.h files.
But Generics and Encodable protocol are not available in Objective-C so it can't translate your Swift function using Generics and Encodable protocol to Objective-C equivalent. Hence You can never call such Swift methods from Objective-C files

Access object created in Objective C

We have an Objective C library that creates objects that are meant to be used in Swift code.
The function returns the object as an id. This is the declaration in Objective C header file (Clazz.h). The header file has been exposed in bridging header as required for interoperability.
+ (id)getObject;
The pointer returned is an instance of AVAssetWriter*. To access this API in Swift, I followed the steps in below post:
Objective-C pointer and swift
This is the Swift 3 code consumer code:
let obj = (Clazz.getObject() as! UnsafeMutableRawPointer).assumingMemoryBoundTo(to: AVAssetWriter.self).pointee
It built fine. However, when this code executes, the app seems to crash.
In Clazz.h, I declared the function as:
+ (AVAssetWriter*)getObject();
and tried to use it in Swift as,
let obj = Clazz.getObject() as AVAssetWriter
Code built fine but it failed when it was executed.
How do we access Objective C created objects in Swift?
Please note that I was able to inspect the value in swift code and the problem is not in bridging. Also, the memory location is not dangling.
By declaring obj variable as below, things worked
let obj:AVAssetWriter = Clazz.getObject() as AVAssetWriter

Call objective-c method from C library

I have a cross platform library written in C (.a) to do cryptographic stuff.
I use it that way on Android
+------------------------+ +-----------------+
| Android (Java) | | Android (Java) |
+------------------------+ +-----------------+
1.| /|\ 3.| /|\
\|/ 4.| \|/ 2.|
+------------------------------------------------------+
| myFramework.a (C) |
+------------------------------------------------------+
So the following function is called by Java, then call Java for something not related to the previous "context"
#ifdef __ANDROID__
#include "jni.h"
static JNIEnv *gEnv;
static jobject gObj;
int doStuff(char* aString) { /* have fun calling java */ }
#else
#include "oni.h" // objective c native interface ? :3
#endif
This function will use JNIEnv and jobject to access Java methods.
I have included the C library in the iOS project but can't find a way to call an objective-c method from the C library (part 2. and 3.)
How can I call an objective-c method from a C library?
Short answer: You can't. C can't invoke Objective-C methods.
That said, Objective-C is a pure superset of C, so you can write C functions in your Objective-C code. Those functions need to have a pure C interface, but internally they can contain Objective-C code. So you need to create a C public interface (Which can be implemented in a mix of C and Objective-C) and call that from your C library.
EDIT:
Actually, you could probably use the Objective-C runtime, which is written in C, to call the C interface to your Objective-C methods. I've dabbled with the Objective-C runtime, but not enough to know it fluently. (Plus I've worked mostly in Swift for long enough now that even my "vanilla" Objective-C is getting rusty.)
You can absolutely call Objective-C methods from C functions. To do so, however, you will need to make sure that your C function has a reference to an Objective-C object of some kind. Your example above doesn't show that.
So, you might write your function as:
int doStuff(id ref, char* aString) {
[ref objcMethod];
....
return 0;
}
Or maybe you would store the ref in static storage in your library, so that it was available to all functions, without passing it explicitly. It really depends on your use-case. Remember that Classes are objects, too, in Objective-C; so if you need ref to be a class (for a static methods), that can work, too.
There is a tangential topic. Sometimes, in Objective-C you want a direct reference to a method implementation so that you can invoke it directly. This is handy in tight loops, where performance is required. If this is your need, this blog post goes into the topic.

How to call objective-c function with double pointer parameter in swift

I have library written on objective c language. It has few methods that take double pointer parameters.
I'm trying to use it in project, that is using swift 2.0
let failedTextFields = AutoreleasingUnsafeMutablePointer<NSArray?>()
UITextField.checkAllFieldsIfIsValidOnView(self.view,
withMatchedFields: nil,
faildedFields: failedTextFields,
updateStates: updateState)
let isValid = failedTextFields.memory?.count > 0
(faildedFields is double pointer parameter)
But when it come to function, it detect, that passed parameter is nil. And because of this, the result is not initialised in function.
Can somebody help me? How can I call this function correctly in swift?

How to define a CGPatternDrawPatternCallback in swift

Im trying to create a CGPattern using callbacks however the following method signature is not of CGPatternDrawPatternCallback type and I can not determine what it should be
func patternDefinitionFunction(#info: UnsafeMutablePointer<Void>, c: CGContext?)
You can't do this in Swift 1.2 or earlier; you'd have to write this part of your code in Objective-C. To write a C function in Swift, you'll need to update to Swift 2.0 (available in the Xcode 7 beta currently).

Resources