iOS baresip with SIP Calling - ios

I am trying to develop an application which provides Audio and Video calling, Now I am following baresip library for the same.
and I wrote following code on button Click :
#IBAction func btnCallClick(_ sender: Any) {
guard libre_init() == 0 else { return }
// Initialize dynamic modules.
mod_init()
// Make configure file.
if let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
conf_path_set(path)
}
guard conf_configure() == 0 else { return }
// Initialize the SIP stack.
guard baresip_init(conf_config(), 0) == 0 else { return }
guard ua_init("SIP", 1, 1, 1, 0) == 0 else { return }
// Load modules.
guard conf_modules() == 0 else { return }
let addr = "sip:101#xxx.xxx.com:port;auth_pass=aaaa;transport=udp;answermode=auto"
// Start user agent.
guard ua_alloc(&agent, addr) == 0 else { return }
// Make an outgoing call.
guard ua_connect(agent, nil, nil, "sip:100#xxx.xxx.com", VIDMODE_OFF) == 0 else { return }
// Start the main loop.
re_main(nil)
}
Now, I am getting a call from one device to another device but it hangs my view, Why it's hanging view? I spent lots of time, anyone can help me?

I think the real problem is your re_main() function on the last line of the function. It is starting the loop execution of the thread. so untill an unless you call the re_cancel() function your execution of the process will remain in the thread.
Solution:
Putting your re_main() function on user initiated global thread will solve your problem. it will start all another process on user initiated global queue and the main thread will be free for your UI Interaction purpose.
DispatchQueue.global(qos: .userInitiated).async {
re_main(nil)
}

Related

Swift if condition fails

Swift if statement works fine on all other devices but the iPhone 4S with iOS 9.2.1.
This is the set of code I am using:
I am printing a bool value above, before applying the condition, and it prints 0, but the compiler jumps directly to the else part, failing the if statement.
print(NSNumber.init(value: socketListener!.isConnected)) //prints 0
if socketListener!.isConnected == false {
// skipped
} else {
// executed
}
I would suggest you go the long, but the correct one, by unwrapping your socket listener optional, or you can even go directly with the long unwrapping:
guard let isConnected = socketListener.isConnected else { return }
print(NSNumber.init(value: isConnected)) //prints 0
if isConnected == false {
// Your code
} else {
// Your code
}

objc_sync_enter / objc_sync_exit not working with DISPATCH_QUEUE_PRIORITY_LOW

