├── .gitignore ├── BelledonneRTP.podspec ├── BelledonneSIP.podspec ├── BelledonneToolbox.podspec ├── FakeServer ├── audio_in.pcap ├── audio_in.pcapng ├── audio_out.pcap ├── audio_out.pcapng ├── server.py ├── video_in.pcap ├── video_in.pcapng ├── video_out.pcap └── video_out.pcapng ├── LICENSE ├── LinPhoneSwift.podspec ├── MediaStreamer.podspec ├── Package.swift ├── README.md ├── Sources ├── BelledonneRTP │ ├── Data.swift │ ├── Handle.swift │ ├── Log.swift │ ├── Packet.swift │ └── Queue.swift ├── BelledonneSIP │ ├── Handle.swift │ ├── Object.swift │ ├── ObjectHandle.swift │ ├── URI.SIP.swift │ └── URI.swift ├── BelledonneToolbox │ ├── Bool.swift │ ├── Handle.swift │ └── LinkedList.swift ├── LinPhone │ ├── Address.swift │ ├── Bool.swift │ ├── Call.swift │ ├── CallLog.swift │ ├── CallParameters.swift │ ├── CallStats.swift │ ├── Conference.swift │ ├── Configuration.swift │ ├── Core.swift │ ├── Enumeration.swift │ ├── ErrorInfo.swift │ ├── Factory.swift │ ├── Handle.swift │ ├── Internal.swift │ ├── MediaEncryption.swift │ ├── ObjectHandle.swift │ ├── PayloadType.swift │ ├── Reason.swift │ ├── RegistrationState.swift │ ├── SipTransports.swift │ ├── StreamType.swift │ ├── Transport.swift │ ├── Tunnel.swift │ └── VideoPolicy.swift └── MediaStreamer │ ├── BitMaskOption.swift │ ├── Bool.swift │ ├── Enumeration.swift │ ├── EventQueue.swift │ ├── Factory.swift │ ├── Filter.swift │ ├── FilterCategory.swift │ ├── FilterDescription.swift │ ├── FilterFlag.swift │ ├── FilterInterface.swift │ ├── FilterMethod.swift │ ├── Handle.swift │ ├── ManagedCString.swift │ ├── Queue.swift │ └── RFC3984.swift ├── Tests ├── BelledonneRTPTests │ └── Tests.swift ├── BelledonneSIPTests │ └── URITests.swift ├── BelledonneToolboxTests │ └── LinkedListTests.swift ├── LinPhoneTests │ ├── AddressTests.swift │ ├── CoreTests.swift │ └── InternalTests.swift ├── LinuxMain.swift └── MediaStreamerTests │ ├── FactoryTests.swift │ └── FilterTests.swift └── Xcode ├── LinPhone.xcodeproj ├── BelledonneRTP-Info.plist ├── BelledonneRTPTests-Info.plist ├── BelledonneSIP-Info.plist ├── BelledonneSIPTests-Info.plist ├── BelledonneToolbox-Info.plist ├── BelledonneToolboxTests-Info.plist ├── LinPhoneSwift-Info.plist ├── LinPhoneTests-Info.plist ├── MediaStreamer-Info.plist ├── MediaStreamerTests-Info.plist ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── BelledonneRTP iOS.xcscheme │ ├── BelledonneRTP macOS.xcscheme │ ├── BelledonneSIP iOS.xcscheme │ ├── BelledonneSIP macOS.xcscheme │ ├── BelledonneToolbox iOS.xcscheme │ ├── BelledonneToolbox macOS.xcscheme │ ├── LinPhoneSwift iOS.xcscheme │ ├── LinPhoneSwift macOS.xcscheme │ ├── MediaStreamer iOS.xcscheme │ ├── MediaStreamer macOS.xcscheme │ └── xcschememanagement.plist └── Modules ├── CBelledonneRTP └── module.modulemap ├── CBelledonneSIP └── module.modulemap ├── CBelledonneToolbox └── module.modulemap ├── CLinPhone └── module.modulemap └── CMediaStreamer2 └── module.modulemap /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | 69 | # Linphone SDK 70 | liblinphone-sdk/* 71 | 72 | # Linphone SDK headers 73 | Xcode/Modules/CBelledonneToolbox/bctoolbox 74 | Xcode/Modules/CBelledonneRTP/ortp 75 | Xcode/Modules/CBelledonneSIP/belle-sip 76 | Xcode/Modules/CMediaStreamer2/mediastreamer2 77 | Xcode/Modules/CLinPhone/linphone 78 | -------------------------------------------------------------------------------- /BelledonneRTP.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'BelledonneRTP' 3 | s.version = '1.0.0' 4 | s.summary = 'Linphone for Swift' 5 | s.license = 'MIT' 6 | s.authors = { "Alsey Coleman Miller" => "colemancda.github.io" } 7 | s.homepage = 'http://github.com/coleman/LinPhoneSwift' 8 | s.description = 'Swift library for Linphone' 9 | s.requires_arc = true 10 | s.ios.deployment_target = '8.0' 11 | s.osx.deployment_target = '10.10' 12 | s.source = { :path => '*' } 13 | s.source_files = 'Sources/BelledonneRTP/*.swift' 14 | s.ios.vendored_frameworks = '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/*.framework' 15 | s.ios.xcconfig = { 16 | 'ENABLE_BITCODE' => 'NO', 17 | 'SWIFT_INCLUDE_PATHS' => '$SRCROOT/../liblinphone-sdk/Modules/CBelledonneRTP $SRCROOT/../liblinphone-sdk/Modules/CBelledonneToolbox', 18 | 'FRAMEWORK_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/Frameworks', 19 | 'LIBRARY_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/lib', 20 | 'OTHER_LDFLAGS' => '-framework ortp -framework bctoolbox' 21 | } 22 | s.dependency 'BelledonneToolbox' 23 | end -------------------------------------------------------------------------------- /BelledonneSIP.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'BelledonneSIP' 3 | s.version = '1.0.0' 4 | s.summary = 'Linphone for Swift' 5 | s.license = 'MIT' 6 | s.authors = { "Alsey Coleman Miller" => "colemancda.github.io" } 7 | s.homepage = 'http://github.com/coleman/LinPhoneSwift' 8 | s.description = 'Swift library for Linphone' 9 | s.requires_arc = true 10 | s.ios.deployment_target = '8.0' 11 | s.osx.deployment_target = '10.10' 12 | s.source = { :path => '*' } 13 | s.source_files = 'Sources/BelledonneSIP/*.swift' 14 | s.ios.vendored_frameworks = '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/Frameworks/*.framework' 15 | s.ios.xcconfig = { 16 | 'ENABLE_BITCODE' => 'NO', 17 | 'SWIFT_INCLUDE_PATHS' => '$SRCROOT/../liblinphone-sdk/Modules/CBelledonneSIP $SRCROOT/../liblinphone-sdk/Modules/CBelledonneToolbox', 18 | 'FRAMEWORK_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/Frameworks', 19 | 'LIBRARY_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/lib', 20 | 'OTHER_LDFLAGS' => '-framework bctoolbox -lbellesip -lantlr3c' 21 | } 22 | s.ios.library = 'z', 'resolv' 23 | s.dependency 'BelledonneToolbox' 24 | end -------------------------------------------------------------------------------- /BelledonneToolbox.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'BelledonneToolbox' 3 | s.version = '1.0.0' 4 | s.summary = 'Linphone for Swift' 5 | s.license = 'MIT' 6 | s.authors = { "Alsey Coleman Miller" => "colemancda.github.io" } 7 | s.homepage = 'http://github.com/coleman/LinPhoneSwift' 8 | s.description = 'Swift library for Linphone' 9 | s.requires_arc = true 10 | s.ios.deployment_target = '8.0' 11 | s.osx.deployment_target = '10.10' 12 | s.source = { :path => '*' } 13 | s.source_files = 'Sources/BelledonneToolbox/*.swift' 14 | s.ios.vendored_frameworks = '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/Frameworks/*.framework' 15 | s.ios.xcconfig = { 16 | 'ENABLE_BITCODE' => 'NO', 17 | 'SWIFT_INCLUDE_PATHS' => '$SRCROOT/../liblinphone-sdk/Modules/CBelledonneToolbox', 18 | 'FRAMEWORK_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/Frameworks', 19 | 'OTHER_LDFLAGS' => '-framework bctoolbox' 20 | } 21 | end -------------------------------------------------------------------------------- /FakeServer/audio_in.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colemancda/LinPhoneSwift/07e8574b22fb49484884e4622df6375ab79e2e58/FakeServer/audio_in.pcap -------------------------------------------------------------------------------- /FakeServer/audio_in.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colemancda/LinPhoneSwift/07e8574b22fb49484884e4622df6375ab79e2e58/FakeServer/audio_in.pcapng -------------------------------------------------------------------------------- /FakeServer/audio_out.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colemancda/LinPhoneSwift/07e8574b22fb49484884e4622df6375ab79e2e58/FakeServer/audio_out.pcap -------------------------------------------------------------------------------- /FakeServer/audio_out.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colemancda/LinPhoneSwift/07e8574b22fb49484884e4622df6375ab79e2e58/FakeServer/audio_out.pcapng -------------------------------------------------------------------------------- /FakeServer/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | from twisted.web import server, resource 4 | from twisted.internet import reactor, protocol 5 | from twisted.protocols import sip 6 | import json 7 | import time 8 | from datetime import datetime 9 | from pcapfile import savefile 10 | 11 | IP = '127.0.0.1' 12 | 13 | audio_testcap = open('audio_in.pcap', "rb") 14 | audio_capfile = savefile.load_savefile(audio_testcap, verbose=True) 15 | 16 | video_testcap = open('video_in.pcap', "rb") 17 | video_capfile = savefile.load_savefile(video_testcap, verbose=True) 18 | 19 | 20 | class Simple(resource.Resource): 21 | isLeaf = True 22 | def render_GET(self, request): 23 | print str(datetime.now()), request 24 | 25 | if request.uri.startswith("/doorbots/history"): 26 | request.responseHeaders.addRawHeader(b"content-type", b"application/json") 27 | return json.dumps([]) 28 | 29 | elif request.uri.startswith("/ring_devices"): 30 | request.responseHeaders.addRawHeader(b"content-type", b"application/json") 31 | return json.dumps({"doorbots":[],"authorized_doorbots":[],"stickup_cams":[],"chimes":[]}) 32 | 33 | elif request.uri.startswith("/dings/active"): 34 | request.responseHeaders.addRawHeader(b"content-type", b"application/json") 35 | return json.dumps([{ 36 | "id": int(round(time.time() * 1000)), 37 | "state": "connected", 38 | "doorbot_id": 1, 39 | "doorbot_description": "Test", 40 | "device_kind": "doorbell", 41 | "protocol": "sip", 42 | "sip_server_ip": IP, 43 | "sip_server_port": 8081, 44 | "sip_server_tls": False, 45 | "sip_session_id": 2, 46 | "sip_from": "sip:1-2@" + IP + ":8081", 47 | "sip_to": "sip:1-2@" + IP + ":8081;transport=tcp", 48 | "kind": "motion" 49 | }]) 50 | 51 | elif request.uri.startswith("/time"): 52 | request.responseHeaders.addRawHeader(b"content-type", b"application/json") 53 | return json.dumps({"now":int(round(time.time() * 1000))}) 54 | 55 | return "Error" 56 | 57 | def render_PUT(self, request): 58 | print str(datetime.now()), request 59 | return "Error" 60 | 61 | def render_POST(self, request): 62 | print str(datetime.now()), request 63 | 64 | if request.uri.startswith("/session"): 65 | request.content.seek(0,0) 66 | print json.loads(request.content.read()) 67 | 68 | request.responseHeaders.addRawHeader(b"content-type", b"application/json") 69 | return json.dumps({ 70 | "profile":{ 71 | "features":{}, 72 | "authentication_token": "nothing", 73 | "email": "test@user.com", 74 | "first_name": "Pepe", 75 | "last_name": "Muleiro", 76 | "id": 1, 77 | "push_notification_channel": "apn" 78 | } 79 | }) 80 | 81 | return "Error" 82 | 83 | def render_DELETE(self, request): 84 | print str(datetime.now()), request 85 | return "Error" 86 | 87 | def render_PATCH(self, request): 88 | print str(datetime.now()), request 89 | 90 | if request.uri.startswith("/device"): 91 | request.responseHeaders.addRawHeader(b"content-type", b"application/json") 92 | return json.dumps({}) 93 | 94 | return "Error" 95 | 96 | class FakeSIP(sip.Base): 97 | addr = None 98 | 99 | def dataReceived(self, data): 100 | self.datagramReceived(data, (self.addr.host, self.addr.port)) 101 | 102 | def sendMessage(self, destURL, message): 103 | self.transport.write(message.toString()) 104 | 105 | def connectionLost(self, reason): 106 | pass 107 | 108 | def handle_request(self, message, addr): 109 | print str(datetime.now()), message.method 110 | f = getattr(self, "handle_%s_request" % message.method, None) 111 | if f is None: 112 | f = self.handle_request_default 113 | 114 | f(message, addr) 115 | 116 | def handle_INVITE_request(self, message, addr): 117 | response = self.responseFromRequest(200, message) 118 | response.headers["Contact"] = [""] 119 | response.headers["Content-Type"] = ["application/sdp"] 120 | response.headers["Content-Disposition"] = ["session"] 121 | response.body = """v=0 122 | o=FreeSWITCH 1427284875 1427284876 IN IP4 %(ip)s 123 | s=FreeSWITCH 124 | c=IN IP4 %(ip)s 125 | t=0 0 126 | m=audio 30510 RTP/AVP 0 101 127 | a=rtpmap:0 PCMU/8000 128 | a=rtpmap:101 telephone-event/8000 129 | a=fmtp:101 0-16 130 | a=ptime:20 131 | a=rtcp:30511 IN IP4 %(ip)s 132 | m=video 30304 RTP/AVP 97 133 | a=rtpmap:97 H264/90000 134 | a=fmtp:97 profile-level-id=42801F 135 | a=rtcp:30305 IN IP4 %(ip)s 136 | """.replace('\n', '\r\n') % {'ip': IP} 137 | response.headers["Content-Length"] = [str(len(response.body))] 138 | self.deliverResponse(response) 139 | 140 | def handle_INFO_request(self, message, addr): 141 | response = self.responseFromRequest(200, message) 142 | response.headers["Content-Length"] = ["0"] 143 | 144 | self.deliverResponse(response) 145 | 146 | def handle_BYE_request(self, message, addr): 147 | response = self.responseFromRequest(200, message) 148 | response.headers["Content-Length"] = ["0"] 149 | 150 | self.deliverResponse(response) 151 | 152 | def handle_request_default(self, message, (srcHost, srcPort)): 153 | print message.method 154 | print message 155 | 156 | def deliverResponse(self, responseMessage): 157 | """Deliver response. 158 | Destination is based on topmost Via header.""" 159 | destVia = sip.parseViaHeader(responseMessage.headers["via"][0]) 160 | # XXX we don't do multicast yet 161 | host = destVia.received or destVia.host 162 | port = destVia.rport or destVia.port or self.PORT 163 | 164 | destAddr = sip.URL(host=host, port=port) 165 | print str(datetime.now()), responseMessage.toString() 166 | self.sendMessage(destAddr, responseMessage) 167 | 168 | def responseFromRequest(self, code, request): 169 | """Create a response to a request message.""" 170 | response = sip.Response(code) 171 | for name in ("via", "to", "from", "call-id", "cseq"): 172 | response.headers[name] = request.headers.get(name, [])[:] 173 | return response 174 | 175 | class FakeSIPFactory(protocol.Factory): 176 | def buildProtocol(self, addr): 177 | new = FakeSIP() 178 | new.addr = addr 179 | return new 180 | 181 | class RTCPHandler(protocol.DatagramProtocol): 182 | def datagramReceived(self, data, addr): 183 | print str(datetime.now()), "Have RTCP data" 184 | 185 | class PcapReplay(protocol.DatagramProtocol): 186 | i = 0 187 | started = False 188 | pcap = None 189 | 190 | def __init__(self, pcap): 191 | self.pcap = pcap 192 | 193 | def datagramReceived(self, data, addr): 194 | if self.started: 195 | return 196 | 197 | print str(datetime.now()), "Start pushing RTP data", addr 198 | self.started = True 199 | self.pushDataIndex(918, addr) 200 | 201 | def pushDataIndex(self, index, addr): 202 | packet = self.pcap.packets[index] 203 | next_packet = self.pcap.packets[index+1] if index+1 < len(self.pcap.packets) else None 204 | self.transport.write(packet.raw()[42:], addr) 205 | 206 | if next_packet is not None: 207 | if next_packet.timestamp - packet.timestamp == 0: 208 | timedif = (next_packet.timestamp_ms - packet.timestamp_ms) / 1000000.0 209 | else: 210 | timedif = (next_packet.timestamp_ms + (1000000 - packet.timestamp_ms)) / 1000000.0 211 | timedif += next_packet.timestamp - packet.timestamp - 1 212 | 213 | reactor.callLater(timedif, self.pushDataIndex, index+1, addr) 214 | else: 215 | print str(datetime.now()), "Finished pushing RTP data" 216 | self.started = False 217 | 218 | 219 | reactor.listenTCP(8080, server.Site(Simple())) 220 | reactor.listenTCP(8081, FakeSIPFactory()) 221 | #reactor.listenUDP(8082, FakeSIP()) 222 | reactor.listenUDP(30510, PcapReplay(audio_capfile)) 223 | reactor.listenUDP(30511, RTCPHandler()) 224 | reactor.listenUDP(30304, PcapReplay(video_capfile)) 225 | reactor.listenUDP(30305, RTCPHandler()) 226 | 227 | reactor.run() 228 | -------------------------------------------------------------------------------- /FakeServer/video_in.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colemancda/LinPhoneSwift/07e8574b22fb49484884e4622df6375ab79e2e58/FakeServer/video_in.pcap -------------------------------------------------------------------------------- /FakeServer/video_in.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colemancda/LinPhoneSwift/07e8574b22fb49484884e4622df6375ab79e2e58/FakeServer/video_in.pcapng -------------------------------------------------------------------------------- /FakeServer/video_out.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colemancda/LinPhoneSwift/07e8574b22fb49484884e4622df6375ab79e2e58/FakeServer/video_out.pcap -------------------------------------------------------------------------------- /FakeServer/video_out.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/colemancda/LinPhoneSwift/07e8574b22fb49484884e4622df6375ab79e2e58/FakeServer/video_out.pcapng -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LinPhoneSwift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'LinPhoneSwift' 3 | s.version = '1.0.0' 4 | s.summary = 'Linphone for Swift' 5 | s.license = 'MIT' 6 | s.authors = { "Alsey Coleman Miller" => "colemancda.github.io" } 7 | s.homepage = 'http://github.com/coleman/LinPhoneSwift' 8 | s.description = 'Swift library for Linphone' 9 | s.requires_arc = true 10 | s.ios.deployment_target = '8.0' 11 | s.osx.deployment_target = '10.10' 12 | s.source = { :path => '*' } 13 | s.source_files = 'Sources/LinPhone/*.swift' 14 | s.ios.vendored_frameworks = '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/*.framework' 15 | s.ios.xcconfig = { 16 | 'ENABLE_BITCODE' => 'NO', 17 | 'SWIFT_INCLUDE_PATHS' => '$SRCROOT/../liblinphone-sdk/Modules/CBelledonneRTP $SRCROOT/../liblinphone-sdk/Modules/CBelledonneSIP $SRCROOT/../liblinphone-sdk/Modules/CBelledonneToolbox $SRCROOT/../liblinphone-sdk/Modules/CLinPhone $SRCROOT/../liblinphone-sdk/Modules/CMediaStreamer2', 18 | 'FRAMEWORK_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/Frameworks', 19 | 'LIBRARY_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/lib', 20 | 'OTHER_LDFLAGS' => '-framework linphone -framework bctoolbox -framework msamr -framework msopenh264 -framework mssilk -framework mswebrtc -framework msx264' 21 | } 22 | s.ios.library = 'xml2', 'sqlite3' 23 | s.dependency 'BelledonneToolbox' 24 | s.dependency 'BelledonneRTP' 25 | s.dependency 'BelledonneSIP' 26 | s.dependency 'MediaStreamer' 27 | s.user_target_xcconfig = { 28 | 'ENABLE_BITCODE' => 'NO', 29 | 'SWIFT_INCLUDE_PATHS' => '$SRCROOT/liblinphone-sdk/Modules/CBelledonneRTP $SRCROOT/liblinphone-sdk/Modules/CBelledonneSIP $SRCROOT/liblinphone-sdk/Modules/CBelledonneToolbox $SRCROOT/liblinphone-sdk/Modules/CLinPhone $SRCROOT/liblinphone-sdk/Modules/CMediaStreamer2', 30 | 'LIBRARY_SEARCH_PATHS' => '$SRCROOT/liblinphone-sdk/iOS/apple-darwin/lib', 31 | 'FRAMEWORK_SEARCH_PATHS' => '$SRCROOT/liblinphone-sdk/iOS/apple-darwin/Frameworks' 32 | } 33 | end -------------------------------------------------------------------------------- /MediaStreamer.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'MediaStreamer' 3 | s.version = '1.0.0' 4 | s.summary = 'Linphone for Swift' 5 | s.license = 'MIT' 6 | s.authors = { "Alsey Coleman Miller" => "colemancda.github.io" } 7 | s.homepage = 'http://github.com/coleman/LinPhoneSwift' 8 | s.description = 'Swift library for Linphone' 9 | s.requires_arc = true 10 | s.ios.deployment_target = '8.0' 11 | s.osx.deployment_target = '10.10' 12 | s.source = { :path => '*' } 13 | s.source_files = 'Sources/MediaStreamer/*.swift' 14 | s.ios.vendored_frameworks = '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/Frameworks/*.framework' 15 | s.ios.xcconfig = { 16 | 'ENABLE_BITCODE' => 'NO', 17 | 'SWIFT_INCLUDE_PATHS' => '$SRCROOT/../liblinphone-sdk/Modules/CBelledonneRTP $SRCROOT/../liblinphone-sdk/Modules/CBelledonneSIP $SRCROOT/../liblinphone-sdk/Modules/CBelledonneToolbox $SRCROOT/../liblinphone-sdk/Modules/CLinPhone $SRCROOT/../liblinphone-sdk/Modules/CMediaStreamer2', 18 | 'FRAMEWORK_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/Frameworks', 19 | 'LIBRARY_SEARCH_PATHS' => '$SRCROOT/../liblinphone-sdk/iOS/apple-darwin/lib', 20 | 'OTHER_LDFLAGS' => '-lbcg729 -framework mediastreamer_base -framework mediastreamer_voip -framework msamr -framework msopenh264 -framework mssilk -framework mswebrtc -framework msx264' 21 | } 22 | s.ios.library = 'xml2', 'sqlite3' 23 | s.dependency 'BelledonneToolbox' 24 | s.dependency 'BelledonneRTP' 25 | s.ios.frameworks = 'CoreMedia', 'CoreVideo', 'VideoToolbox', 'QuartzCore', 'AudioToolbox', 'AVFoundation', 'UIKit', 'CoreGraphics', 'OpenGLES' 26 | end -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:3.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "LinPhoneSwift" 7 | ) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LinPhoneSwift 2 | Swift library for Linphone 3 | 4 | # Setup 5 | Copy the compiled SDK ([iOS](http://www.linphone.org/releases/ios/liblinphone-iphone-sdk-3.16.4.zip), [macOS](http://www.linphone.org/releases/macosx/linphone-sdk-3.11.1-mac.zip)) folder `apple-darwin` to `liblinphone-sdk/ios` or `liblinphone-sdk/macos`, depending on the platform. -------------------------------------------------------------------------------- /Sources/BelledonneRTP/Data.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Data.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/30/17. 6 | // 7 | // 8 | 9 | import CBelledonneRTP.stringutils 10 | 11 | internal final class DataBuffer { 12 | 13 | // MARK: - Properties 14 | 15 | @_versioned 16 | internal let managedPointer: ManagedPointer 17 | 18 | // MARK: - Initialization 19 | 20 | internal init(_ managedPointer: ManagedPointer) { 21 | 22 | self.managedPointer = managedPointer 23 | } 24 | } 25 | 26 | // MARK: - ManagedHandle 27 | 28 | extension DataBuffer: ManagedHandle { 29 | 30 | typealias RawPointer = DataBuffer.UnmanagedPointer.RawPointer 31 | } 32 | 33 | extension DataBuffer { 34 | 35 | struct UnmanagedPointer: BelledonneRTP.UnmanagedPointer { 36 | 37 | let rawPointer: OpaquePointer 38 | 39 | @inline(__always) 40 | init(_ rawPointer: OpaquePointer) { 41 | self.rawPointer = rawPointer 42 | } 43 | 44 | @inline(__always) 45 | func retain() { 46 | 47 | dblk_ref(rawPointer) 48 | } 49 | 50 | @inline(__always) 51 | func release() { 52 | 53 | dblk_unref(rawPointer) 54 | } 55 | 56 | var referenceCount: Int { 57 | 58 | @inline(__always) 59 | get { return Int(dblk_ref_value(rawPointer)) } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Sources/BelledonneRTP/Handle.swift: -------------------------------------------------------------------------------- 1 | ../LinPhone/Handle.swift -------------------------------------------------------------------------------- /Sources/BelledonneRTP/Log.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Log.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/22/17. 6 | // 7 | // 8 | 9 | import CBelledonneRTP.logging 10 | import CBelledonneRTP.port 11 | 12 | public struct Log { 13 | 14 | // MARK: - Static Properties 15 | 16 | /// Tell oRTP the id of the thread used to output the logs. 17 | /// This is meant to output all the logs from the same thread to prevent deadlock problems at the application level. 18 | public static var threadIdentifier: UInt { 19 | 20 | @inline(__always) 21 | get { return __ortp_thread_self() } 22 | 23 | @inline(__always) 24 | set { ortp_set_log_thread_id(newValue) } 25 | } 26 | 27 | // MARK: - Static Methods 28 | 29 | /// Flushes the log output queue. 30 | /// 31 | /// - Warning: Must be called from the thread that has been defined with `threadIdentifier`. 32 | @inline(__always) 33 | public static func flush() { 34 | 35 | ortp_logv_flush() 36 | } 37 | } 38 | 39 | // MARK: - Supporting Types 40 | 41 | public extension Log { 42 | 43 | public enum Level { 44 | 45 | case debug 46 | 47 | case trace 48 | 49 | case message 50 | 51 | case warning 52 | 53 | case error 54 | 55 | case fatal 56 | 57 | public static let all: Set = [.debug, .trace, .message, .warning, .error, .fatal] 58 | } 59 | } 60 | 61 | extension Log.Level: Equatable { 62 | 63 | @inline(__always) 64 | public static func == (lhs: Log.Level, rhs: Log.Level) -> Bool { 65 | 66 | return lhs.ortpLevel.rawValue == rhs.ortpLevel.rawValue 67 | } 68 | } 69 | 70 | extension Log.Level: Hashable { 71 | 72 | public var hashValue: Int { 73 | 74 | @inline(__always) 75 | get { return ortpLevel.rawValue.hashValue } 76 | } 77 | } 78 | 79 | public extension Log.Level { 80 | 81 | public init?(_ ortpLevel: OrtpLogLevel) { 82 | 83 | switch ortpLevel { 84 | case ORTP_DEBUG: self = .debug 85 | case ORTP_TRACE: self = .trace 86 | case ORTP_MESSAGE: self = .message 87 | case ORTP_WARNING: self = .warning 88 | case ORTP_ERROR: self = .error 89 | case ORTP_FATAL: self = .fatal 90 | default: return nil 91 | } 92 | } 93 | 94 | public var ortpLevel: OrtpLogLevel { 95 | 96 | switch self { 97 | case .debug: return ORTP_DEBUG 98 | case .trace: return ORTP_TRACE 99 | case .message: return ORTP_MESSAGE 100 | case .warning: return ORTP_WARNING 101 | case .error: return ORTP_ERROR 102 | case .fatal: return ORTP_FATAL 103 | } 104 | } 105 | 106 | public static func ortpLevelMask(from levels: Set) -> OrtpLogLevel.RawValue { 107 | 108 | return levels 109 | .map({ $0.ortpLevel.rawValue }) 110 | .reduce(0, { $0 | $1 }) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Sources/BelledonneRTP/Packet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Packet.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/30/17. 6 | // 7 | // 8 | 9 | import CBelledonneRTP.stringutils 10 | 11 | /// Linked List media packet / message that contains RTP data. 12 | public final class Packet { 13 | 14 | public typealias RawPointer = UnsafeMutablePointer 15 | 16 | // MARK: - Properties 17 | 18 | @_versioned 19 | internal private(set) var rawPointer: RawPointer 20 | 21 | // MARK: - Initialization 22 | 23 | deinit { 24 | 25 | freemsg(rawPointer) 26 | } 27 | 28 | public init(rawPointer: RawPointer) { 29 | 30 | self.rawPointer = rawPointer 31 | } 32 | 33 | public init(size: Int) { 34 | 35 | self.rawPointer = allocb(size, 0) 36 | } 37 | 38 | // MARK: - Accessors 39 | 40 | /// Make a copy of the internal raw pointer. 41 | internal var duplicateRawPointer: RawPointer { 42 | 43 | return dupmsg(rawPointer) 44 | } 45 | } 46 | 47 | public extension Packet { 48 | 49 | /// Access the underlying C structure instance. 50 | /// 51 | /// - Note: The pointer is only guarenteed to be valid for the lifetime of the closure. 52 | public func withUnsafeRawPointer (_ body: (RawPointer) throws -> Result) rethrows -> Result { 53 | 54 | return try body(rawPointer) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/BelledonneRTP/Queue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Queue.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/30/17. 6 | // 7 | // 8 | 9 | import CBelledonneRTP.stringutils 10 | 11 | /// Linked list queue. 12 | public final class Queue { 13 | 14 | // MARK: - Properties 15 | 16 | @_versioned 17 | internal private(set) var internalData = queue_t() 18 | 19 | // MARK: - Initialization 20 | 21 | deinit { 22 | 23 | flush() 24 | } 25 | 26 | public init() { 27 | 28 | qinit(&internalData) 29 | } 30 | 31 | // MARK: - Accessors 32 | 33 | public var count: Int { 34 | 35 | return Int(internalData.q_mcount) 36 | } 37 | 38 | public var isEmpty: Bool { 39 | 40 | return count == 0 41 | } 42 | 43 | // MARK: - Methods 44 | 45 | /// Remove and free all messages in the queue. 46 | public func flush() { 47 | 48 | flushq(&internalData, 0) 49 | } 50 | 51 | /// Push an item to the queue. 52 | public func push(_ packet: Packet) { 53 | 54 | // copy packet 55 | 56 | let copy = packet.duplicateRawPointer 57 | 58 | putq(&internalData, copy) 59 | } 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /Sources/BelledonneSIP/Handle.swift: -------------------------------------------------------------------------------- 1 | ../LinPhone/Handle.swift -------------------------------------------------------------------------------- /Sources/BelledonneSIP/Object.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Object.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/4/17. 6 | // 7 | // 8 | 9 | import CBelledonneSIP 10 | 11 | /// It is the base protocol for all BelleSIP non-trivial objects. Can be class or struct. 12 | public protocol BelledonneObject { 13 | 14 | associatedtype RawPointer 15 | 16 | /// Access the underlying C structure instance. 17 | /// 18 | /// - Note: The pointer is only guarenteed to be valid for the lifetime of the closure. 19 | mutating func withUnsafeMutableRawPointer (_ body: (RawPointer) throws -> Result) rethrows -> Result 20 | 21 | /// Access the underlying C structure instance. 22 | /// 23 | /// - Note: The pointer is only guarenteed to be valid for the lifetime of the closure. 24 | func withUnsafeRawPointer (_ body: (RawPointer) throws -> Result) rethrows -> Result 25 | } 26 | -------------------------------------------------------------------------------- /Sources/BelledonneSIP/ObjectHandle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BelledonneObjectHandle.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/5/17. 6 | // 7 | // 8 | 9 | import CBelledonneSIP 10 | 11 | /// Belledonne Object manual reference count type. 12 | internal struct BelledonneUnmanagedObject: UnmanagedPointer { 13 | 14 | let rawPointer: OpaquePointer 15 | 16 | @inline(__always) 17 | init(_ rawPointer: OpaquePointer) { 18 | self.rawPointer = rawPointer 19 | } 20 | 21 | @inline(__always) 22 | func retain() { 23 | belle_sip_object_ref(UnsafeMutableRawPointer(rawPointer)) 24 | } 25 | 26 | @inline(__always) 27 | func release() { 28 | belle_sip_object_unref(UnsafeMutableRawPointer(rawPointer)) 29 | } 30 | } 31 | 32 | internal protocol BelledonneObjectHandle: ManagedHandle, CopyableHandle, CustomStringConvertible where RawPointer == OpaquePointer { 33 | 34 | var rawPointer: OpaquePointer { get } 35 | 36 | var managedPointer: ManagedPointer { get } 37 | 38 | init(_ managedPointer: ManagedPointer) 39 | } 40 | 41 | internal extension BelledonneObjectHandle { 42 | 43 | var objectTypeDescription: String { 44 | 45 | return getString { belle_sip_object_describe(📦($0)) } ?? "" 46 | } 47 | 48 | var copy: Self? { 49 | 50 | let belleObjectPointer = unsafeBitCast(self.rawPointer, to: UnsafeMutablePointer.self) 51 | 52 | guard let copyBelleObjectPointer = belle_sip_object_clone(belleObjectPointer) 53 | else { return nil } 54 | 55 | let copyRawPointer = OpaquePointer(copyBelleObjectPointer) 56 | 57 | let copy = Self.init(ManagedPointer(BelledonneUnmanagedObject(copyRawPointer))) 58 | 59 | return copy 60 | } 61 | } 62 | 63 | extension BelledonneObjectHandle { 64 | 65 | public var description: String { 66 | 67 | return getString { belle_sip_object_to_string(📦($0)) } ?? "" 68 | } 69 | } 70 | 71 | /// Cast any type to unsafe raw pointer. 72 | @inline(__always) 73 | private func 📦 (_ rawPointer: RawPointer) -> UnsafeMutableRawPointer { 74 | 75 | let opaquePointer = unsafeBitCast(rawPointer, to: OpaquePointer.self) 76 | 77 | return UnsafeMutableRawPointer(opaquePointer) 78 | } 79 | 80 | /* 81 | internal extension BelledonneObject where Self: ReferenceConvertible { 82 | 83 | /// Access the underlying C structure instance. 84 | /// 85 | /// - Note: The pointer is only guarenteed to be valid for the lifetime of the closure. 86 | @inline(__always) 87 | mutating func _withUnsafeMutableRawPointer (_ body: (Reference.RawPointer) throws -> Result) rethrows -> Result { 88 | 89 | let rawPointer = internalReference.mutatingReference.rawPointer 90 | 91 | return try body(rawPointer) 92 | } 93 | 94 | /// Access the underlying C structure instance. 95 | /// 96 | /// - Note: The pointer is only guarenteed to be valid for the lifetime of the closure. 97 | @inline(__always) 98 | func _withUnsafeRawPointer (_ body: (Reference.RawPointer) throws -> Result) rethrows -> Result { 99 | 100 | let rawPointer = internalReference.reference.rawPointer 101 | 102 | return try body(rawPointer) 103 | } 104 | }*/ 105 | -------------------------------------------------------------------------------- /Sources/BelledonneSIP/URI.SIP.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SIPURI.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/3/17. 6 | // 7 | // 8 | 9 | import CBelledonneSIP 10 | 11 | public extension URI { 12 | 13 | /// SIP URI used with Belledonne libraries (e.g. Linphone). 14 | public struct SIP { 15 | 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/BelledonneSIP/URI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URI.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/3/17. 6 | // 7 | // 8 | 9 | import CBelledonneSIP 10 | 11 | /// Generic URI used with Belledonne libraries (e.g. Linphone). 12 | public struct URI: RawRepresentable { 13 | 14 | // MARK: - Properties 15 | 16 | @_versioned // private(set) in Swift 4 17 | internal fileprivate(set) var internalReference: CopyOnWrite 18 | 19 | // MARK: - Initialization 20 | 21 | @inline(__always) 22 | internal init(_ internalReference: CopyOnWrite) { 23 | 24 | self.internalReference = internalReference 25 | } 26 | 27 | /// Initialize an empty URI. 28 | public init() { 29 | 30 | self.init(referencing: Reference()) 31 | } 32 | 33 | /// Initialize an URI from a string. 34 | public init?(rawValue: String) { 35 | 36 | guard let reference = Reference(string: rawValue) 37 | else { return nil } 38 | 39 | self.init(referencing: reference) 40 | } 41 | 42 | // MARK: - Accessors 43 | 44 | public var rawValue: String { 45 | 46 | get { return internalReference.reference.description } 47 | } 48 | 49 | public var scheme: String? { 50 | 51 | get { return internalReference.reference.getString(belle_generic_uri_get_scheme) } 52 | 53 | mutating set { internalReference.mutatingReference.setString(belle_generic_uri_set_scheme, newValue) } 54 | } 55 | 56 | public var user: String? { 57 | 58 | get { return internalReference.reference.getString(belle_generic_uri_get_user) } 59 | 60 | mutating set { internalReference.mutatingReference.setString(belle_generic_uri_set_user, newValue) } 61 | } 62 | 63 | public var password: String? { 64 | 65 | get { return internalReference.reference.getString(belle_generic_uri_get_user_password) } 66 | 67 | mutating set { internalReference.mutatingReference.setString(belle_generic_uri_set_user_password, newValue) } 68 | } 69 | 70 | public var host: String? { 71 | 72 | get { return internalReference.reference.getString(belle_generic_uri_get_host) } 73 | 74 | mutating set { internalReference.mutatingReference.setString(belle_generic_uri_set_host, newValue) } 75 | } 76 | 77 | public var path: String? { 78 | 79 | get { return internalReference.reference.getString(belle_generic_uri_get_path) } 80 | 81 | mutating set { internalReference.mutatingReference.setString(belle_generic_uri_set_path, newValue) } 82 | } 83 | 84 | public var query: String? { 85 | 86 | get { return internalReference.reference.getString(belle_generic_uri_get_query) } 87 | 88 | mutating set { internalReference.mutatingReference.setString(belle_generic_uri_set_query, newValue) } 89 | } 90 | 91 | public var port: Int32 { 92 | 93 | get { return belle_generic_uri_get_port(internalReference.reference.rawPointer) } 94 | 95 | mutating set { belle_generic_uri_set_port(internalReference.mutatingReference.rawPointer, newValue) } 96 | } 97 | } 98 | 99 | // MARK: - Equatable 100 | 101 | extension URI: Equatable { 102 | 103 | public static func == (lhs: URI, rhs: URI) -> Bool { 104 | 105 | return lhs.rawValue == rhs.rawValue 106 | } 107 | } 108 | 109 | // MARK: - Hashable 110 | 111 | extension URI: Hashable { 112 | 113 | public var hashValue: Int { 114 | 115 | @inline(__always) 116 | get { return rawValue.hashValue } 117 | } 118 | } 119 | 120 | // MARK: - CustomStringConvertible 121 | 122 | extension URI: CustomStringConvertible { 123 | 124 | public var description: String { 125 | 126 | @inline(__always) 127 | get { return rawValue } 128 | } 129 | } 130 | 131 | // MARK: - BelledonneObject 132 | 133 | extension URI: BelledonneObject { 134 | 135 | public typealias RawPointer = OpaquePointer 136 | 137 | public mutating func withUnsafeMutableRawPointer (_ body: (OpaquePointer) throws -> Result) rethrows -> Result { 138 | 139 | let rawPointer = internalReference.mutatingReference.rawPointer 140 | 141 | return try body(rawPointer) 142 | } 143 | 144 | public func withUnsafeRawPointer (_ body: (OpaquePointer) throws -> Result) rethrows -> Result { 145 | 146 | let rawPointer = internalReference.reference.rawPointer 147 | 148 | return try body(rawPointer) 149 | } 150 | } 151 | 152 | // MARK: - ReferenceConvertible 153 | 154 | extension URI: ReferenceConvertible { 155 | 156 | internal final class Reference: BelledonneObjectHandle { 157 | 158 | internal typealias UnmanagedPointer = BelledonneUnmanagedObject 159 | 160 | internal typealias RawPointer = UnmanagedPointer.RawPointer 161 | 162 | // MARK: - Properties 163 | 164 | @_versioned 165 | internal let managedPointer: ManagedPointer 166 | 167 | // MARK: - Initialization 168 | 169 | internal init(_ managedPointer: ManagedPointer) { 170 | 171 | self.managedPointer = managedPointer 172 | } 173 | 174 | convenience init() { 175 | 176 | guard let rawPointer = belle_generic_uri_new() 177 | else { fatalError("Could not allocate instance") } 178 | 179 | self.init(ManagedPointer(UnmanagedPointer(rawPointer))) 180 | } 181 | 182 | convenience init?(string: String) { 183 | 184 | guard let rawPointer = belle_generic_uri_parse(string) 185 | else { return nil } 186 | 187 | self.init(ManagedPointer(UnmanagedPointer(rawPointer))) 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /Sources/BelledonneToolbox/Bool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bool.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/8/17. 6 | // 7 | // 8 | 9 | import CBelledonneToolbox 10 | 11 | internal extension CBelledonneToolbox.bool_t { 12 | 13 | @_versioned 14 | @inline(__always) 15 | init(_ bool: Bool) { 16 | 17 | self = bool ? 1 : 0 18 | } 19 | 20 | @_versioned 21 | var boolValue: Bool { 22 | 23 | @inline(__always) 24 | get { return self > 0 } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/BelledonneToolbox/Handle.swift: -------------------------------------------------------------------------------- 1 | ../LinPhone/Handle.swift -------------------------------------------------------------------------------- /Sources/BelledonneToolbox/LinkedList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkedList.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/2/17. 6 | // 7 | // 8 | 9 | #if os(macOS) || os(iOS) 10 | import Darwin.C 11 | #elseif os(Linux) 12 | import Glibc 13 | #endif 14 | 15 | import CBelledonneToolbox.list 16 | import struct Foundation.Data 17 | import class Foundation.NSMutableData 18 | 19 | /// Linked List structure 20 | public struct LinkedList { 21 | 22 | // MARK: - Properties 23 | 24 | @_versioned 25 | internal let internalReference: Reference? 26 | 27 | // MARK: - Initialization 28 | 29 | internal init(_ internalReference: Reference?) { 30 | 31 | self.internalReference = internalReference 32 | } 33 | 34 | /// Initialize linked list from a data array. 35 | public init(data: [Data]) { 36 | 37 | let mutableData = data.map { NSMutableData(data: $0) } 38 | 39 | self.init(Reference(mutableData: mutableData)) 40 | } 41 | 42 | /// Initialize linked list from a string array. 43 | public init(strings: [String]) { 44 | 45 | self.init(Reference(strings: strings)) 46 | } 47 | 48 | // MARK: - Accessors 49 | 50 | /// Get the value as a string. 51 | public var strings: [String] { 52 | 53 | return internalReference?.data.map { String(cStringData: $0) } ?? [] 54 | } 55 | 56 | /// Get the linked list data. 57 | public var data: [Data] { 58 | 59 | return internalReference?.data.map { Data(referencing: $0) } ?? [] 60 | } 61 | 62 | public var isEmpty: Bool { 63 | 64 | return internalReference == nil 65 | } 66 | 67 | // MARK: - Accessors 68 | 69 | /// Access the underlying C structure instance with read-only access. 70 | /// 71 | /// - Warning: The pointer is only guarenteed to be valid for the lifetime of the closure. 72 | /// Do not attempt to use the pointer outside of the closure, or attempt to mutate it in any way. 73 | public func withUnsafeRawPointer (_ body: (UnsafePointer?) throws -> Result) rethrows -> Result { 74 | 75 | let rawPointer: UnsafePointer? 76 | 77 | if let reference = self.internalReference { 78 | 79 | rawPointer = UnsafePointer(reference.rawPointer) 80 | 81 | } else { 82 | 83 | rawPointer = nil 84 | } 85 | 86 | return try body(rawPointer) 87 | } 88 | } 89 | 90 | // MARK: - Equatable 91 | 92 | extension LinkedList: Equatable { 93 | 94 | public static func == (lhs: LinkedList, rhs: LinkedList) -> Bool { 95 | 96 | return (lhs.internalReference?.data ?? []) == (rhs.internalReference?.data ?? []) 97 | } 98 | } 99 | 100 | // MARK: - Hashable 101 | 102 | extension LinkedList: Hashable { 103 | 104 | public var hashValue: Int { 105 | 106 | return description.hashValue 107 | } 108 | } 109 | 110 | // MARK: - CustomStringConvertible 111 | 112 | extension LinkedList: CustomStringConvertible { 113 | 114 | public var description: String { 115 | 116 | return "\(strings)" 117 | } 118 | } 119 | 120 | // MARK: - 121 | 122 | public extension LinkedList { 123 | 124 | /// Extract the string values from a linked list raw pointer. 125 | public static func strings(from rawPointer: UnsafePointer) -> [String] { 126 | 127 | let count = bctbx_list_size(rawPointer) 128 | 129 | var values = [String]() 130 | values.reserveCapacity(count) 131 | 132 | for index in 0 ..< count { 133 | 134 | guard let dataPointer = bctbx_list_nth_data(rawPointer, Int32(index)) 135 | else { fatalError("No data for linked list at index \(index)") } 136 | 137 | let cString = dataPointer.assumingMemoryBound(to: CChar.self) 138 | 139 | let element = String(cString: cString) 140 | 141 | values.append(element) 142 | } 143 | 144 | return values 145 | } 146 | } 147 | 148 | // MARK: - Reference 149 | 150 | extension LinkedList { 151 | 152 | internal final class Reference: Handle { 153 | 154 | typealias RawPointer = UnsafeMutablePointer 155 | 156 | // MARK: - Properties 157 | 158 | /// Underlying `bctbx_list_t` pointer. Always the first element. 159 | @_versioned 160 | internal let rawPointer: RawPointer 161 | 162 | /// Keep reference for ARC. `bctbx_list_t` only manages memory of list structure, not the attached data. WTF? 163 | @_versioned 164 | internal let data: [NSMutableData] 165 | 166 | // MARK: - Initialization 167 | 168 | deinit { 169 | 170 | bctbx_list_free(rawPointer) 171 | } 172 | 173 | fileprivate init?(mutableData: [NSMutableData]) { 174 | 175 | guard let firstData = mutableData.first, 176 | let rawPointer = bctbx_list_new(firstData.mutableBytes) 177 | else { return nil } 178 | 179 | /// append other data. 180 | for data in mutableData.suffix(from: 1) { 181 | 182 | bctbx_list_append(rawPointer, data.mutableBytes) 183 | } 184 | 185 | self.rawPointer = rawPointer 186 | self.data = mutableData 187 | } 188 | 189 | convenience init?(strings: [String]) { 190 | 191 | // convert strings to data 192 | 193 | let data = strings.map { $0.cStringData } 194 | 195 | self.init(mutableData: data) 196 | } 197 | } 198 | } 199 | 200 | // MARK: - Private Extensions 201 | 202 | fileprivate extension String { 203 | 204 | var cStringData: NSMutableData { 205 | 206 | return self.withCString { NSMutableData(bytes: $0, length: Int(strlen($0)) + 1) } 207 | } 208 | 209 | init(cStringData data: NSMutableData) { 210 | 211 | self.init(cString: data.mutableBytes.assumingMemoryBound(to: UInt8.self)) 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /Sources/LinPhone/Address.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Address.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/4/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | import CBelledonneToolbox.port 11 | import struct BelledonneSIP.URI 12 | import class Foundation.NSString 13 | 14 | /// LinPhone Address class. 15 | public struct Address: RawRepresentable { 16 | 17 | // MARK: - Properties 18 | 19 | @_versioned // private(set) in Swift 4 20 | internal fileprivate(set) var internalReference: CopyOnWrite 21 | 22 | // MARK: - Initialization 23 | 24 | internal init(_ internalReference: CopyOnWrite) { 25 | 26 | self.internalReference = internalReference 27 | } 28 | 29 | /// Initialize an `Address` from a string. 30 | public init?(rawValue: String) { 31 | 32 | guard let reference = Reference(string: rawValue) 33 | else { return nil } 34 | 35 | self.init(referencing: reference) 36 | } 37 | 38 | // MARK: - Accessors 39 | 40 | public var rawValue: String { 41 | 42 | get { return internalReference.reference.stringValue } 43 | } 44 | 45 | /// Returns the SIP URI only as a string, that is display name is removed. 46 | private var uriString: String? { 47 | 48 | get { return internalReference.reference.getString(linphone_address_as_string_uri_only) } 49 | } 50 | 51 | /// Returns the SIP URI only, that is display name is removed. 52 | private var sip: URI? { 53 | 54 | get { return URI(rawValue: uriString ?? "") } 55 | } 56 | 57 | /// Whether address is a routable SIP address. 58 | public var isSIP: Bool { 59 | 60 | get { return linphone_address_is_sip(internalReference.reference.rawPointer).boolValue } 61 | } 62 | 63 | /// Whether the address refers to a secure location (sips). 64 | public var isSecure: Bool { 65 | 66 | get { return linphone_address_get_secure(internalReference.reference.rawPointer).boolValue } 67 | 68 | mutating set { linphone_address_set_secure(internalReference.mutatingReference.rawPointer, bool_t(newValue)) } 69 | } 70 | 71 | /// Port number as an integer value. 72 | public var port: Int32 { 73 | 74 | get { return linphone_address_get_port(internalReference.reference.rawPointer) } 75 | 76 | mutating set { linphone_address_set_port(internalReference.mutatingReference.rawPointer, newValue) } 77 | } 78 | 79 | /// The address scheme, normally "sip". 80 | public var scheme: String? { 81 | 82 | get { return internalReference.reference.getString(linphone_address_get_scheme) } 83 | } 84 | 85 | /// The display name. 86 | public var displayName: String? { 87 | 88 | get { return internalReference.reference.getString(linphone_address_get_display_name) } 89 | 90 | mutating set { internalReference.mutatingReference.setString(linphone_address_set_display_name, newValue).lpAssert() } 91 | } 92 | 93 | /// The username. 94 | public var username: String? { 95 | 96 | get { return internalReference.reference.getString(linphone_address_get_username) } 97 | 98 | mutating set { internalReference.mutatingReference.setString(linphone_address_set_username, newValue).lpAssert() } 99 | } 100 | 101 | /// The password encoded in the address. 102 | /// 103 | /// - Note: It is used for basic authentication (not recommended). 104 | public var password: String? { 105 | 106 | get { return internalReference.reference.getString(linphone_address_get_password) } 107 | 108 | mutating set { internalReference.mutatingReference.setString(linphone_address_set_password, newValue) } 109 | } 110 | 111 | /// The domain name. 112 | public var domain: String? { 113 | 114 | get { return internalReference.reference.getString(linphone_address_get_domain) } 115 | 116 | mutating set { internalReference.mutatingReference.setString(linphone_address_set_domain, newValue).lpAssert() } 117 | } 118 | 119 | /// The transport. 120 | public var transportType: TransportType { 121 | 122 | get { return TransportType(linphone_address_get_transport(internalReference.reference.rawPointer)) } 123 | 124 | mutating set { linphone_address_set_transport(internalReference.mutatingReference.rawPointer, newValue.linPhoneType).lpAssert() } 125 | } 126 | 127 | /// The value of the method parameter. 128 | public var method: String? { 129 | 130 | get { return internalReference.reference.getString(linphone_address_get_method_param) } 131 | 132 | mutating set { internalReference.mutatingReference.setString(linphone_address_set_method_param, newValue) } 133 | } 134 | 135 | // MARK: - Methods 136 | 137 | /// Removes address's tags and uri headers so that it is displayable to the user. 138 | public mutating func clean() { 139 | 140 | linphone_address_clean(internalReference.mutatingReference.rawPointer) 141 | } 142 | 143 | /// Get the header encoded in the address. 144 | public func header(_ name: String) -> String? { 145 | 146 | return internalReference.reference.getString { linphone_address_get_header($0, name) } 147 | } 148 | 149 | /// Set a header into the address. 150 | /// 151 | /// Headers appear in the URI with '?', such as ``. 152 | public mutating func setHeader(_ name: String, value: String?) { 153 | 154 | internalReference.mutatingReference.setString({ linphone_address_set_header($0, name, $1) }, value) 155 | } 156 | 157 | /// Whether the address contains the parameter. 158 | public func hasParameter(_ name: String) -> Bool { 159 | 160 | return linphone_address_has_param(internalReference.reference.rawPointer, name).boolValue 161 | } 162 | 163 | /// Get the parameter encoded in the address. 164 | public func parameter(_ name: String) -> String? { 165 | 166 | return internalReference.reference.getString { linphone_address_get_param($0, name) } 167 | } 168 | 169 | /// Set a parameter into the address. 170 | public mutating func setParameter(_ name: String, value: String?) { 171 | 172 | internalReference.mutatingReference.setString({ linphone_address_set_param($0, name, $1) }, value) 173 | } 174 | 175 | /// Whether the address contains the parameter. 176 | public func hasURIParameter(_ name: String) -> Bool { 177 | 178 | return linphone_address_has_uri_param(internalReference.reference.rawPointer, name).boolValue 179 | } 180 | 181 | /// Get the parameter encoded in the address. 182 | public func uriParameter(_ name: String) -> String? { 183 | 184 | return internalReference.reference.getString { linphone_address_get_uri_param($0, name) } 185 | } 186 | 187 | /// Set a parameter into the address. 188 | public mutating func setURIParameter(_ name: String, value: String?) { 189 | 190 | internalReference.mutatingReference.setString({ linphone_address_set_uri_param($0, name, $1) }, value) 191 | } 192 | 193 | // MARK: - Subscripting 194 | 195 | public subscript (header name: String) -> String? { 196 | 197 | get { return header(name) } 198 | 199 | mutating set { setHeader(name, value: newValue) } 200 | } 201 | 202 | public subscript (parameter name: String) -> String? { 203 | 204 | get { return parameter(name) } 205 | 206 | mutating set { setParameter(name, value: newValue) } 207 | } 208 | 209 | public subscript (uriParameter name: String) -> String? { 210 | 211 | get { return uriParameter(name) } 212 | 213 | mutating set { setURIParameter(name, value: newValue) } 214 | } 215 | } 216 | 217 | // MARK: - Equatable 218 | 219 | extension Address: Equatable { 220 | 221 | @inline(__always) 222 | public static func == (lhs: Address, rhs: Address) -> Bool { 223 | 224 | // same as `linphone_address_equal`. The function `linphone_address_weak_equal` 225 | // compares all properties, but not sure which one is more efficient and accurate. 226 | return lhs.rawValue == rhs.rawValue 227 | } 228 | } 229 | 230 | // MARK: - Hashable 231 | 232 | extension Address: Hashable { 233 | 234 | public var hashValue: Int { 235 | 236 | @inline(__always) 237 | get { return rawValue.hashValue } 238 | } 239 | } 240 | 241 | // MARK: - CustomStringConvertible 242 | 243 | extension Address: CustomStringConvertible { 244 | 245 | public var description: String { 246 | 247 | @inline(__always) 248 | get { return rawValue } 249 | } 250 | } 251 | 252 | // MARK: - Supporting Types 253 | 254 | public extension Address { 255 | 256 | /// Enum describing transport type for `Linphone.Address`. 257 | public enum TransportType: UInt32, LinPhoneEnumeration { 258 | 259 | public typealias LinPhoneType = LinphoneTransportType 260 | 261 | case udp 262 | case tcp 263 | case tls 264 | case dtls 265 | } 266 | } 267 | 268 | // MARK: - ReferenceConvertible 269 | 270 | extension Address: ReferenceConvertible { 271 | 272 | internal final class Reference: CopyableHandle { 273 | 274 | // MARK: - Properties 275 | 276 | @_versioned 277 | internal let managedPointer: ManagedPointer 278 | 279 | // MARK: - Initialization 280 | 281 | internal init(_ managedPointer: ManagedPointer) { 282 | 283 | self.managedPointer = managedPointer 284 | } 285 | 286 | convenience init?(string: String) { 287 | 288 | let cString = string.lpCString 289 | 290 | guard let rawPointer = linphone_address_new(cString) 291 | else { return nil } 292 | 293 | self.init(ManagedPointer(UnmanagedPointer(rawPointer))) 294 | } 295 | 296 | var copy: Address.Reference? { 297 | 298 | guard let rawPointer = linphone_address_clone(self.rawPointer) 299 | else { return nil } 300 | 301 | let copy = Address.Reference(ManagedPointer(UnmanagedPointer(rawPointer))) 302 | 303 | return copy 304 | } 305 | 306 | // MARK: - Accessors 307 | 308 | internal var stringValue: String { 309 | 310 | get { return getString(linphone_address_as_string) ?? "" } 311 | } 312 | } 313 | } 314 | 315 | // MARK: - ManagedHandle 316 | 317 | extension Address.Reference: ManagedHandle { 318 | 319 | typealias RawPointer = Address.UnmanagedPointer.RawPointer 320 | } 321 | 322 | extension Address { 323 | 324 | struct UnmanagedPointer: LinPhoneSwift.UnmanagedPointer { 325 | 326 | let rawPointer: OpaquePointer 327 | 328 | @inline(__always) 329 | init(_ rawPointer: OpaquePointer) { 330 | self.rawPointer = rawPointer 331 | } 332 | 333 | @inline(__always) 334 | func retain() { 335 | linphone_address_ref(rawPointer) 336 | } 337 | 338 | @inline(__always) 339 | func release() { 340 | linphone_address_unref(rawPointer) 341 | } 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /Sources/LinPhone/Bool.swift: -------------------------------------------------------------------------------- 1 | ../BelledonneToolbox/Bool.swift -------------------------------------------------------------------------------- /Sources/LinPhone/CallLog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CallLog.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/4/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | public extension Call { 12 | 13 | public final class Log { 14 | 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/LinPhone/CallParameters.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CallParameters.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/9/17. 6 | // 7 | // 8 | 9 | import CLinPhone.core 10 | import struct CMediaStreamer2.MSVideoSize 11 | import typealias CBelledonneToolbox.bool_t 12 | 13 | public extension Call { 14 | 15 | public struct Parameters { 16 | 17 | // MARK: - Properties 18 | 19 | @_versioned // private(set) in Swift 4 20 | internal fileprivate(set) var internalReference: CopyOnWrite 21 | 22 | // MARK: - Initialization 23 | 24 | internal init(_ internalReference: CopyOnWrite) { 25 | 26 | self.internalReference = internalReference 27 | } 28 | 29 | // MARK: - Accessors 30 | 31 | /// Get the size of the video that is received. 32 | @available(*, deprecated) 33 | public var recievedVideoSize: MSVideoSize { 34 | 35 | get { return linphone_call_params_get_received_video_size(internalReference.reference.rawPointer) } 36 | } 37 | 38 | /// A boolean value telling whether to enable video or not. 39 | public var isVideoEnabled: Bool { 40 | 41 | get { return linphone_call_params_video_enabled(internalReference.reference.rawPointer).boolValue } 42 | 43 | mutating set { linphone_call_params_enable_video(internalReference.mutatingReference.rawPointer, bool_t(newValue)) } 44 | } 45 | 46 | /// A boolean value telling whether audio is enabled or not. 47 | public var isAudioEnabled: Bool { 48 | 49 | get { return linphone_call_params_audio_enabled(internalReference.reference.rawPointer).boolValue } 50 | 51 | mutating set { linphone_call_params_enable_audio(internalReference.mutatingReference.rawPointer, bool_t(newValue)) } 52 | } 53 | } 54 | } 55 | 56 | extension Call.Parameters: ReferenceConvertible { 57 | 58 | internal final class Reference: CopyableHandle { 59 | 60 | // MARK: - Properties 61 | 62 | @_versioned 63 | internal let managedPointer: ManagedPointer 64 | 65 | // MARK: - Initialization 66 | 67 | internal init(_ managedPointer: ManagedPointer) { 68 | 69 | self.managedPointer = managedPointer 70 | } 71 | 72 | internal var copy: Call.Parameters.Reference? { 73 | 74 | guard let rawPointer = linphone_call_params_copy(self.rawPointer) 75 | else { return nil } 76 | 77 | let copy = Call.Parameters.Reference(ManagedPointer(UnmanagedPointer(rawPointer))) 78 | 79 | return copy 80 | } 81 | } 82 | } 83 | 84 | extension Call.Parameters.Reference: ManagedHandle { 85 | 86 | typealias RawPointer = Call.Parameters.UnmanagedPointer.RawPointer 87 | } 88 | 89 | extension Call.Parameters { 90 | 91 | typealias RawPointer = UnmanagedPointer.RawPointer 92 | 93 | struct UnmanagedPointer: LinPhoneSwift.UnmanagedPointer { 94 | 95 | let rawPointer: OpaquePointer 96 | 97 | @inline(__always) 98 | init(_ rawPointer: OpaquePointer) { 99 | self.rawPointer = rawPointer 100 | } 101 | 102 | @inline(__always) 103 | func retain() { 104 | linphone_call_params_ref(rawPointer) 105 | } 106 | 107 | @inline(__always) 108 | func release() { 109 | linphone_call_params_unref(rawPointer) 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Sources/LinPhone/CallStats.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CallStats.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/9/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | public extension Call { 12 | 13 | public struct Stats { 14 | 15 | // MARK: - Properties 16 | 17 | @_versioned 18 | internal let internalReference: Reference 19 | 20 | // MARK: - Initialization 21 | 22 | internal init(referencing reference: Reference) { 23 | 24 | self.internalReference = reference 25 | } 26 | 27 | // MARK: - Accessors 28 | 29 | internal var rawPointer: UnmanagedPointer.RawPointer { 30 | 31 | get { return internalReference.managedPointer.unmanagedPointer.rawPointer } 32 | } 33 | 34 | /// The type of the stream the stats refer to. 35 | public var type: StreamType { 36 | 37 | get { return StreamType(linphone_call_stats_get_type(rawPointer)) } 38 | } 39 | 40 | /// The bandwidth measurement of the received stream, expressed in kbit/s, including IP/UDP/RTP headers. 41 | public var downloadBandwidth: Float { 42 | 43 | get { return linphone_call_stats_get_download_bandwidth(rawPointer) } 44 | } 45 | 46 | /// The bandwidth measurement of the sent stream, expressed in kbit/s, including IP/UDP/RTP headers. 47 | public var uploadBandwidth: Float { 48 | 49 | get { return linphone_call_stats_get_upload_bandwidth(rawPointer) } 50 | } 51 | } 52 | } 53 | 54 | extension Call.Stats { 55 | 56 | internal final class Reference: BelledonneObjectHandle { 57 | 58 | typealias RawPointer = BelledonneUnmanagedObject.RawPointer 59 | 60 | // MARK: - Properties 61 | 62 | @_versioned 63 | internal let managedPointer: ManagedPointer 64 | 65 | // MARK: - Initialization 66 | 67 | internal init(_ managedPointer: ManagedPointer) { 68 | 69 | self.managedPointer = managedPointer 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Sources/LinPhone/Conference.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Conference.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/5/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | 12 | -------------------------------------------------------------------------------- /Sources/LinPhone/Configuration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Configuration.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/1/17. 6 | // 7 | // 8 | 9 | import CLinPhone.core 10 | import CBelledonneToolbox.port 11 | import BelledonneToolbox 12 | 13 | /// The `LinPhone.Configuration` object is used to manipulate a configuration file. 14 | /// 15 | /// The format of the configuration file is a `.ini` like format: 16 | /// 17 | /// sections are defined in `[]` 18 | /// each section contains a sequence of `key=value` pairs. 19 | /// Example: 20 | /// 21 | /// ``` 22 | /// [sound] 23 | /// echocanceler=1 24 | /// playback_dev=ALSA: Default device 25 | /// [video] 26 | /// enabled=1 27 | /// ``` 28 | public final class Configuration { 29 | 30 | // MARK: - Properties 31 | 32 | @_versioned 33 | internal let managedPointer: ManagedPointer 34 | 35 | // MARK: - Initialization 36 | 37 | internal init(_ managedPointer: ManagedPointer) { 38 | 39 | self.managedPointer = managedPointer 40 | } 41 | 42 | /// Instantiates a `Linphone.Configuration` object from a user config file. 43 | public convenience init?(filename: String) { 44 | 45 | guard let rawPointer = linphone_config_new(filename) 46 | else { return nil } 47 | 48 | self.init(ManagedPointer(UnmanagedPointer(rawPointer))) 49 | } 50 | 51 | // Documentation is unclear on memory and value semantics. 52 | // Does `Core` own the config? Or are its values just populated from it? 53 | 54 | /// Instantiates a `Linphone.Configuration` object from a user config file. 55 | public convenience init?(filename: String, core: Core) { 56 | 57 | guard let rawPointer = linphone_core_create_config(core.rawPointer, filename) 58 | else { return nil } 59 | 60 | self.init(ManagedPointer(UnmanagedPointer(rawPointer))) 61 | } 62 | 63 | /// Instantiates a `Linphone.Configuration` object from a user provided string. 64 | public convenience init?(string: String) { 65 | 66 | guard let rawPointer = linphone_config_new_from_buffer(string) 67 | else { return nil } 68 | 69 | self.init(ManagedPointer(UnmanagedPointer(rawPointer))) 70 | } 71 | 72 | /// Instantiates a `Linphone.Configuration` object from a user config file and a factory config file. 73 | /// 74 | /// The user config file is read first to fill the `Linphone.Configuration` and then the factory config file is read. 75 | /// Therefore the configuration parameters defined in the user config file will be overwritten 76 | /// by the parameters defined in the factory config file. 77 | public convenience init?(filename: String, factoryFilename: String) { 78 | 79 | guard let rawPointer = linphone_config_new_with_factory(filename, factoryFilename) 80 | else { return nil } 81 | 82 | self.init(ManagedPointer(UnmanagedPointer(rawPointer))) 83 | } 84 | 85 | // MARK: - Methods 86 | 87 | /// Reads a user configuration file and fills the reciever with the read configuration values. 88 | public func read(file filename: String) -> Bool { 89 | 90 | return linphone_config_read_file(rawPointer, filename) == .success 91 | } 92 | 93 | /* 94 | /// Reads a user configuration file and fills the reciever with the read configuration values. 95 | public func readRelative(file filename: String) -> Bool { 96 | 97 | return linphone_config_read_relative_file(rawPointer, filename) == .success 98 | }*/ 99 | 100 | /// Whether file exists relative to the to the current location. 101 | public func relativeFileExists(_ filename: String) -> Bool { 102 | 103 | return linphone_config_relative_file_exists(rawPointer, filename).boolValue 104 | } 105 | 106 | /// Writes the config file to disk. 107 | public func synchronize() -> Bool { 108 | 109 | return linphone_config_sync(rawPointer) == .success 110 | } 111 | 112 | /// Dumps the `Linphone.Configuration` in the specified format. 113 | public func dump(_ format: Format) -> String { 114 | 115 | switch format { 116 | 117 | case .ini: 118 | 119 | return getString(linphone_config_dump) ?? "" 120 | 121 | case .xml: 122 | 123 | return getString(linphone_config_dump_as_xml) ?? "" 124 | } 125 | } 126 | 127 | // MARK: - Setters 128 | 129 | /// Set the value for the specified key and section in the configuration file. 130 | public func set(_ value: Float, for key: String, in section: String) { 131 | 132 | linphone_config_set_float(rawPointer, section, key, value) 133 | } 134 | 135 | /// Set the value for the specified key and section in the configuration file. 136 | public func set(_ value: Int64, for key: String, in section: String) { 137 | 138 | linphone_config_set_int64(rawPointer, section, key, value) 139 | } 140 | 141 | /// Set the value for the specified key and section in the configuration file. 142 | public func set(_ value: Int32, for key: String, in section: String) { 143 | 144 | linphone_config_set_int(rawPointer, section, key, value) 145 | } 146 | 147 | /// Set the value for the specified key and section in the configuration file. 148 | public func set(_ value: Bool, for key: String, in section: String) { 149 | 150 | linphone_config_set_int(rawPointer, section, key, value ? 1 : 0) 151 | } 152 | 153 | /// Set the value for the specified key and section in the configuration file. 154 | /// 155 | /// - Note: Sets an integer config item, but stores it as hexadecimal 156 | public func setHexadecimal(_ value: Int32, for key: String, in section: String) { 157 | 158 | linphone_config_set_int_hex(rawPointer, section, key, value) 159 | } 160 | 161 | /// Sets the overwrite flag for a config item (used when dumping config as xml). 162 | public func setOverwriteFlag(_ flag: Bool, for key: String, in section: String) { 163 | 164 | linphone_config_set_overwrite_flag_for_entry(rawPointer, section, key, bool_t(flag)) 165 | } 166 | 167 | /// Sets the overwrite flag for a config section (used when dumping config as xml). 168 | public func setOverwriteFlag(_ flag: Bool, for section: String) { 169 | 170 | linphone_config_set_overwrite_flag_for_section(rawPointer, section, bool_t(flag)) 171 | } 172 | 173 | /// Sets a range config item. 174 | public func set(_ range: ClosedRange, for key: String, in section: String) { 175 | 176 | linphone_config_set_range(rawPointer, section, key, range.lowerBound, range.upperBound) 177 | } 178 | 179 | /// Sets the skip flag for a config item (used when dumping config as xml). 180 | public func setSkipFlag(_ flag: Bool, for key: String, in section: String) { 181 | 182 | linphone_config_set_skip_flag_for_entry(rawPointer, section, key, bool_t(flag)) 183 | } 184 | 185 | /// Sets the skip flag for a config item (used when dumping config as xml). 186 | public func setSkipFlag(_ flag: Bool, for section: String) { 187 | 188 | linphone_config_set_skip_flag_for_section(rawPointer, section, bool_t(flag)) 189 | } 190 | 191 | /// Set the string value for the specified key and section in the configuration file. 192 | public func set(_ value: String, for key: String, in section: String) { 193 | 194 | linphone_config_set_string(rawPointer, section, key, value) 195 | } 196 | 197 | /// Set the string list value for the specified key and section in the configuration file. 198 | public func set(_ linkedList: LinkedList, for key: String, in section: String) { 199 | 200 | // we guarentee the linked list wont be modified, no need to create a mutable copy 201 | linkedList.withUnsafeRawPointer { linphone_config_set_string_list(rawPointer, section, key, $0) } 202 | } 203 | 204 | // MARK: - Getters 205 | 206 | 207 | 208 | // MARK: - Subcripting 209 | 210 | 211 | } 212 | 213 | extension Configuration: CustomDebugStringConvertible { 214 | 215 | /// Dumps the LinphoneConfig as INI into a buffer. 216 | public var debugDescription: String { 217 | 218 | @inline(__always) 219 | get { return dump(.ini) } 220 | } 221 | } 222 | 223 | // MARK: - Supporting Types 224 | 225 | public extension Configuration { 226 | 227 | public enum Format { 228 | 229 | case ini 230 | case xml 231 | } 232 | } 233 | 234 | // MARK: - Internal 235 | 236 | extension Configuration: ManagedHandle { 237 | 238 | typealias RawPointer = UnmanagedPointer.RawPointer 239 | 240 | struct UnmanagedPointer: LinPhoneSwift.UnmanagedPointer { 241 | 242 | let rawPointer: OpaquePointer 243 | 244 | @inline(__always) 245 | init(_ rawPointer: OpaquePointer) { 246 | 247 | self.rawPointer = rawPointer 248 | } 249 | 250 | @inline(__always) 251 | func retain() { 252 | linphone_config_ref(rawPointer) 253 | } 254 | 255 | @inline(__always) 256 | func release() { 257 | linphone_config_unref(rawPointer) 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /Sources/LinPhone/Enumeration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InternalEnum.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 6/30/17. 6 | // 7 | // 8 | 9 | public protocol LinPhoneEnumeration: RawRepresentable { 10 | 11 | associatedtype LinPhoneType: RawRepresentable 12 | 13 | init?(_ linPhoneType: LinPhoneType) 14 | 15 | var linPhoneType: LinPhoneType { get } 16 | } 17 | 18 | public extension LinPhoneEnumeration where Self.RawValue == LinPhoneType.RawValue { 19 | 20 | @inline(__always) 21 | init(_ linPhoneType: LinPhoneType) { 22 | 23 | self.init(rawValue: linPhoneType.rawValue)! 24 | } 25 | 26 | var linPhoneType: LinPhoneType { 27 | 28 | @inline(__always) 29 | get { return LinPhoneType(rawValue: self.rawValue)! } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/LinPhone/ErrorInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Error.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/5/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | /// Struct representing full details about a signaling error or status. 12 | public struct ErrorInfo { 13 | 14 | // MARK: - Properties 15 | 16 | @_versioned // private(set) in Swift 4 17 | internal fileprivate(set) var internalReference: CopyOnWrite 18 | 19 | // MARK: - Initialization 20 | 21 | @inline(__always) 22 | internal init(_ internalReference: CopyOnWrite) { 23 | 24 | self.internalReference = internalReference 25 | } 26 | 27 | public init(factory: Factory = Factory.shared) { 28 | 29 | self.init(referencing: Reference(factory: factory)) 30 | } 31 | 32 | // MARK: - Accessors 33 | 34 | public var detailedErrorInfo: ErrorInfo? { 35 | 36 | get { return internalReference.reference.getReferenceConvertible(.copy, linphone_error_info_get_sub_error_info) } 37 | 38 | mutating set { internalReference.mutatingReference.setReferenceConvertible(copy: false, linphone_error_info_set_sub_error_info, newValue) } 39 | } 40 | 41 | /// Get reason code from the error info. 42 | public var reason: Reason { 43 | 44 | get { return Reason(linphone_error_info_get_reason(internalReference.reference.rawPointer)) } 45 | 46 | mutating set { linphone_error_info_set_reason(internalReference.mutatingReference.rawPointer, newValue.linPhoneType) } 47 | } 48 | 49 | /// The protocol name. 50 | public var `protocol`: String? { 51 | 52 | get { return internalReference.reference.getString(linphone_error_info_get_protocol) } 53 | 54 | mutating set { internalReference.mutatingReference.setString(linphone_error_info_set_protocol, newValue) } 55 | } 56 | 57 | /// The status code from the low level protocol (e.g. a SIP status code). 58 | public var protocolCode: Int32 { 59 | 60 | get { return linphone_error_info_get_protocol_code(internalReference.reference.rawPointer) } 61 | 62 | mutating set { linphone_error_info_set_protocol_code(internalReference.mutatingReference.rawPointer, newValue) } 63 | } 64 | 65 | /// The textual phrase from the error info. 66 | /// This is the text that is provided by the peer in the protocol (SIP). 67 | public var phrase: String? { 68 | 69 | get { return internalReference.reference.getString(linphone_error_info_get_phrase) } 70 | 71 | mutating set { internalReference.mutatingReference.setString(linphone_error_info_set_phrase, newValue) } 72 | } 73 | 74 | /// Provides additional information regarding the failure. 75 | /// With SIP protocol, the content of "Warning" headers are returned. 76 | public var warnings: String? { 77 | 78 | get { return internalReference.reference.getString(linphone_error_info_get_warnings) } 79 | 80 | mutating set { internalReference.mutatingReference.setString(linphone_error_info_set_warnings, newValue) } 81 | } 82 | } 83 | 84 | // MARK: - ReferenceConvertible 85 | 86 | extension ErrorInfo: ReferenceConvertible { 87 | 88 | /// Object representing full details about a signaling error or status. 89 | /// All LinphoneErrorInfo object returned by the liblinphone API are readonly and transcients. 90 | /// For safety they must be used immediately after obtaining them. 91 | /// Any other function call to the liblinphone may change their content or invalidate the pointer. 92 | internal final class Reference: BelledonneObjectHandle { 93 | 94 | typealias RawPointer = BelledonneUnmanagedObject.RawPointer 95 | 96 | // MARK: - Properties 97 | 98 | @_versioned 99 | internal let managedPointer: ManagedPointer 100 | 101 | // MARK: - Initialization 102 | 103 | internal init(_ managedPointer: ManagedPointer) { 104 | 105 | self.managedPointer = managedPointer 106 | } 107 | 108 | convenience init() { 109 | 110 | guard let rawPointer = linphone_error_info_new() 111 | else { fatalError("Could not allocate instance") } 112 | 113 | self.init(ManagedPointer(BelledonneUnmanagedObject(rawPointer))) 114 | } 115 | 116 | convenience init(factory: Factory) { 117 | 118 | guard let rawPointer = linphone_factory_create_error_info(factory.rawPointer) 119 | else { fatalError("Could not allocate instance") } 120 | 121 | self.init(ManagedPointer(BelledonneUnmanagedObject(rawPointer))) 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Sources/LinPhone/Factory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Factory.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/1/17. 6 | // 7 | // 8 | 9 | import CLinPhone.factory 10 | 11 | /// `LinPhone.Factory` is a singleton object devoted to the creation of all the objects of 12 | /// LinPhone that cannot created by `Linphone.Core` itself. 13 | public final class Factory { 14 | 15 | // MARK: - Singleton 16 | 17 | public static let shared = Factory() 18 | 19 | // MARK: - Properties 20 | 21 | internal let rawPointer: OpaquePointer 22 | 23 | // MARK: - Initialization 24 | 25 | deinit { 26 | 27 | // Clean the factory. 28 | /// This function is generally useless as the factory is unique per process, 29 | /// however calling this function at the end avoid getting reports from belle-sip leak detector' 30 | /// about memory leaked in `linphone_factory_get()`. 31 | linphone_factory_clean() 32 | } 33 | 34 | /// Create the singleton factory. 35 | private init() { 36 | 37 | self.rawPointer = linphone_factory_get() 38 | } 39 | } 40 | 41 | // MARK: - Internal 42 | 43 | extension Factory: Handle { } 44 | -------------------------------------------------------------------------------- /Sources/LinPhone/Internal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Internal.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/1/17. 6 | // 7 | // 8 | 9 | import typealias CLinPhone.LinphoneStatus 10 | 11 | // MARK: - Assertions 12 | 13 | internal extension LinphoneStatus { 14 | 15 | @inline(__always) 16 | func lpAssert(function: String = #function, file: StaticString = #file, line: UInt = #line) { 17 | 18 | assert(self == .success, lpAssertMessage(function: function, file: file, line: line), file: file, line: line) 19 | } 20 | } 21 | 22 | internal extension Bool { 23 | 24 | @inline(__always) 25 | func lpAssert(function: String = #function, file: StaticString = #file, line: UInt = #line) { 26 | 27 | assert(self, lpAssertMessage(function: function, file: file, line: line), file: file, line: line) 28 | } 29 | } 30 | 31 | internal extension Optional { 32 | 33 | @inline(__always) 34 | func lpAssert(function: String = #function, file: StaticString = #file, line: UInt = #line) -> Wrapped { 35 | 36 | guard let value = self 37 | else { linphoneFatalError(function: function, file: file, line: line) } // not really assert 38 | 39 | return value 40 | } 41 | } 42 | 43 | @_silgen_name("_linphone_swift_fatal_error") 44 | internal func linphoneFatalError(function: String = #function, file: StaticString = #file, line: UInt = #line) -> Never { 45 | 46 | fatalError(lpFatalErrorMessage(function: function, file: file, line: line), file: file, line: line) 47 | } 48 | 49 | @inline(__always) 50 | func lpFatalErrorMessage(function: String = #function, file: StaticString = #file, line: UInt = #line) -> String { 51 | 52 | return "An internal Linphone exception occurred in \(function)" 53 | } 54 | 55 | @inline(__always) 56 | func lpAssertMessage(function: String = #function, file: StaticString = #file, line: UInt = #line) -> String { 57 | 58 | return "A Linphone assertion failed in \(function)" 59 | } 60 | -------------------------------------------------------------------------------- /Sources/LinPhone/MediaEncryption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MediaEncryption.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/8/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | /// Enum describing type of media encryption types. 12 | public enum MediaEncryption: UInt32, LinPhoneEnumeration { 13 | 14 | public typealias LinPhoneType = LinphoneMediaEncryption 15 | 16 | /// No media encryption is used 17 | case none 18 | 19 | /// Use SRTP media encryption 20 | case srtp 21 | 22 | /// Use ZRTP media encryption 23 | case zrtp 24 | 25 | /// Use DTLS media encryption 26 | case dtls 27 | } 28 | 29 | extension MediaEncryption: CustomStringConvertible { 30 | 31 | public var description: String { 32 | 33 | return String(lpCString: linphone_media_encryption_to_string(linPhoneType)) ?? "" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/LinPhone/ObjectHandle.swift: -------------------------------------------------------------------------------- 1 | ../BelledonneSIP/ObjectHandle.swift -------------------------------------------------------------------------------- /Sources/LinPhone/PayloadType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PayloadType.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/12/17. 6 | // 7 | // 8 | 9 | import CLinPhone.core 10 | import CBelledonneToolbox.port 11 | 12 | public final class PayloadType { 13 | 14 | // MARK: - Properties 15 | 16 | @_versioned 17 | internal let managedPointer: ManagedPointer 18 | 19 | // MARK: - Initialization 20 | 21 | internal init(_ managedPointer: ManagedPointer) { 22 | 23 | self.managedPointer = managedPointer 24 | } 25 | 26 | // MARK: - Accessors 27 | 28 | /// Get the type of a payload type. 29 | public var category: Category { 30 | 31 | get { return Category(rawValue: linphone_payload_type_get_type(rawPointer))! } 32 | } 33 | 34 | /// Whether a payload type is enabled. 35 | public var isEnabled: Bool { 36 | 37 | get { return linphone_payload_type_enabled(rawPointer).boolValue } 38 | 39 | set { linphone_payload_type_enable(rawPointer, bool_t(newValue)) } 40 | } 41 | 42 | /// Return a string describing a payload type. The format of the string is //. 43 | public var description: String { 44 | 45 | return getString(linphone_payload_type_get_description)! 46 | } 47 | 48 | /// The description of the encoder used to provide a payload type. 49 | /// Can be `nil` if the payload type is not supported by `Mediastreamer2`. 50 | public var encoderDescription: String? { 51 | 52 | return getString(linphone_payload_type_get_encoder_description) 53 | } 54 | 55 | /// Get the normal bitrate in bits/s. 56 | public var normalBitrate: Int { 57 | 58 | get { return Int(linphone_payload_type_get_normal_bitrate(rawPointer)) } 59 | 60 | set { linphone_payload_type_set_normal_bitrate(rawPointer, Int32(newValue)) } 61 | } 62 | 63 | /// The mime type. 64 | public var mimeType: String { 65 | 66 | return getString(linphone_payload_type_get_mime_type)! 67 | } 68 | 69 | /// The number of channels. 70 | public var channels: Int { 71 | 72 | get { return Int(linphone_payload_type_get_channels(rawPointer)) } 73 | } 74 | 75 | /// Check whether the payload is usable according the bandwidth targets set in the `Core`. 76 | public var isUsable: Bool { 77 | 78 | get { return linphone_payload_type_is_usable(rawPointer).boolValue } 79 | } 80 | 81 | /// Whether the specified payload type represents a variable bitrate codec. 82 | public var isVariableBitrate: Bool { 83 | 84 | get { return linphone_payload_type_is_vbr(rawPointer).boolValue } 85 | } 86 | } 87 | 88 | extension PayloadType: CustomStringConvertible { } 89 | 90 | // MARK: - Supporting Types 91 | 92 | public extension PayloadType { 93 | 94 | public enum Category: Int32 { 95 | 96 | case continuousAudio 97 | 98 | case packetizedAudio 99 | 100 | case video 101 | 102 | case other 103 | } 104 | } 105 | 106 | // MARK: - BelledonneObjectHandle 107 | 108 | extension PayloadType: BelledonneObjectHandle { 109 | 110 | internal typealias UnmanagedPointer = BelledonneUnmanagedObject 111 | 112 | internal typealias RawPointer = UnmanagedPointer.RawPointer 113 | } 114 | -------------------------------------------------------------------------------- /Sources/LinPhone/Reason.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Reason.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/5/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | /// Enum describing various failure reasons or contextual information for some events. 12 | public enum Reason: UInt32, LinPhoneEnumeration { 13 | 14 | public typealias LinPhoneType = LinphoneReason 15 | 16 | /// No reason has been set by the `Core` 17 | case none 18 | 19 | /// No response received from remote 20 | case noResponse 21 | 22 | /// Authentication failed due to bad credentials or resource forbidden 23 | case forbidden 24 | 25 | /// The call has been declined 26 | case declined 27 | 28 | /// Destination of the call was not found 29 | case notFound 30 | 31 | /// The call was not answered in time (request timeout) 32 | case notAnswered 33 | 34 | /// Phone line was busy 35 | case busy 36 | 37 | /// Unsupported content 38 | case unsupportedContent 39 | 40 | /// Transport error: connection failures, disconnections etc... 41 | case inputOutputError 42 | 43 | /// Do not disturb reason 44 | case doNotDisturb 45 | 46 | /// Operation is unauthorized because missing credential 47 | case unauthorized 48 | 49 | /// Operation is rejected due to incompatible or unsupported media parameters 50 | case notAcceptable 51 | 52 | /// Operation could not be executed by server or remote client because it didn't have any context for it 53 | case noMatch 54 | 55 | /// Resource moved permanently 56 | case movedPermanently 57 | 58 | /// Resource no longer exists 59 | case gone 60 | 61 | /// Temporarily unavailable 62 | case temporarilyUnavailable 63 | 64 | /// Address incomplete 65 | case addressIncomplete 66 | 67 | /// Not implemented 68 | case notImplemented 69 | 70 | /// Bad gateway 71 | case badGateway 72 | 73 | /// Server timeout 74 | case serverTimeout 75 | 76 | /// Unknown reason 77 | case unknown 78 | 79 | // backwards compatibility 80 | 81 | static let badCredentials: Reason = .forbidden // LinphoneReasonBadCredentials 82 | 83 | static let media: Reason = .unsupportedContent // LinphoneReasonMedia 84 | } 85 | 86 | // MARK: - ErrorCode 87 | 88 | public typealias ErrorCode = Int32 89 | 90 | public extension Reason { 91 | 92 | /// Converts an error code to a `Linphone.Reason`. 93 | init(errorCode: ErrorCode) { 94 | 95 | self.init(linphone_error_code_to_reason(errorCode)) 96 | } 97 | 98 | /// Converts a `Linphone.Reason` to an error code. 99 | /// 100 | /// - Returns: The error code corresponding to the specified `Linphone.Reason`. 101 | var errorCode: ErrorCode { 102 | 103 | @inline(__always) 104 | get { return linphone_reason_to_error_code(linPhoneType) } 105 | } 106 | } 107 | 108 | // MARK: - CustomStringConvertible 109 | 110 | extension Reason: CustomStringConvertible { 111 | 112 | public var description: String { 113 | 114 | @inline(__always) 115 | get { return String(cString: linphone_reason_to_string(linPhoneType)) } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Sources/LinPhone/RegistrationState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RegistrationState.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/6/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | /// `Linphone.RegistrationState` describes proxy registration states. 12 | public enum RegistrationState: UInt32, LinPhoneEnumeration { 13 | 14 | public typealias LinPhoneType = LinphoneRegistrationState 15 | 16 | /// Initial state for registrations 17 | case none 18 | 19 | /// Registration is in progress 20 | case progress 21 | 22 | /// Registration is successful 23 | case successful // LinphoneRegistrationOk 24 | 25 | /// Unregistration succeeded 26 | case cleared 27 | 28 | /// Registration failed 29 | case failed 30 | } 31 | 32 | extension RegistrationState: CustomStringConvertible { 33 | 34 | public var description: String { 35 | 36 | return String(lpCString: linphone_registration_state_to_string(linPhoneType)) ?? "" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/LinPhone/SipTransports.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SipTransports.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/18/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | /// SIP transport ports. 12 | public struct SipTransports { 13 | 14 | public var udp: Port 15 | 16 | public var tcp: Port 17 | 18 | public var dtls: Port 19 | 20 | public var tls: Port 21 | } 22 | 23 | // MARK: - Equatable 24 | 25 | extension SipTransports: Equatable { 26 | 27 | public static func == (lhs: SipTransports, rhs: SipTransports) -> Bool { 28 | 29 | return lhs.udp == rhs.udp 30 | && lhs.tcp == rhs.tcp 31 | && lhs.dtls == rhs.dtls 32 | && lhs.tls == rhs.tls 33 | } 34 | } 35 | 36 | // MARK: - Supporting Types 37 | 38 | public extension SipTransports { 39 | 40 | public typealias Port = Int32 41 | 42 | /// Disable a sip transport. 43 | public static var disabled: Port { return LC_SIP_TRANSPORT_DISABLED } 44 | 45 | /// Randomly chose a sip port for this transport. 46 | public static var random: Port { return LC_SIP_TRANSPORT_RANDOM } 47 | 48 | /// Don't create any server socket for this transport (e.i. don't bind on any port). 49 | public static var noBind: Port { return LC_SIP_TRANSPORT_DONTBIND } 50 | } 51 | 52 | // MARK: - LinPhone 53 | 54 | internal extension SipTransports { 55 | 56 | typealias LinPhoneType = LinphoneSipTransports 57 | 58 | init(_ linPhoneType: LinPhoneType) { 59 | 60 | self.udp = linPhoneType.udp_port 61 | self.tcp = linPhoneType.tcp_port 62 | self.dtls = linPhoneType.dtls_port 63 | self.tls = linPhoneType.tls_port 64 | } 65 | 66 | var linPhoneType: LinPhoneType { 67 | 68 | return LinPhoneType(udp_port: udp, 69 | tcp_port: tcp, 70 | dtls_port: dtls, 71 | tls_port: tls) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Sources/LinPhone/StreamType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StreamType.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 6/30/17. 6 | // 7 | // 8 | 9 | import struct CLinPhone.LinphoneStreamType 10 | import func CLinPhone.linphone_stream_type_to_string 11 | 12 | /// Enum describing the Linphone stream types. 13 | public enum StreamType: UInt32, LinPhoneEnumeration { 14 | 15 | public typealias LinPhoneType = LinphoneStreamType 16 | 17 | case audio 18 | case video 19 | case text 20 | case unknown 21 | } 22 | 23 | extension StreamType: CustomStringConvertible { 24 | 25 | public var description: String { 26 | 27 | return String(lpCString: linphone_stream_type_to_string(self.linPhoneType)) ?? "" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/LinPhone/Transport.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transport.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/5/17. 6 | // 7 | // 8 | 9 | import CLinPhone 10 | 11 | public final class Transport { 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Sources/LinPhone/Tunnel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tunnel.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/11/17. 6 | // 7 | // 8 | 9 | import CLinPhone.tunnel 10 | import CBelledonneToolbox.port 11 | 12 | public final class Tunnel { 13 | 14 | // MARK: - Properties 15 | 16 | @_versioned 17 | internal let managedPointer: ManagedPointer 18 | 19 | // MARK: - Initialization 20 | 21 | internal init(_ managedPointer: ManagedPointer) { 22 | 23 | self.managedPointer = managedPointer 24 | } 25 | 26 | // MARK: - Accessors 27 | 28 | public var mode: Mode { 29 | 30 | get { return Mode(linphone_tunnel_get_mode(rawPointer)) } 31 | 32 | set { linphone_tunnel_set_mode(rawPointer, mode.linPhoneType) } 33 | } 34 | 35 | /// A boolean value telling whether SIP packets shall pass through the tunnel. 36 | public var isSIPEnabled: Bool { 37 | 38 | get { return linphone_tunnel_sip_enabled(rawPointer).boolValue } 39 | 40 | set { linphone_tunnel_enable_sip(rawPointer, bool_t(newValue)) } 41 | } 42 | 43 | /// Check whether the tunnel is connected. 44 | public var isConnected: Bool { 45 | 46 | return linphone_tunnel_connected(rawPointer).boolValue 47 | } 48 | 49 | /// Returns whether the tunnel is activated. 50 | /// If mode is set to auto, this gives indication whether the automatic detection 51 | /// determined that tunnel was necessary or not. 52 | public var isActivated: Bool { 53 | 54 | return linphone_tunnel_get_activated(rawPointer).boolValue 55 | } 56 | 57 | // MARK: - Methods 58 | 59 | /// Force reconnection to the tunnel server. 60 | /// 61 | /// This method is useful when the device switches from wifi to Edge/3G or vice versa. 62 | /// In most cases the tunnel client socket won't be notified promptly that its connection is now zombie, 63 | /// so it is recommended to call this method that will cause the lost connection to be closed 64 | /// and new connection to be issued. 65 | public func reconnect() { 66 | 67 | linphone_tunnel_reconnect(rawPointer) 68 | } 69 | } 70 | 71 | public extension Tunnel { 72 | 73 | public final class Configuration { 74 | 75 | // MARK: - Properties 76 | 77 | @_versioned 78 | internal let managedPointer: ManagedPointer 79 | 80 | // MARK: - Initialization 81 | 82 | internal init(_ managedPointer: ManagedPointer) { 83 | 84 | self.managedPointer = managedPointer 85 | } 86 | 87 | /// Create a new tunnel configuration. 88 | public convenience init() { 89 | 90 | guard let rawPointer = linphone_tunnel_config_new() 91 | else { fatalError("Could not allocate instance") } 92 | 93 | self.init(ManagedPointer(UnmanagedPointer(rawPointer))) 94 | } 95 | 96 | // MARK: - Accessors 97 | 98 | 99 | 100 | // MARK: - Methods 101 | } 102 | } 103 | 104 | // MARK: - Supporting Types 105 | 106 | public extension Tunnel { 107 | 108 | public enum Mode: UInt32, LinPhoneEnumeration { 109 | 110 | public typealias LinPhoneType = LinphoneTunnelMode 111 | 112 | /// The tunnel is disabled. 113 | case disable 114 | 115 | /// The tunnel is enabled. 116 | case enable 117 | 118 | /// The tunnel is enabled automatically if it is required. 119 | case auto 120 | 121 | /// Convert a string into `Linphone.Tunnel.Mode` enum. 122 | public init(string: String) { 123 | 124 | self.init(linphone_tunnel_mode_from_string(string)) 125 | } 126 | 127 | /// Convert a tunnel mode enum into string. 128 | public var stringValue: String { 129 | 130 | return String(lpCString: linphone_tunnel_mode_to_string(linPhoneType))! 131 | } 132 | } 133 | } 134 | 135 | extension Tunnel.Mode: CustomStringConvertible { 136 | 137 | public var description: String { 138 | 139 | @inline(__always) 140 | get { return stringValue } 141 | } 142 | } 143 | 144 | extension Tunnel: BelledonneObjectHandle { 145 | 146 | internal typealias UnmanagedPointer = BelledonneUnmanagedObject 147 | 148 | internal typealias RawPointer = UnmanagedPointer.RawPointer 149 | } 150 | 151 | extension Tunnel.Configuration: ManagedHandle { 152 | 153 | typealias RawPointer = UnmanagedPointer.RawPointer 154 | 155 | struct UnmanagedPointer: LinPhoneSwift.UnmanagedPointer { 156 | 157 | let rawPointer: OpaquePointer 158 | 159 | @inline(__always) 160 | init(_ rawPointer: OpaquePointer) { 161 | self.rawPointer = rawPointer 162 | } 163 | 164 | @inline(__always) 165 | func retain() { 166 | linphone_tunnel_config_ref(rawPointer) 167 | } 168 | 169 | @inline(__always) 170 | func release() { 171 | linphone_tunnel_config_unref(rawPointer) 172 | } 173 | } 174 | } 175 | 176 | -------------------------------------------------------------------------------- /Sources/LinPhone/VideoPolicy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VideoPolicy.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/12/17. 6 | // 7 | // 8 | 9 | import CLinPhone.types 10 | import CBelledonneToolbox.port 11 | 12 | /// Structure describing policy regarding video streams establishments. 13 | public struct VideoPolicy { 14 | 15 | public typealias LinPhoneType = LinphoneVideoPolicy 16 | 17 | /// Video shall be initiated by default for outgoing calls. 18 | public var automaticallyAccept: Bool 19 | 20 | /// Video shall be accepter by default for incoming calls. 21 | public var automaticallyStart: Bool 22 | 23 | public init(automaticallyAccept: Bool = false, 24 | automaticallyStart: Bool = false) { 25 | 26 | self.automaticallyAccept = automaticallyAccept 27 | self.automaticallyStart = automaticallyStart 28 | } 29 | } 30 | 31 | public extension VideoPolicy { 32 | 33 | init(_ linPhoneType: LinPhoneType) { 34 | 35 | self.automaticallyAccept = linPhoneType.automatically_accept.boolValue 36 | self.automaticallyStart = linPhoneType.automatically_initiate.boolValue 37 | } 38 | 39 | var linPhoneType: LinPhoneType { 40 | 41 | var linPhoneType = LinPhoneType() 42 | 43 | linPhoneType.automatically_accept = bool_t(automaticallyAccept) 44 | linPhoneType.automatically_initiate = bool_t(automaticallyStart) 45 | 46 | return linPhoneType 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/BitMaskOption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BitMaskOption.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 6/6/17. 6 | // 7 | 8 | /// Enum represents a bit mask flag / option. 9 | public protocol BitMaskOption: RawRepresentable, Hashable { 10 | 11 | /// All the cases of the enum. 12 | static var all: Set { get } 13 | } 14 | 15 | /// Convert Swift enums for option flags into their raw values OR'd. 16 | public extension Collection where Iterator.Element: BitMaskOption, Iterator.Element.RawValue: BinaryInteger { 17 | 18 | var flags: Iterator.Element.RawValue { 19 | 20 | @inline(__always) 21 | get { return reduce(0, { $0 | $1.rawValue }) } 22 | } 23 | } 24 | 25 | public extension BitMaskOption where RawValue: BinaryInteger { 26 | 27 | /// Whether the enum case is present in the raw value. 28 | @inline(__always) 29 | func isContained(in rawValue: RawValue) -> Bool { 30 | 31 | return (self.rawValue & rawValue) != 0 32 | } 33 | 34 | @inline(__always) 35 | static func from(flags: RawValue) -> Set { 36 | 37 | return Set(Self.all.filter({ $0.isContained(in: flags) })) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/Bool.swift: -------------------------------------------------------------------------------- 1 | ../BelledonneToolbox/Bool.swift -------------------------------------------------------------------------------- /Sources/MediaStreamer/Enumeration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Enumeration.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/12/17. 6 | // 7 | // 8 | 9 | public protocol MediaStreamerEnumeration { 10 | 11 | associatedtype MediaStreamerType: RawRepresentable 12 | 13 | init?(_ mediaStreamerType: MediaStreamerType) 14 | 15 | var mediaStreamerType: MediaStreamerType { get } 16 | } 17 | 18 | public extension MediaStreamerEnumeration where Self: RawRepresentable, Self.RawValue == MediaStreamerType.RawValue { 19 | 20 | @inline(__always) 21 | init(_ mediaStreamerType: MediaStreamerType) { 22 | 23 | self.init(rawValue: mediaStreamerType.rawValue)! 24 | } 25 | 26 | var mediaStreamerType: MediaStreamerType { 27 | 28 | @inline(__always) 29 | get { return MediaStreamerType(rawValue: self.rawValue)! } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/EventQueue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventQueue.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/16/17. 6 | // 7 | // 8 | 9 | import CMediaStreamer2.eventqueue 10 | 11 | public final class EventQueue { 12 | 13 | public typealias RawPointer = OpaquePointer 14 | 15 | // MARK: - Properties 16 | 17 | @_versioned 18 | internal let rawPointer: RawPointer 19 | 20 | // MARK: - Initialization 21 | 22 | deinit { 23 | 24 | ms_event_queue_destroy(rawPointer) 25 | } 26 | 27 | /// Creates an event queue to receive notifications from MSFilters. 28 | public init?() { 29 | 30 | guard let rawPointer = ms_event_queue_new() 31 | else { return nil } 32 | 33 | self.rawPointer = rawPointer 34 | } 35 | 36 | // MARK: - Methods 37 | 38 | /// Run callbacks associated to the events received. 39 | public func pump() { 40 | 41 | ms_event_queue_pump(rawPointer) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/Factory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Factory.swift 3 | // MediaStreamer 4 | // 5 | // Created by Alsey Coleman Miller on 7/1/17. 6 | // 7 | // 8 | 9 | import CMediaStreamer2.factory 10 | import CBelledonneToolbox.port 11 | import struct BelledonneToolbox.LinkedList 12 | 13 | public final class Factory { 14 | 15 | public typealias RawPointer = UnsafeMutablePointer 16 | 17 | // MARK: - Properties 18 | 19 | @_versioned 20 | internal let rawPointer: RawPointer 21 | 22 | @_versioned 23 | internal let isOwner: Bool 24 | 25 | // MARK: - Initialization 26 | 27 | deinit { 28 | 29 | if isOwner { 30 | 31 | ms_factory_destroy(rawPointer) 32 | } 33 | } 34 | 35 | /// Instantiate from raw C pointer and specify whether the object will own (manage) the raw pointer. 36 | public init(rawPointer: RawPointer, isOwner: Bool = true) { 37 | 38 | self.rawPointer = rawPointer 39 | self.isOwner = isOwner 40 | } 41 | 42 | /// Create a mediastreamer2 `Factory`. 43 | /// This is the root object that will create everything else from mediastreamer2. 44 | public convenience init() { 45 | 46 | guard let rawPointer = ms_factory_new() 47 | else { fatalError("Nil pointer") } 48 | 49 | self.init(rawPointer: rawPointer) 50 | } 51 | 52 | /// Create a mediastreamer2 `Factory` and initialize all voip related filter, card and webcam managers. 53 | public static var voip: Factory { 54 | 55 | guard let rawPointer = ms_factory_new_with_voip() 56 | else { fatalError("Nil pointer") } 57 | 58 | return Factory(rawPointer: rawPointer) 59 | } 60 | 61 | /// Create a mediastreamer2 `Factory`, initialize all voip related filters, 62 | /// cards and webcam managers and load the plugins from the specified directory. 63 | public convenience init(voip directory: (plugins: String, images: String)) { 64 | 65 | guard let rawPointer = ms_factory_new_with_voip_and_directories(directory.plugins, directory.images) 66 | else { fatalError("Nil pointer") } 67 | 68 | self.init(rawPointer: rawPointer) 69 | } 70 | 71 | // MARK: - Accessors 72 | 73 | /// Get number of available cpus for processing. 74 | /// The factory initializes this value to the number of logicial processors available on the machine where it runs. 75 | public var cpuCount: UInt { 76 | 77 | @inline(__always) 78 | get { return UInt(ms_factory_get_cpu_count(rawPointer)) } 79 | 80 | @inline(__always) 81 | set { ms_factory_set_cpu_count(rawPointer, UInt32(newValue)) } 82 | } 83 | 84 | public var maximumTransmissionUnit: UInt { 85 | 86 | @inline(__always) 87 | get { return UInt(ms_factory_get_mtu(rawPointer)) } 88 | 89 | @inline(__always) 90 | set { ms_factory_set_mtu(rawPointer, Int32(newValue)) } 91 | } 92 | 93 | public var platformTags: [String] { 94 | 95 | guard let listRawPointer = ms_factory_get_platform_tags(rawPointer) 96 | else { return [] } 97 | 98 | return LinkedList.strings(from: listRawPointer) 99 | } 100 | 101 | public var payloadMaxSize: Int { 102 | 103 | get { return Int(ms_factory_get_payload_max_size(rawPointer)) } 104 | 105 | set { ms_factory_set_payload_max_size(rawPointer, Int32(newValue)) } 106 | } 107 | 108 | /// The name of the echo canceller filter to use. 109 | public var echoCancellerFilterName: String { 110 | 111 | get { return String(cString: ms_factory_get_echo_canceller_filter_name(rawPointer)) } 112 | 113 | set { ms_factory_set_echo_canceller_filter_name(rawPointer, newValue) } 114 | } 115 | 116 | // MARK: - Methods 117 | 118 | @inline(__always) 119 | public func initializePlugins() { 120 | 121 | ms_factory_init_plugins(rawPointer) 122 | } 123 | 124 | @inline(__always) 125 | public func uninitializePlugins() { 126 | 127 | ms_factory_uninit_plugins(rawPointer) 128 | } 129 | 130 | /// Attempt to load plugins from specified directory or default location. 131 | @discardableResult 132 | public func loadPlugins(from directory: String? = nil) throws -> UInt { 133 | 134 | guard let pluginsCount = ms_factory_load_plugins(rawPointer, directory).nonErrorValue 135 | else { throw Error.pluginsUnsupported } 136 | 137 | return pluginsCount 138 | } 139 | 140 | /// Specify if a filter is enabled or not. 141 | @discardableResult 142 | public func enableFilter(_ enable: Bool, for name: String) -> Bool { 143 | 144 | return ms_factory_enable_filter_from_name(rawPointer, name, bool_t(enable)) == .success 145 | } 146 | 147 | /// Register a filter description. 148 | public func register(filter description: Filter.Description) { 149 | 150 | ms_factory_register_filter(rawPointer, description.internalReference.reference.rawPointer) 151 | } 152 | 153 | /// Add platform tag. 154 | @inline(__always) 155 | public func add(platform tag: String) { 156 | 157 | ms_factory_add_platform_tag(rawPointer, tag) 158 | } 159 | 160 | /// Initialize VOIP features (registration of codecs, sound card and webcam managers). 161 | @inline(__always) 162 | public func initializeVoip() { 163 | 164 | ms_factory_init_voip(rawPointer) 165 | } 166 | 167 | /// Uninitialize VOIP features (registration of codecs, sound card and webcam managers). 168 | @inline(__always) 169 | public func uninitializeVoip() { 170 | 171 | ms_factory_uninit_voip(rawPointer) 172 | } 173 | } 174 | 175 | // MARK: - Supporting Types 176 | 177 | public extension Factory { 178 | 179 | public enum Error: Swift.Error { 180 | 181 | /// No loadable plugin support: plugins cannot be loaded. 182 | case pluginsUnsupported 183 | } 184 | } 185 | 186 | /// Libraries used with `MediaStreamer2` 187 | public enum MediaLibrary { 188 | 189 | case amr 190 | case x264 191 | case openh264 192 | case silk 193 | case webrtc 194 | 195 | /// All media libraries availible for `MediaStreamer`. 196 | public static let all: Set = [amr, x264, openh264, silk, webrtc] 197 | } 198 | 199 | // MARK: - Loading Plugins on iOS 200 | 201 | #if os(iOS) 202 | 203 | public extension Factory { 204 | 205 | func load(_ mediaLibraries: Set) { 206 | 207 | for library in mediaLibraries { 208 | 209 | switch library { 210 | case .amr: libmsamr_init(rawPointer) 211 | case .x264: libmsx264_init(rawPointer) 212 | case .openh264: libmsopenh264_init(rawPointer) 213 | case .silk: libmssilk_init(rawPointer) 214 | case .webrtc: libmswebrtc_init(rawPointer) 215 | } 216 | } 217 | } 218 | } 219 | 220 | // On iOS, plugins are built as static libraries so Liblinphone will not be able to load them at runtime dynamically. 221 | // Instead, you should declare their prototypes 222 | 223 | /// extern void libmsamr_init(MSFactory *factory); 224 | @_silgen_name("libmsamr_init") 225 | fileprivate func libmsamr_init(_ factory: UnsafeMutablePointer) 226 | 227 | /// extern void libmsx264_init(MSFactory *factory); 228 | @_silgen_name("libmsx264_init") 229 | fileprivate func libmsx264_init(_ factory: UnsafeMutablePointer) 230 | 231 | /// extern void libmsopenh264_init(MSFactory *factory); 232 | @_silgen_name("libmsopenh264_init") 233 | fileprivate func libmsopenh264_init(_ factory: UnsafeMutablePointer) 234 | 235 | /// extern void libmssilk_init(MSFactory *factory); 236 | @_silgen_name("libmssilk_init") 237 | fileprivate func libmssilk_init(_ factory: UnsafeMutablePointer) 238 | 239 | /// extern void libmswebrtc_init(MSFactory *factory); 240 | @_silgen_name("libmswebrtc_init") 241 | fileprivate func libmswebrtc_init(_ factory: UnsafeMutablePointer) 242 | 243 | #endif 244 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/Filter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Filter.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/10/17. 6 | // 7 | // 8 | 9 | #if os(macOS) || os(iOS) 10 | import Darwin.C.stdlib 11 | #elseif os(Linux) 12 | import Glibc 13 | #endif 14 | 15 | import CMediaStreamer2.filter 16 | 17 | public final class Filter { 18 | 19 | public typealias RawPointer = UnsafeMutablePointer 20 | 21 | // MARK: - Properties 22 | 23 | @_versioned 24 | internal let rawPointer: RawPointer 25 | 26 | /// The `Filter.Description` this filter was created from. 27 | public let description: Filter.Description? 28 | 29 | // MARK: - Initialization 30 | 31 | deinit { 32 | 33 | // no need to clear user data 34 | 35 | ms_filter_destroy(rawPointer) 36 | } 37 | 38 | /// Instantiate from raw C pointer and specify whether the object will own (manage) the raw pointer. 39 | private init(rawPointer: RawPointer) { 40 | 41 | self.rawPointer = rawPointer 42 | self.description = nil 43 | setUserData() 44 | } 45 | 46 | /// Create decoder filter according to a filter's description. 47 | public init?(description: Description, factory: Factory) { 48 | 49 | guard let rawPointer = ms_factory_create_filter_from_desc(factory.rawPointer, description.internalReference.reference.rawPointer) 50 | else { return nil } 51 | 52 | self.rawPointer = rawPointer 53 | self.description = description 54 | setUserData() 55 | } 56 | 57 | /// Create decoder filter according to a filter's identifier. 58 | public convenience init?(identifier: Identifier, factory: Factory) { 59 | 60 | guard let rawPointer = ms_factory_create_filter(factory.rawPointer, identifier) 61 | else { return nil } 62 | 63 | self.init(rawPointer: rawPointer) 64 | } 65 | 66 | /// Create decoder filter according to a filter's name. 67 | public convenience init?(name: String, factory: Factory) { 68 | 69 | guard let rawPointer = ms_factory_create_filter_from_name(factory.rawPointer, name) 70 | else { return nil } 71 | 72 | self.init(rawPointer: rawPointer) 73 | } 74 | 75 | /// Create encoder filter according to codec name. 76 | public convenience init?(encoder name: String, factory: Factory) { 77 | 78 | guard let rawPointer = ms_factory_create_encoder(factory.rawPointer, name) 79 | else { return nil } 80 | 81 | self.init(rawPointer: rawPointer) 82 | } 83 | 84 | /// Create decoder filter according to codec name. 85 | public convenience init?(decoder name: String, factory: Factory) { 86 | 87 | guard let rawPointer = ms_factory_create_decoder(factory.rawPointer, name) 88 | else { return nil } 89 | 90 | self.init(rawPointer: rawPointer) 91 | } 92 | 93 | // MARK: - Accessors 94 | 95 | /// The identifier of the filter. 96 | public var identifier: Identifier { 97 | 98 | return ms_filter_get_id(rawPointer) 99 | } 100 | 101 | /// The name of the filter. 102 | public var name: String { 103 | 104 | return String(cString: ms_filter_get_name(rawPointer)) 105 | } 106 | 107 | // MARK: - Methods 108 | 109 | /// Link one OUTPUT pin from a filter to an INPUT pin of another filter. 110 | /// 111 | /// All data coming from the OUTPUT pin of one filter will be distributed 112 | /// to the INPUT pin of the second filter. 113 | public func link(pin: CInt, to filter: Filter, pin pin2: CInt) -> Bool { 114 | 115 | return ms_filter_link(rawPointer, pin, filter.rawPointer, pin2) == 0 116 | } 117 | 118 | /// Unlink one OUTPUT pin from a filter to an INPUT pin of another filter. 119 | public func unlink(pin: CInt, to filter: Filter, pin pin2: CInt) -> Bool { 120 | 121 | return ms_filter_unlink(rawPointer, pin, filter.rawPointer, pin2) == 0 122 | } 123 | 124 | /// Returns whether the filter implements a given method. 125 | public func implements(method: UInt) -> Bool { 126 | 127 | return ms_filter_has_method(rawPointer, CUnsignedInt(method)).boolValue 128 | } 129 | } 130 | 131 | // MARK: - BelledonneObject 132 | 133 | public extension Filter /* : BelledonneObject */ { 134 | 135 | public func withUnsafeMutableRawPointer (_ body: (UnsafeMutablePointer) throws -> Result) rethrows -> Result { 136 | 137 | rawPointer.pointee.lock() 138 | 139 | defer { rawPointer.pointee.unlock() } 140 | 141 | return try body(rawPointer) 142 | } 143 | } 144 | 145 | // MARK: - UserDataHandle 146 | 147 | extension Filter { 148 | 149 | /// Attempt to get the Swift object associated with the raw C instance. 150 | static func from(rawPointer: RawPointer) -> Filter? { 151 | 152 | // lock to access data 153 | rawPointer.pointee.lock() 154 | 155 | defer { rawPointer.pointee.unlock() } 156 | 157 | guard let userData = rawPointer.pointee.data 158 | else { return nil } 159 | 160 | let unmanaged = Unmanaged.fromOpaque(userData) 161 | 162 | let object = unmanaged.takeUnretainedValue() 163 | 164 | return object 165 | } 166 | } 167 | 168 | private extension Filter { 169 | 170 | func setUserData() { 171 | 172 | let userData = createUserData() 173 | 174 | withUnsafeMutableRawPointer { $0.pointee.data = userData } 175 | } 176 | 177 | @inline(__always) 178 | private func createUserData() -> UnsafeMutableRawPointer { 179 | 180 | let unmanaged = Unmanaged.passUnretained(self) 181 | 182 | let objectPointer = unmanaged.toOpaque() 183 | 184 | return objectPointer 185 | } 186 | } 187 | 188 | // MARK: - RawPointer 189 | 190 | public extension MSFilter { 191 | 192 | @inline(__always) 193 | mutating func lock() { 194 | 195 | pthread_mutex_lock(&lock) 196 | } 197 | 198 | @inline(__always) 199 | mutating func unlock() { 200 | 201 | pthread_mutex_unlock(&lock) 202 | } 203 | } 204 | 205 | // MARK: - Supporting Types 206 | 207 | public extension Filter { 208 | 209 | public typealias Identifier = MSFilterId 210 | } 211 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/FilterCategory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterCategory.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 9/5/17. 6 | // 7 | // 8 | 9 | import struct CMediaStreamer2.MSFilterCategory 10 | 11 | public extension Filter { 12 | 13 | /// Describes filter's category. 14 | public enum Category: UInt32, MediaStreamerEnumeration { 15 | 16 | public typealias MediaStreamerType = MSFilterCategory 17 | 18 | /// Other filters. 19 | case other 20 | 21 | /// Used by encoders. 22 | case encoder 23 | 24 | /// Used by decoders. 25 | case decoder 26 | 27 | /// Used by capture filters that perform encoding. 28 | case encodingCapturer 29 | 30 | /// Used by filters that perform decoding and rendering. 31 | case decoderRenderer 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/FilterFlag.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterFlag.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 9/6/17. 6 | // 7 | // 8 | 9 | import CMediaStreamer2.filter 10 | 11 | public extension Filter { 12 | 13 | public enum Flag { 14 | 15 | /// The filter must be called in process function every tick. 16 | case pump 17 | 18 | /// Flag to specify if a filter is enabled or not. 19 | case enabled 20 | } 21 | } 22 | 23 | extension Filter.Flag: BitMaskOption { 24 | 25 | public static var all: Set { return [.pump, .enabled] } 26 | } 27 | 28 | extension Filter.Flag: MediaStreamerEnumeration { 29 | 30 | public typealias MediaStreamerType = MSFilterFlags 31 | 32 | public init?(_ mediaStreamerType: MediaStreamerType) { 33 | 34 | switch mediaStreamerType { 35 | case MS_FILTER_IS_PUMP: self = .pump 36 | case MS_FILTER_IS_ENABLED: self = .enabled 37 | default: return nil 38 | } 39 | } 40 | 41 | public var mediaStreamerType: MediaStreamerType { 42 | 43 | switch self { 44 | case .pump: return MS_FILTER_IS_PUMP 45 | case .enabled: return MS_FILTER_IS_ENABLED 46 | } 47 | } 48 | } 49 | 50 | extension Filter.Flag: RawRepresentable { 51 | 52 | public typealias RawValue = MediaStreamerType.RawValue 53 | 54 | public init?(rawValue: RawValue) { 55 | 56 | self.init(MediaStreamerType(rawValue)) 57 | } 58 | 59 | public var rawValue: RawValue { 60 | 61 | return mediaStreamerType.rawValue 62 | } 63 | } 64 | 65 | extension Filter.Flag: Equatable { 66 | 67 | public static func == (lhs: Filter.Flag, rhs: Filter.Flag) -> Bool { 68 | 69 | return lhs.rawValue == rhs.rawValue 70 | } 71 | } 72 | 73 | extension Filter.Flag: Hashable { 74 | 75 | public var hashValue: Int { 76 | 77 | return Int(rawValue) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/FilterInterface.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterInterface.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/12/17. 6 | // 7 | // 8 | 9 | import struct CMediaStreamer2.MSFilterInterfaceId 10 | 11 | public extension Filter { 12 | 13 | /// Interface IDs, used to generate method names. 14 | public enum Interface: UInt32, MediaStreamerEnumeration { 15 | 16 | public typealias MediaStreamerType = MSFilterInterfaceId 17 | 18 | case begin = 16384 19 | 20 | /// Player interface, used to control playing of files. 21 | case player 22 | 23 | /// Recorder interface, used to control recording of stream into files. 24 | case recorder 25 | 26 | /// Video display interface, used to control the rendering of raw pictures onscreen 27 | case videoDisplay 28 | 29 | /// Echo canceller interface, used to control echo canceller implementations. 30 | case echoCanceller 31 | 32 | /// Video decoder interface 33 | case videoDecoder 34 | 35 | /// Video capture interface 36 | case videoCapture 37 | 38 | /// Audio Decoder interface 39 | case audioDecoder 40 | 41 | /// Video encoder interface 42 | case videoEncoder 43 | 44 | /// Interface for audio capture filters 45 | case audioCapture 46 | 47 | /// Interface for audio playback filters. 48 | case audioPlayback 49 | 50 | /// Video encoder interface 51 | case audioEncoder 52 | 53 | /// Void source/sink interface 54 | case void 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/FilterMethod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterMethod.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 9/6/17. 6 | // 7 | // 8 | 9 | import CMediaStreamer2 10 | 11 | public extension Filter { 12 | 13 | public enum Method { 14 | 15 | case getVideoSize((Filter) -> MSVideoSize) 16 | case setVideoSize((Filter, MSVideoSize) -> ()) 17 | } 18 | } 19 | 20 | internal extension Filter.Method { 21 | 22 | var id: FilterMethodIdentifier { 23 | 24 | switch self { 25 | case .getVideoSize(_): return FilterMethodIdentifier() //.getVideoSize // TODO: FIXME 26 | case .setVideoSize(_): return FilterMethodIdentifier() //.setVideoSize 27 | } 28 | } 29 | 30 | var function: MSFilterMethodFunc { 31 | 32 | switch self { 33 | case .getVideoSize(_): return FilterGetVideoSize 34 | case .setVideoSize(_): return FilterSetVideoSize 35 | } 36 | } 37 | } 38 | 39 | // MARK: - Supporting Types 40 | 41 | internal extension Filter.Description { 42 | 43 | final class Methods { 44 | 45 | typealias Element = Filter.Method 46 | 47 | typealias Buffer = UnsafeMutablePointer 48 | 49 | let buffer: Buffer? 50 | 51 | let size: Int 52 | 53 | let elements: [Filter.Method] 54 | 55 | deinit { 56 | 57 | if let buffer = self.buffer { 58 | 59 | buffer.deinitialize(count: size) 60 | buffer.deallocate(capacity: size) 61 | } 62 | } 63 | 64 | init(_ elements: [Filter.Method]) { 65 | 66 | self.elements = elements 67 | 68 | if elements.isEmpty { 69 | 70 | self.size = 0 71 | self.buffer = nil 72 | 73 | } else { 74 | 75 | // allocate array 76 | self.size = elements.count + 1 // null terminated array 77 | let buffer = Buffer.allocate(capacity: size) 78 | buffer.initialize(to: MSFilterMethod(), count: size) 79 | 80 | // set buffer contents 81 | for (index, method) in elements.enumerated() { 82 | 83 | buffer[index] = MSFilterMethod(id: method.id.rawValue, method: method.function) 84 | } 85 | 86 | self.buffer = buffer 87 | } 88 | } 89 | } 90 | } 91 | 92 | extension Filter.Description.Methods: ExpressibleByArrayLiteral { 93 | 94 | convenience init(arrayLiteral elements: Element...) { 95 | 96 | self.init(elements) 97 | } 98 | } 99 | 100 | // MARK: - Private Function 101 | 102 | private extension Filter.Method { 103 | 104 | typealias Status = Int32 105 | 106 | typealias Argument = UnsafeMutableRawPointer 107 | } 108 | 109 | private func FilterGetVideoSize(_ rawPointer: Filter.RawPointer?, _ arg: Filter.Method.Argument?) -> Filter.Method.Status { 110 | 111 | guard let rawPointer = rawPointer, 112 | let filter = Filter.from(rawPointer: rawPointer), 113 | let description = filter.description, 114 | let arg = arg 115 | else { return .error } 116 | 117 | for method in description.methods { 118 | 119 | guard case let .getVideoSize(body) = method 120 | else { continue } 121 | 122 | let videoSize = arg.assumingMemoryBound(to: MSVideoSize.self) 123 | 124 | videoSize.pointee = body(filter) 125 | 126 | return .success 127 | } 128 | 129 | return .error 130 | } 131 | 132 | private func FilterSetVideoSize(_ rawPointer: Filter.RawPointer?, _ arg: Filter.Method.Argument?) -> Filter.Method.Status { 133 | 134 | guard let rawPointer = rawPointer, 135 | let filter = Filter.from(rawPointer: rawPointer), 136 | let description = filter.description, 137 | let arg = arg 138 | else { return .error } 139 | 140 | for method in description.methods { 141 | 142 | guard case let .setVideoSize(body) = method 143 | else { continue } 144 | 145 | let videoSize = arg.assumingMemoryBound(to: MSVideoSize.self).pointee 146 | 147 | body(filter, videoSize) 148 | 149 | return .success 150 | } 151 | 152 | return .error 153 | } 154 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/Handle.swift: -------------------------------------------------------------------------------- 1 | ../LinPhone/Handle.swift -------------------------------------------------------------------------------- /Sources/MediaStreamer/ManagedCString.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ManagedCString.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 9/6/17. 6 | // 7 | // 8 | 9 | #if os(macOS) || os(iOS) 10 | import Darwin.C.stdlib 11 | #elseif os(Linux) 12 | import Glibc 13 | #endif 14 | 15 | internal final class ManagedCString { 16 | 17 | typealias RawPointer = UnsafeMutablePointer? 18 | 19 | typealias DidChange = (CString) -> () 20 | 21 | // MARK: - Properties 22 | 23 | @_versioned 24 | internal private(set) var rawPointer: RawPointer = nil 25 | 26 | @_versioned 27 | internal var string: String? = nil { 28 | 29 | didSet { stringChanged() } 30 | } 31 | 32 | internal var didChange: DidChange 33 | 34 | // MARK: - Initialization 35 | 36 | deinit { 37 | 38 | if let pointer = rawPointer { 39 | 40 | free(pointer) 41 | } 42 | } 43 | 44 | init(didChange: @escaping DidChange) { 45 | 46 | self.didChange = didChange 47 | } 48 | 49 | private func stringChanged() { 50 | 51 | // free C string of old value 52 | if let oldPointer = rawPointer { 53 | 54 | free(oldPointer) 55 | } 56 | 57 | // set new string buffer 58 | self.rawPointer = string?.withCString { strdup($0) } 59 | 60 | // call callback 61 | let cString = unsafeBitCast(rawPointer, to: CString.self) 62 | didChange(cString) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/Queue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Queue.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/18/17. 6 | // 7 | // 8 | 9 | import CMediaStreamer2.queue 10 | 11 | public final class Queue { 12 | 13 | public typealias RawPointer = UnsafeMutablePointer 14 | 15 | // MARK: - Properties 16 | 17 | @_versioned 18 | internal let rawPointer: RawPointer 19 | 20 | public let previous: ConnectionPoint 21 | 22 | public let next: ConnectionPoint 23 | 24 | // MARK: - Initialization 25 | 26 | deinit { 27 | 28 | ms_queue_destroy(rawPointer) 29 | } 30 | 31 | public init(previous: ConnectionPoint, next: ConnectionPoint) { 32 | 33 | self.rawPointer = ms_queue_new(previous.filter.rawPointer, Int32(previous.pin), 34 | next.filter.rawPointer, Int32(next.pin)) 35 | 36 | self.previous = previous 37 | self.next = next 38 | } 39 | 40 | // MARK: - Accessors 41 | 42 | public var isEmpty: Bool { 43 | 44 | return ms_queue_empty(rawPointer).boolValue 45 | } 46 | 47 | // MARK: - Methods 48 | 49 | @inline(__always) 50 | public func flush() { 51 | 52 | ms_queue_flush(rawPointer) 53 | } 54 | } 55 | 56 | // MARK: - Supporting Types 57 | 58 | public extension Queue { 59 | 60 | public final class ConnectionPoint { 61 | 62 | public let filter: Filter 63 | 64 | public let pin: Int 65 | 66 | public init(filter: Filter, pin: Int) { 67 | 68 | self.filter = filter 69 | self.pin = pin 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Sources/MediaStreamer/RFC3984.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RFC3984.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 8/17/17. 6 | // 7 | // 8 | 9 | import CBelledonneToolbox.port 10 | import CBelledonneRTP.stringutils 11 | import CMediaStreamer2.rfc3984 12 | import class BelledonneRTP.Packet 13 | 14 | /// Used to pack/unpack H264 nals as described in RFC3984 15 | public final class Rfc3984Context { 16 | 17 | public typealias RawPointer = UnsafeMutablePointer 18 | 19 | // MARK: - Properties 20 | 21 | @_versioned 22 | internal let rawPointer: RawPointer 23 | 24 | // MARK: - Initialization 25 | 26 | deinit { 27 | 28 | rfc3984_destroy(rawPointer) 29 | } 30 | 31 | public init() { 32 | 33 | guard let rawPointer = rfc3984_new() 34 | else { fatalError("Could not create object") } 35 | 36 | self.rawPointer = rawPointer 37 | } 38 | 39 | // MARK: - Accessors 40 | 41 | public var mode: Bool { 42 | 43 | @inline(__always) 44 | get { return rawPointer.pointee.mode.boolValue } 45 | 46 | @inline(__always) 47 | set { rawPointer.pointee.mode = bool_t(newValue) } 48 | } 49 | 50 | public var isSingleTimeAggregationPacketAEnabled: Bool { 51 | 52 | @inline(__always) 53 | get { return rawPointer.pointee.stap_a_allowed.boolValue } 54 | 55 | @inline(__always) 56 | set { rawPointer.pointee.stap_a_allowed = bool_t(newValue) } 57 | } 58 | 59 | public var maxSize: Int { 60 | 61 | @inline(__always) 62 | get { return Int(rawPointer.pointee.maxsz) } 63 | 64 | @inline(__always) 65 | set { rawPointer.pointee.maxsz = Int32(newValue) } 66 | } 67 | 68 | // MARK: - Methods 69 | 70 | /// Process NALUs and pack them into rtp payload. 71 | public func pack(nalu: Queue, rtp: Queue, ts: UInt) { 72 | 73 | rfc3984_pack(rawPointer, nalu.rawPointer, rtp.rawPointer, UInt32(ts)) 74 | } 75 | 76 | /// Process incoming rtp data and output NALUs, whenever possible. 77 | /// 78 | /// - Parameter packet: A new H264 packet to process. 79 | /// - Parameter nalu: A `Queue` into which a frame ready to be decoded will be output, 80 | /// in the form of a sequence of NAL units. 81 | public func unpack(packet: Packet, nalu: Queue) -> Rfc3984Status { 82 | 83 | let status = packet.withUnsafeRawPointer { rfc3984_unpack2(rawPointer, UnsafeMutablePointer($0), nalu.rawPointer) } 84 | 85 | return Rfc3984Status(status) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Tests/BelledonneRTPTests/Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 9/5/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /Tests/BelledonneSIPTests/URITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URITests.swift 3 | // BelledonneSIPTests 4 | // 5 | // Created by Alsey Coleman Miller on 6/30/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import BelledonneSIP 11 | 12 | final class URITests: XCTestCase { 13 | 14 | static var allTests = [ 15 | ("testBasicURI", testBasicURI), 16 | ("testValueSemantics", testValueSemantics) 17 | ] 18 | 19 | func testBasicURI() { 20 | 21 | do { 22 | 23 | let rawURI = "http://www.linphone.org/index.html" 24 | 25 | guard let sourceURI = URI(rawValue: rawURI) 26 | else { XCTFail(); return } 27 | 28 | XCTAssert(sourceURI.rawValue == rawURI) 29 | 30 | guard let firstURI = URI(rawValue: sourceURI.rawValue) 31 | else { XCTFail(); return } 32 | 33 | let uri = firstURI // no copy since we are using value types 34 | 35 | XCTAssert(uri.scheme == "http") 36 | XCTAssert(uri.host == "www.linphone.org") 37 | XCTAssert(uri.path == "/index.html") 38 | XCTAssert(uri.rawValue == uri.description) 39 | XCTAssert(uri.rawValue == rawURI) 40 | } 41 | 42 | do { 43 | 44 | let rawURI = "http://www.linphone.org/" 45 | 46 | guard let sourceURI = URI(rawValue: rawURI) 47 | else { XCTFail(); return } 48 | 49 | XCTAssert(sourceURI.path == "/") 50 | } 51 | 52 | do { 53 | 54 | let rawURI = "http://www.linphone.org/a/b/c" 55 | 56 | guard let sourceURI = URI(rawValue: rawURI) 57 | else { XCTFail(); return } 58 | 59 | XCTAssert(sourceURI.path == "/a/b/c") 60 | XCTAssert(sourceURI.rawValue == "http://www.linphone.org/a/b/c") 61 | XCTAssert(sourceURI.description == sourceURI.rawValue) 62 | } 63 | } 64 | 65 | func testValueSemantics() { 66 | 67 | let rawURI = "http://www.linphone.org/index.html" 68 | 69 | guard let sourceURI = URI(rawValue: rawURI) 70 | else { XCTFail(); return } 71 | 72 | let unmutatedCopy = sourceURI 73 | let unmutatedCopy2 = unmutatedCopy 74 | XCTAssert(sourceURI.internalReference.reference === unmutatedCopy.internalReference.reference) 75 | XCTAssert(sourceURI.internalReference.reference.unmanagedPointer.rawPointer == unmutatedCopy.internalReference.reference.unmanagedPointer.rawPointer) 76 | XCTAssert(sourceURI.internalReference.reference === unmutatedCopy2.internalReference.reference) 77 | XCTAssert(unmutatedCopy.internalReference.reference === unmutatedCopy2.internalReference.reference) 78 | 79 | var mutableCopy = sourceURI 80 | XCTAssert(sourceURI.internalReference.reference === mutableCopy.internalReference.reference) 81 | mutableCopy.port = 8080 82 | XCTAssert(sourceURI.internalReference.reference !== mutableCopy.internalReference.reference) 83 | XCTAssert(sourceURI.internalReference.reference.unmanagedPointer.rawPointer != mutableCopy.internalReference.reference.unmanagedPointer.rawPointer) 84 | XCTAssert(unmutatedCopy.internalReference.reference !== mutableCopy.internalReference.reference) 85 | XCTAssert(unmutatedCopy2.internalReference.reference !== mutableCopy.internalReference.reference) 86 | XCTAssert(sourceURI.internalReference.reference === unmutatedCopy.internalReference.reference) 87 | XCTAssert(sourceURI.internalReference.reference === unmutatedCopy2.internalReference.reference) 88 | XCTAssert(unmutatedCopy.internalReference.reference === unmutatedCopy2.internalReference.reference) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Tests/BelledonneToolboxTests/LinkedListTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Core.swift 3 | // LinPhoneTests 4 | // 5 | // Created by Alsey Coleman Miller on 6/30/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import BelledonneToolbox 11 | 12 | final class LinkedListTests: XCTestCase { 13 | 14 | static var allTests = [ 15 | ("testStringList", testStringList), 16 | ("testDataList", testDataList), 17 | ("testEmptyList", testEmptyList), 18 | ("testRawPointer", testRawPointer) 19 | ] 20 | 21 | func testStringList() { 22 | 23 | let items = (1 ... 10).map { "item\($0)" } 24 | 25 | let list = LinkedList(strings: items) 26 | XCTAssert(list.strings == items) 27 | XCTAssert(list.data.count == items.count) 28 | XCTAssert(list.isEmpty == false) 29 | XCTAssert(list.description == "\(items)") 30 | list.withUnsafeRawPointer { XCTAssert($0 != nil) } 31 | } 32 | 33 | func testDataList() { 34 | 35 | let items = (1 ... 10).map { "item\($0)".data(using: String.Encoding.utf8)! } 36 | 37 | let list = LinkedList(data: items) 38 | XCTAssert(list.data == items) 39 | XCTAssert(list.strings.count == items.count) 40 | XCTAssert(list.isEmpty == false) 41 | XCTAssert(list.description.isEmpty == false) 42 | list.withUnsafeRawPointer { XCTAssert($0 != nil) } 43 | } 44 | 45 | func testEmptyList() { 46 | 47 | let items = [Data]() 48 | 49 | let list = LinkedList(data: items) 50 | XCTAssert(list.isEmpty) 51 | XCTAssert(list.strings.isEmpty) 52 | XCTAssert(list.data.isEmpty) 53 | XCTAssert(list.description == "\(items)") 54 | list.withUnsafeRawPointer { XCTAssert($0 == nil) } 55 | } 56 | 57 | func testRawPointer() { 58 | 59 | let lists = [["1", "2"], ["1"], []] 60 | .map { LinkedList(strings: $0) } 61 | 62 | for list in lists { 63 | 64 | list.withUnsafeRawPointer { (rawPointer) in 65 | 66 | if let rawPointer = rawPointer { 67 | 68 | let extractedStrings = LinkedList.strings(from: rawPointer) 69 | 70 | XCTAssert(list.strings == extractedStrings) 71 | 72 | let clonedList = LinkedList(strings: list.strings) 73 | 74 | XCTAssert(clonedList == list) 75 | 76 | } else { 77 | 78 | XCTAssert(list.isEmpty) 79 | } 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Tests/LinPhoneTests/AddressTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AddressTests.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 7/9/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import LinPhoneSwift 11 | 12 | final class AddressTests: XCTestCase { 13 | 14 | func testParsingNil() { 15 | 16 | let rawValues = ["sip:@sip.linphone.org", 17 | "", 18 | "google.com"] 19 | 20 | for rawValue in rawValues { 21 | 22 | XCTAssert(Address(rawValue: rawValue) == nil, rawValue) 23 | } 24 | } 25 | 26 | func testParsing() { 27 | 28 | let rawValues = ["sip:5105347@ring.com", 29 | "sip:toto@titi", 30 | "sips:toto@titi", 31 | "sip:toto@titi;transport=tcp", 32 | "sip:toto@titu", 33 | "sip:toto@titi;transport=udp", 34 | "sip:toto@titi?X-Create-Account=yes"] 35 | 36 | for rawValue in rawValues { 37 | 38 | guard let _ = Address(rawValue: rawValue) 39 | else { XCTFail("Could not create address \(rawValue)"); return } 40 | 41 | //XCTAssert(address.rawValue == rawValue, "\(address.rawValue) != \(rawValue)") 42 | } 43 | } 44 | 45 | func testValueSemantics() { 46 | 47 | let rawValue = "sip:toto@titi" 48 | 49 | guard let address = Address(rawValue: rawValue) 50 | else { XCTFail("Could not create address \(rawValue)"); return } 51 | 52 | let unmutatedCopy = address 53 | let unmutatedCopy2 = unmutatedCopy 54 | XCTAssert(address.internalReference.reference === unmutatedCopy.internalReference.reference) 55 | XCTAssert(address.internalReference.reference.unmanagedPointer.rawPointer == unmutatedCopy.internalReference.reference.unmanagedPointer.rawPointer) 56 | XCTAssert(address.internalReference.reference === unmutatedCopy2.internalReference.reference) 57 | XCTAssert(unmutatedCopy.internalReference.reference === unmutatedCopy2.internalReference.reference) 58 | 59 | var mutableCopy = address 60 | XCTAssert(address.internalReference.reference === mutableCopy.internalReference.reference) 61 | mutableCopy.port = 8080 62 | mutableCopy.clean() 63 | XCTAssert(address.internalReference.reference !== mutableCopy.internalReference.reference) 64 | XCTAssert(address.internalReference.reference.unmanagedPointer.rawPointer != mutableCopy.internalReference.reference.unmanagedPointer.rawPointer) 65 | XCTAssert(unmutatedCopy.internalReference.reference !== mutableCopy.internalReference.reference) 66 | XCTAssert(unmutatedCopy2.internalReference.reference !== mutableCopy.internalReference.reference) 67 | XCTAssert(address.internalReference.reference === unmutatedCopy.internalReference.reference) 68 | XCTAssert(address.internalReference.reference === unmutatedCopy2.internalReference.reference) 69 | XCTAssert(unmutatedCopy.internalReference.reference === unmutatedCopy2.internalReference.reference) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Tests/LinPhoneTests/InternalTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InternalTests.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 10/13/17. 6 | // 7 | 8 | import XCTest 9 | @testable import LinPhoneSwift 10 | 11 | final class InternalTests: XCTestCase { 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import LinPhoneSwiftTests 3 | 4 | XCTMain([ 5 | testCase(LinPhoneSwiftTests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /Tests/MediaStreamerTests/FactoryTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FactoryTests.swift 3 | // LinPhoneTests 4 | // 5 | // Created by Alsey Coleman Miller on 6/30/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | @testable import MediaStreamer 11 | 12 | final class FactoryTests: XCTestCase { 13 | 14 | static var allTests = [ 15 | ("testLibraries", testLibraries), 16 | ] 17 | 18 | func testLibraries() { 19 | 20 | let factory = MediaStreamer.Factory() 21 | 22 | factory.loadPlugins() 23 | 24 | #if os(iOS) 25 | factory.load(MediaLibrary.all) 26 | #endif 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Tests/MediaStreamerTests/FilterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterTests.swift 3 | // LinPhone 4 | // 5 | // Created by Alsey Coleman Miller on 9/6/17. 6 | // 7 | // 8 | 9 | import XCTest 10 | import CMediaStreamer2.filter 11 | @testable import MediaStreamer 12 | 13 | final class FilterTests: XCTestCase { 14 | 15 | func testCustomFilter() { 16 | 17 | let factory = Factory() 18 | 19 | var description = Filter.Description() 20 | 21 | let filterDescriptionReference = description.internalReference.reference 22 | 23 | // set new values 24 | description.identifier = MS_VT_H264_DEC_ID 25 | description.name = "TestFilter Decoder" 26 | description.encodingFormat = "H264" 27 | description.text = "A test filter" 28 | description.category = .decoder 29 | description.inputCount = 1 30 | description.outputCount = 1 31 | description.flags = [.pump, .enabled] 32 | description.methods = [] 33 | 34 | XCTAssert(description.flags == [.pump, .enabled]) 35 | XCTAssert(description.internalReference.reference === filterDescriptionReference) 36 | 37 | description.initialization = { _ in print("Filter created") } 38 | 39 | let uninitExpectation = self.expectation(description: "Filter uninitialized") 40 | 41 | description.uninitialization = { (filter) in 42 | 43 | print("\(filter.name) destroyed") 44 | 45 | // assert values 46 | XCTAssert(filter.name == description.name) 47 | 48 | // assert backing references 49 | XCTAssert(filter.description?.internalReference.reference === filterDescriptionReference) 50 | XCTAssert(filter.description?.internalReference.reference === description.internalReference.reference) 51 | 52 | uninitExpectation.fulfill() 53 | } 54 | 55 | // create custom filter 56 | var filter = Filter(description: description, factory: factory) 57 | XCTAssertNotNil(filter, "Could not create filter") 58 | XCTAssert(filter?.name == description.name) 59 | XCTAssert(filter?.description?.internalReference.reference === filterDescriptionReference) 60 | XCTAssert(filter?.description?.internalReference.reference === description.internalReference.reference) 61 | 62 | // release 63 | filter = nil 64 | 65 | waitForExpectations(timeout: 2) 66 | } 67 | 68 | func testNewFilterDescription() { 69 | 70 | var description = Filter.Description() 71 | 72 | // validate new filter description 73 | XCTAssert(description.name == nil) 74 | XCTAssert(description.encodingFormat == nil) 75 | XCTAssert(description.text == nil) 76 | XCTAssert(description.category == .other) 77 | XCTAssert(description.category.rawValue == 0) 78 | XCTAssert(description.inputCount == 0) 79 | XCTAssert(description.outputCount == 0) 80 | XCTAssert(description.implements(interface: .begin) == false) 81 | } 82 | 83 | func testFilterDescriptionValueSemantics() { 84 | 85 | var description = Filter.Description() 86 | 87 | let filterDescriptionReference = description.internalReference.reference 88 | 89 | // set new values 90 | description.identifier = MS_VT_H264_DEC_ID 91 | description.name = "TestFilter Decoder" 92 | description.text = "A test filter" 93 | description.category = .decoder 94 | description.inputCount = 1 95 | description.outputCount = 1 96 | description.flags = [.pump, .enabled] 97 | description.methods = [] 98 | 99 | XCTAssert(description.internalReference.reference === filterDescriptionReference) 100 | 101 | let unmutatedCopy = description 102 | let unmutatedCopy2 = unmutatedCopy 103 | XCTAssert(description.internalReference.reference === unmutatedCopy.internalReference.reference) 104 | XCTAssert(description.internalReference.reference.rawPointer == unmutatedCopy.internalReference.reference.rawPointer) 105 | XCTAssert(description.internalReference.reference === unmutatedCopy2.internalReference.reference) 106 | XCTAssert(unmutatedCopy.internalReference.reference === unmutatedCopy2.internalReference.reference) 107 | 108 | var mutableCopy = description 109 | XCTAssert(description.internalReference.reference === mutableCopy.internalReference.reference) 110 | XCTAssert(mutableCopy.name == description.name) 111 | let newValue = "New value" 112 | mutableCopy.name = newValue 113 | XCTAssert(mutableCopy.name != description.name) 114 | XCTAssert(description.name != newValue) 115 | XCTAssert(mutableCopy.name == newValue) 116 | XCTAssert(description.internalReference.reference !== mutableCopy.internalReference.reference) 117 | XCTAssert(description.internalReference.reference.rawPointer != mutableCopy.internalReference.reference.rawPointer) 118 | XCTAssert(unmutatedCopy.internalReference.reference !== mutableCopy.internalReference.reference) 119 | XCTAssert(unmutatedCopy2.internalReference.reference !== mutableCopy.internalReference.reference) 120 | XCTAssert(description.internalReference.reference === unmutatedCopy.internalReference.reference) 121 | XCTAssert(description.internalReference.reference === unmutatedCopy2.internalReference.reference) 122 | XCTAssert(unmutatedCopy.internalReference.reference === unmutatedCopy2.internalReference.reference) 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/BelledonneRTP-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/BelledonneRTPTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/BelledonneSIP-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/BelledonneSIPTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/BelledonneToolbox-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/BelledonneToolboxTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/LinPhoneSwift-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/LinPhoneTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/MediaStreamer-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/MediaStreamerTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CFBundleDevelopmentRegion 5 | en 6 | CFBundleExecutable 7 | $(EXECUTABLE_NAME) 8 | CFBundleIdentifier 9 | $(PRODUCT_BUNDLE_IDENTIFIER) 10 | CFBundleInfoDictionaryVersion 11 | 6.0 12 | CFBundleName 13 | $(PRODUCT_NAME) 14 | CFBundlePackageType 15 | BNDL 16 | CFBundleShortVersionString 17 | 1.0 18 | CFBundleSignature 19 | ???? 20 | CFBundleVersion 21 | $(CURRENT_PROJECT_VERSION) 22 | NSPrincipalClass 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/BelledonneRTP iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/BelledonneRTP macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/BelledonneSIP iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/BelledonneSIP macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/BelledonneToolbox iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/BelledonneToolbox macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/LinPhoneSwift iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 76 | 78 | 79 | 82 | 83 | 85 | 88 | 89 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/LinPhoneSwift macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/MediaStreamer iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/MediaStreamer macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Xcode/LinPhone.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SchemeUserState 5 | 6 | LinPhoneSwift.xcscheme 7 | 8 | 9 | SuppressBuildableAutocreation 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Xcode/Modules/CBelledonneRTP/module.modulemap: -------------------------------------------------------------------------------- 1 | module CBelledonneRTP { 2 | 3 | header "ortp/ortp.h" 4 | 5 | module port { 6 | header "ortp/port.h" 7 | } 8 | 9 | module b64 { 10 | header "ortp/b64.h" 11 | } 12 | 13 | module event { 14 | header "ortp/event.h" 15 | } 16 | 17 | module logging { 18 | header "ortp/logging.h" 19 | } 20 | 21 | module payloadtype { 22 | header "ortp/payloadtype.h" 23 | } 24 | 25 | module rtcp { 26 | header "ortp/rtcp.h" 27 | } 28 | 29 | module rtp { 30 | header "ortp/rtp.h" 31 | } 32 | 33 | module rtpprofile { 34 | header "ortp/rtpprofile.h" 35 | } 36 | 37 | module rtpsession { 38 | header "ortp/rtpsession.h" 39 | } 40 | 41 | module rtpsignaltable { 42 | header "ortp/rtpsignaltable.h" 43 | } 44 | 45 | module sessionset { 46 | header "ortp/sessionset.h" 47 | } 48 | 49 | module stringutils { 50 | header "ortp/str_utils.h" 51 | } 52 | 53 | module telephonyevents { 54 | header "ortp/telephonyevents.h" 55 | } 56 | 57 | module utils { 58 | header "ortp/utils.h" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Xcode/Modules/CBelledonneSIP/module.modulemap: -------------------------------------------------------------------------------- 1 | module CBelledonneSIP { 2 | 3 | umbrella header "belle-sip/belle-sip.h" 4 | 5 | module * { export * } 6 | export * 7 | } 8 | -------------------------------------------------------------------------------- /Xcode/Modules/CBelledonneToolbox/module.modulemap: -------------------------------------------------------------------------------- 1 | module CBelledonneToolbox { 2 | 3 | module port { 4 | header "bctoolbox/port.h" 5 | } 6 | 7 | module crypto { 8 | header "bctoolbox/crypto.h" 9 | } 10 | 11 | module defs { 12 | header "bctoolbox/defs.h" 13 | } 14 | 15 | module list { 16 | header "bctoolbox/list.h" 17 | } 18 | 19 | module logging { 20 | header "bctoolbox/logging.h" 21 | } 22 | 23 | module map { 24 | header "bctoolbox/map.h" 25 | } 26 | 27 | module parser { 28 | header "bctoolbox/parser.h" 29 | } 30 | 31 | module vconnect { 32 | header "bctoolbox/vconnect.h" 33 | } 34 | 35 | module vfs { 36 | header "bctoolbox/vfs.h" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Xcode/Modules/CLinPhone/module.modulemap: -------------------------------------------------------------------------------- 1 | module CLinPhone { 2 | 3 | module types { 4 | header "linphone/types.h" 5 | } 6 | 7 | module address { 8 | header "linphone/address.h" 9 | } 10 | 11 | module core { 12 | header "linphone/core.h" 13 | } 14 | 15 | module coreutils { 16 | header "linphone/core_utils.h" 17 | } 18 | 19 | module tunnel { 20 | header "linphone/tunnel.h" 21 | } 22 | 23 | module factory { 24 | header "linphone/factory.h" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Xcode/Modules/CMediaStreamer2/module.modulemap: -------------------------------------------------------------------------------- 1 | module CMediaStreamer2 { 2 | 3 | header "mediastreamer2/msswift.h" 4 | 5 | module common { 6 | header "mediastreamer2/mscommon.h" 7 | } 8 | 9 | module mediastream { 10 | header "mediastreamer2/mediastream.h" 11 | } 12 | 13 | module eventqueue { 14 | header "mediastreamer2/mseventqueue.h" 15 | } 16 | 17 | module rfc3984 { 18 | header "mediastreamer2/rfc3984.h" 19 | } 20 | 21 | module queue { 22 | header "mediastreamer2/msqueue.h" 23 | } 24 | 25 | module codecutils { 26 | header "mediastreamer2/mscodecutils.h" 27 | } 28 | 29 | module interfaces { 30 | header "mediastreamer2/msinterfaces.h" 31 | } 32 | 33 | module video { 34 | header "mediastreamer2/msvideo.h" 35 | } 36 | 37 | module factory { 38 | header "mediastreamer2/msfactory.h" 39 | } 40 | 41 | module filter { 42 | header "mediastreamer2/msfilter.h" 43 | } 44 | } 45 | --------------------------------------------------------------------------------