I need a read\write lock for my application. I've read https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
and wrote my own class, cause there are no read/write lock in swift
class ReadWriteLock {
var logging = true
var b = 0
let r = "vdsbsdbs" // string1 for locking
let g = "VSDBVSDBSDBNSDN" // string2 for locking
func waitAndStartWriting() {
log("wait Writing")
objc_sync_enter(g)
log("enter writing")
}
func finishWriting() {
objc_sync_exit(g)
log("exit writing")
}
// ждет пока все чтение завершится чтобы начать чтение
// и захватить мютекс
func waitAndStartReading() {
log("wait reading")
objc_sync_enter(r)
log("enter reading")
b++
if b == 1 {
objc_sync_enter(g)
log("read lock writing")
}
print("b = \(b)")
objc_sync_exit(r)
}
func finishReading() {
objc_sync_enter(r)
b--
if b == 0 {
objc_sync_exit(g)
log("read unlock writing")
}
print("b = \(b)")
objc_sync_exit(r)
}
private func log(s: String) {
if logging {
print(s)
}
}
}
It works good, until i try to use it from GCD threads.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
When i try to use this class from different async blocks at some moment it allows to write when write is locked
here is sample log:
wait reading
enter reading
read lock writing
b = 1
wait reading
enter reading
b = 2
wait reading
enter reading
b = 3
wait reading
enter reading
b = 4
wait reading
enter reading
b = 5
wait reading
enter reading
b = 6
wait reading
enter reading
b = 7
wait reading
enter reading
b = 8
wait reading
enter reading
b = 9
b = 8
b = 7
b = 6
b = 5
wait Writing
enter writing
exit writing
wait Writing
enter writing
So, as you can see g was locked, but objc_sync_enter(g) allows to continue.
Why could this happen ?
BTW i checked how many times ReadWriteLock constructed, and it's 1.
Why objc_sync_exit not working and allowing to objc_sync_enter(g) when it's not freed ?
PS Readwirtelock defined as
class UserData {
static let lock = ReadWriteLock()
Thanks.
objc_sync_enter is an extremely low-level primitive, and isn't intended to be used directly. It's an implementation detail of the old #synchronized system in ObjC. Even that is extremely out-dated and should generally be avoided.
Synchronized access in Cocoa is best achieved with GCD queues. For example, this is a common approach that achieves a reader/writer lock (concurrent reading, exclusive writing).
public class UserData {
private let myPropertyQueue = dispatch_queue_create("com.example.mygreatapp.property", DISPATCH_QUEUE_CONCURRENT)
private var _myProperty = "" // Backing storage
public var myProperty: String {
get {
var result = ""
dispatch_sync(myPropertyQueue) {
result = self._myProperty
}
return result
}
set {
dispatch_barrier_async(myPropertyQueue) {
self._myProperty = newValue
}
}
}
}
All your concurrent properties can share a single queue, or you can give each property its own queue. It depends on how much contention you expect (a writer will lock the entire queue).
The "barrier" in "dispatch_barrier_async" means that it is the only thing allowed to run on the queue at that time, so all previous reads will have completed, and all future reads will be prevented until it completes. This scheme means that you can have as many concurrent readers as you want without starving writers (since writers will always be serviced), and writes are never blocking. On reads are blocking, and only if there is actual contention. In the normal, uncontested case, this is extremely very fast.
Are you 100% sure your blocks are actually executing on different threads?
objc_sync_enter() / objc_sync_exit() are guarding you only from object being accessed from different threads. They use a recursive mutex under the hood, so they won't either deadlock or prevent you from repeatedly accessing object from the same thread.
So if you lock in one async block and unlock in another one, the third block executed in-between can have access to the guarded object.
This is one of those very subtle nuances that is easy to miss.
Locks in Swift
You have to really careful what you use as a Lock. In Swift, String is a struct, meaning it's pass-by-value.
Whenever you call objc_sync_enter(g), you are not giving it g, but a copy of g. So each thread is essentially creating its own lock, which in effect, is like having no locking at all.
Use NSObject
Instead of using a String or Int, use a plain NSObject.
let lock = NSObject()
func waitAndStartWriting() {
log("wait Writing")
objc_sync_enter(lock)
log("enter writing")
}
func finishWriting() {
objc_sync_exit(lock)
log("exit writing")
}
That should take care of it!
In addition to #rob-napier's solution. I've updated this to Swift 5.1, added generic typing and a couple of convenient append methods. Note that only methods that access resultArray via get/set or append are thread safe, so I added a concurrent append also for my practical use case where the result data is updated over many result calls from instances of Operation.
public class ConcurrentResultData<E> {
private let resultPropertyQueue = dispatch_queue_concurrent_t.init(label: UUID().uuidString)
private var _resultArray = [E]() // Backing storage
public var resultArray: [E] {
get {
var result = [E]()
resultPropertyQueue.sync {
result = self._resultArray
}
return result
}
set {
resultPropertyQueue.async(group: nil, qos: .default, flags: .barrier) {
self._resultArray = newValue
}
}
}
public func append(element : E) {
resultPropertyQueue.async(group: nil, qos: .default, flags: .barrier) {
self._resultArray.append(element)
}
}
public func appendAll(array : [E]) {
resultPropertyQueue.async(group: nil, qos: .default, flags: .barrier) {
self._resultArray.append(contentsOf: array)
}
}
}
For an example running in a playground add this
//MARK:- helpers
var count:Int = 0
let numberOfOperations = 50
func operationCompleted(d:ConcurrentResultData<Dictionary<AnyHashable, AnyObject>>) {
if count + 1 < numberOfOperations {
count += 1
}
else {
print("All operations complete \(d.resultArray.count)")
print(d.resultArray)
}
}
func runOperationAndAddResult(queue:OperationQueue, result:ConcurrentResultData<Dictionary<AnyHashable, AnyObject>> ) {
queue.addOperation {
let id = UUID().uuidString
print("\(id) running")
let delay:Int = Int(arc4random_uniform(2) + 1)
for _ in 0..<delay {
sleep(1)
}
let dict:[Dictionary<AnyHashable, AnyObject>] = [[ "uuid" : NSString(string: id), "delay" : NSString(string:"\(delay)") ]]
result.appendAll(array:dict)
DispatchQueue.main.async {
print("\(id) complete")
operationCompleted(d:result)
}
}
}
let q = OperationQueue()
let d = ConcurrentResultData<Dictionary<AnyHashable, AnyObject>>()
for _ in 0..<10 {
runOperationAndAddResult(queue: q, result: d)
}
I had the same problem using queues in background. The synchronization is not working all the time in queues with "background" (low) priority.
One fix I found was to use semaphores instead of "obj_sync":
static private var syncSemaphores: [String: DispatchSemaphore] = [:]
static func synced(_ lock: String, closure: () -> ()) {
//get the semaphore or create it
var semaphore = syncSemaphores[lock]
if semaphore == nil {
semaphore = DispatchSemaphore(value: 1)
syncSemaphores[lock] = semaphore
}
//lock semaphore
semaphore!.wait()
//execute closure
closure()
//unlock semaphore
semaphore!.signal()
}
The function idea comes from What is the Swift equivalent to Objective-C's "#synchronized"?, an answer of #bryan-mclemore.

Signal that a network call inside a for-loop is done, then move onto the next item in the for loop?

How would I tell the for-loop to move on to the next item in the array in Swift?
for (key, value) in commentIds {
NetworkHelper.makeNetworkCall(key, completionHandler:{
//Tell current thread the for-loop is being called, to move on to the next item in the for loop?
}
}
I'm planning on having the for-loop in a dispatch_async thread, so it doesn't block the main thread.. Am I designing this wrong..? Should I have a flag?
edit
Flags in the main thread seem to work. Once the network call is done, flip the flag.
I would make the assumption that if the makeNetworkCall method takes a completionHandler parameter that it will be doing its work asynchronously. Given that, the for loop will call makeNetworkCall for every key in commentIds before any of them complete.
If you want to process them in series and not start the next one until the prior has finished, you will need to create an array of the keys and write some code like this:
var commentIdKeys: Array<KeyType>()?
var keyIndex: Int?
func startRequests() {
commentIdKeys = Array(commentIds.keys)
keyIndex = 0
processNextKey()
}
func processNextKey() {
guard let keys = commentIdKeys, let index = keyIndex else {
print("processNextKey() invoked without values set")
return
}
guard keyIndex < keys.count else {
commentIdKeys = nil
keyIndex = nil
print("Finished processing keys")
return
}
NetworkHelper.makeNetworkCall(key, completionHandler:{
// Do some work
self.keyIndex = ++index
self.processNextKey()
}
}

optimized way to search a device ip address within a range in iphone

I have situation where-in i have to search IP address of **router ** and I know only it's range is from range 163.289.2.0 to 163.289.2.255.
I know this is not good way to search.
for i in 1... 255 {
var str = "163.289.2." + "i"
var tempIP = Ping.getIPAddress(str)
if(tempIP == true)
{
break;
}
}
Now my problem is my custom class Ping.getIPAddress() takes 3 seconds to get the result for a given IP value. So for 255 searches it takes approx 765 seconds (12.75 minutes). I have restriction that search should complete in max 2 minutes. So is there anyway i can achieve this in iPhone using swift.
I must use only this custom function Ping.getIPAddress() which gives true if given IP address exists else false.
Please provide me example or reference or approach to solve this issue .
Using NSOperationQueue with MaxConcurrentOperationCount set to 10 will be good ?
Synchronous approach
If we perform each call to Ping.getIPAddress(str) only after the previous one has completed of course we need to wait for (3 seconds * 256) = 768 seconds.
Asynchronous approach
On the other hand we can perform several concurrent calls to Ping.getIPAddress(str).
The fake Ping class
This is a class I created to test your function.
class Ping {
class func getIPAddress(str:String) -> Bool {
sleep(3)
return str == "163.289.2.255"
}
}
As you see the class does wait for 3 seconds (to simulate your scenario) and then returns true only if the passed ip is 163.289.2.255. This allows me to replicated the worst case scenario.
Solution
This is the class I prepared
class QuantumComputer {
func search(completion:(existingIP:String?) -> ()) {
var resultFound = false
var numProcessed = 0
let serialQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL)
for i in 0...255 {
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0)) {
var ip = "163.289.2." + "\(i)"
let foundThisOne = Ping.getIPAddress(ip)
dispatch_async(serialQueue) {
if !resultFound {
resultFound = foundThisOne
numProcessed++
if resultFound {
completion(existingIP:ip)
} else if numProcessed == 256 {
completion(existingIP: nil)
}
}
}
}
}
}
}
The class performs 256 asynchronous calls to Ping.getIPAddress(...).
The results from the 256 async closures is processed by this code:
dispatch_async(serialQueue) {
if !resultFound {
resultFound = foundThisOne
numProcessed++
if resultFound {
completion(existingIP:ip)
} else if numProcessed == 256 {
completion(existingIP: nil)
}
}
}
The previous block of code (from line #2 to #9) is executed in my queue serialQueue. Here the 256 distinct closures run synchronously.
this is crucial to ensure a consistent access to the variables resultFound and numProcessed;
on the other hand this is not a problem by a performance point of view since this code is pretty fast (just a bunch of arithmetic operations)
Test
And this is how I call it from a standard ViewController.
class ViewController: UIViewController {
var computer = QuantumComputer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
debugPrintln(NSDate())
computer.search { (existingIP) -> () in
debugPrintln("existingIP: \(existingIP)")
debugPrintln(NSDate())
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Conclusions
Finally this is the output when I test it on my iOS simulator. Please remind that this is the worst case scenario (since the last checked number is a valid IP).
2015-09-04 20:56:17 +0000
"existingIP: Optional(\"163.289.2.255\")"
2015-09-04 20:56:29 +0000
It's only 12 seconds!
Hope this helps.

Completion Block seemingly being ignored

So I have a function with a completion block that handles animation and a function calling that function. During the function call the completion block is seemingly skipped over because no print lines are printed. I have tried putting the code to be executed into the main queue but it has not yielded any results. Here is how I'm calling the function:
runAnimations(past.count, currentIteration: 0, animationsArray: past, completion: {
finished in
var randomr = self.randomInRange(0,hi: 3)
println("sell")
past.append(randomr)
for i in past123{
if(past.count >= 10){
}
else{
// have tried with and without dispatch_async.. neither print little did I know
dispatch_async(dispatch_get_main_queue()) {
println("little did I know")
self.incrementGame(past)
}
}
}
})
I know it is not an issue with the past.count if statement because the sell print line is not executed either. A breakpoint at the function call simply shows it skipping over however I am aware this is due to it being in an async thread.
Here is the code for runAnimations function:
func runAnimations(numberToIterate:Int, currentIteration:Int, animationsArray : [Int], completion: ((Bool) -> Void)?) {
UIView.animateWithDuration(1, animations: {
if(animationsArray[currentIteration] == 0){
self.label.text="circle!"
//self.label.alpha = 0.0
}
else if(animationsArray[currentIteration] == 1){
self.label.text="square!"
//self.label.alpha = 0.0
}
else if(animationsArray[currentIteration] == 2){
self.label.text="triangle!"
//self.label.alpha = 0.0
}
else if(animationsArray[currentIteration] == 3){
self.label.text="star!"
//self.label.alpha = 0.0
}
}, completion: {
finished in
println("BRO")
if(currentIteration+1>=numberToIterate){
self.label.alpha = 1.0
println("ook")
}
else{
println("okies")
self.runAnimations(numberToIterate, currentIteration: currentIteration+1, animationsArray: animationsArray, completion: { finished in
})
//self.runAnimations(numberToIterate, currentIteration: currentIteration+1, animationsArray: animationsArray)
}
})
The prints in runAnimation execute properly.
You actually have to call the completion block, which you haven't done by doing
completion(finished)
The completion block you defined can be seen as a separate method, which you need to call. In your case you have left your block as an optional so you must do optional checking as per the standard (completion != nil, etc)
This is a very "swift" guide on a completion block in swift, which is now called a closure. Take a look: here

Resources