Merge lp:~morphis/aethercast/hw-encoding-support into lp:aethercast

Proposed by Simon Fels
Status: Superseded
Proposed branch: lp:~morphis/aethercast/hw-encoding-support
Merge into: lp:aethercast
Diff against target: 20104 lines (+9512/-8610)
158 files modified
CMakeLists.txt (+16/-4)
conf/CMakeLists.txt (+3/-0)
conf/aethercast.conf.in (+14/-1)
conf/dhcpd.conf (+5/-0)
data/fi.w1.wpa_supplicant1.xml (+109/-0)
debian/aethercast.install (+1/-0)
debian/control (+3/-0)
debian/rules (+3/-0)
debian/usr.sbin.aethercast (+11/-0)
src/CMakeLists.txt (+52/-16)
src/client/application.cpp (+8/-3)
src/mcs/android/fileoutputtarget.cpp (+55/-0)
src/mcs/android/fileoutputtarget.h (+42/-0)
src/mcs/android/h264encoder.cpp (+160/-0)
src/mcs/android/h264encoder.h (+77/-0)
src/mcs/android/pipedoutputtarget.cpp (+54/-0)
src/mcs/android/pipedoutputtarget.h (+42/-0)
src/mcs/basesourcemediamanager.cpp (+20/-13)
src/mcs/basesourcemediamanager.h (+1/-0)
src/mcs/config.h.in (+8/-8)
src/mcs/dbushelpers.cpp (+46/-3)
src/mcs/dbushelpers.h (+9/-2)
src/mcs/forwardingmiracastcontroller.cpp (+2/-2)
src/mcs/forwardingmiracastcontroller.h (+1/-1)
src/mcs/forwardingnetworkdevice.cpp (+0/-51)
src/mcs/forwardingnetworkdevice.h (+0/-42)
src/mcs/gobject_deleter.h (+2/-0)
src/mcs/gstsourcemediamanager.cpp (+11/-1)
src/mcs/initgstreameronce.cpp (+88/-0)
src/mcs/initgstreameronce.h (+29/-0)
src/mcs/mediamanagerfactory.cpp (+6/-3)
src/mcs/mir/sourcemediamanager.cpp (+37/-88)
src/mcs/mir/sourcemediamanager.h (+14/-6)
src/mcs/miracastcontroller.h (+2/-1)
src/mcs/miracastcontrollerskeleton.cpp (+1/-4)
src/mcs/miracastservice.cpp (+61/-16)
src/mcs/miracastservice.h (+4/-1)
src/mcs/miracastsourceclient.cpp (+1/-1)
src/mcs/miracastsourcemanager.cpp (+3/-3)
src/mcs/networkdevice.cpp (+3/-3)
src/mcs/networkdeviceskeleton.cpp (+0/-142)
src/mcs/networkmanager.cpp (+10/-0)
src/mcs/networkmanager.h (+12/-2)
src/mcs/networkmanagerfactory.cpp (+69/-6)
src/mcs/networkmanagerfactory.h (+21/-0)
src/mcs/networkutils.cpp (+21/-0)
src/mcs/networkutils.h (+1/-0)
src/mcs/testsourcemediamanager.cpp (+29/-4)
src/mcs/utils.cpp (+14/-0)
src/mcs/utils.h (+8/-0)
src/mcs/videoformat.cpp (+383/-0)
src/mcs/videoformat.h (+43/-0)
src/mcs/x11sourcemediamanager.cpp (+51/-0)
src/mcs/x11sourcemediamanager.h (+38/-0)
src/mcs/x264.cpp (+206/-0)
src/mcs/x264.h (+82/-0)
src/w11t/commandqueue.cpp (+0/-103)
src/w11t/commandqueue.h (+0/-63)
src/w11t/dhcpclient.cpp (+0/-102)
src/w11t/dhcpserver.cpp (+0/-99)
src/w11t/gdhcp/client.c (+0/-3282)
src/w11t/gdhcp/common.c (+0/-780)
src/w11t/gdhcp/common.h (+0/-220)
src/w11t/gdhcp/gdhcp.h (+0/-244)
src/w11t/gdhcp/ipv4ll.c (+0/-135)
src/w11t/gdhcp/ipv4ll.h (+0/-55)
src/w11t/gdhcp/server.c (+0/-934)
src/w11t/gdhcp/unaligned.h (+0/-163)
src/w11t/message.cpp (+0/-128)
src/w11t/message.h (+0/-203)
src/w11t/networkdevice.cpp (+0/-67)
src/w11t/networkdevice.h (+0/-54)
src/w11t/networkmanager.cpp (+0/-740)
src/w11t/networkmanager.h (+0/-121)
src/w11t/wfddeviceinfo.cpp (+0/-74)
src/w11t/wfddeviceinfo.h (+0/-65)
src/w11tng/config.h.in (+8/-18)
src/w11tng/dhcpclient.cpp (+112/-0)
src/w11tng/dhcpclient.h (+71/-0)
src/w11tng/dhcpleaseparser.cpp (+130/-0)
src/w11tng/dhcpleaseparser.h (+29/-36)
src/w11tng/dhcpserver.cpp (+129/-0)
src/w11tng/dhcpserver.h (+30/-23)
src/w11tng/filemonitor.cpp (+74/-0)
src/w11tng/filemonitor.h (+60/-0)
src/w11tng/hostname1stub.cpp (+136/-0)
src/w11tng/hostname1stub.h (+73/-0)
src/w11tng/informationelement.cpp (+171/-0)
src/w11tng/informationelement.h (+165/-0)
src/w11tng/interfaceselector.cpp (+125/-0)
src/w11tng/interfaceselector.h (+66/-0)
src/w11tng/interfacestub.cpp (+95/-0)
src/w11tng/interfacestub.h (+69/-0)
src/w11tng/managerstub.cpp (+202/-0)
src/w11tng/managerstub.h (+83/-0)
src/w11tng/netlinklistener.cpp (+205/-0)
src/w11tng/netlinklistener.h (+64/-0)
src/w11tng/networkdevice.cpp (+126/-0)
src/w11tng/networkdevice.h (+92/-0)
src/w11tng/networkmanager.cpp (+645/-0)
src/w11tng/networkmanager.h (+153/-0)
src/w11tng/p2pdevicestub.cpp (+447/-0)
src/w11tng/p2pdevicestub.h (+112/-0)
src/w11tng/peerstub.cpp (+165/-0)
src/w11tng/peerstub.h (+77/-0)
src/w11tng/processexecutor.cpp (+102/-0)
src/w11tng/processexecutor.h (+56/-0)
src/w11tng/wififirmwareloader.cpp (+6/-3)
src/w11tng/wififirmwareloader.h (+4/-2)
tests/3rd_party/lxc-nl/CMakeLists.txt (+6/-0)
tests/3rd_party/lxc-nl/network.c (+308/-0)
tests/3rd_party/lxc-nl/network.h (+34/-0)
tests/3rd_party/lxc-nl/nl.c (+313/-0)
tests/3rd_party/lxc-nl/nl.h (+260/-0)
tests/CMakeLists.txt (+15/-3)
tests/common/dbusfixture.cpp (+190/-0)
tests/common/dbusfixture.h (+67/-0)
tests/common/dbusnameowner.cpp (+43/-0)
tests/common/dbusnameowner.h (+44/-0)
tests/common/glibhelpers.cpp (+43/-0)
tests/common/glibhelpers.h (+34/-0)
tests/common/virtualnetwork.cpp (+56/-0)
tests/common/virtualnetwork.h (+42/-0)
tests/mcs/CMakeLists.txt (+4/-4)
tests/mcs/acceptance_tests/CMakeLists.txt (+0/-2)
tests/mcs/forwardingmiracastcontroller_tests.cpp (+3/-3)
tests/mcs/forwardingnetworkdevice_tests.cpp (+0/-50)
tests/mcs/mediamanagerfactory_tests.cpp (+3/-3)
tests/mcs/miracastcontrollerskeleton_tests.cpp (+3/-3)
tests/mcs/mock_network_device.h (+0/-35)
tests/mcs/networkdevice_tests.cpp (+0/-36)
tests/mcs/networkdeviceskeleton_tests.cpp (+0/-51)
tests/mcs/networkmanagerfactory_tests.cpp (+44/-0)
tests/mcs/x264_tests.cpp (+86/-0)
tests/scoped_gobject_tests.cpp (+1/-0)
tests/w11t/CMakeLists.txt (+0/-7)
tests/w11t/wfddeviceinfo_test.cpp (+0/-38)
tests/w11t/wpasupplicantcommandqueue_test.cpp (+0/-108)
tests/w11t/wpasupplicantmessage_test.cpp (+0/-126)
tests/w11tng/CMakeLists.txt (+14/-0)
tests/w11tng/baseskeleton.cpp (+58/-0)
tests/w11tng/baseskeleton.h (+49/-0)
tests/w11tng/dhcp_tests.cpp (+66/-0)
tests/w11tng/dhcpleaseparser_tests.cpp (+93/-0)
tests/w11tng/informationelement_tests.cpp (+62/-0)
tests/w11tng/interfaceselector_tests.cpp (+158/-0)
tests/w11tng/interfaceskeleton.cpp (+43/-0)
tests/w11tng/interfaceskeleton.h (+45/-0)
tests/w11tng/interfacestub_tests.cpp (+75/-0)
tests/w11tng/netlinklistener_tests.cpp (+67/-0)
tests/w11tng/p2pdeviceskeleton.cpp (+137/-0)
tests/w11tng/p2pdeviceskeleton.h (+72/-0)
tests/w11tng/p2pdevicestub_tests.cpp (+192/-0)
tests/w11tng/peerskeleton.cpp (+40/-0)
tests/w11tng/peerskeleton.h (+44/-0)
tests/w11tng/peerstub_tests.cpp (+73/-0)
tools/CMakeLists.txt (+25/-0)
tools/mirscreencast_to_android_hw_enc.cpp (+526/-0)
To merge this branch: bzr merge lp:~morphis/aethercast/hw-encoding-support
Reviewer Review Type Date Requested Status
Ubuntu Phablet Team Pending
Review via email: mp+284112@code.launchpad.net

This proposal has been superseded by a proposal from 2016-01-27.

Description of the change

Add HW encoding support

To post a comment you must log in.
137. By Simon Fels

Abstract mir stream connection behind a connector

138. By Simon Fels

Add stream renderer which gets frames from mir and sends them to the encoder

139. By Simon Fels

Integrate stream renderer with miracast source manager

140. By Simon Fels

Make d'tor of base class correctly virtual

141. By Simon Fels

Force mir as default media manager

142. By Simon Fels

Add missing return type for function

143. By Simon Fels

Extended debugging output for mir source manager

144. By Simon Fels

All changes to get streaming working

145. By Simon Fels

Add support to retrieve raw output from the encoder

146. By Simon Fels

Actually stop the stream renderer on destruction

147. By Simon Fels

Set H264 profile/level/constraint for encoder

148. By Simon Fels

Make sure the encoder os properly initialized before starting

149. By Simon Fels

Take raw h264 frames from encoder as input for the pipeline

150. By Simon Fels

Check for possible errors on encoder construction

151. By Simon Fels

Don't call not existing libmedia API method for now

152. By Simon Fels

Construct pipeline with parse/mux/pay elements

153. By Simon Fels

Limit what resolutions, fps, codec parameters we can provide

154. By Simon Fels

Raise our GO intent to always become the group owner

155. By Simon Fels

Drop superflous pipeline state change

156. By Simon Fels

Dump the actual framerate we're recording with from mir

157. By Simon Fels

Drop h264parse element and just use caps

158. By Simon Fels

Simply mirscreencast utility to just dump to a file

159. By Simon Fels

Add queue elements for extended buffering

160. By Simon Fels

Add proper .gitignore file

161. By Simon Fels

Take buffers from android and put them into Gstreamer ones

162. By Simon Fels

Add utility to use plain streaming for testing

163. By Simon Fels

tools: stream: start source on startup

164. By Simon Fels

tools: screencast: initialize gstreamer on startup

165. By Simon Fels

tools: stream: run forever and react on SIGINT/SIGTERM

166. By Simon Fels

Include current thread id in each log message

167. By Simon Fels

Only submit buffers to the pipeline when its ready for new ones

If we're producing buffers at a too hight rate we're getting them with
incorrect timestamps into the pipeline which leads to delays on the
receiver side because PCR/PTS of the MPEGTS stream doesn't match anymore.

This will be further optimized.

168. By Simon Fels

Ignore unused function parameters

169. By Simon Fels

Drop superflous debug statements

170. By Simon Fels

Add dirty option to dump the stream rather than sending it out

171. By Simon Fels

Link source and mux together with a pad to specify the MPEGTS PID

The WiFi Display spec requires us to send the video stream on a
specific PID (0x1011) which we can request to the mpegtsmux
element by request a pad with a specific name.

172. By Simon Fels

mir: simply pad request/link for mpegtsmux element

173. By Simon Fels

Drop changed PMT/PAT intervals

174. By Simon Fels

Comment on how we're requesting a different stream PID

175. By Simon Fels

Switch to nal alignment

176. By Simon Fels

Merge branch 'trunk' into hw-encoding-support

177. By Simon Fels

Merge trunk

178. By Simon Fels

Add missing files lost due to a failed merge with trunk

179. By Simon Fels

Request 188 byte length packages from MPEGTS element

180. By Simon Fels

debian: add missing build depends

181. By Simon Fels

debian: add missing libgstreamer-plugins-base1.0-dev dependency

182. By Simon Fels

Fail when pipeline can't be configured

183. By Simon Fels

Add support for an extended display

184. By Simon Fels

Correct vertex position data to use the full screen

185. By Simon Fels

Draw white background so we're able to discover empty fragments

186. By Simon Fels

Add base encoder class and start a H264EncoderNext implementation

187. By Simon Fels

Print out timestamps for performance analysis

188. By Simon Fels

Refactor encoder integration and finalize new H264 implementation

189. By Simon Fels

Make new h264 encoder working properly

190. By Simon Fels

Tune default encoder values to follow what Android does for WFD

191. By Simon Fels

Implement MPEGTS packetizer

Based on the implementation from Android.

192. By Simon Fels

Optimizer buffer timestamps and encoder configuration

193. By Simon Fels

Adding missing encoder config field

194. By Simon Fels

A lot more work on getting rid of gstreamer

Adding own RTP sender implementation which is now properly used
from a new source media manager type called 'mir-next'.

This also refactors some parts of the already existing code.

195. By Simon Fels

Drop accidentially added code

196. By Simon Fels

Enable dumping of the MPEGTS stream

197. By Simon Fels

Extract codec specific data and prepend to AVC buffers

198. By Simon Fels

Be less verbose for encoder output

199. By Simon Fels

Tell MPEGTS packetizer to include SPS/PPS with IDR frames

200. By Simon Fels

Add utility method to create a hexdump

201. By Simon Fels

Take SPS/PPS from codec data when available

202. By Simon Fels

Add H264 analyzer to collect statistics

203. By Simon Fels

Don't tell the MPEGST packtizer to add SPS/PPS to IDR frames

204. By Simon Fels

Let encoder submit buffer with codec-specific data for transmission

205. By Simon Fels

Add output to measure performance

206. By Simon Fels

Pass local address down to our WDS delegate

We need to transmit our local address correctly within the RTSP
message we're exchanging with the other side which we missed
until now.

207. By Simon Fels

Extract timestamp from buffer we get from the encoder

208. By Simon Fels

Use proper constants for encoder configuration

209. By Simon Fels

Increase video bitrate to have a stable picture

210. By Simon Fels

Check for valid meta data structure before accessing it

211. By Simon Fels

Don't set buffer timestamp manually

212. By Simon Fels

Let encoder include SPS/PPS with each IDR frame

213. By Simon Fels

Ask encoder to store meta data in buffers

214. By Simon Fels

Adjust for WDS 1.0.0 API changes

215. By Simon Fels

MPEGTS packetizer fixes

216. By Simon Fels

Raise our process priority

217. By Simon Fels

Revert try to move buffer timestamp ahead

218. By Simon Fels

Add a proper buffer queue for Media/RTP sender

219. By Simon Fels

Add a measure point abstraction class

220. By Simon Fels

Decouple texture creation and rendering

221. By Simon Fels

Add missing macro

222. By Simon Fels

But add the macro at the right place

223. By Simon Fels

Work with a not-blocking socket

224. By Simon Fels

Revert buffer queue for stream renderer

225. By Simon Fels

Force GO intent to 15 for now

226. By Simon Fels

Cleanup old H264Encoder instance

227. By Simon Fels

tools: let utility build again even if not functional now

228. By Simon Fels

android: first bits of the h264 encoder implementation

229. By Simon Fels

Implement new encoder which directly forwards native buffers from mir

230. By Simon Fels

Unblock input buffer queue when taking a buffer out

231. By Simon Fels

tools: mpegts_muxer: specifiy file open mode properly

232. By Simon Fels

tools: mirscreencast_to_stream: add cmdline option to extend the display

233. By Simon Fels

Pass dimensions correct to the screencast instance

234. By Simon Fels

Drop unneeded log message

235. By Simon Fels

Some further explaining comments

236. By Simon Fels

Fix syntax error in build configuration

237. By Simon Fels

Disable gstreamer initialization for now

238. By Simon Fels

Do an async swap buffers call to mir for direct rendering

239. By Simon Fels

Correct debug statement order

240. By Simon Fels

Optimize some more debug statements

241. By Simon Fels

Optimize buffer timestamp logging

We're only interested in how late we're with a buffer and nothing
else as that is what is causing our delay.

242. By Simon Fels

Timestamp buffer directly after we received them

243. By Simon Fels

Further timestamp logging optimizations

244. By Simon Fels

Drop unneeded buffer refcount logging

245. By Simon Fels

Further timestamp logging adjustments

246. By Simon Fels

Drop two more unneeded debug log statements

247. By Simon Fels

Include now in timestamp logging

248. By Simon Fels

For stick to synchronously processing a single buffer

249. By Simon Fels

Increase UDP send buffer size

250. By Simon Fels

Add type definitions for timestamps

251. By Simon Fels

Stop media sender and encoder too when pipeline goes down

252. By Simon Fels

Implement infrastructure for screen/system locks

253. By Simon Fels

Adjust buffer timestamp to respect our framerate

254. By Simon Fels

Further timestamp logging changes

255. By Simon Fels

Add cross compilation setup (copied from mir)

256. By Simon Fels

Add some more timestamp logging

257. By Simon Fels

Build with debug configuration

258. By Simon Fels

Don't check for matching buffer and just drop the queue head

259. By Simon Fels

Use a buffer queue for the renderer with a max size of two

260. By Simon Fels

Revert substracting a static offset from timestamps

261. By Simon Fels

Stop whole pipeline properly on termination

262. By Simon Fels

Correct apparmor rules for our dhcpd use

263. By Simon Fels

We only support extend mode for now

264. By Simon Fels

Properly terminate pipeline for the stream tool

265. By Simon Fels

Add some more statistics we collect over time

266. By Simon Fels

Ignore multiple build folders

267. By Simon Fels

Switch back to same UDP packet size Android uses

268. By Simon Fels

Printout a warning when we can't find a optimal video format

269. By Simon Fels

Bring GST based media manager in line with recent changes

270. By Simon Fels

Some more explanation comments

271. By Simon Fels

Fix test source media manager

272. By Simon Fels

Extend logger to be able to set severity on startup

273. By Simon Fels

Have a proper video format fallback instead of invalid values

274. By Simon Fels

Free GLib error messages once done with it

275. By Simon Fels

Let media buffer allocate the memory to transfer ownership

276. By Simon Fels

Implement DisconnectAll manager method

277. By Simon Fels

Add unit tests to verify wds video format selection

278. By Simon Fels

tools: install mirscreencast_to_stream utility

279. By Simon Fels

debian: package mirscreencast_to_stream utility too

280. By Simon Fels

debian: add a dependency on -tools for aethercast for now

281. By Simon Fels

Do correct video format negotiation

282. By Simon Fels

debian: install additional files we missed before

283. By Simon Fels

Disable power save mode of p2p network interface

284. By Simon Fels

Temporarily disable logging of buffer timestamps

285. By Simon Fels

debian: fix apparmor profile extension for dhcpd

286. By Simon Fels

Listen on all local addresses for incoming RTSP connection requests

287. By Simon Fels

Set GO intent to 7 and let user change that with an env variable

288. By Simon Fels

Setup a route when running as DHCP server

289. By Simon Fels

Select resolution based on env variable

290. By Simon Fels

Disable per timestamping according to framerate

291. By Simon Fels

Set names for our threads to be able to identify them

292. By Simon Fels

Save statistics for RTP bandwidth

293. By Simon Fels

Print out statistics when our source manager goes down

294. By Simon Fels

Don't produce more frames than we have to

295. By Simon Fels

Sent RTP packets directly to remote via sendto

296. By Simon Fels

Send all RTP packets a TS frames belongs too together

297. By Simon Fels

Allow remote to ask us for an IDR frame

298. By Simon Fels

Check mime type correctly for video/audio prefix

299. By Simon Fels

Correct RTP bandwidth statistics output

300. By Simon Fels

Refactor local address assignmnet for source manager

301. By Simon Fels

Enable driver side miracast mode on successful connection

302. By Simon Fels

Return an error for a failing scan call

303. By Simon Fels

Don't allow dhcpd to edit our configuration file

304. By Simon Fels

Add support for new wpa API method to send driver commands

305. By Simon Fels

debian: fix apparmor setup

* reload dhcpd profile on startup
* add DAC override for dhcpd to overcome a bug in its package

306. By Simon Fels

Dump additional information for GO negotiation response

307. By Simon Fels

Pass correct arguments to dbus error message creation

308. By Simon Fels

Small adjustments to the connect logic

309. By Simon Fels

Limit us to only support 720p with 30 Hz for now

310. By Simon Fels

Print out group negotiation error for easier debugging

311. By Simon Fels

Format debug message correctly and supply all arguments

312. By Simon Fels

Workaround problems with WDS rate/resolution selection

313. By Simon Fels

Use plain sockets for RTP connection rather than GLib

314. By Simon Fels

Extend GetEnvValue function to be able to return a default value

315. By Simon Fels

Wind local RTP port up the stack and don't use a static one

316. By Simon Fels

Setup miracast source manager when we're connected and not earlier

317. By Simon Fels

Define DHCP server address on construction

318. By Simon Fels

Drop result argument for SendDriverCommand method

319. By Simon Fels

Lock the display when we're connecting until we get disconnected

320. By Simon Fels

Force IPv4 for our DHCP client

321. By Simon Fels

Improve renderer/encoder to really stream a constant framerate

Also optimizes logging in different parts of the code

322. By Simon Fels

Only support CBP with level 3.1 for now

323. By Simon Fels

Trying to resend RTP packages one time and then fail

324. By Simon Fels

Implement missing interface method

325. By Simon Fels

Adjust for WPA DBus API changes

326. By Simon Fels

Don't adjust interface powersave mode

327. By Simon Fels

Keep pointer to management wifi interface

328. By Simon Fels

Refactor code to send private driver commands a bit

329. By Simon Fels

Drop all code for the GL rendering code path which we don't need anymore

330. By Simon Fels

Missing changes for cmake configuration

331. By Simon Fels

Drop some more unused code fragments for logging

332. By Simon Fels

Small code cleanups

333. By Simon Fels

Drop unused gstreamer x264 encoder wrapper

334. By Simon Fels

Remove unused system power state controller

335. By Simon Fels

Drop unused unit tests

336. By Simon Fels

Fix encoder class

337. By Simon Fels

Add unit tests for buffer class

338. By Simon Fels

Add video format extraction tests (missing VESA/HH support)

339. By Simon Fels

Correctly release media buffer

340. By Simon Fels

Update WFD IE to indicate a session is not available when connected

341. By Simon Fels

Drop unnecessary dependencies

342. By Simon Fels

Move MediaSender into streaming namespace

343. By Simon Fels

Add interfaces for RTP sender / MPEGTS packetizer classes to make MediaSender testable

344. By Simon Fels

Add unit tests for media sender class

345. By Simon Fels

Add utility function to set thread name

346. By Simon Fels

Add unit test to make sure we're requesting PCR/PAT and PMT

Unmerged revisions

346. By Simon Fels

Add unit test to make sure we're requesting PCR/PAT and PMT

345. By Simon Fels

Add utility function to set thread name

344. By Simon Fels

Add unit tests for media sender class

343. By Simon Fels

Add interfaces for RTP sender / MPEGTS packetizer classes to make MediaSender testable

342. By Simon Fels

Move MediaSender into streaming namespace

341. By Simon Fels

Drop unnecessary dependencies

340. By Simon Fels

Update WFD IE to indicate a session is not available when connected

339. By Simon Fels

Correctly release media buffer

338. By Simon Fels

Add video format extraction tests (missing VESA/HH support)

337. By Simon Fels

Add unit tests for buffer class

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2015-12-10 06:47:03 +0000
3+++ CMakeLists.txt 2016-01-27 13:00:21 +0000
4@@ -58,12 +58,23 @@
5 find_package(PkgConfig)
6 find_package(Threads)
7
8-pkg_check_modules(GLIB glib-2.0)
9-pkg_check_modules(GIO gio-2.0)
10-pkg_check_modules(GIO-UNIX gio-unix-2.0)
11+pkg_check_modules(GLIB REQUIRED glib-2.0)
12+pkg_check_modules(GIO REQUIRED gio-2.0)
13+pkg_check_modules(GIO-UNIX REQUIRED gio-unix-2.0)
14 pkg_check_modules(GST REQUIRED gstreamer-1.0)
15 pkg_check_modules(WDS REQUIRED wds)
16-pkg_check_modules(READLINE readline)
17+# FIXME for the time being mir is required to do proper hardware
18+# encoding on Android platforms. This will be refactored at some
19+# point to be abstracted by gstreamer completely or made optional.
20+pkg_check_modules(MIRCLIENT REQUIRED mirclient)
21+# Same as mentioned above applies for the hybris and android
22+# things below.
23+pkg_check_modules(HYBRIS_MEDIA REQUIRED libmedia)
24+pkg_check_modules(ANDROID_HEADERS REQUIRED android-headers)
25+pkg_check_modules(EGL REQUIRED egl)
26+pkg_check_modules(GLESV2 REQUIRED glesv2)
27+add_definitions(-DMESA_EGL_NO_X11_HEADERS)
28+
29 # Build with system gmock and embedded gtest
30 set (GMOCK_INCLUDE_DIR "/usr/include/gmock/include" CACHE PATH "gmock source include directory")
31 set (GMOCK_SOURCE_DIR "/usr/src/gmock" CACHE PATH "gmock source directory")
32@@ -78,3 +89,4 @@
33 add_subdirectory(conf)
34 add_subdirectory(src)
35 add_subdirectory(tests)
36+add_subdirectory(tools)
37
38=== removed directory 'build'
39=== modified file 'conf/CMakeLists.txt'
40--- conf/CMakeLists.txt 2015-12-10 10:17:57 +0000
41+++ conf/CMakeLists.txt 2016-01-27 13:00:21 +0000
42@@ -5,3 +5,6 @@
43
44 install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/aethercast-dbus.conf
45 DESTINATION /etc/dbus-1/system.d/)
46+
47+install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dhcpd.conf
48+ DESTINATION /etc/aethercast/)
49
50=== modified file 'conf/aethercast.conf.in'
51--- conf/aethercast.conf.in 2015-12-10 10:17:57 +0000
52+++ conf/aethercast.conf.in 2016-01-27 13:00:21 +0000
53@@ -5,4 +5,17 @@
54
55 respawn
56
57-exec /usr/sbin/aethercast
58+script
59+ if [ -x `which getprop` ] ; then
60+ iface=`getprop wifi.direct.interface`
61+ if [ "$iface" != "" ] ; then
62+ export AETHERCAST_DEDICATED_P2P_INTERFACE=$iface
63+ # FIXME this might not be true for all devices but it should
64+ # not cause any for those which doesn't need any firmware as
65+ # the Android WiFi firmware loader should just pass through
66+ export AETHERCAST_NEED_FIRMWARE=1
67+ fi
68+ fi
69+
70+ exec /usr/sbin/aethercast
71+end script
72
73=== added file 'conf/dhcpd.conf'
74--- conf/dhcpd.conf 1970-01-01 00:00:00 +0000
75+++ conf/dhcpd.conf 2016-01-27 13:00:21 +0000
76@@ -0,0 +1,5 @@
77+subnet 192.168.7.0 netmask 255.255.255.0 {
78+ range 192.168.7.5 192.168.7.10;
79+ option subnet-mask 255.255.255.0;
80+ option broadcast-address 192.168.7.255;
81+}
82
83=== added file 'data/fi.w1.wpa_supplicant1.xml'
84--- data/fi.w1.wpa_supplicant1.xml 1970-01-01 00:00:00 +0000
85+++ data/fi.w1.wpa_supplicant1.xml 2016-01-27 13:00:21 +0000
86@@ -0,0 +1,109 @@
87+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
88+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
89+<node>
90+ <interface name="fi.w1.wpa_supplicant1">
91+ <method name="CreateInterface">
92+ <arg name="args" type="a{sv}" direction="in"/>
93+ <arg name="path" type="o" direction="out"/>
94+ </method>
95+ <signal name="InterfaceAdded">
96+ <arg name="path" type="o"/>
97+ <arg name="properties" type="a{sv}"/>
98+ </signal>
99+ <signal name="InterfaceRemoved">
100+ <arg name="path" type="o"/>
101+ </signal>
102+ <property name="Interfaces" type="ao" access="read"/>
103+ <property name="Capabilities" type="as" access="read"/>
104+ <property name="WFDIEs" type="ay" access="readwrite">
105+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
106+ </property>
107+ </interface>
108+ <interface name="fi.w1.wpa_supplicant1.Interface">
109+ <property name="Capabilities" type="a{sv}" access="read"/>
110+ <property name="State" type="s" access="read"/>
111+ <property name="Ifname" type="s" access="read"/>
112+ <property name="Driver" type="s" access="read"/>
113+ </interface>
114+ <interface name="fi.w1.wpa_supplicant1.Interface.P2PDevice">
115+ <method name="Find">
116+ <arg name="args" type="a{sv}" direction="in"/>
117+ </method>
118+ <method name="StopFind"/>
119+ <method name="ExtendedListen">
120+ <arg name="args" type="a{sv}" direction="in"/>
121+ </method>
122+ <method name="Connect">
123+ <arg name="args" type="a{sv}" direction="in"/>
124+ <arg name="group" type="s" direction="out"/>
125+ </method>
126+ <method name="Cancel"/>
127+ <method name="Disconnect"/>
128+ <method name="Flush"/>
129+ <signal name="DeviceFound">
130+ <arg name="path" type="o"/>
131+ </signal>
132+ <signal name="DeviceLost">
133+ <arg name="path" type="o"/>
134+ </signal>
135+ <signal name="FindStopped"/>
136+ <signal name="GONegotiationSuccess">
137+ <arg name="properties" type="a{sv}"/>
138+ </signal>
139+ <signal name="GONegotiationFailure">
140+ <arg name="properties" type="a{sv}"/>
141+ </signal>
142+ <signal name="GroupStarted">
143+ <arg name="properties" type="a{sv}"/>
144+ </signal>
145+ <signal name="GroupFinished">
146+ <arg name="properties" type="a{sv}"/>
147+ </signal>
148+ <signal name="GroupFormationFailure">
149+ <arg name="reason" type="s"/>
150+ </signal>
151+ <signal name="GONegotiationRequest">
152+ <arg name="path" type="o"/>
153+ <arg name="dev_passwd_id" type="i"/>
154+ </signal>
155+ <property name="P2PDeviceConfig" type="a{sv}" access="readwrite"/>
156+ <property name="Peers" type="ao" access="read"/>
157+ </interface>
158+ <interface name="fi.w1.wpa_supplicant1.Peer">
159+ <property name="DeviceName" type="s" access="read"/>
160+ <property name="Manufacturer" type="s" access="read"/>
161+ <property name="ModelName" type="s" access="read"/>
162+ <property name="ModelNumber" type="s" access="read"/>
163+ <property name="SerialNumber" type="s" access="read"/>
164+ <property name="PrimaryDeviceType" type="ay" access="read"/>
165+ <property name="config_method" type="q" access="read"/>
166+ <property name="level" type="i" access="read"/>
167+ <property name="devicecapability" type="y" access="read"/>
168+ <property name="groupcapability" type="y" access="read"/>
169+ <property name="SecondaryDeviceTypes" type="aay" access="read"/>
170+ <property name="VendorExtension" type="aay" access="read"/>
171+ <property name="IEs" type="ay" access="read"/>
172+ <property name="DeviceAddress" type="ay" access="read">
173+ <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
174+ </property>
175+ <property name="Groups" type="ao" access="read"/>
176+ </interface>
177+ <interface name="fi.w1.wpa_supplicant1.Group">
178+ <property name="Members" type="s" access="read"/>
179+ <property name="Group" type="o" access="read"/>
180+ <property name="Role" type="s" access="read"/>
181+ <property name="SSID" type="ay" access="read"/>
182+ <property name="BSSID" type="ay" access="read"/>
183+ <property name="Frequency" type="q" access="read"/>
184+ <property name="Passphrase" type="s" access="read"/>
185+ <property name="PSK" type="ay" access="read"/>
186+ <property name="WPSVendorExtensions" type="aay" access="read"/>
187+ <signal name="PeerJoined">
188+ <arg name="peer" type="o"/>
189+ </signal>
190+ <signal name="PeerDisconnected">
191+ <arg name="peer" type="o"/>
192+ </signal>
193+ </interface>
194+</node>
195+
196
197=== added file 'debian/aethercast.install'
198--- debian/aethercast.install 1970-01-01 00:00:00 +0000
199+++ debian/aethercast.install 2016-01-27 13:00:21 +0000
200@@ -0,0 +1,1 @@
201+debian/usr.sbin.aethercast /etc/apparmor.d/dhcpd.d/
202
203=== modified file 'debian/control'
204--- debian/control 2015-12-10 06:47:03 +0000
205+++ debian/control 2016-01-27 13:00:21 +0000
206@@ -5,6 +5,7 @@
207 XSBC-Original-Maintainer: Simon Fels <simon.fels@canonical.com>
208 Build-Depends: cmake,
209 debhelper (>= 9),
210+ dbus,
211 google-mock,
212 libboost-dev,
213 libboost-filesystem-dev,
214@@ -31,6 +32,8 @@
215 Architecture: any
216 Depends: ${misc:Depends},
217 ${shlibs:Depends},
218+ isc-dhcp-server,
219+ isc-dhcp-client,
220 wpasupplicant
221 Description: Display casting service
222 A management service for remote displays which it can stream the
223
224=== modified file 'debian/rules'
225--- debian/rules 2015-11-19 12:17:57 +0000
226+++ debian/rules 2016-01-27 13:00:21 +0000
227@@ -17,3 +17,6 @@
228
229 %:
230 dh $@ --parallel --fail-missing
231+
232+override_dh_auto_test:
233+ # disable
234
235=== added file 'debian/usr.sbin.aethercast'
236--- debian/usr.sbin.aethercast 1970-01-01 00:00:00 +0000
237+++ debian/usr.sbin.aethercast 2016-01-27 13:00:21 +0000
238@@ -0,0 +1,11 @@
239+# vim:syntax=apparmor
240+
241+ # Allow aethercast to start dhcpd with its own configuration
242+ # file it needs to provide DHCP for groups it manages through
243+ # WiFi Direct. This need to stay as long as NetworkManager does
244+ # not has support for WiFi Direct and aethercast is using that.
245+ /etc/aethercast/dhcpd.conf r,
246+ # In addition aethercast will also point dhcpd to a private
247+ # lease/pid file
248+ /{,var/}run/aethercast/dhcpd.leases* lrw,
249+ /{,var/}run/aethercast/dhcpd.pid lrw,
250
251=== modified file 'src/CMakeLists.txt'
252--- src/CMakeLists.txt 2015-12-18 17:15:31 +0000
253+++ src/CMakeLists.txt 2016-01-27 13:00:21 +0000
254@@ -9,14 +9,33 @@
255 --interface-prefix org.aethercast.
256 ${CMAKE_CURRENT_SOURCE_DIR}/../data/org.aethercast.xml)
257
258+execute_process(COMMAND ${GDBUS_CODEGEN_EXECUTABLE}
259+ --c-namespace WpaSupplicant
260+ --c-generate-object-manager
261+ --generate-c-code ${CMAKE_CURRENT_BINARY_DIR}/mcs/wpasupplicantinterface
262+ --interface-prefix fi.w1.wpa_supplicant1.
263+ ${CMAKE_CURRENT_SOURCE_DIR}/../data/fi.w1.wpa_supplicant1.xml)
264+
265 # Make sure that generated header files can be found
266 include_directories(${CMAKE_CURRENT_BINARY_DIR}/mcs)
267
268+set(AETHERCAST_DHCP_HELPER "/usr/sbin/aethercast-dhcp-helper")
269+set(DHCP_SERVER_PATH "/usr/sbin/dhcpd")
270+set(DHCP_CLIENT_PATH "/sbin/dhclient")
271+
272+configure_file(mcs/config.h.in mcs/config.h @ONLY)
273+configure_file(w11tng/config.h.in w11tng/config.h @ONLY)
274+
275 set(HEADERS
276 mcs/ip_v4_address.h
277 mcs/keep_alive.h
278 mcs/mac_address.h
279 mcs/types.h
280+ mcs/shared_gobject.h
281+ mcs/keep_alive.h
282+
283+ mcs/config.h
284+ w11tng/config.h
285 )
286
287 set(SOURCES
288@@ -24,10 +43,12 @@
289 mcs/networkutils.cpp
290 mcs/mediamanagerfactory.cpp
291 mcs/basesourcemediamanager.cpp
292+ mcs/initgstreameronce.cpp
293 mcs/gstsourcemediamanager.cpp
294 mcs/testsourcemediamanager.cpp
295+ mcs/x11sourcemediamanager.cpp
296+ mcs/videoformat.cpp
297 mcs/logger.cpp
298- mcs/mirsourcemediamanager.cpp
299 mcs/forwardingmiracastcontroller.cpp
300 mcs/forwardingnetworkdevice.cpp
301 mcs/miracastcontroller.cpp
302@@ -38,24 +59,35 @@
303 mcs/networkmanager.cpp
304 mcs/networkmanagerfactory.cpp
305 mcs/networkdevice.cpp
306-
307+ mcs/x264.cpp
308 ${CMAKE_CURRENT_BINARY_DIR}/mcs/aethercastinterface.c
309 mcs/dbushelpers.cpp
310 mcs/networkdeviceskeleton.cpp
311
312- w11t/gdhcp/common.c
313- w11t/gdhcp/ipv4ll.c
314- w11t/gdhcp/server.c
315- w11t/gdhcp/client.c
316- w11t/dhcpclient.cpp
317- w11t/dhcpserver.cpp
318- w11t/wififirmwareloader.cpp
319- w11t/wfddeviceinfo.cpp
320- w11t/message.cpp
321- w11t/command.cpp
322- w11t/commandqueue.cpp
323- w11t/networkdevice.cpp
324- w11t/networkmanager.cpp
325+ mcs/mir/sourcemediamanager.cpp
326+
327+ mcs/android/h264encoder.cpp
328+ mcs/android/pipedoutputtarget.cpp
329+ mcs/android/fileoutputtarget.cpp
330+
331+ ${CMAKE_CURRENT_BINARY_DIR}/mcs/wpasupplicantinterface.c
332+ w11tng/networkmanager.cpp
333+ w11tng/networkdevice.cpp
334+ w11tng/interfaceselector.cpp
335+ w11tng/p2pdevicestub.cpp
336+ w11tng/managerstub.cpp
337+ w11tng/peerstub.cpp
338+ w11tng/interfacestub.cpp
339+ w11tng/groupstub.cpp
340+ w11tng/informationelement.cpp
341+ w11tng/dhcpleaseparser.cpp
342+ w11tng/dhcpclient.cpp
343+ w11tng/dhcpserver.cpp
344+ w11tng/processexecutor.cpp
345+ w11tng/filemonitor.cpp
346+ w11tng/netlinklistener.cpp
347+ w11tng/wififirmwareloader.cpp
348+ w11tng/hostname1stub.cpp
349 )
350
351 link_directories(
352@@ -63,6 +95,7 @@
353 ${GIO_LIBRARY_DIRS}
354 ${GIO-UNIX_LIBRARY_DIRS}
355 ${WDS_LIBRARY_DIRS}
356+ ${HYBRIS_MEDIA_LIBRARY_DIRS}
357 )
358
359 include_directories(
360@@ -72,8 +105,10 @@
361 ${GIO-UNIX_INCLUDE_DIRS}
362 ${GST_INCLUDE_DIRS}
363 ${WDS_INCLUDE_DIRS}
364- ${CMAKE_CURRENT_SOURCE_DIR}/w11t/gdhcp
365+ ${HYBRIS_MEDIA_INCLDUE_DIRS}
366+ ${ANDROID_HEADERS_INCLUDE_DIRS}
367 ${CMAKE_CURRENT_BINARY_DIR}/src
368+ ${CMAKE_CURRENT_BINARY_DIR}/src/w11tng
369 )
370
371 add_library(aethercast-core ${SOURCES} ${HEADERS})
372@@ -88,6 +123,7 @@
373 ${GST_LIBRARIES}
374 ${CMAKE_THREAD_LIBS_INIT}
375 ${WDS_LIBRARIES}
376+ ${HYBRIS_MEDIA_LIBRARIES}
377 -ldl
378 )
379
380
381=== modified file 'src/client/application.cpp'
382--- src/client/application.cpp 2015-12-16 06:47:41 +0000
383+++ src/client/application.cpp 2016-01-27 13:00:21 +0000
384@@ -31,6 +31,9 @@
385
386 using namespace std::placeholders;
387
388+namespace {
389+const unsigned int kDBusTimeout = 120;
390+
391 class PromptSaver {
392 public:
393 PromptSaver() {
394@@ -59,6 +62,7 @@
395 int saved_point_;
396 char *saved_line_;
397 };
398+}
399
400 namespace mcs {
401 namespace client {
402@@ -434,9 +438,10 @@
403 return;
404 }
405
406- // Use a high enough timeout to make sure we get the end of the scan
407- // method call which has an internal timeout of 30 seconds
408- g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(inst->manager_), 60 * 1000);
409+ // Use a high enough timeout to make sure we wait enough for the service to
410+ // respond as the connection process can take some time depending on different
411+ // factors.
412+ g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(inst->manager_), kDBusTimeout * 1000);
413
414 aethercast_interface_object_manager_client_new(inst->bus_connection_,
415 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
416
417=== added directory 'src/mcs/android'
418=== added file 'src/mcs/android/fileoutputtarget.cpp'
419--- src/mcs/android/fileoutputtarget.cpp 1970-01-01 00:00:00 +0000
420+++ src/mcs/android/fileoutputtarget.cpp 2016-01-27 13:00:21 +0000
421@@ -0,0 +1,55 @@
422+/*
423+ * Copyright (C) 2016 Canonical, Ltd.
424+ *
425+ * This program is free software: you can redistribute it and/or modify it
426+ * under the terms of the GNU General Public License version 3, as published
427+ * by the Free Software Foundation.
428+ *
429+ * This program is distributed in the hope that it will be useful, but
430+ * WITHOUT ANY WARRANTY; without even the implied warranties of
431+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
432+ * PURPOSE. See the GNU General Public License for more details.
433+ *
434+ * You should have received a copy of the GNU General Public License along
435+ * with this program. If not, see <http://www.gnu.org/licenses/>.
436+ *
437+ */
438+
439+#include <unistd.h>
440+#include <sys/stat.h>
441+#include <sys/types.h>
442+#include <fcntl.h>
443+
444+#include "mcs/logger.h"
445+#include "mcs/android/fileoutputtarget.h"
446+
447+namespace mcs {
448+namespace android {
449+
450+FileOutputTarget::FileOutputTarget(const std::string &path, const H264Encoder::OutputFormat &format) :
451+ fd_(-1),
452+ format_(format) {
453+
454+ ::unlink(path.c_str());
455+ fd_ = ::open(path.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
456+ if (fd_ < 0) {
457+ MCS_ERROR("Failed to create output file at path %s", path);
458+ return;
459+ }
460+}
461+
462+FileOutputTarget::~FileOutputTarget() {
463+ if (fd_ > 0)
464+ close(fd_);
465+}
466+
467+int FileOutputTarget::FileDescriptor() const {
468+ return fd_;
469+}
470+
471+mcs::android::H264Encoder::OutputFormat FileOutputTarget::Format() const {
472+ return format_;
473+}
474+
475+} // namespace android
476+} // namespace mcs
477
478=== added file 'src/mcs/android/fileoutputtarget.h'
479--- src/mcs/android/fileoutputtarget.h 1970-01-01 00:00:00 +0000
480+++ src/mcs/android/fileoutputtarget.h 2016-01-27 13:00:21 +0000
481@@ -0,0 +1,42 @@
482+/*
483+ * Copyright (C) 2016 Canonical, Ltd.
484+ *
485+ * This program is free software: you can redistribute it and/or modify it
486+ * under the terms of the GNU General Public License version 3, as published
487+ * by the Free Software Foundation.
488+ *
489+ * This program is distributed in the hope that it will be useful, but
490+ * WITHOUT ANY WARRANTY; without even the implied warranties of
491+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
492+ * PURPOSE. See the GNU General Public License for more details.
493+ *
494+ * You should have received a copy of the GNU General Public License along
495+ * with this program. If not, see <http://www.gnu.org/licenses/>.
496+ *
497+ */
498+
499+#ifndef MCS_ANDORID_FILEOUTPUTTARET_H_
500+#define MCS_ANDORID_FILEOUTPUTTARET_H_
501+
502+#include <string>
503+
504+#include "mcs/android/h264encoder.h"
505+
506+namespace mcs {
507+namespace android {
508+class FileOutputTarget : public mcs::android::H264Encoder::OutputTarget {
509+public:
510+ FileOutputTarget(const std::string &path, const mcs::android::H264Encoder::OutputFormat &format);
511+ ~FileOutputTarget();
512+
513+ int FileDescriptor() const override;
514+ mcs::android::H264Encoder::OutputFormat Format() const override;
515+
516+private:
517+ int fd_;
518+ mcs::android::H264Encoder::OutputFormat format_;
519+};
520+} // namespace android
521+} // namespace mcs
522+
523+#endif
524
525=== added file 'src/mcs/android/h264encoder.cpp'
526--- src/mcs/android/h264encoder.cpp 1970-01-01 00:00:00 +0000
527+++ src/mcs/android/h264encoder.cpp 2016-01-27 13:00:21 +0000
528@@ -0,0 +1,160 @@
529+/*
530+ * Copyright (C) 2016 Canonical, Ltd.
531+ *
532+ * This program is free software: you can redistribute it and/or modify it
533+ * under the terms of the GNU General Public License version 3, as published
534+ * by the Free Software Foundation.
535+ *
536+ * This program is distributed in the hope that it will be useful, but
537+ * WITHOUT ANY WARRANTY; without even the implied warranties of
538+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
539+ * PURPOSE. See the GNU General Public License for more details.
540+ *
541+ * You should have received a copy of the GNU General Public License along
542+ * with this program. If not, see <http://www.gnu.org/licenses/>.
543+ *
544+ */
545+
546+#include <unistd.h>
547+
548+#include <hybris/media/media_recorder_layer.h>
549+
550+#include "mcs/logger.h"
551+#include "mcs/utils.h"
552+#include "mcs/android/h264encoder.h"
553+
554+namespace mcs {
555+namespace android {
556+
557+H264Encoder::Ptr H264Encoder::Create(const OutputTarget &output) {
558+ return std::shared_ptr<H264Encoder>(new H264Encoder(output));
559+}
560+
561+H264Encoder::H264Encoder(const OutputTarget &output) :
562+ recorder_(nullptr),
563+ recorder_observer_(nullptr),
564+ recorder_source_(nullptr) {
565+
566+ ::OutputFormat format = ANDROID_OUTPUT_FORMAT_DEFAULT;
567+
568+ switch (output.Format()) {
569+ case OutputFormat::kMPEG2TS:
570+ format = ANDROID_OUTPUT_FORMAT_MPEG2TS;
571+ break;
572+ case OutputFormat::kMPEG4:
573+ format = ANDROID_OUTPUT_FORMAT_MPEG_4;
574+ break;
575+ case OutputFormat::kRTPAVP:
576+ format = ANDROID_OUTPUT_FORMAT_RTP_AVP;
577+ break;
578+ default:
579+ MCS_ERROR("Unsupported output format");
580+ return;
581+ }
582+
583+ // FIXME we need to instantiate an observer here as otherwise
584+ // the camera service can't find one and will crash.
585+ recorder_observer_ = android_media_recorder_observer_new();
586+ if (!recorder_observer_) {
587+ MCS_ERROR("Failed to create recorder observer instance");
588+ return;
589+ }
590+
591+ // Also need to install a proper callback here for the observer
592+ // until it properly checks for a assigned callback internally.
593+ android_media_recorder_observer_set_cb(recorder_observer_, [](bool started, void *context) {
594+ (void) context;
595+
596+ if (started)
597+ MCS_DEBUG("Recording started");
598+ else
599+ MCS_DEBUG("Recording stopped");
600+ }, nullptr);
601+
602+ recorder_ = android_media_new_recorder();
603+ if (!recorder_) {
604+ MCS_ERROR("Failed to create a recorder instance");
605+ return;
606+ }
607+
608+ // It's really important that we set the video source first as otherwise
609+ // the encoder doesn't enter the 'configured' state and all subsequent
610+ // calls will fail.
611+ android_recorder_setVideoSource(recorder_, ANDROID_VIDEO_SOURCE_GRALLOC_BUFFER);
612+
613+ android_recorder_setOutputFormat(recorder_, format);
614+ android_recorder_setVideoEncoder(recorder_, ANDROID_VIDEO_ENCODER_H264);
615+ android_recorder_setOutputFile(recorder_, output.FileDescriptor());
616+}
617+
618+H264Encoder::~H264Encoder() {
619+ if (recorder_)
620+ android_recorder_release(recorder_);
621+
622+ if (recorder_observer_)
623+ android_media_recorder_observer_release(recorder_observer_);
624+}
625+
626+void* H264Encoder::NativeWindowHandle() const {
627+ if (!recorder_ && !recorder_source_)
628+ return nullptr;
629+
630+ return android_recorder_source_get_native_handle(recorder_source_);
631+}
632+
633+void H264Encoder::SetFramerate(unsigned int framerate) {
634+ if (!recorder_)
635+ return;
636+
637+ android_recorder_setVideoFrameRate(recorder_, framerate);
638+}
639+
640+void H264Encoder::SetBitrate(unsigned int bitrate) {
641+ if (!recorder_)
642+ return;
643+
644+ auto param = mcs::Utils::Sprintf("video-param-encoding-bitrate=%d", bitrate);
645+
646+ android_recorder_setParameters(recorder_, param.c_str());
647+}
648+
649+void H264Encoder::SetIFrameInterval(unsigned int interval) {
650+ if (!recorder_)
651+ return;
652+
653+ auto param = mcs::Utils::Sprintf("video-param-i-frames-interval=%d", interval);
654+
655+ android_recorder_setParameters(recorder_, param.c_str());
656+}
657+
658+void H264Encoder::SetDimensions(unsigned int width, unsigned int height) {
659+ if (!recorder_)
660+ return;
661+
662+ android_recorder_setVideoSize(recorder_, width, height);
663+}
664+
665+void H264Encoder::Start() {
666+ if (!recorder_)
667+ return;
668+
669+ android_recorder_prepare(recorder_);
670+ android_recorder_start(recorder_);
671+
672+ recorder_source_ = android_recorder_query_source(recorder_);
673+ if (!recorder_source_) {
674+ MCS_ERROR("Failed to query source from recorder instance");
675+ return;
676+ }
677+}
678+
679+void H264Encoder::Stop() {
680+ if (!recorder_)
681+ return;
682+
683+ android_recorder_stop(recorder_);
684+ recorder_source_ = nullptr;
685+}
686+
687+} // namespace android
688+} // namespace mcs
689
690=== added file 'src/mcs/android/h264encoder.h'
691--- src/mcs/android/h264encoder.h 1970-01-01 00:00:00 +0000
692+++ src/mcs/android/h264encoder.h 2016-01-27 13:00:21 +0000
693@@ -0,0 +1,77 @@
694+/*
695+ * Copyright (C) 2016 Canonical, Ltd.
696+ *
697+ * This program is free software: you can redistribute it and/or modify it
698+ * under the terms of the GNU General Public License version 3, as published
699+ * by the Free Software Foundation.
700+ *
701+ * This program is distributed in the hope that it will be useful, but
702+ * WITHOUT ANY WARRANTY; without even the implied warranties of
703+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
704+ * PURPOSE. See the GNU General Public License for more details.
705+ *
706+ * You should have received a copy of the GNU General Public License along
707+ * with this program. If not, see <http://www.gnu.org/licenses/>.
708+ *
709+ */
710+
711+#ifndef MCS_ANDORID_ENCODER_H_
712+#define MCS_ANDORID_ENCODER_H_
713+
714+#include <memory>
715+
716+#include "mcs/non_copyable.h"
717+
718+struct MediaRecorderWrapper;
719+struct MediaRecorderObserver;
720+struct MediaRecorderSource;
721+
722+namespace mcs {
723+namespace android {
724+class H264Encoder {
725+public:
726+ typedef std::shared_ptr<H264Encoder> Ptr;
727+
728+ enum class OutputFormat {
729+ kRaw = 0,
730+ kMPEG4,
731+ kMPEG2TS,
732+ kRTPAVP
733+ };
734+
735+ class OutputTarget : public mcs::NonCopyable {
736+ public:
737+ // This will return a file descriptor the encoder can write its
738+ // data to.
739+ virtual int FileDescriptor() const = 0;
740+
741+ // Describes the output format the encoder should use
742+ virtual OutputFormat Format() const = 0;
743+ };
744+
745+ static Ptr Create(const OutputTarget &output);
746+
747+ ~H264Encoder();
748+
749+ void Start();
750+ void Stop();
751+
752+ void* NativeWindowHandle() const;
753+
754+ void SetFramerate(unsigned int framerate);
755+ void SetBitrate(unsigned int bitrate);
756+ void SetIFrameInterval(unsigned int interval);
757+ void SetDimensions(unsigned int width, unsigned int height);
758+
759+private:
760+ H264Encoder(const OutputTarget &output);
761+
762+private:
763+ MediaRecorderWrapper *recorder_;
764+ MediaRecorderObserver *recorder_observer_;
765+ MediaRecorderSource *recorder_source_;
766+};
767+} // namespace android
768+} // namespace mcs
769+
770+#endif
771
772=== added file 'src/mcs/android/pipedoutputtarget.cpp'
773--- src/mcs/android/pipedoutputtarget.cpp 1970-01-01 00:00:00 +0000
774+++ src/mcs/android/pipedoutputtarget.cpp 2016-01-27 13:00:21 +0000
775@@ -0,0 +1,54 @@
776+/*
777+ * Copyright (C) 2016 Canonical, Ltd.
778+ *
779+ * This program is free software: you can redistribute it and/or modify it
780+ * under the terms of the GNU General Public License version 3, as published
781+ * by the Free Software Foundation.
782+ *
783+ * This program is distributed in the hope that it will be useful, but
784+ * WITHOUT ANY WARRANTY; without even the implied warranties of
785+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
786+ * PURPOSE. See the GNU General Public License for more details.
787+ *
788+ * You should have received a copy of the GNU General Public License along
789+ * with this program. If not, see <http://www.gnu.org/licenses/>.
790+ *
791+ */
792+
793+#include <unistd.h>
794+
795+#include "mcs/logger.h"
796+#include "mcs/android/pipedoutputtarget.h"
797+
798+namespace mcs {
799+namespace android {
800+
801+PipedOutputTarget::PipedOutputTarget(const H264Encoder::OutputFormat &format) :
802+ format_(format) {
803+ if (::pipe(fds_) < 0) {
804+ MCS_ERROR("Failed to create piped output target");
805+ return;
806+ }
807+}
808+
809+PipedOutputTarget::~PipedOutputTarget() {
810+ if (fds_[0] > 0) {
811+ close(fds_[0]);
812+ close(fds_[1]);
813+ }
814+}
815+
816+int PipedOutputTarget::FileDescriptor() const {
817+ return fds_[1];
818+}
819+
820+mcs::android::H264Encoder::OutputFormat PipedOutputTarget::Format() const {
821+ return format_;
822+}
823+
824+int PipedOutputTarget::OutputFileDescriptor() const {
825+ return fds_[0];
826+}
827+
828+} // namespace android
829+} // namespace mcs
830
831=== added file 'src/mcs/android/pipedoutputtarget.h'
832--- src/mcs/android/pipedoutputtarget.h 1970-01-01 00:00:00 +0000
833+++ src/mcs/android/pipedoutputtarget.h 2016-01-27 13:00:21 +0000
834@@ -0,0 +1,42 @@
835+/*
836+ * Copyright (C) 2016 Canonical, Ltd.
837+ *
838+ * This program is free software: you can redistribute it and/or modify it
839+ * under the terms of the GNU General Public License version 3, as published
840+ * by the Free Software Foundation.
841+ *
842+ * This program is distributed in the hope that it will be useful, but
843+ * WITHOUT ANY WARRANTY; without even the implied warranties of
844+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
845+ * PURPOSE. See the GNU General Public License for more details.
846+ *
847+ * You should have received a copy of the GNU General Public License along
848+ * with this program. If not, see <http://www.gnu.org/licenses/>.
849+ *
850+ */
851+
852+#ifndef MCS_ANDORID_PIPEDOUTPUTTARET_H_
853+#define MCS_ANDORID_PIPEDOUTPUTTARET_H_
854+
855+#include "mcs/android/h264encoder.h"
856+
857+namespace mcs {
858+namespace android {
859+class PipedOutputTarget : public mcs::android::H264Encoder::OutputTarget {
860+public:
861+ PipedOutputTarget(const mcs::android::H264Encoder::OutputFormat &format);
862+ ~PipedOutputTarget();
863+
864+ int FileDescriptor() const override;
865+ mcs::android::H264Encoder::OutputFormat Format() const override;
866+
867+ int OutputFileDescriptor() const;
868+
869+private:
870+ int fds_[2];
871+ mcs::android::H264Encoder::OutputFormat format_;
872+};
873+} // namespace android
874+} // namespace mcs
875+
876+#endif
877
878=== modified file 'src/mcs/basesourcemediamanager.cpp'
879--- src/mcs/basesourcemediamanager.cpp 2015-12-07 16:02:43 +0000
880+++ src/mcs/basesourcemediamanager.cpp 2016-01-27 13:00:21 +0000
881@@ -15,9 +15,12 @@
882 *
883 */
884
885+#include <iostream>
886+
887 #include <glib.h>
888
889 #include "basesourcemediamanager.h"
890+#include "videoformat.h"
891 #include "logger.h"
892
893 namespace mcs {
894@@ -38,24 +41,23 @@
895 return sink_port1_;
896 }
897
898-std::vector<wds::H264VideoCodec> GetH264VideoCodecs() {
899+std::vector<wds::H264VideoCodec> BaseSourceMediaManager::GetH264VideoCodecs() {
900 static std::vector<wds::H264VideoCodec> codecs;
901 if (codecs.empty()) {
902 wds::RateAndResolutionsBitmap cea_rr;
903 wds::RateAndResolutionsBitmap vesa_rr;
904 wds::RateAndResolutionsBitmap hh_rr;
905 wds::RateAndResolution i;
906- // declare that we support all resolutions, CHP and level 4.2
907- // gstreamer should handle all of it :)
908+
909 for (i = wds::CEA640x480p60; i <= wds::CEA1920x1080p24; ++i)
910 cea_rr.set(i);
911- for (i = wds::VESA800x600p30; i <= wds::VESA1920x1200p30; ++i)
912- vesa_rr.set(i);
913- for (i = wds::HH800x480p30; i <= wds::HH848x480p60; ++i)
914- hh_rr.set(i);
915
916- wds::H264VideoCodec codec(wds::CHP, wds::k4_2, cea_rr, vesa_rr, hh_rr);
917+ wds::H264VideoCodec codec(wds::CHP, wds::k4, cea_rr, vesa_rr, hh_rr);
918 codecs.push_back(codec);
919+
920+ DEBUG("Video codecs supported by us:");
921+ for (auto c : codecs)
922+ mcs::video::DumpVideoCodec(c);
923 }
924
925 return codecs;
926@@ -64,15 +66,20 @@
927 bool BaseSourceMediaManager::InitOptimalVideoFormat(const wds::NativeVideoFormat& sink_native_format,
928 const std::vector<wds::H264VideoCodec>& sink_supported_codecs) {
929
930+ DEBUG("Sink native resolution:");
931+ mcs::video::DumpNativeFormat(sink_native_format);
932+
933+ DEBUG("Sink supports the following codecs:");
934+ for (auto sink_codec : sink_supported_codecs) {
935+ mcs::video::DumpVideoCodec(sink_codec);
936+ }
937+
938 format_ = wds::FindOptimalVideoFormat(sink_native_format,
939 GetH264VideoCodecs(),
940 sink_supported_codecs);
941
942- INFO("Found optimal video format");
943- INFO(" profile: %d", format_.profile);
944- INFO(" level: %d", format_.level);
945- INFO(" res type %d", format_.type);
946- INFO(" rate & resolution %d", format_.rate_resolution);
947+ DEBUG("Found optimal video format:");
948+ mcs::video::DumpVideoFormat(format_);
949
950 Configure();
951
952
953=== modified file 'src/mcs/basesourcemediamanager.h'
954--- src/mcs/basesourcemediamanager.h 2015-11-26 16:48:53 +0000
955+++ src/mcs/basesourcemediamanager.h 2016-01-27 13:00:21 +0000
956@@ -38,6 +38,7 @@
957
958 protected:
959 virtual void Configure() = 0;
960+ virtual std::vector<wds::H264VideoCodec> GetH264VideoCodecs();
961
962 protected:
963 int sink_port1_;
964
965=== renamed file 'src/w11t/command.cpp' => 'src/mcs/config.h.in'
966--- src/w11t/command.cpp 2015-12-18 17:15:31 +0000
967+++ src/mcs/config.h.in 2016-01-27 13:00:21 +0000
968@@ -15,11 +15,11 @@
969 *
970 */
971
972-#include "command.h"
973-
974-namespace w11t {
975-Command::Command(const Message &message, ResponseCallback callback) :
976- message(message),
977- callback(callback) {
978-}
979-}
980+#ifndef MCS_CONFIG_H_
981+#define MCS_CONFIG_H_
982+
983+namespace mcs {
984+constexpr const char* kRuntimePath{"/run/aethercast"};
985+}
986+
987+#endif
988
989=== modified file 'src/mcs/dbushelpers.cpp'
990--- src/mcs/dbushelpers.cpp 2015-12-07 15:40:38 +0000
991+++ src/mcs/dbushelpers.cpp 2016-01-27 13:00:21 +0000
992@@ -19,15 +19,58 @@
993
994 namespace mcs {
995
996-gchar** DBusHelpers::GenerateCapabilities(const std::vector<NetworkDeviceRole> roles) {
997- gchar** capabilities = g_new0(gchar*, roles.size() + 1);
998+gchar** DBusHelpers::GenerateDeviceCapabilities(const std::vector<NetworkDeviceRole> &roles) {
999+ gchar **capabilities = g_new0(gchar*, roles.size() + 1);
1000 int n = 0;
1001 for (auto role : roles)
1002- capabilities[n] = g_strdup(NetworkDevice::RoleToStr(roles[n++]).c_str());
1003+ capabilities[n] = g_strdup(NetworkDevice::RoleToStr(role).c_str());
1004 capabilities[n] = nullptr;
1005 return capabilities;
1006 }
1007
1008+gchar** DBusHelpers::GenerateCapabilities(const std::vector<NetworkManager::Capability> &capabilities) {
1009+ gchar** out_capabilities = g_new0(gchar*, capabilities.size() + 1);
1010+ int n = 0;
1011+ for (auto capability : capabilities) {
1012+ auto value = NetworkManager::CapabilityToStr(capability);
1013+ out_capabilities[n++] = g_strdup(value.c_str());
1014+ }
1015+ out_capabilities[n] = nullptr;
1016+ return out_capabilities;
1017+}
1018+
1019+void DBusHelpers::ParseDictionary(GVariant *properties, std::function<void(std::string, GVariant*)> callback, const std::string &key_filter) {
1020+ if (!callback || !properties)
1021+ return;
1022+
1023+ for (int n = 0; n < g_variant_n_children(properties); n++) {
1024+ auto property = g_variant_get_child_value(properties, n);
1025+ auto key_v = g_variant_get_child_value(property, 0);
1026+ auto value_v = g_variant_get_child_value(property, 1);
1027+
1028+ std::string key = g_variant_get_string(key_v, nullptr);
1029+
1030+ if (key_filter.length() > 0) {
1031+ if (key_filter != key)
1032+ continue;
1033+
1034+ callback(key, value_v);
1035+ }
1036+ else
1037+ callback(key, value_v);
1038+ }
1039+}
1040+
1041+void DBusHelpers::ParseArray(GVariant *array, std::function<void(GVariant*)> callback) {
1042+ if (!callback || !array)
1043+ return;
1044+
1045+ for (int n = 0; n < g_variant_n_children(array); n++) {
1046+ auto element = g_variant_get_child_value(array, n);
1047+ callback(element);
1048+ }
1049+}
1050+
1051 } // namespace mcs
1052
1053
1054
1055=== modified file 'src/mcs/dbushelpers.h'
1056--- src/mcs/dbushelpers.h 2015-12-07 15:40:38 +0000
1057+++ src/mcs/dbushelpers.h 2016-01-27 13:00:21 +0000
1058@@ -18,14 +18,21 @@
1059 #ifndef DBUSHELPERS_H_
1060 #define DBUSHELPERS_H_
1061
1062+#include <functional>
1063+
1064 #include <glib.h>
1065+#include <gio/gio.h>
1066
1067-#include "networkdevice.h"
1068+#include "networkmanager.h"
1069+#include "scoped_gobject.h"
1070
1071 namespace mcs {
1072
1073 struct DBusHelpers {
1074- static gchar** GenerateCapabilities(const std::vector<NetworkDeviceRole> roles);
1075+ static gchar** GenerateCapabilities(const std::vector<NetworkManager::Capability> &capabilities);
1076+ static gchar** GenerateDeviceCapabilities(const std::vector<NetworkDeviceRole> &roles);
1077+ static void ParseDictionary(GVariant *properties, std::function<void(std::string, GVariant*)> callback, const std::string &key_filter = "");
1078+ static void ParseArray(GVariant *array, std::function<void(GVariant*)> callback);
1079 };
1080
1081 } // namespace mcs
1082
1083=== modified file 'src/mcs/forwardingmiracastcontroller.cpp'
1084--- src/mcs/forwardingmiracastcontroller.cpp 2015-12-11 22:02:52 +0000
1085+++ src/mcs/forwardingmiracastcontroller.cpp 2016-01-27 13:00:21 +0000
1086@@ -50,8 +50,8 @@
1087 return fwd_->State();
1088 }
1089
1090-std::vector<NetworkDeviceRole> ForwardingMiracastController::SupportedRoles() const {
1091- return fwd_->SupportedRoles();
1092+std::vector<NetworkManager::Capability> ForwardingMiracastController::Capabilities() const {
1093+ return fwd_->Capabilities();
1094 }
1095
1096 bool ForwardingMiracastController::Scanning() const {
1097
1098=== modified file 'src/mcs/forwardingmiracastcontroller.h'
1099--- src/mcs/forwardingmiracastcontroller.h 2015-12-11 22:02:52 +0000
1100+++ src/mcs/forwardingmiracastcontroller.h 2016-01-27 13:00:21 +0000
1101@@ -35,7 +35,7 @@
1102 virtual void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) override;
1103
1104 virtual NetworkDeviceState State() const override;
1105- virtual std::vector<NetworkDeviceRole> SupportedRoles() const override;
1106+ virtual std::vector<NetworkManager::Capability> Capabilities() const override;
1107 virtual bool Scanning() const override;
1108
1109 private:
1110
1111=== added file 'src/mcs/forwardingnetworkdevice.cpp'
1112--- src/mcs/forwardingnetworkdevice.cpp 1970-01-01 00:00:00 +0000
1113+++ src/mcs/forwardingnetworkdevice.cpp 2016-01-27 13:00:21 +0000
1114@@ -0,0 +1,51 @@
1115+/*
1116+* Copyright (C) 2015 Canonical, Ltd.
1117+*
1118+* This program is free software: you can redistribute it and/or modify it
1119+* under the terms of the GNU General Public License version 3, as published
1120+* by the Free Software Foundation.
1121+*
1122+* This program is distributed in the hope that it will be useful, but
1123+* WITHOUT ANY WARRANTY; without even the implied warranties of
1124+* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1125+* PURPOSE. See the GNU General Public License for more details.
1126+*
1127+* You should have received a copy of the GNU General Public License along
1128+* with this program. If not, see <http://www.gnu.org/licenses/>.
1129+*
1130+*/
1131+
1132+#include "forwardingnetworkdevice.h"
1133+
1134+namespace mcs {
1135+
1136+ForwardingNetworkDevice::ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd) : fwd_(fwd) {
1137+ if (not fwd_) {
1138+ throw std::logic_error{"Cannot operate without a valid NetworkDevice instance."};
1139+ }
1140+}
1141+
1142+MacAddress ForwardingNetworkDevice::Address() const {
1143+ return fwd_->Address();
1144+}
1145+
1146+IpV4Address ForwardingNetworkDevice::IPv4Address() const {
1147+ return fwd_->IPv4Address();
1148+}
1149+
1150+std::string ForwardingNetworkDevice::Name() const {
1151+ return fwd_->Name();
1152+}
1153+
1154+NetworkDeviceState ForwardingNetworkDevice::State() const {
1155+ return fwd_->State();
1156+}
1157+
1158+std::vector<NetworkDeviceRole> ForwardingNetworkDevice::SupportedRoles() const {
1159+ return fwd_->SupportedRoles();
1160+}
1161+
1162+const NetworkDevice::Ptr& ForwardingNetworkDevice::Fwd() const {
1163+ return fwd_;
1164+}
1165+} // namespace mcs
1166
1167=== removed file 'src/mcs/forwardingnetworkdevice.cpp'
1168--- src/mcs/forwardingnetworkdevice.cpp 2015-12-16 08:04:35 +0000
1169+++ src/mcs/forwardingnetworkdevice.cpp 1970-01-01 00:00:00 +0000
1170@@ -1,51 +0,0 @@
1171-/*
1172-* Copyright (C) 2015 Canonical, Ltd.
1173-*
1174-* This program is free software: you can redistribute it and/or modify it
1175-* under the terms of the GNU General Public License version 3, as published
1176-* by the Free Software Foundation.
1177-*
1178-* This program is distributed in the hope that it will be useful, but
1179-* WITHOUT ANY WARRANTY; without even the implied warranties of
1180-* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1181-* PURPOSE. See the GNU General Public License for more details.
1182-*
1183-* You should have received a copy of the GNU General Public License along
1184-* with this program. If not, see <http://www.gnu.org/licenses/>.
1185-*
1186-*/
1187-
1188-#include "forwardingnetworkdevice.h"
1189-
1190-namespace mcs {
1191-
1192-ForwardingNetworkDevice::ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd) : fwd_(fwd) {
1193- if (not fwd_) {
1194- throw std::logic_error{"Cannot operate without a valid NetworkDevice instance."};
1195- }
1196-}
1197-
1198-MacAddress ForwardingNetworkDevice::Address() const {
1199- return fwd_->Address();
1200-}
1201-
1202-IpV4Address ForwardingNetworkDevice::IPv4Address() const {
1203- return fwd_->IPv4Address();
1204-}
1205-
1206-std::string ForwardingNetworkDevice::Name() const {
1207- return fwd_->Name();
1208-}
1209-
1210-NetworkDeviceState ForwardingNetworkDevice::State() const {
1211- return fwd_->State();
1212-}
1213-
1214-std::vector<NetworkDeviceRole> ForwardingNetworkDevice::SupportedRoles() const {
1215- return fwd_->SupportedRoles();
1216-}
1217-
1218-const NetworkDevice::Ptr& ForwardingNetworkDevice::Fwd() const {
1219- return fwd_;
1220-}
1221-} // namespace mcs
1222
1223=== added file 'src/mcs/forwardingnetworkdevice.h'
1224--- src/mcs/forwardingnetworkdevice.h 1970-01-01 00:00:00 +0000
1225+++ src/mcs/forwardingnetworkdevice.h 2016-01-27 13:00:21 +0000
1226@@ -0,0 +1,42 @@
1227+/*
1228+* Copyright (C) 2015 Canonical, Ltd.
1229+*
1230+* This program is free software: you can redistribute it and/or modify it
1231+* under the terms of the GNU General Public License version 3, as published
1232+* by the Free Software Foundation.
1233+*
1234+* This program is distributed in the hope that it will be useful, but
1235+* WITHOUT ANY WARRANTY; without even the implied warranties of
1236+* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1237+* PURPOSE. See the GNU General Public License for more details.
1238+*
1239+* You should have received a copy of the GNU General Public License along
1240+* with this program. If not, see <http://www.gnu.org/licenses/>.
1241+*
1242+*/
1243+
1244+#ifndef FORWARDINGNETWORKDEVICE_H_
1245+#define FORWARDINGNETWORKDEVICE_H_
1246+
1247+#include "networkdevice.h"
1248+
1249+namespace mcs {
1250+
1251+class ForwardingNetworkDevice : public NetworkDevice {
1252+public:
1253+ ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd);
1254+
1255+ MacAddress Address() const override;
1256+ IpV4Address IPv4Address() const override;
1257+ std::string Name() const override;
1258+ NetworkDeviceState State() const override;
1259+ std::vector<NetworkDeviceRole> SupportedRoles() const override;
1260+
1261+protected:
1262+ const NetworkDevice::Ptr& Fwd() const;
1263+
1264+private:
1265+ NetworkDevice::Ptr fwd_;
1266+};
1267+} // namespace mcs
1268+#endif
1269
1270=== removed file 'src/mcs/forwardingnetworkdevice.h'
1271--- src/mcs/forwardingnetworkdevice.h 2015-12-16 08:04:35 +0000
1272+++ src/mcs/forwardingnetworkdevice.h 1970-01-01 00:00:00 +0000
1273@@ -1,42 +0,0 @@
1274-/*
1275-* Copyright (C) 2015 Canonical, Ltd.
1276-*
1277-* This program is free software: you can redistribute it and/or modify it
1278-* under the terms of the GNU General Public License version 3, as published
1279-* by the Free Software Foundation.
1280-*
1281-* This program is distributed in the hope that it will be useful, but
1282-* WITHOUT ANY WARRANTY; without even the implied warranties of
1283-* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1284-* PURPOSE. See the GNU General Public License for more details.
1285-*
1286-* You should have received a copy of the GNU General Public License along
1287-* with this program. If not, see <http://www.gnu.org/licenses/>.
1288-*
1289-*/
1290-
1291-#ifndef FORWARDINGNETWORKDEVICE_H_
1292-#define FORWARDINGNETWORKDEVICE_H_
1293-
1294-#include "networkdevice.h"
1295-
1296-namespace mcs {
1297-
1298-class ForwardingNetworkDevice : public NetworkDevice {
1299-public:
1300- ForwardingNetworkDevice(const NetworkDevice::Ptr& fwd);
1301-
1302- MacAddress Address() const override;
1303- IpV4Address IPv4Address() const override;
1304- std::string Name() const override;
1305- NetworkDeviceState State() const override;
1306- std::vector<NetworkDeviceRole> SupportedRoles() const override;
1307-
1308-protected:
1309- const NetworkDevice::Ptr& Fwd() const;
1310-
1311-private:
1312- NetworkDevice::Ptr fwd_;
1313-};
1314-} // namespace mcs
1315-#endif
1316
1317=== modified file 'src/mcs/gobject_deleter.h'
1318--- src/mcs/gobject_deleter.h 2015-11-30 10:41:56 +0000
1319+++ src/mcs/gobject_deleter.h 2016-01-27 13:00:21 +0000
1320@@ -19,6 +19,8 @@
1321
1322 #include <glib-object.h>
1323
1324+#include <mcs/logger.h>
1325+
1326 namespace mcs {
1327 // A GObjectDeleter considers T to be a GObject and
1328 // provides an operator() that decrements the reference
1329
1330=== modified file 'src/mcs/gstsourcemediamanager.cpp'
1331--- src/mcs/gstsourcemediamanager.cpp 2015-12-09 16:07:13 +0000
1332+++ src/mcs/gstsourcemediamanager.cpp 2016-01-27 13:00:21 +0000
1333@@ -60,7 +60,7 @@
1334 g_free (debug);
1335 break;
1336 default:
1337- /* unhandled message */
1338+ DEBUG("");
1339 break;
1340 }
1341
1342@@ -68,6 +68,8 @@
1343 }
1344
1345 void GstSourceMediaManager::Configure() {
1346+ DEBUG("");
1347+
1348 pipeline_ = ConstructPipeline(format_);
1349
1350 ScopedGObject<GstBus> bus{gst_pipeline_get_bus (GST_PIPELINE(pipeline_.get()))};
1351@@ -81,6 +83,8 @@
1352 if (!pipeline_)
1353 return;
1354
1355+ DEBUG("");
1356+
1357 gst_element_set_state(pipeline_.get(), GST_STATE_PLAYING);
1358 }
1359
1360@@ -88,6 +92,8 @@
1361 if (!pipeline_)
1362 return;
1363
1364+ DEBUG("");
1365+
1366 gst_element_set_state(pipeline_.get(), GST_STATE_PAUSED);
1367 }
1368
1369@@ -95,6 +101,8 @@
1370 if (!pipeline_)
1371 return;
1372
1373+ DEBUG("");
1374+
1375 gst_element_set_state(pipeline_.get(), GST_STATE_READY);
1376 }
1377
1378@@ -102,6 +110,8 @@
1379 if (!pipeline_)
1380 return true;
1381
1382+ DEBUG("");
1383+
1384 GstState state;
1385 gst_element_get_state(pipeline_.get(), &state, nullptr, GST_CLOCK_TIME_NONE);
1386
1387
1388=== added file 'src/mcs/initgstreameronce.cpp'
1389--- src/mcs/initgstreameronce.cpp 1970-01-01 00:00:00 +0000
1390+++ src/mcs/initgstreameronce.cpp 2016-01-27 13:00:21 +0000
1391@@ -0,0 +1,88 @@
1392+/*
1393+ * Copyright (C) 2015 Canonical, Ltd.
1394+ *
1395+ * This program is free software: you can redistribute it and/or modify it
1396+ * under the terms of the GNU General Public License version 3, as published
1397+ * by the Free Software Foundation.
1398+ *
1399+ * This program is distributed in the hope that it will be useful, but
1400+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1401+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1402+ * PURPOSE. See the GNU General Public License for more details.
1403+ *
1404+ * You should have received a copy of the GNU General Public License along
1405+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1406+ *
1407+ */
1408+
1409+#include <atomic>
1410+
1411+#include <gst/gst.h>
1412+
1413+#include "initgstreameronce.h"
1414+#include "logger.h"
1415+
1416+namespace {
1417+void GstLog (GstDebugCategory *category,
1418+ GstDebugLevel level,
1419+ const gchar *file,
1420+ const gchar *function,
1421+ gint line,
1422+ GObject *object,
1423+ GstDebugMessage *message,
1424+ gpointer user_data) {
1425+
1426+ boost::optional<mcs::Logger::Location> location;
1427+ if (file && function && line > 0) {
1428+ location = mcs::Logger::Location{file, function, line};
1429+ }
1430+
1431+ mcs::Log().Log(mcs::GstDebugLevelToSeverity(level), gst_debug_message_get(message), location);
1432+}
1433+}
1434+namespace mcs {
1435+Logger::Severity GstDebugLevelToSeverity(GstDebugLevel level) {
1436+ switch (level) {
1437+ case GST_LEVEL_NONE:
1438+ case GST_LEVEL_ERROR:
1439+ return Logger::Severity::kError;
1440+ case GST_LEVEL_WARNING:
1441+ case GST_LEVEL_FIXME:
1442+ return Logger::Severity::kWarning;
1443+ case GST_LEVEL_INFO:
1444+ return Logger::Severity::kInfo;
1445+ case GST_LEVEL_DEBUG:
1446+ return Logger::Severity::kDebug;
1447+ case GST_LEVEL_LOG:
1448+ return Logger::Severity::kDebug;
1449+ case GST_LEVEL_TRACE:
1450+ case GST_LEVEL_MEMDUMP:
1451+ return Logger::Severity::kTrace;
1452+ default:
1453+ return Logger::Severity::kInfo;
1454+ }
1455+}
1456+
1457+void InitGstreamerOnceOrThrow() {
1458+ static std::atomic<bool> initialized(false);
1459+ if (initialized.exchange(true))
1460+ return;
1461+
1462+ GError* error = nullptr;
1463+ if (gst_init_check(nullptr, nullptr, &error) == FALSE) {
1464+ auto what = Utils::Sprintf("Failed to initialize gstreamer (%s: %s)", g_quark_to_string(error->domain), error->message);
1465+ g_error_free(error);
1466+ throw std::runtime_error{what};
1467+ }
1468+
1469+ // Get rid of gstreamer's default log function.
1470+ gst_debug_remove_log_function(nullptr);
1471+ // And install our own.
1472+ gst_debug_add_log_function(GstLog, nullptr, nullptr);
1473+ // No need to, our logging infra takes care of that, too.
1474+ gst_debug_set_colored(FALSE);
1475+ auto gst_debug = Utils::GetEnvValue("AETHERCAST_GST_DEBUG");
1476+ if (not gst_debug.empty())
1477+ gst_debug_set_threshold_from_string(gst_debug.c_str(), FALSE);
1478+}
1479+}
1480
1481=== added file 'src/mcs/initgstreameronce.h'
1482--- src/mcs/initgstreameronce.h 1970-01-01 00:00:00 +0000
1483+++ src/mcs/initgstreameronce.h 2016-01-27 13:00:21 +0000
1484@@ -0,0 +1,29 @@
1485+/*
1486+ * Copyright (C) 2015 Canonical, Ltd.
1487+ *
1488+ * This program is free software: you can redistribute it and/or modify it
1489+ * under the terms of the GNU General Public License version 3, as published
1490+ * by the Free Software Foundation.
1491+ *
1492+ * This program is distributed in the hope that it will be useful, but
1493+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1494+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1495+ * PURPOSE. See the GNU General Public License for more details.
1496+ *
1497+ * You should have received a copy of the GNU General Public License along
1498+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1499+ *
1500+ */
1501+
1502+#include <gst/gst.h>
1503+
1504+#include "logger.h"
1505+
1506+namespace mcs {
1507+// GstDebugLevelToSeverity maps a GstDebugLevel to a Logger::Severity;
1508+Logger::Severity GstDebugLevelToSeverity(GstDebugLevel);
1509+
1510+// InitGstreamerOnceOrThrow initializes GStreamer, redirecting
1511+// its debug output to the mcs::Logger facilities.
1512+void InitGstreamerOnceOrThrow();
1513+}
1514
1515=== modified file 'src/mcs/mediamanagerfactory.cpp'
1516--- src/mcs/mediamanagerfactory.cpp 2015-12-07 16:02:43 +0000
1517+++ src/mcs/mediamanagerfactory.cpp 2016-01-27 13:00:21 +0000
1518@@ -19,7 +19,8 @@
1519
1520 #include "logger.h"
1521 #include "mediamanagerfactory.h"
1522-#include "mirsourcemediamanager.h"
1523+#include "mir/sourcemediamanager.h"
1524+#include "x11sourcemediamanager.h"
1525 #include "testsourcemediamanager.h"
1526 #include "utils.h"
1527 #include "logging.h"
1528@@ -49,10 +50,12 @@
1529 std::shared_ptr<BaseSourceMediaManager> MediaManagerFactory::CreateSource(const std::string &remote_address) {
1530 std::string type = Utils::GetEnvValue("MIRACAST_SOURCE_TYPE");
1531
1532- WARNING("Creating source media manager of type %s", type.c_str());
1533+ DEBUG("Creating source media manager of type %s", type.c_str());
1534
1535 if (type.length() == 0 || type == "mir")
1536- return std::make_shared<MirSourceMediaManager>(remote_address);
1537+ return std::make_shared<mcs::mir::SourceMediaManager>(remote_address);
1538+ else if (type == "x11")
1539+ return X11SourceMediaManager::create(remote_address);
1540 else if (type == "test")
1541 return TestSourceMediaManager::create(remote_address);
1542
1543
1544=== added directory 'src/mcs/mir'
1545=== renamed file 'src/mcs/mirsourcemediamanager.cpp' => 'src/mcs/mir/sourcemediamanager.cpp'
1546--- src/mcs/mirsourcemediamanager.cpp 2015-12-07 16:02:43 +0000
1547+++ src/mcs/mir/sourcemediamanager.cpp 2016-01-27 13:00:21 +0000
1548@@ -15,99 +15,48 @@
1549 *
1550 */
1551
1552+#include <cassert>
1553 #include <sstream>
1554
1555-#include "mirsourcemediamanager.h"
1556-#include "utils.h"
1557-#include "logger.h"
1558+#include "mcs/utils.h"
1559+#include "mcs/logger.h"
1560+
1561+#include "mcs/videoformat.h"
1562+
1563+#include "mcs/mir/sourcemediamanager.h"
1564
1565 namespace mcs {
1566-MirSourceMediaManager::MirSourceMediaManager(const std::string &remote_address) :
1567- remote_address_(remote_address) {
1568-}
1569-
1570-MirSourceMediaManager::~MirSourceMediaManager() {
1571-}
1572-
1573-SharedGObject<GstElement> MirSourceMediaManager::ConstructPipeline(const wds::H264VideoFormat &format) {
1574- int width = 0, height = 0;
1575- std::string profile = "constrained-baseline";
1576-
1577- switch (format.profile) {
1578- case wds::CBP:
1579- profile = "constrained-baseline";
1580- break;
1581- case wds::CHP:
1582- profile = "high";
1583- break;
1584- }
1585-
1586- switch (format.type) {
1587- case wds::CEA:
1588- switch (format.rate_resolution) {
1589- case wds::CEA640x480p60:
1590- width = 640;
1591- height = 480;
1592- break;
1593- case wds::CEA720x480p60:
1594- case wds::CEA720x480i60:
1595- width = 720;
1596- height = 480;
1597- break;
1598- case wds::CEA720x576p50:
1599- case wds::CEA720x576i50:
1600- width = 720;
1601- height = 576;
1602- break;
1603- case wds::CEA1280x720p30:
1604- case wds::CEA1280x720p60:
1605- width = 1280;
1606- height = 720;
1607- break;
1608- case wds::CEA1920x1080p30:
1609- case wds::CEA1920x1080p60:
1610- case wds::CEA1920x1080i60:
1611- width = 1920;
1612- height = 1080;
1613- break;
1614- case wds::CEA1280x720p25:
1615- case wds::CEA1280x720p50:
1616- case wds::CEA1280x720p24:
1617- width = 1280;
1618- height = 720;
1619- break;
1620- case wds::CEA1920x1080p25:
1621- case wds::CEA1920x1080p50:
1622- case wds::CEA1920x1080i50:
1623- case wds::CEA1920x1080p24:
1624- width = 1920;
1625- height = 1080;
1626- break;
1627- default:
1628- break;
1629- }
1630- break;
1631- default:
1632- break;
1633- }
1634-
1635- std::stringstream ss;
1636- ss << "mirimagesrc mir-socket=/run/mir_socket ! videoconvert ! videoscale ! ";
1637- ss << Utils::Sprintf("video/x-raw,width=%d,height=%d ! ", width, height);
1638- ss << "videoflip method=counterclockwise ! queue2 ! video/x-raw,format=I420 ! ";
1639- ss << "x264enc aud=false byte-stream=true tune=zerolatency ! ";
1640- ss << Utils::Sprintf("video/x-h264,profile=%s ! ", profile.c_str());
1641- ss << "mpegtsmux ! rtpmp2tpay ! ";
1642- ss << Utils::Sprintf("udpsink name=sink host=%s port=%d", remote_address_.c_str(), sink_port1_);
1643-
1644- GError *error = nullptr;
1645- GstElement *pipeline = gst_parse_launch(ss.str().c_str(), &error);
1646- if (error) {
1647- ERROR("Failed to setup GStreamer pipeline: %s", error->message);
1648- g_error_free(error);
1649- return nullptr;
1650- }
1651+namespace mir {
1652+
1653+SourceMediaManager::SourceMediaManager(const std::string &remote_address) :
1654+ remote_address_(remote_address),
1655+ output_(mcs::android::H264Encoder::OutputFormat::kRTPAVP) {
1656+}
1657+
1658+SourceMediaManager::~SourceMediaManager() {
1659+}
1660+
1661+SharedGObject<GstElement> SourceMediaManager::ConstructPipeline(const wds::H264VideoFormat &format) {
1662+ auto rr = mcs::video::ExtractRateAndResolution(format);
1663+
1664+ encoder_ = mcs::android::H264Encoder::Create(output_);
1665+
1666+ encoder_->SetDimensions(rr.width, rr.height);
1667+ encoder_->SetFramerate(rr.framerate);
1668+
1669+ GstElement *pipeline = gst_pipeline_new("video-stream");
1670+ GstElement *source = gst_element_factory_make("fdsrc", "video-in");
1671+ GstElement *sink = gst_element_factory_make("udpsink", "stream-output");
1672+
1673+ // Set the pipeline plugin properties
1674+ g_object_set(G_OBJECT(source), "fd", output_.OutputFileDescriptor(), nullptr);
1675+ g_object_set(G_OBJECT(sink), "host", remote_address_.c_str(), nullptr);
1676+ g_object_set(G_OBJECT(sink), "port", sink_port1_, nullptr);
1677+
1678+ gst_bin_add_many(GST_BIN(pipeline), source, sink, nullptr);
1679+ gst_element_link_many(source, sink, nullptr);
1680
1681 return make_shared_gobject(pipeline);
1682 }
1683+} // namespace mir
1684 } // namespace mcs
1685
1686=== renamed file 'src/mcs/mirsourcemediamanager.h' => 'src/mcs/mir/sourcemediamanager.h'
1687--- src/mcs/mirsourcemediamanager.h 2015-11-30 10:41:56 +0000
1688+++ src/mcs/mir/sourcemediamanager.h 2016-01-27 13:00:21 +0000
1689@@ -15,22 +15,30 @@
1690 *
1691 */
1692
1693-#ifndef MIRMEDIAMANAGER_H_
1694-#define MIRMEDIAMANAGER_H_
1695+#ifndef MCS_MIR_SOURCEMEDIAMANAGER_H_
1696+#define MCS_MIR_SOURCEMEDIAMANAGER_H_
1697
1698-#include "gstsourcemediamanager.h"
1699+#include "mcs/gstsourcemediamanager.h"
1700+#include "mcs/android/h264encoder.h"
1701+#include "mcs/android/pipedoutputtarget.h"
1702
1703 namespace mcs {
1704-class MirSourceMediaManager : public GstSourceMediaManager {
1705+namespace mir {
1706+
1707+class SourceMediaManager : public GstSourceMediaManager {
1708 public:
1709- explicit MirSourceMediaManager(const std::string &remote_address);
1710- ~MirSourceMediaManager();
1711+ explicit SourceMediaManager(const std::string &remote_address);
1712+ ~SourceMediaManager();
1713
1714 protected:
1715 SharedGObject<GstElement> ConstructPipeline(const wds::H264VideoFormat &format) override;
1716
1717 private:
1718 std::string remote_address_;
1719+ mcs::android::H264Encoder::Ptr encoder_;
1720+ mcs::android::PipedOutputTarget output_;
1721 };
1722+} // namespace mir
1723 } // namespace mcs
1724+
1725 #endif
1726
1727=== modified file 'src/mcs/miracastcontroller.h'
1728--- src/mcs/miracastcontroller.h 2015-12-16 08:04:35 +0000
1729+++ src/mcs/miracastcontroller.h 2016-01-27 13:00:21 +0000
1730@@ -21,6 +21,7 @@
1731 #include <chrono>
1732 #include <memory>
1733
1734+#include "networkmanager.h"
1735 #include "networkdevice.h"
1736 #include "non_copyable.h"
1737 #include "types.h"
1738@@ -54,7 +55,7 @@
1739 virtual void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30}) = 0;
1740
1741 virtual NetworkDeviceState State() const = 0;
1742- virtual std::vector<NetworkDeviceRole> SupportedRoles() const = 0;
1743+ virtual std::vector<NetworkManager::Capability> Capabilities() const = 0;
1744 virtual bool Scanning() const = 0;
1745
1746 protected:
1747
1748=== modified file 'src/mcs/miracastcontrollerskeleton.cpp'
1749--- src/mcs/miracastcontrollerskeleton.cpp 2015-12-21 15:20:11 +0000
1750+++ src/mcs/miracastcontrollerskeleton.cpp 2016-01-27 13:00:21 +0000
1751@@ -55,10 +55,7 @@
1752 aethercast_interface_manager_set_state(manager_obj_.get(),
1753 NetworkDevice::StateToStr(State()).c_str());
1754
1755- // Capabilities are a collection of different things our local adapter
1756- // supports. The supported roles are just one part of this.
1757- auto roles = SupportedRoles();
1758- auto capabilities = DBusHelpers::GenerateCapabilities(roles);
1759+ auto capabilities = DBusHelpers::GenerateCapabilities(Capabilities());
1760
1761 aethercast_interface_manager_set_capabilities(manager_obj_.get(), capabilities);
1762
1763
1764=== modified file 'src/mcs/miracastservice.cpp'
1765--- src/mcs/miracastservice.cpp 2015-12-18 19:48:09 +0000
1766+++ src/mcs/miracastservice.cpp 2016-01-27 13:00:21 +0000
1767@@ -27,8 +27,12 @@
1768
1769 #include <chrono>
1770
1771+#include <boost/filesystem.hpp>
1772+
1773 #include <wds/logging.h>
1774
1775+#include "initgstreameronce.h"
1776+#include "config.h"
1777 #include "keep_alive.h"
1778 #include "logger.h"
1779 #include "miracastservice.h"
1780@@ -37,12 +41,11 @@
1781 #include "types.h"
1782 #include "logging.h"
1783
1784-#include <w11t/wfddeviceinfo.h>
1785-
1786 namespace {
1787 // TODO(morphis, tvoss): Expose the port as a construction-time parameter.
1788 const std::uint16_t kMiracastDefaultRtspCtrlPort{7236};
1789 const std::chrono::milliseconds kStateIdleTimeout{5000};
1790+const std::chrono::seconds kShutdownGracePreriod{1};
1791
1792 // SafeLog serves as integration point to the wds::LogSystem world.
1793 template <mcs::Logger::Severity severity>
1794@@ -93,11 +96,24 @@
1795 }
1796
1797 struct Runtime {
1798- static int OnSignalRaised(gpointer user_data) {
1799+ static gboolean OnSignalRaised(gpointer user_data) {
1800 auto thiz = static_cast<Runtime*>(user_data);
1801- g_main_loop_quit(thiz->ml);
1802-
1803- return 0;
1804+
1805+ // This will bring down everything and the timeout below will give
1806+ // things a small amount of time to perform their shutdown jobs.
1807+ thiz->service->Shutdown();
1808+
1809+ MCS_DEBUG("Exiting");
1810+
1811+ g_timeout_add_seconds(kShutdownGracePreriod.count(), [](gpointer user_data) {
1812+ auto thiz = static_cast<Runtime*>(user_data);
1813+ g_main_loop_quit(thiz->ml);
1814+ return FALSE;
1815+ }, thiz);
1816+
1817+ // A second SIGTERM should really terminate us and also overlay
1818+ // the grace period for a proper shutdown we're performing.
1819+ return FALSE;
1820 }
1821
1822 Runtime() {
1823@@ -107,6 +123,9 @@
1824 g_unix_signal_add(SIGINT, OnSignalRaised, this);
1825 g_unix_signal_add(SIGTERM, OnSignalRaised, this);
1826
1827+ // Initialize gstreamer.
1828+ mcs::InitGstreamerOnceOrThrow();
1829+
1830 // Redirect all wds logging to our own.
1831 wds::LogSystem::set_vlog_func(SafeLog<mcs::Logger::Severity::kTrace>);
1832 wds::LogSystem::set_log_func(SafeLog<mcs::Logger::Severity::kInfo>);
1833@@ -140,11 +159,14 @@
1834 // Become a reaper of all our children
1835 if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
1836 g_warning("Failed to make us a subreaper of our children");
1837+
1838+ network_manager = mcs::NetworkManagerFactory::Create();
1839+ service = mcs::MiracastService::Create(network_manager);
1840+ mcsa = mcs::MiracastControllerSkeleton::create(service);
1841 }
1842
1843 ~Runtime() {
1844 g_main_loop_unref(ml);
1845- gst_deinit();
1846 }
1847
1848 void Run() {
1849@@ -153,12 +175,11 @@
1850
1851 GMainLoop *ml = g_main_loop_new(nullptr, FALSE);
1852 bool is_gst_initialized = gst_init_check(nullptr, nullptr, nullptr);
1853+ mcs::NetworkManager::Ptr network_manager;
1854+ mcs::MiracastService::Ptr service;
1855+ mcs::MiracastControllerSkeleton::Ptr mcsa;
1856 } rt;
1857
1858- auto network_manager = mcs::NetworkManagerFactory::Create();
1859- auto service = mcs::MiracastService::Create(network_manager);
1860- auto mcsa = mcs::MiracastControllerSkeleton::create(service);
1861-
1862 rt.Run();
1863
1864 return 0;
1865@@ -173,6 +194,8 @@
1866 current_state_(kIdle),
1867 scan_timeout_source_(0),
1868 supported_roles_({kSource}) {
1869+
1870+ CreateRuntimeDirectory();
1871 }
1872
1873 std::shared_ptr<MiracastService> MiracastService::FinalizeConstruction(const NetworkManager::Ptr &network_manager) {
1874@@ -191,6 +214,15 @@
1875 g_source_remove(scan_timeout_source_);
1876 }
1877
1878+void MiracastService::CreateRuntimeDirectory() {
1879+ boost::filesystem::path runtime_dir(mcs::kRuntimePath);
1880+
1881+ if (boost::filesystem::is_directory(runtime_dir))
1882+ boost::filesystem::remove_all(runtime_dir);
1883+
1884+ boost::filesystem::create_directory(runtime_dir);
1885+}
1886+
1887 void MiracastService::SetDelegate(const std::weak_ptr<MiracastController::Delegate> &delegate) {
1888 delegate_ = delegate;
1889 }
1890@@ -203,8 +235,8 @@
1891 return current_state_;
1892 }
1893
1894-std::vector<NetworkDeviceRole> MiracastService::SupportedRoles() const {
1895- return supported_roles_;
1896+std::vector<NetworkManager::Capability> MiracastService::Capabilities() const {
1897+ return network_manager_->Capabilities();
1898 }
1899
1900 bool MiracastService::Scanning() const {
1901@@ -273,6 +305,9 @@
1902 return;
1903
1904 AdvanceState(device->State());
1905+
1906+ if (auto sp = delegate_.lock())
1907+ sp->OnDeviceChanged(device);
1908 }
1909
1910 void MiracastService::OnDeviceChanged(const NetworkDevice::Ptr &device) {
1911@@ -297,7 +332,8 @@
1912 }
1913
1914 void MiracastService::StartIdleTimer() {
1915- g_timeout_add(kStateIdleTimeout.count(), &MiracastService::OnIdleTimer, new SharedKeepAlive<MiracastService>{shared_from_this()});
1916+ g_timeout_add(kStateIdleTimeout.count(), &MiracastService::OnIdleTimer,
1917+ new SharedKeepAlive<MiracastService>{shared_from_this()});
1918 }
1919
1920 void MiracastService::FinishConnectAttempt(mcs::Error error) {
1921@@ -309,6 +345,7 @@
1922
1923 void MiracastService::Connect(const NetworkDevice::Ptr &device, ResultCallback callback) {
1924 if (current_device_) {
1925+ MCS_DEBUG("Tried to connect again while we're already trying to connect a device");
1926 callback(Error::kAlready);
1927 return;
1928 }
1929@@ -318,10 +355,10 @@
1930 return;
1931 }
1932
1933- DEBUG("Connecting remote device %s", device->Address());
1934+ DEBUG("address %s", device->Address());
1935
1936 if (!network_manager_->Connect(device)) {
1937- DEBUG("FAiled to connect remote device");
1938+ DEBUG("Failed to connect remote device");
1939 callback(Error::kFailed);
1940 return;
1941 }
1942@@ -347,4 +384,12 @@
1943 void MiracastService::Scan(const std::chrono::seconds &timeout) {
1944 network_manager_->Scan(timeout);
1945 }
1946+
1947+void MiracastService::Shutdown() {
1948+ if (current_device_)
1949+ network_manager_->Disconnect(current_device_);
1950+
1951+ network_manager_->Release();
1952+}
1953+
1954 } // namespace miracast
1955
1956=== modified file 'src/mcs/miracastservice.h'
1957--- src/mcs/miracastservice.h 2015-12-11 21:10:24 +0000
1958+++ src/mcs/miracastservice.h 2016-01-27 13:00:21 +0000
1959@@ -67,7 +67,7 @@
1960 void Scan(const std::chrono::seconds &timeout = std::chrono::seconds{30});
1961
1962 NetworkDeviceState State() const;
1963- std::vector<NetworkDeviceRole> SupportedRoles() const;
1964+ std::vector<NetworkManager::Capability> Capabilities() const;
1965 bool Scanning() const;
1966
1967 void OnClientDisconnected();
1968@@ -91,6 +91,9 @@
1969 void StartIdleTimer();
1970 void LoadWiFiFirmware();
1971
1972+ void Shutdown();
1973+ void CreateRuntimeDirectory();
1974+
1975 private:
1976 std::weak_ptr<MiracastController::Delegate> delegate_;
1977 std::shared_ptr<NetworkManager> network_manager_;
1978
1979=== modified file 'src/mcs/miracastsourceclient.cpp'
1980--- src/mcs/miracastsourceclient.cpp 2015-12-09 16:07:13 +0000
1981+++ src/mcs/miracastsourceclient.cpp 2016-01-27 13:00:21 +0000
1982@@ -25,7 +25,7 @@
1983 #include "keep_alive.h"
1984 #include "logger.h"
1985 #include "miracastsourceclient.h"
1986-#include "mirsourcemediamanager.h"
1987+#include "mcs/mir/sourcemediamanager.h"
1988 #include "testsourcemediamanager.h"
1989 #include "mediamanagerfactory.h"
1990
1991
1992=== modified file 'src/mcs/miracastsourcemanager.cpp'
1993--- src/mcs/miracastsourcemanager.cpp 2015-12-09 16:07:13 +0000
1994+++ src/mcs/miracastsourcemanager.cpp 2016-01-27 13:00:21 +0000
1995@@ -24,9 +24,7 @@
1996 namespace mcs {
1997 std::shared_ptr<MiracastSourceManager> MiracastSourceManager::Create(const IpV4Address &address, unsigned short port) {
1998 auto sp = std::shared_ptr<MiracastSourceManager>{new MiracastSourceManager{}};
1999- DEBUG("Before setup");
2000 sp->Setup(address, port);
2001- DEBUG("After setup");
2002 return sp;
2003 }
2004
2005@@ -52,7 +50,7 @@
2006 }
2007
2008 bool MiracastSourceManager::Setup(const IpV4Address &address, unsigned short port) {
2009- GError *error;
2010+ GError *error = nullptr;
2011
2012 if (socket_)
2013 return false;
2014@@ -110,6 +108,8 @@
2015 gboolean MiracastSourceManager::OnNewConnection(GSocket *socket, GIOCondition cond, gpointer user_data) {
2016 auto inst = static_cast<WeakKeepAlive<MiracastSourceManager>*>(user_data)->GetInstance().lock();
2017
2018+ MCS_DEBUG("");
2019+
2020 // The callback context was deleted while the wait for connection was active.
2021 // Hardly anything we can do about it except for returning early.
2022 if (not inst)
2023
2024=== modified file 'src/mcs/networkdevice.cpp'
2025--- src/mcs/networkdevice.cpp 2015-12-18 17:15:31 +0000
2026+++ src/mcs/networkdevice.cpp 2016-01-27 13:00:21 +0000
2027@@ -17,8 +17,6 @@
2028
2029 #include "networkdevice.h"
2030
2031-#include <w11t/wfddeviceinfo.h>
2032-
2033 namespace mcs {
2034 std::string NetworkDevice::StateToStr(NetworkDeviceState state) {
2035 switch (state) {
2036@@ -27,7 +25,9 @@
2037 case kFailure:
2038 return "failure";
2039 case kAssociation:
2040- return "connecting";
2041+ return "association";
2042+ case kConfiguration:
2043+ return "configuration";
2044 case kConnected:
2045 return "connected";
2046 case kDisconnected:
2047
2048=== added file 'src/mcs/networkdeviceskeleton.cpp'
2049--- src/mcs/networkdeviceskeleton.cpp 1970-01-01 00:00:00 +0000
2050+++ src/mcs/networkdeviceskeleton.cpp 2016-01-27 13:00:21 +0000
2051@@ -0,0 +1,142 @@
2052+/*
2053+ * Copyright (C) 2015 Canonical, Ltd.
2054+ *
2055+ * This program is free software: you can redistribute it and/or modify it
2056+ * under the terms of the GNU General Public License version 3, as published
2057+ * by the Free Software Foundation.
2058+ *
2059+ * This program is distributed in the hope that it will be useful, but
2060+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2061+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2062+ * PURPOSE. See the GNU General Public License for more details.
2063+ *
2064+ * You should have received a copy of the GNU General Public License along
2065+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2066+ *
2067+ */
2068+
2069+#include <algorithm>
2070+#include <boost/concept_check.hpp>
2071+
2072+#include "networkdeviceskeleton.h"
2073+#include "utils.h"
2074+#include "keep_alive.h"
2075+#include "logger.h"
2076+#include "dbushelpers.h"
2077+
2078+namespace mcs {
2079+
2080+NetworkDeviceSkeleton::Ptr NetworkDeviceSkeleton::Create(const SharedGObject<GDBusConnection> &connection, const std::string &path, const NetworkDevice::Ptr &device, const MiracastController::Ptr &controller) {
2081+ return std::shared_ptr<NetworkDeviceSkeleton>(new NetworkDeviceSkeleton(connection, path, device, controller))->FinalizeConstruction();
2082+}
2083+
2084+NetworkDeviceSkeleton::NetworkDeviceSkeleton(const SharedGObject<GDBusConnection> &connection, const std::string &path, const NetworkDevice::Ptr &device, const MiracastController::Ptr &controller) :
2085+ ForwardingNetworkDevice(device),
2086+ connection_(connection),
2087+ object_(make_shared_gobject(aethercast_interface_object_skeleton_new(path.c_str()))),
2088+ path_(path),
2089+ controller_(controller),
2090+ device_iface_(aethercast_interface_device_skeleton_new()) {
2091+}
2092+
2093+std::shared_ptr<NetworkDeviceSkeleton> NetworkDeviceSkeleton::FinalizeConstruction() {
2094+ auto sp = shared_from_this();
2095+
2096+ g_signal_connect(device_iface_.get(), "handle-connect",
2097+ G_CALLBACK(&NetworkDeviceSkeleton::OnHandleConnect),
2098+ new WeakKeepAlive<NetworkDeviceSkeleton>{sp});
2099+ g_signal_connect(device_iface_.get(), "handle-disconnect",
2100+ G_CALLBACK(&NetworkDeviceSkeleton::OnHandleDisconnect),
2101+ new WeakKeepAlive<NetworkDeviceSkeleton>{sp});
2102+
2103+ SyncProperties();
2104+
2105+ if (!object_)
2106+ ERROR("Failed to create object for device %s", Address());
2107+ else
2108+ aethercast_interface_object_skeleton_set_device(object_.get(), device_iface_.get());
2109+
2110+ return sp;
2111+}
2112+
2113+void NetworkDeviceSkeleton::SyncProperties() {
2114+ aethercast_interface_device_set_address(device_iface_.get(), Address().c_str());
2115+ aethercast_interface_device_set_name(device_iface_.get(), Name().c_str());
2116+ aethercast_interface_device_set_state(device_iface_.get(), NetworkDevice::StateToStr(State()).c_str());
2117+
2118+ auto capabilities = DBusHelpers::GenerateDeviceCapabilities(SupportedRoles());
2119+ aethercast_interface_device_set_capabilities(device_iface_.get(), capabilities);
2120+ g_strfreev(capabilities);
2121+}
2122+
2123+GDBusObjectSkeleton* NetworkDeviceSkeleton::DBusObject() const {
2124+ return G_DBUS_OBJECT_SKELETON(object_.get());
2125+}
2126+
2127+std::string NetworkDeviceSkeleton::Path() const {
2128+ return path_;
2129+}
2130+
2131+// TODO(tvoss,morphis): Refactor mcs::NetworkDevice to have Connect/Disconnect defined on its interfaces.
2132+// It feels quite dirty to require both an instance of mcs::NetworkDevice and mcs::MiracastController to
2133+// implement the connect/disconnect calls coming in via the bus. The complication then is the async handling of
2134+// the invocation, as we will likely have to reach out to WPASupplicant for example (which is dispatched via the same
2135+// event loop as we are). In addition, we should not start littering our public interfaces by handing down callbacks.
2136+gboolean NetworkDeviceSkeleton::OnHandleConnect(AethercastInterfaceDevice *skeleton, GDBusMethodInvocation *invocation,
2137+ const gchar *role, gpointer user_data)
2138+{
2139+ boost::ignore_unused_variable_warning(skeleton);
2140+ boost::ignore_unused_variable_warning(role);
2141+
2142+ auto inst = static_cast<WeakKeepAlive<NetworkDeviceSkeleton>*>(user_data)->GetInstance().lock();
2143+
2144+ if (not inst) {
2145+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
2146+ return TRUE;
2147+ }
2148+
2149+ g_object_ref(invocation);
2150+ auto inv = make_shared_gobject(invocation);
2151+
2152+ inst->controller_->Connect(inst->Fwd(), [inv](mcs::Error error) {
2153+ if (error != Error::kNone) {
2154+ g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
2155+ "%s", mcs::ErrorToString(error).c_str());
2156+ return;
2157+ }
2158+
2159+ g_dbus_method_invocation_return_value(inv.get(), nullptr);
2160+ });
2161+
2162+ return TRUE;
2163+}
2164+
2165+gboolean NetworkDeviceSkeleton::OnHandleDisconnect(AethercastInterfaceDevice *skeleton, GDBusMethodInvocation *invocation,
2166+ gpointer user_data)
2167+{
2168+ boost::ignore_unused_variable_warning(skeleton);
2169+
2170+ auto inst = static_cast<WeakKeepAlive<NetworkDeviceSkeleton>*>(user_data)->GetInstance().lock();
2171+
2172+ if (not inst) {
2173+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
2174+ return TRUE;
2175+ }
2176+
2177+ g_object_ref(invocation);
2178+ auto inv = make_shared_gobject(invocation);
2179+
2180+ inst->controller_->Disconnect(inst->Fwd(), [inv](mcs::Error error) {
2181+ if (error != Error::kNone) {
2182+ g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
2183+ "%s", mcs::ErrorToString(error).c_str());
2184+ return;
2185+ }
2186+
2187+ g_dbus_method_invocation_return_value(inv.get(), nullptr);
2188+ });
2189+
2190+ return TRUE;
2191+}
2192+
2193+} // namespace mcs
2194
2195=== removed file 'src/mcs/networkdeviceskeleton.cpp'
2196--- src/mcs/networkdeviceskeleton.cpp 2015-12-21 15:20:11 +0000
2197+++ src/mcs/networkdeviceskeleton.cpp 1970-01-01 00:00:00 +0000
2198@@ -1,142 +0,0 @@
2199-/*
2200- * Copyright (C) 2015 Canonical, Ltd.
2201- *
2202- * This program is free software: you can redistribute it and/or modify it
2203- * under the terms of the GNU General Public License version 3, as published
2204- * by the Free Software Foundation.
2205- *
2206- * This program is distributed in the hope that it will be useful, but
2207- * WITHOUT ANY WARRANTY; without even the implied warranties of
2208- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2209- * PURPOSE. See the GNU General Public License for more details.
2210- *
2211- * You should have received a copy of the GNU General Public License along
2212- * with this program. If not, see <http://www.gnu.org/licenses/>.
2213- *
2214- */
2215-
2216-#include <algorithm>
2217-#include <boost/concept_check.hpp>
2218-
2219-#include "networkdeviceskeleton.h"
2220-#include "utils.h"
2221-#include "keep_alive.h"
2222-#include "logger.h"
2223-#include "dbushelpers.h"
2224-
2225-namespace mcs {
2226-
2227-NetworkDeviceSkeleton::Ptr NetworkDeviceSkeleton::Create(const SharedGObject<GDBusConnection> &connection, const std::string &path, const NetworkDevice::Ptr &device, const MiracastController::Ptr &controller) {
2228- return std::shared_ptr<NetworkDeviceSkeleton>(new NetworkDeviceSkeleton(connection, path, device, controller))->FinalizeConstruction();
2229-}
2230-
2231-NetworkDeviceSkeleton::NetworkDeviceSkeleton(const SharedGObject<GDBusConnection> &connection, const std::string &path, const NetworkDevice::Ptr &device, const MiracastController::Ptr &controller) :
2232- ForwardingNetworkDevice(device),
2233- connection_(connection),
2234- object_(make_shared_gobject(aethercast_interface_object_skeleton_new(path.c_str()))),
2235- path_(path),
2236- controller_(controller),
2237- device_iface_(aethercast_interface_device_skeleton_new()) {
2238-}
2239-
2240-std::shared_ptr<NetworkDeviceSkeleton> NetworkDeviceSkeleton::FinalizeConstruction() {
2241- auto sp = shared_from_this();
2242-
2243- g_signal_connect(device_iface_.get(), "handle-connect",
2244- G_CALLBACK(&NetworkDeviceSkeleton::OnHandleConnect),
2245- new WeakKeepAlive<NetworkDeviceSkeleton>{sp});
2246- g_signal_connect(device_iface_.get(), "handle-disconnect",
2247- G_CALLBACK(&NetworkDeviceSkeleton::OnHandleDisconnect),
2248- new WeakKeepAlive<NetworkDeviceSkeleton>{sp});
2249-
2250- SyncProperties();
2251-
2252- if (!object_)
2253- ERROR("Failed to create object for device %s", Address());
2254- else
2255- aethercast_interface_object_skeleton_set_device(object_.get(), device_iface_.get());
2256-
2257- return sp;
2258-}
2259-
2260-void NetworkDeviceSkeleton::SyncProperties() {
2261- aethercast_interface_device_set_address(device_iface_.get(), Address().c_str());
2262- aethercast_interface_device_set_name(device_iface_.get(), Name().c_str());
2263- aethercast_interface_device_set_state(device_iface_.get(), NetworkDevice::StateToStr(State()).c_str());
2264-
2265- auto capabilities = DBusHelpers::GenerateCapabilities(SupportedRoles());
2266- aethercast_interface_device_set_capabilities(device_iface_.get(), capabilities);
2267- g_strfreev(capabilities);
2268-}
2269-
2270-GDBusObjectSkeleton* NetworkDeviceSkeleton::DBusObject() const {
2271- return G_DBUS_OBJECT_SKELETON(object_.get());
2272-}
2273-
2274-std::string NetworkDeviceSkeleton::Path() const {
2275- return path_;
2276-}
2277-
2278-// TODO(tvoss,morphis): Refactor mcs::NetworkDevice to have Connect/Disconnect defined on its interfaces.
2279-// It feels quite dirty to require both an instance of mcs::NetworkDevice and mcs::MiracastController to
2280-// implement the connect/disconnect calls coming in via the bus. The complication then is the async handling of
2281-// the invocation, as we will likely have to reach out to WPASupplicant for example (which is dispatched via the same
2282-// event loop as we are). In addition, we should not start littering our public interfaces by handing down callbacks.
2283-gboolean NetworkDeviceSkeleton::OnHandleConnect(AethercastInterfaceDevice *skeleton, GDBusMethodInvocation *invocation,
2284- const gchar *role, gpointer user_data)
2285-{
2286- boost::ignore_unused_variable_warning(skeleton);
2287- boost::ignore_unused_variable_warning(role);
2288-
2289- auto inst = static_cast<WeakKeepAlive<NetworkDeviceSkeleton>*>(user_data)->GetInstance().lock();
2290-
2291- if (not inst) {
2292- g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
2293- return TRUE;
2294- }
2295-
2296- g_object_ref(invocation);
2297- auto inv = make_shared_gobject(invocation);
2298-
2299- inst->controller_->Connect(inst->Fwd(), [inv](mcs::Error error) {
2300- if (error != Error::kNone) {
2301- g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
2302- "%s", mcs::ErrorToString(error).c_str());
2303- return;
2304- }
2305-
2306- g_dbus_method_invocation_return_value(inv.get(), nullptr);
2307- });
2308-
2309- return TRUE;
2310-}
2311-
2312-gboolean NetworkDeviceSkeleton::OnHandleDisconnect(AethercastInterfaceDevice *skeleton, GDBusMethodInvocation *invocation,
2313- gpointer user_data)
2314-{
2315- boost::ignore_unused_variable_warning(skeleton);
2316-
2317- auto inst = static_cast<WeakKeepAlive<NetworkDeviceSkeleton>*>(user_data)->GetInstance().lock();
2318-
2319- if (not inst) {
2320- g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Invalid state");
2321- return TRUE;
2322- }
2323-
2324- g_object_ref(invocation);
2325- auto inv = make_shared_gobject(invocation);
2326-
2327- inst->controller_->Disconnect(inst->Fwd(), [inv](mcs::Error error) {
2328- if (error != Error::kNone) {
2329- g_dbus_method_invocation_return_error(inv.get(), G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
2330- "%s", mcs::ErrorToString(error).c_str());
2331- return;
2332- }
2333-
2334- g_dbus_method_invocation_return_value(inv.get(), nullptr);
2335- });
2336-
2337- return TRUE;
2338-}
2339-
2340-} // namespace mcs
2341
2342=== modified file 'src/mcs/networkmanager.cpp'
2343--- src/mcs/networkmanager.cpp 2015-11-26 16:27:30 +0000
2344+++ src/mcs/networkmanager.cpp 2016-01-27 13:00:21 +0000
2345@@ -16,3 +16,13 @@
2346 */
2347
2348 #include "networkmanager.h"
2349+
2350+namespace mcs {
2351+std::string NetworkManager::CapabilityToStr(Capability capability) {
2352+ if (capability == Capability::kSink)
2353+ return "sink";
2354+ else if (capability == Capability::kSource)
2355+ return "source";
2356+ return "";
2357+}
2358+} // namespace mcs
2359
2360=== modified file 'src/mcs/networkmanager.h'
2361--- src/mcs/networkmanager.h 2015-12-09 16:07:13 +0000
2362+++ src/mcs/networkmanager.h 2016-01-27 13:00:21 +0000
2363@@ -45,15 +45,25 @@
2364 Delegate() = default;
2365 };
2366
2367+ enum class Capability {
2368+ kSource,
2369+ kSink
2370+ };
2371+
2372+ static std::string CapabilityToStr(Capability capability);
2373+
2374 virtual void SetDelegate(Delegate * delegate) = 0;
2375
2376+ virtual void SetCapabilities(const std::vector<Capability> &capabilities) = 0;
2377+ virtual std::vector<Capability> Capabilities() const = 0;
2378+
2379 virtual bool Setup() = 0;
2380+ virtual void Release() = 0;
2381+
2382 virtual void Scan(const std::chrono::seconds &timeout) = 0;
2383 virtual bool Connect(const NetworkDevice::Ptr &device) = 0;
2384 virtual bool Disconnect(const NetworkDevice::Ptr &device) = 0;
2385
2386- virtual void SetWfdSubElements(const std::list<std::string> &elements) = 0;
2387-
2388 virtual std::vector<NetworkDevice::Ptr> Devices() const = 0;
2389 virtual IpV4Address LocalAddress() const = 0;
2390 virtual bool Running() const = 0;
2391
2392=== modified file 'src/mcs/networkmanagerfactory.cpp'
2393--- src/mcs/networkmanagerfactory.cpp 2015-12-18 17:15:31 +0000
2394+++ src/mcs/networkmanagerfactory.cpp 2016-01-27 13:00:21 +0000
2395@@ -17,18 +17,81 @@
2396
2397 #include <boost/concept_check.hpp>
2398
2399+#include <w11tng/networkmanager.h>
2400+
2401 #include "networkmanagerfactory.h"
2402
2403-#include <w11t/networkmanager.h>
2404+#include "logger.h"
2405+#include "utils.h"
2406
2407 namespace mcs {
2408
2409+void NullNetworkManager::SetDelegate(Delegate * delegate) {
2410+ ERROR("Not implemented");
2411+}
2412+
2413+bool NullNetworkManager::Setup() {
2414+ ERROR("Not implemented");
2415+ return false;
2416+}
2417+
2418+void NullNetworkManager::Release() {
2419+ ERROR("Not implemented");
2420+}
2421+
2422+void NullNetworkManager::Scan(const std::chrono::seconds &timeout) {
2423+ ERROR("Not implemented");
2424+}
2425+
2426+bool NullNetworkManager::Connect(const NetworkDevice::Ptr &device) {
2427+ ERROR("Not implemented");
2428+ return false;
2429+}
2430+
2431+bool NullNetworkManager::Disconnect(const NetworkDevice::Ptr &device) {
2432+ ERROR("Not implemented");
2433+ return false;
2434+}
2435+
2436+std::vector<NetworkDevice::Ptr> NullNetworkManager::Devices() const {
2437+ ERROR("Not implemented");
2438+ return std::vector<NetworkDevice::Ptr>();
2439+}
2440+
2441+IpV4Address NullNetworkManager::LocalAddress() const {
2442+ ERROR("Not implemented");
2443+ return IpV4Address();
2444+}
2445+
2446+bool NullNetworkManager::Running() const {
2447+ ERROR("Not implemented");
2448+ return false;
2449+}
2450+
2451+bool NullNetworkManager::Scanning() const {
2452+ ERROR("Not implemented");
2453+ return false;
2454+}
2455+
2456+void NullNetworkManager::SetCapabilities(const std::vector<Capability> &capabilities) {
2457+ ERROR("Not implemented");
2458+}
2459+
2460+std::vector<NetworkManager::Capability> NullNetworkManager::Capabilities() const {
2461+ return std::vector<NetworkManager::Capability>{};
2462+}
2463+
2464 NetworkManager::Ptr NetworkManagerFactory::Create(const std::string &type) {
2465- boost::ignore_unused_variable_warning(type);
2466-
2467- // FIXME for now we only can create the wpa one but this will be extended
2468- // with further types.
2469- return std::make_shared<w11t::NetworkManager>();
2470+ auto final_type = type.length() > 0 ? type : Utils::GetEnvValue("AETHERCAST_NETWORK_MANAGER");
2471+
2472+ DEBUG("Creating network manager of type %s", final_type.length() > 0 ? final_type : "w11tng");
2473+
2474+ // We will always default to the w11t implementation if no invalid
2475+ // type is specified.
2476+ if (final_type == "w11tng" || final_type.length() == 0)
2477+ return w11tng::NetworkManager::Create();
2478+
2479+ return std::make_shared<NullNetworkManager>();
2480 }
2481
2482 } // namespace mcs
2483
2484=== modified file 'src/mcs/networkmanagerfactory.h'
2485--- src/mcs/networkmanagerfactory.h 2015-12-09 16:07:13 +0000
2486+++ src/mcs/networkmanagerfactory.h 2016-01-27 13:00:21 +0000
2487@@ -22,6 +22,27 @@
2488
2489 namespace mcs {
2490
2491+// Only here to make unit testing easier for the factory class
2492+class NullNetworkManager : public mcs::NetworkManager {
2493+public:
2494+ void SetDelegate(Delegate * delegate) override;
2495+
2496+ bool Setup() override;
2497+ void Release() override;
2498+
2499+ void Scan(const std::chrono::seconds &timeout) override;
2500+ bool Connect(const NetworkDevice::Ptr &device) override;
2501+ bool Disconnect(const NetworkDevice::Ptr &device) override;
2502+
2503+ std::vector<NetworkDevice::Ptr> Devices() const override;
2504+ IpV4Address LocalAddress() const override;
2505+ bool Running() const override;
2506+ bool Scanning() const override;
2507+
2508+ void SetCapabilities(const std::vector<Capability> &capabilities) override;
2509+ std::vector<Capability> Capabilities() const override;
2510+};
2511+
2512 class NetworkManagerFactory {
2513 public:
2514 static NetworkManager::Ptr Create(const std::string &type = "");
2515
2516=== modified file 'src/mcs/networkutils.cpp'
2517--- src/mcs/networkutils.cpp 2015-12-07 16:02:43 +0000
2518+++ src/mcs/networkutils.cpp 2016-01-27 13:00:21 +0000
2519@@ -194,6 +194,27 @@
2520 return ifr.ifr_ifindex;;
2521 }
2522
2523+std::string NetworkUtils::RetrieveInterfaceName(int index) {
2524+ if (index < 0)
2525+ return "";
2526+
2527+ auto sock = ::socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
2528+ if (sock < 0)
2529+ return "";
2530+
2531+ struct ifreq ifr = { };
2532+ ifr.ifr_ifindex = index;
2533+
2534+ auto err = ::ioctl(sock, SIOCGIFNAME, &ifr);
2535+
2536+ ::close(sock);
2537+
2538+ if (err < 0)
2539+ return "";
2540+
2541+ return std::string(ifr.ifr_name);
2542+}
2543+
2544 int NetworkUtils::ResetInterface(int index)
2545 {
2546 struct ifreq ifr, addr_ifr;
2547
2548=== modified file 'src/mcs/networkutils.h'
2549--- src/mcs/networkutils.h 2015-11-26 16:48:53 +0000
2550+++ src/mcs/networkutils.h 2016-01-27 13:00:21 +0000
2551@@ -23,6 +23,7 @@
2552 {
2553 public:
2554 static int RetrieveInterfaceIndex(const char *name);
2555+ static std::string RetrieveInterfaceName(int index);
2556 static int ModifyInterfaceAddress(int cmd, int flags, int index, int family,
2557 const char *address, const char *peer,
2558 unsigned char prefixlen, const char *broadcast);
2559
2560=== modified file 'src/mcs/testsourcemediamanager.cpp'
2561--- src/mcs/testsourcemediamanager.cpp 2015-12-07 16:02:43 +0000
2562+++ src/mcs/testsourcemediamanager.cpp 2016-01-27 13:00:21 +0000
2563@@ -15,6 +15,8 @@
2564 *
2565 */
2566
2567+#include <sstream>
2568+
2569 #include <gst/gst.h>
2570
2571 #include "logger.h"
2572@@ -22,6 +24,8 @@
2573 #include "utils.h"
2574 #include "logging.h"
2575
2576+#include "videoformat.h"
2577+
2578 namespace mcs {
2579 std::shared_ptr<TestSourceMediaManager> TestSourceMediaManager::create(const std::string &remote_address) {
2580 return std::shared_ptr<TestSourceMediaManager>{new TestSourceMediaManager{remote_address}};
2581@@ -35,13 +39,34 @@
2582 }
2583
2584 SharedGObject<GstElement> TestSourceMediaManager::ConstructPipeline(const wds::H264VideoFormat &format) {
2585- auto config = Utils::Sprintf("videotestsrc ! videoconvert ! video/x-raw,format=I420 ! x264enc ! mpegtsmux ! rtpmp2tpay ! udpsink name=sink host=%s port=%d",
2586- remote_address_.c_str(), sink_port1_);
2587+ auto profile = mcs::video::ExtractH264Profile(format);
2588+ auto rr = mcs::video::ExtractRateAndResolution(format);
2589+
2590+#if 0
2591+ std::stringstream ss;
2592+ ss << Utils::Sprintf("videotestsrc ! video/x-raw,format=I420,framerate=%d/1,width=%d,height=%d,pixel-aspect-ratio=1/1 ! ", rr.framerate, rr.width, rr.height);
2593+ ss << "x264enc tune=zerolatency byte-stream=true ! ";
2594+ ss << Utils::Sprintf("video/x-h264,profile=%s ! ", profile.c_str());
2595+ ss << "mpegtsmux ! rtpmp2tpay ! ";
2596+ ss << Utils::Sprintf("udpsink name=sink host=%s port=%d", remote_address_.c_str(), sink_port1_);
2597+#else
2598+ std::stringstream ss;
2599+ ss << "ximagesrc ";
2600+ ss << Utils::Sprintf("videoconvert ! video/x-raw,format=I420,framerate=%d/1,pixel-aspect-ratio=1/1 ! ", rr.framerate);
2601+ ss << Utils::Sprintf("videoscale ! video/x-raw,width=%d,height=%d ! ", rr.width, rr.height);
2602+ ss << "queue2 ! ";
2603+ ss << "x264enc byte-stream=true tune=zerolatency interlaced=false ! ";
2604+ ss << Utils::Sprintf("video/x-h264,profile=%s !", profile.c_str());
2605+ ss << "mpegtsmux ! rtpmp2tpay ! ";
2606+ ss << Utils::Sprintf("udpsink name=sink host=%s port=%d", remote_address_.c_str(), sink_port1_);
2607+#endif
2608+
2609+ DEBUG("pipeline: %s", ss.str());
2610
2611 GError *error = nullptr;
2612- GstElement *pipeline = gst_parse_launch(config.c_str(), &error);
2613+ GstElement *pipeline = gst_parse_launch(ss.str().c_str(), &error);
2614 if (error) {
2615- WARNING("Failed to setup GStreamer pipeline: %s", error->message);
2616+ ERROR("Failed to setup GStreamer pipeline: %s", error->message);
2617 g_error_free(error);
2618 return nullptr;
2619 }
2620
2621=== modified file 'src/mcs/utils.cpp'
2622--- src/mcs/utils.cpp 2015-12-03 07:43:27 +0000
2623+++ src/mcs/utils.cpp 2016-01-27 13:00:21 +0000
2624@@ -15,9 +15,11 @@
2625 *
2626 */
2627
2628+#include <boost/filesystem.hpp>
2629 #include <boost/algorithm/string.hpp>
2630
2631 #include <memory>
2632+#include <fstream>
2633
2634 #include <cstring>
2635 #include <cstdarg>
2636@@ -46,4 +48,16 @@
2637 return std::string("");
2638 return std::string(value);
2639 }
2640+
2641+bool Utils::CreateFile(const std::string &file_path) {
2642+ boost::filesystem::path p(file_path);
2643+ if (boost::filesystem::exists(p))
2644+ return false;
2645+
2646+ std::ofstream of;
2647+ of.open(file_path, std::ofstream::out);
2648+ of << "";
2649+ of.close();
2650+ return true;
2651+}
2652 } // namespace mcs
2653
2654=== modified file 'src/mcs/utils.h'
2655--- src/mcs/utils.h 2015-12-03 07:43:27 +0000
2656+++ src/mcs/utils.h 2016-01-27 13:00:21 +0000
2657@@ -40,6 +40,14 @@
2658 static std::string Sprintf(const std::string& fmt_str, Types&&... args);
2659 // GetEnv - returns a variable value from the environment
2660 static std::string GetEnvValue(const std::string &name);
2661+ // CreateFile - create an empty file at the specified path
2662+ static bool CreateFile(const std::string &file_path);
2663+
2664+ // CreateScopedPtrWithDeleterFor - create a std::unique_ptr with a custom deleter
2665+ template <typename Owned, typename Deleter>
2666+ inline std::unique_ptr<Owned, Deleter> CreateScopedPtrWithDeleterFor(Owned* owned, Deleter&& deleter) {
2667+ return {owned, deleter};
2668+ }
2669 };
2670
2671 namespace impl {
2672
2673=== added file 'src/mcs/videoformat.cpp'
2674--- src/mcs/videoformat.cpp 1970-01-01 00:00:00 +0000
2675+++ src/mcs/videoformat.cpp 2016-01-27 13:00:21 +0000
2676@@ -0,0 +1,383 @@
2677+/*
2678+ * Copyright (C) 2016 Canonical, Ltd.
2679+ *
2680+ * This program is free software: you can redistribute it and/or modify it
2681+ * under the terms of the GNU General Public License version 3, as published
2682+ * by the Free Software Foundation.
2683+ *
2684+ * This program is distributed in the hope that it will be useful, but
2685+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2686+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2687+ * PURPOSE. See the GNU General Public License for more details.
2688+ *
2689+ * You should have received a copy of the GNU General Public License along
2690+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2691+ *
2692+ */
2693+
2694+#include "videoformat.h"
2695+#include "logger.h"
2696+
2697+namespace mcs {
2698+namespace video {
2699+
2700+std::string ResolutionTypeToString(wds::ResolutionType type) {
2701+ switch (type) {
2702+ case wds::CEA:
2703+ return "CEA";
2704+ case wds::VESA:
2705+ return "VESA";
2706+ case wds::HH:
2707+ return "HH";
2708+ default:
2709+ break;
2710+ }
2711+ return "unknown";
2712+}
2713+
2714+std::string CEARatesAndResolutionsToString(wds::CEARatesAndResolutions type) {
2715+ switch (type) {
2716+ case wds::CEA640x480p60:
2717+ return "640x480p60";
2718+ case wds::CEA720x480p60:
2719+ return "720x480p60";
2720+ case wds::CEA720x480i60:
2721+ return "720x480i60";
2722+ case wds::CEA720x576p50:
2723+ return "720x576p50";
2724+ case wds::CEA720x576i50:
2725+ return "720x576i50";
2726+ case wds::CEA1280x720p30:
2727+ return "1280x720p30";
2728+ case wds::CEA1280x720p60:
2729+ return "1280x720p60";
2730+ case wds::CEA1920x1080p30:
2731+ return "1920x1080p30";
2732+ case wds::CEA1920x1080p60:
2733+ return "1920x1080p60";
2734+ case wds::CEA1920x1080i60:
2735+ return "1920x1080i60";
2736+ case wds::CEA1280x720p25:
2737+ return "1280x720p25";
2738+ case wds::CEA1280x720p50:
2739+ return "1280x720p50";
2740+ case wds::CEA1920x1080p25:
2741+ return "1920x1080p25";
2742+ case wds::CEA1920x1080p50:
2743+ return "1920x1080p50";
2744+ case wds::CEA1920x1080i50:
2745+ return "1920x1080i50";
2746+ case wds::CEA1280x720p24:
2747+ return "1280x720p24";
2748+ case wds::CEA1920x1080p24:
2749+ return "1920x1080p24";
2750+ default:
2751+ break;
2752+ }
2753+ return "unknown";
2754+}
2755+
2756+std::string VESARatesAndResolutionsToString(wds::VESARatesAndResolutions type) {
2757+ switch (type) {
2758+ case wds::VESA800x600p30:
2759+ return "800x600p30";
2760+ case wds::VESA800x600p60:
2761+ return "800x600p60";
2762+ case wds::VESA1024x768p30:
2763+ return "1024x768p30";
2764+ case wds::VESA1024x768p60:
2765+ return "1024x768p60";
2766+ case wds::VESA1152x864p30:
2767+ return "1152x864p30";
2768+ case wds::VESA1152x864p60:
2769+ return "1152x864p60";
2770+ case wds::VESA1280x768p30:
2771+ return "1280x768p30";
2772+ case wds::VESA1280x768p60:
2773+ return "1280x768p60";
2774+ case wds::VESA1280x800p30:
2775+ return "1280x800p30";
2776+ case wds::VESA1280x800p60:
2777+ return "1280x800p60";
2778+ case wds::VESA1360x768p30:
2779+ return "1360x768p30";
2780+ case wds::VESA1360x768p60:
2781+ return "1360x768p60";
2782+ case wds::VESA1366x768p30:
2783+ return "1366x768p30";
2784+ case wds::VESA1366x768p60:
2785+ return "1366x768p60";
2786+ case wds::VESA1280x1024p30:
2787+ return "1280x1024p30";
2788+ case wds::VESA1280x1024p60:
2789+ return "1280x1024p60";
2790+ case wds::VESA1400x1050p30:
2791+ return "1400x1050p30";
2792+ case wds::VESA1400x1050p60:
2793+ return "1400x1050p60";
2794+ case wds::VESA1440x900p30:
2795+ return "1440x900p30";
2796+ case wds::VESA1440x900p60:
2797+ return "1440x900p60";
2798+ case wds::VESA1600x900p30:
2799+ return "1600x900p30";
2800+ case wds::VESA1600x900p60:
2801+ return "1600x900p60";
2802+ case wds::VESA1600x1200p30:
2803+ return "1600x1200p30";
2804+ case wds::VESA1600x1200p60:
2805+ return "1600x1200p60";
2806+ case wds::VESA1680x1024p30:
2807+ return "1680x1024p30";
2808+ case wds::VESA1680x1024p60:
2809+ return "1680x1024p60";
2810+ case wds::VESA1680x1050p30:
2811+ return "1680x1050p30";
2812+ case wds::VESA1680x1050p60:
2813+ return "1680x1050p60";
2814+ case wds::VESA1920x1200p30:
2815+ return "1920x1200p30";
2816+ default:
2817+ break;
2818+ }
2819+ return "unknown";
2820+}
2821+
2822+std::string HHRatesAndResolutionsToString(wds::HHRatesAndResolutions type) {
2823+ switch (type) {
2824+ case wds::HH800x480p30:
2825+ return "800x480p30";
2826+ case wds::HH800x480p60:
2827+ return "800x480p60";
2828+ case wds::HH854x480p30:
2829+ return "854x480p30";
2830+ case wds::HH854x480p60:
2831+ return "854x480p60";
2832+ case wds::HH864x480p30:
2833+ return "864x480p30";
2834+ case wds::HH864x480p60:
2835+ return "864x480p60";
2836+ case wds::HH640x360p30:
2837+ return "640x360p30";
2838+ case wds::HH640x360p60:
2839+ return "640x360p60";
2840+ case wds::HH960x540p30:
2841+ return "960x540p30";
2842+ case wds::HH960x540p60:
2843+ return "960x540p60";
2844+ case wds::HH848x480p30:
2845+ return "848x480p30";
2846+ case wds::HH848x480p60:
2847+ return "848x480p60";
2848+ default:
2849+ break;
2850+ }
2851+ return "unknown";
2852+}
2853+
2854+std::string LevelToString(wds::H264Level level) {
2855+ switch (level) {
2856+ case wds::k3_1:
2857+ return "3.1";
2858+ case wds::k3_2:
2859+ return "3.2";
2860+ case wds::k4:
2861+ return "4";
2862+ case wds::k4_1:
2863+ return "4.1";
2864+ case wds::k4_2:
2865+ return "4.2";
2866+ default:
2867+ break;
2868+ }
2869+ return "unknown";
2870+}
2871+
2872+std::string ProfileToString(wds::H264Profile profile) {
2873+ switch (profile) {
2874+ case wds::CBP:
2875+ return "cbp";
2876+ case wds::CHP:
2877+ return "chp";
2878+ default:
2879+ break;
2880+ }
2881+ return "unknown";
2882+}
2883+
2884+void DumpVideoCodec(const wds::H264VideoCodec &codec) {
2885+ int i = 0;
2886+
2887+ DEBUG(" profile: %s", ProfileToString(codec.profile));
2888+ DEBUG(" level: %s", LevelToString(codec.level));
2889+
2890+ DEBUG(" CEA resolutions: ");
2891+ for (i = wds::CEA640x480p60; i <= wds::CEA1920x1080p24; ++i)
2892+ if (codec.cea_rr.test(i))
2893+ DEBUG(" %s", CEARatesAndResolutionsToString((wds::CEARatesAndResolutions) i).c_str());
2894+
2895+ DEBUG(" VESA resolutions: ");
2896+ for (i = wds::VESA800x600p30; i <= wds::VESA1920x1200p30; ++i)
2897+ if (codec.vesa_rr.test(i))
2898+ DEBUG(" %s", VESARatesAndResolutionsToString((wds::VESARatesAndResolutions) i).c_str());
2899+
2900+ DEBUG(" HH resolutions: ");
2901+ for (i = wds::HH800x480p30; i <= wds::HH848x480p60; ++i)
2902+ if (codec.hh_rr.test(i))
2903+ DEBUG(" %s", HHRatesAndResolutionsToString((wds::HHRatesAndResolutions) i).c_str());
2904+}
2905+
2906+void DumpVideoFormat(const wds::H264VideoFormat &format) {
2907+ DEBUG(" profile: %s", ProfileToString(format.profile));
2908+ DEBUG(" level: %s", LevelToString(format.level));
2909+ DEBUG(" resolution type: %s", ResolutionTypeToString(format.type));
2910+
2911+ if (format.type == wds::CEA)
2912+ DEBUG("resolution: %s", CEARatesAndResolutionsToString((wds::CEARatesAndResolutions) format.rate_resolution));
2913+ if (format.type == wds::VESA)
2914+ DEBUG("resolution: %s", VESARatesAndResolutionsToString((wds::VESARatesAndResolutions) format.rate_resolution));
2915+ if (format.type == wds::HH)
2916+ DEBUG("resolution: %s", HHRatesAndResolutionsToString((wds::HHRatesAndResolutions) format.rate_resolution));
2917+}
2918+
2919+void DumpNativeFormat(const wds::NativeVideoFormat &format) {
2920+ DEBUG(" resolution type: %s", ResolutionTypeToString(format.type));
2921+
2922+ if (format.type == wds::CEA)
2923+ DEBUG("resolution: %s", CEARatesAndResolutionsToString((wds::CEARatesAndResolutions) format.rate_resolution));
2924+ if (format.type == wds::VESA)
2925+ DEBUG("resolution: %s", VESARatesAndResolutionsToString((wds::VESARatesAndResolutions) format.rate_resolution));
2926+ if (format.type == wds::HH)
2927+ DEBUG("resolution: %s", HHRatesAndResolutionsToString((wds::HHRatesAndResolutions) format.rate_resolution));
2928+}
2929+
2930+std::string ExtractH264Profile(const wds::H264VideoFormat &format) {
2931+ std::string profile;
2932+ switch (format.profile) {
2933+ case wds::CBP:
2934+ profile = "constrained-baseline";
2935+ break;
2936+ case wds::CHP:
2937+ profile = "high";
2938+ break;
2939+ default:
2940+ break;
2941+ }
2942+ return profile;
2943+}
2944+
2945+std::string ExtractH264Level(const wds::H264VideoFormat &format) {
2946+ std::string level;
2947+ switch (format.level) {
2948+ case wds::k3_1:
2949+ level = "3.1";
2950+ break;
2951+ case wds::k3_2:
2952+ level = "3.2";
2953+ break;
2954+ case wds::k4:
2955+ level = "4";
2956+ break;
2957+ case wds::k4_1:
2958+ level = "4.1";
2959+ break;
2960+ case wds::k4_2:
2961+ level = "4.2";
2962+ break;
2963+ default:
2964+ break;
2965+ }
2966+ return level;
2967+}
2968+
2969+RateAndResolution ExtractRateAndResolution(const wds::H264VideoFormat &format) {
2970+ RateAndResolution rr;
2971+ switch (format.type) {
2972+ case wds::CEA:
2973+ switch (format.rate_resolution) {
2974+ case wds::CEA640x480p60:
2975+ rr.width = 640;
2976+ rr.height = 480;
2977+ rr.framerate = 60;
2978+ break;
2979+ case wds::CEA720x480p60:
2980+ case wds::CEA720x480i60:
2981+ rr.width = 720;
2982+ rr.height = 480;
2983+ rr.framerate = 60;
2984+ break;
2985+ case wds::CEA720x576p50:
2986+ case wds::CEA720x576i50:
2987+ rr.width = 720;
2988+ rr.height = 576;
2989+ rr.framerate = 50;
2990+ break;
2991+ case wds::CEA1280x720p30:
2992+ rr.width = 1280;
2993+ rr.height = 720;
2994+ rr.framerate = 30;
2995+ break;
2996+ case wds::CEA1280x720p60:
2997+ rr.width = 1280;
2998+ rr.height = 720;
2999+ rr.framerate = 60;
3000+ break;
3001+ case wds::CEA1920x1080p30:
3002+ rr.width = 1920;
3003+ rr.height = 1080;
3004+ rr.framerate = 30;
3005+ break;
3006+ case wds::CEA1920x1080p60:
3007+ case wds::CEA1920x1080i60:
3008+ rr.width = 1920;
3009+ rr.height = 1080;
3010+ rr.framerate = 60;
3011+ break;
3012+ case wds::CEA1280x720p25:
3013+ rr.width = 1280;
3014+ rr.height = 720;
3015+ rr.framerate = 25;
3016+ break;
3017+ case wds::CEA1280x720p50:
3018+ rr.width = 1280;
3019+ rr.height = 720;
3020+ rr.framerate = 50;
3021+ break;
3022+ case wds::CEA1280x720p24:
3023+ rr.width = 1280;
3024+ rr.height = 720;
3025+ rr.framerate = 24;
3026+ break;
3027+ case wds::CEA1920x1080p25:
3028+ rr.width = 1920;
3029+ rr.height = 1080;
3030+ rr.framerate = 25;
3031+ break;
3032+ case wds::CEA1920x1080p50:
3033+ rr.width = 1920;
3034+ rr.height = 1080;
3035+ rr.framerate = 50;
3036+ break;
3037+ case wds::CEA1920x1080i50:
3038+ rr.width = 1920;
3039+ rr.height = 1080;
3040+ rr.framerate = 50;
3041+ break;
3042+ case wds::CEA1920x1080p24:
3043+ rr.width = 1920;
3044+ rr.height = 1080;
3045+ rr.framerate = 24;
3046+ break;
3047+ default:
3048+ break;
3049+ }
3050+ break;
3051+ // FIXME Add support for VESA and HH
3052+ default:
3053+ break;
3054+ }
3055+ return rr;
3056+}
3057+
3058+} // namespace video
3059+} // namespace mcs
3060
3061=== added file 'src/mcs/videoformat.h'
3062--- src/mcs/videoformat.h 1970-01-01 00:00:00 +0000
3063+++ src/mcs/videoformat.h 2016-01-27 13:00:21 +0000
3064@@ -0,0 +1,43 @@
3065+/*
3066+ * Copyright (C) 2016 Canonical, Ltd.
3067+ *
3068+ * This program is free software: you can redistribute it and/or modify it
3069+ * under the terms of the GNU General Public License version 3, as published
3070+ * by the Free Software Foundation.
3071+ *
3072+ * This program is distributed in the hope that it will be useful, but
3073+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3074+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3075+ * PURPOSE. See the GNU General Public License for more details.
3076+ *
3077+ * You should have received a copy of the GNU General Public License along
3078+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3079+ *
3080+ */
3081+
3082+#ifndef MCS_VIDEOFORMAT_H_
3083+#define MCS_VIDEOFORMAT_H_
3084+
3085+#include <wds/video_format.h>
3086+
3087+namespace mcs {
3088+namespace video {
3089+
3090+void DumpVideoCodec(const wds::H264VideoCodec &codec);
3091+void DumpVideoFormat(const wds::H264VideoFormat &format);
3092+void DumpNativeFormat(const wds::NativeVideoFormat &format);
3093+
3094+struct RateAndResolution {
3095+ unsigned int width;
3096+ unsigned int height;
3097+ unsigned int framerate;
3098+};
3099+
3100+RateAndResolution ExtractRateAndResolution(const wds::H264VideoFormat &format);
3101+std::string ExtractH264Profile(const wds::H264VideoFormat &format);
3102+std::string ExtractH264Level(const wds::H264VideoFormat &format);
3103+
3104+} // namespace video
3105+} // namespace mcs
3106+
3107+#endif
3108
3109=== added file 'src/mcs/x11sourcemediamanager.cpp'
3110--- src/mcs/x11sourcemediamanager.cpp 1970-01-01 00:00:00 +0000
3111+++ src/mcs/x11sourcemediamanager.cpp 2016-01-27 13:00:21 +0000
3112@@ -0,0 +1,51 @@
3113+/*
3114+ * Copyright (C) 2015 Canonical, Ltd.
3115+ *
3116+ * This program is free software: you can redistribute it and/or modify it
3117+ * under the terms of the GNU General Public License version 3, as published
3118+ * by the Free Software Foundation.
3119+ *
3120+ * This program is distributed in the hope that it will be useful, but
3121+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3122+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3123+ * PURPOSE. See the GNU General Public License for more details.
3124+ *
3125+ * You should have received a copy of the GNU General Public License along
3126+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3127+ *
3128+ */
3129+
3130+#include <gst/gst.h>
3131+
3132+#include "logger.h"
3133+#include "x11sourcemediamanager.h"
3134+#include "utils.h"
3135+#include "logging.h"
3136+
3137+namespace mcs {
3138+std::shared_ptr<X11SourceMediaManager> X11SourceMediaManager::create(const std::string &remote_address) {
3139+ return std::shared_ptr<X11SourceMediaManager>{new X11SourceMediaManager{remote_address}};
3140+}
3141+
3142+X11SourceMediaManager::X11SourceMediaManager(const std::string &remote_address) :
3143+ remote_address_(remote_address) {
3144+}
3145+
3146+X11SourceMediaManager::~X11SourceMediaManager() {
3147+}
3148+
3149+SharedGObject<GstElement> X11SourceMediaManager::ConstructPipeline(const wds::H264VideoFormat &format) {
3150+ auto config = Utils::Sprintf("ximagesrc ! videoconvert ! video/x-raw,format=I420 ! x264enc ! mpegtsmux ! rtpmp2tpay ! udpsink name=sink host=%s port=%d",
3151+ remote_address_.c_str(), sink_port1_);
3152+
3153+ GError *error = nullptr;
3154+ GstElement *pipeline = gst_parse_launch(config.c_str(), &error);
3155+ if (error) {
3156+ WARNING("Failed to setup GStreamer pipeline: %s", error->message);
3157+ g_error_free(error);
3158+ return nullptr;
3159+ }
3160+
3161+ return make_shared_gobject(pipeline);
3162+}
3163+} // namespace mcs
3164
3165=== added file 'src/mcs/x11sourcemediamanager.h'
3166--- src/mcs/x11sourcemediamanager.h 1970-01-01 00:00:00 +0000
3167+++ src/mcs/x11sourcemediamanager.h 2016-01-27 13:00:21 +0000
3168@@ -0,0 +1,38 @@
3169+/*
3170+ * Copyright (C) 2015 Canonical, Ltd.
3171+ *
3172+ * This program is free software: you can redistribute it and/or modify it
3173+ * under the terms of the GNU General Public License version 3, as published
3174+ * by the Free Software Foundation.
3175+ *
3176+ * This program is distributed in the hope that it will be useful, but
3177+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3178+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3179+ * PURPOSE. See the GNU General Public License for more details.
3180+ *
3181+ * You should have received a copy of the GNU General Public License along
3182+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3183+ *
3184+ */
3185+
3186+#ifndef X11SOURCEMEDIAMANAGER_H_
3187+#define X11SOURCEMEDIAMANAGER_H_
3188+
3189+#include "gstsourcemediamanager.h"
3190+
3191+namespace mcs {
3192+class X11SourceMediaManager : public GstSourceMediaManager {
3193+public:
3194+ static std::shared_ptr<X11SourceMediaManager> create(const std::string &remote_address);
3195+ ~X11SourceMediaManager();
3196+
3197+protected:
3198+ SharedGObject<GstElement> ConstructPipeline(const wds::H264VideoFormat &format) override;
3199+
3200+private:
3201+ explicit X11SourceMediaManager(const std::string &remote_address);
3202+ std::string remote_address_;
3203+};
3204+} // namespace mcs
3205+
3206+#endif
3207
3208=== added file 'src/mcs/x264.cpp'
3209--- src/mcs/x264.cpp 1970-01-01 00:00:00 +0000
3210+++ src/mcs/x264.cpp 2016-01-27 13:00:21 +0000
3211@@ -0,0 +1,206 @@
3212+/*
3213+ * Copyright (C) 2015 Canonical, Ltd.
3214+ *
3215+ * This program is free software: you can redistribute it and/or modify it
3216+ * under the terms of the GNU General Public License version 3, as published
3217+ * by the Free Software Foundation.
3218+ *
3219+ * This program is distributed in the hope that it will be useful, but
3220+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3221+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3222+ * PURPOSE. See the GNU General Public License for more details.
3223+ *
3224+ * You should have received a copy of the GNU General Public License along
3225+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3226+ *
3227+ */
3228+
3229+#include <atomic>
3230+
3231+#include "logger.h"
3232+#include "x264.h"
3233+
3234+namespace {
3235+
3236+static std::function<mcs::x264::Encoder::Ptr()>& MutableEncoderFactory() {
3237+ static std::function<mcs::x264::Encoder::Ptr()> factory = []() { return mcs::x264::Encoder::Ptr{}; };
3238+ return factory;
3239+}
3240+
3241+static const std::function<mcs::x264::Encoder::Ptr()>& EncoderFactory() {
3242+ return MutableEncoderFactory();
3243+}
3244+
3245+struct McsH264EncoderClass {
3246+ static GstStaticPadTemplate* SinkFactory() {
3247+ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE (
3248+ "sink",
3249+ GST_PAD_SINK,
3250+ GST_PAD_ALWAYS,
3251+ GST_STATIC_CAPS ("ANY"));
3252+ return &sink_factory;
3253+ }
3254+
3255+ static GstStaticPadTemplate* SrcFactory() {
3256+ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE (
3257+ "src",
3258+ GST_PAD_SRC,
3259+ GST_PAD_ALWAYS,
3260+ GST_STATIC_CAPS ("ANY"));
3261+
3262+ return &src_factory;
3263+ }
3264+
3265+ static void Init(McsH264EncoderClass *klass);
3266+
3267+ GstElementClass parent_class;
3268+};
3269+
3270+struct McsH264Encoder {
3271+ // Data ensures that we can 'new' the object, actually calling
3272+ // the ctors of contained objects (mcs::SharedGObject<T>).
3273+ struct Data {
3274+ mcs::SharedGObject<GstPad> sink;
3275+ mcs::SharedGObject<GstPad> source;
3276+ mcs::x264::GstEncoder::Ptr impl;
3277+ };
3278+
3279+ static GType Type();
3280+
3281+ static McsH264Encoder* CastInstanceFrom(GObject *obj) {
3282+ return G_TYPE_CHECK_INSTANCE_CAST(obj,McsH264Encoder::Type(),McsH264Encoder);
3283+ }
3284+
3285+ static McsH264EncoderClass* CastClassFrom(GObjectClass *klass) {
3286+ return G_TYPE_CHECK_CLASS_CAST((klass),McsH264Encoder::Type(),McsH264EncoderClass);
3287+ }
3288+
3289+ static bool IsInstanceOf(GObject *obj) {
3290+ return G_TYPE_CHECK_INSTANCE_TYPE((obj),McsH264Encoder::Type());
3291+ }
3292+
3293+ static bool IsClassOf(GObjectClass *klass) {
3294+ return G_TYPE_CHECK_CLASS_TYPE((klass),McsH264Encoder::Type());
3295+ }
3296+
3297+ static void Init(McsH264Encoder *self) {
3298+ MCS_TRACE("self %p", self);
3299+ self->d = new McsH264Encoder::Data{
3300+ mcs::make_shared_gobject(gst_pad_new_from_static_template (McsH264EncoderClass::SinkFactory(), "sink")),
3301+ mcs::make_shared_gobject(gst_pad_new_from_static_template (McsH264EncoderClass::SrcFactory(), "src")),
3302+ std::make_shared<mcs::x264::GstEncoder>(EncoderFactory()())
3303+ };
3304+
3305+ //gst_pad_set_event_function (filter->sinkpad, GST_DEBUG_FUNCPTR(gst_plugin_template_sink_event));
3306+ gst_pad_set_chain_function (self->d->sink.get(), McsH264Encoder::Chain);
3307+
3308+ gst_element_add_pad (GST_ELEMENT (self), self->d->sink.get());
3309+ gst_element_add_pad (GST_ELEMENT (self), self->d->source.get());
3310+ }
3311+
3312+ static void Finalize(GObject *obj) {
3313+ MCS_TRACE("obj %p", obj);
3314+ if (auto thiz = CastInstanceFrom(obj)) {
3315+ delete thiz->d;
3316+ }
3317+ }
3318+
3319+ static GstFlowReturn Chain(GstPad *pad, GstObject *parent, GstBuffer *buffer) {
3320+ MCS_TRACE("Chain(%p, %p, %p)", pad, parent, buffer);
3321+
3322+ struct Scope {
3323+ ~Scope() { if (buffer) gst_buffer_unref(buffer); }
3324+ GstBuffer *buffer;
3325+ } scope {buffer};
3326+
3327+ auto result = GST_FLOW_ERROR;
3328+
3329+ if (auto thiz = CastInstanceFrom(G_OBJECT(parent))) {
3330+ // TODO(tvoss): We should catch exceptions here, return
3331+ // appropriate error codes and signal errors to the gst bus.
3332+ result = gst_pad_push(thiz->d->source.get(), thiz->d->impl->Encode(buffer));
3333+ }
3334+
3335+ return result;
3336+ }
3337+
3338+ GstElement element;
3339+ Data *d;
3340+};
3341+
3342+#define GST_TYPE_MCS_H264_ENCODER() (gst_mcs_h264_encoder_get_type())
3343+#define GST_MCS_H264_ENCODER(obj) McsH264Encoder::CastInstanceFrom(obj)
3344+#define GST_MCS_H264_ENCODER_CLASS(klass) McsH264Encoder::CastClassFrom(klass)
3345+#define GST_IS_MCS_H264_ENCODER(obj) McsH264Encoder::IsInstanceOf(obj)
3346+#define GST_IS_MCS_H264_ENCODER_CLASS(klass) McsH264Encoder::IsClassOf(klass)
3347+
3348+GType mcs_h264_encoder_get_type (void);
3349+
3350+G_DEFINE_TYPE(McsH264Encoder, mcs_h264_encoder, GST_TYPE_ELEMENT)
3351+
3352+void McsH264EncoderClass::Init(McsH264EncoderClass *klass) {
3353+ MCS_TRACE("klass %p", klass);
3354+
3355+ auto gobject_class = reinterpret_cast<GObjectClass*>(klass);
3356+ auto gst_element_class = reinterpret_cast<GstElementClass*>(klass);
3357+
3358+ gobject_class->finalize = McsH264Encoder::Finalize;
3359+
3360+ gst_element_class_set_details_simple(gst_element_class, "ah264", "FIXME(classification)", "FIXME(description)", "Thomas Voß (thomas.voss@canonical.com)");
3361+ gst_element_class_add_pad_template(gst_element_class, gst_static_pad_template_get(McsH264EncoderClass::SinkFactory()));
3362+ gst_element_class_add_pad_template(gst_element_class, gst_static_pad_template_get(McsH264EncoderClass::SrcFactory()));
3363+}
3364+
3365+void mcs_h264_encoder_class_init(McsH264EncoderClass *klass) {
3366+ McsH264EncoderClass::Init(klass);
3367+}
3368+
3369+void mcs_h264_encoder_init(McsH264Encoder *self) {
3370+ McsH264Encoder::Init(self);
3371+}
3372+
3373+GType McsH264Encoder::Type() {
3374+ return mcs_h264_encoder_get_type();
3375+}
3376+
3377+gboolean InitPlugin(GstPlugin* plugin) {
3378+ return gst_element_register(plugin, "ah264", 0, McsH264Encoder::Type());
3379+}
3380+}
3381+
3382+namespace mcs {
3383+namespace x264 {
3384+
3385+bool GstEncoder::Plugin::RegisterWithEncoderFactory(const std::function<Encoder::Ptr()>& factory) {
3386+ static bool registered(false);
3387+ static std::atomic<bool> once(false);
3388+
3389+ if (once.exchange(true)) {
3390+ return registered;
3391+ }
3392+
3393+ MutableEncoderFactory() = factory;
3394+
3395+ const auto result = gst_plugin_register_static(
3396+ GST_VERSION_MAJOR,
3397+ GST_VERSION_MINOR,
3398+ mcs::x264::GstEncoder::Plugin::name,
3399+ mcs::x264::GstEncoder::Plugin::description,
3400+ InitPlugin,
3401+ mcs::x264::GstEncoder::Plugin::version,
3402+ mcs::x264::GstEncoder::Plugin::license,
3403+ mcs::x264::GstEncoder::Plugin::source,
3404+ mcs::x264::GstEncoder::Plugin::package,
3405+ mcs::x264::GstEncoder::Plugin::origin);
3406+
3407+ return registered = result == TRUE;
3408+}
3409+
3410+GstEncoder::GstEncoder(const Encoder::Ptr &encoder) : encoder_(encoder) {
3411+}
3412+
3413+GstBuffer* mcs::x264::GstEncoder::Encode(GstBuffer *buffer) {
3414+ return encoder_->Encode(buffer);
3415+}
3416+}
3417+}
3418
3419=== added file 'src/mcs/x264.h'
3420--- src/mcs/x264.h 1970-01-01 00:00:00 +0000
3421+++ src/mcs/x264.h 2016-01-27 13:00:21 +0000
3422@@ -0,0 +1,82 @@
3423+/*
3424+ * Copyright (C) 2015 Canonical, Ltd.
3425+ *
3426+ * This program is free software: you can redistribute it and/or modify it
3427+ * under the terms of the GNU General Public License version 3, as published
3428+ * by the Free Software Foundation.
3429+ *
3430+ * This program is distributed in the hope that it will be useful, but
3431+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3432+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3433+ * PURPOSE. See the GNU General Public License for more details.
3434+ *
3435+ * You should have received a copy of the GNU General Public License along
3436+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3437+ *
3438+ */
3439+
3440+#ifndef GSTH264HWENCODER_H_
3441+#define GSTH264HWENCODER_H_
3442+
3443+#include <cstdint>
3444+#include <memory>
3445+
3446+#include <gst/gst.h>
3447+
3448+#include "non_copyable.h"
3449+#include "shared_gobject.h"
3450+
3451+namespace mcs {
3452+namespace x264 {
3453+// An Encoder abstracts encoding of MirNativeBuffer
3454+class Encoder : public mcs::NonCopyable {
3455+public:
3456+ typedef std::shared_ptr<Encoder> Ptr;
3457+
3458+ // Encode takes the nativeBuffer and encodes it, returning
3459+ // a Frame instance describing the raw memory segment containing
3460+ // the encoded frame.
3461+ virtual GstBuffer*Encode(GstBuffer *) = 0;
3462+
3463+protected:
3464+ Encoder() = default;
3465+};
3466+
3467+// A GstEncoder exposes an h264::Encoder to the gstreamer world,
3468+// implemenating an element, that encodes incoming GstBuffer instances.
3469+class GstEncoder {
3470+public:
3471+ typedef std::shared_ptr<GstEncoder> Ptr;
3472+
3473+ struct Plugin {
3474+ static bool RegisterWithEncoderFactory(const std::function<Encoder::Ptr()> &factory);
3475+
3476+ static constexpr const char *name = "mcs::h264::Encoder";
3477+ static constexpr const char *description = "h264 encoder leveraging hw-accelerated codecs provided by Android";
3478+ static constexpr const char *version = "0.0";
3479+ static constexpr const char *license = "LGPL";
3480+ static constexpr const char *source = "aethercast";
3481+ static constexpr const char *package = "aethercast";
3482+ static constexpr const char *origin = "https://launchpad.net/aethercast";
3483+ };
3484+
3485+ // GstEncoder creates a new instance, leveraging encoder for carrying out the actual
3486+ // encoding.
3487+ GstEncoder(const Encoder::Ptr &encoder);
3488+
3489+ // SinkPad returns the GstPad describing the sink pad of the element.
3490+ SharedGObject<GstPad*> SinkPad() const;
3491+ // SourcePad returns the GstPad describing the source pad of the element.
3492+ SharedGObject<GstPad*> SourcePad() const;
3493+
3494+ // Encode extracts a MirNativeBuffer from the given GstBuffer and hands it on
3495+ // to the actual Encoder instance.
3496+ GstBuffer* Encode(GstBuffer *buffer);
3497+
3498+private:
3499+ Encoder::Ptr encoder_;
3500+};
3501+}
3502+}
3503+
3504+#endif
3505
3506=== removed directory 'src/w11t'
3507=== removed file 'src/w11t/commandqueue.cpp'
3508--- src/w11t/commandqueue.cpp 2015-12-18 17:15:31 +0000
3509+++ src/w11t/commandqueue.cpp 1970-01-01 00:00:00 +0000
3510@@ -1,103 +0,0 @@
3511-/*
3512- * Copyright (C) 2015 Canonical, Ltd.
3513- *
3514- * This program is free software: you can redistribute it and/or modify it
3515- * under the terms of the GNU General Public License version 3, as published
3516- * by the Free Software Foundation.
3517- *
3518- * This program is distributed in the hope that it will be useful, but
3519- * WITHOUT ANY WARRANTY; without even the implied warranties of
3520- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3521- * PURPOSE. See the GNU General Public License for more details.
3522- *
3523- * You should have received a copy of the GNU General Public License along
3524- * with this program. If not, see <http://www.gnu.org/licenses/>.
3525- *
3526- */
3527-
3528-#include <glib.h>
3529-
3530-#include "commandqueue.h"
3531-
3532-namespace w11t {
3533-CommandQueue::CommandQueue(Delegate *delegate) :
3534- delegate_(delegate),
3535- current_(nullptr),
3536- idle_source_(0) {
3537-}
3538-
3539-CommandQueue::~CommandQueue() {
3540- if (idle_source_ > 0)
3541- g_source_remove(idle_source_);
3542-}
3543-
3544-void CommandQueue::EnqueueCommand(const Message &message, Command::ResponseCallback callback) {
3545- queue_.push(new Command(message, callback));
3546- RestartQueue();
3547-}
3548-
3549-void CommandQueue::HandleMessage(Message message) {
3550- if (message.ItsType() == Message::Type::kInvalid)
3551- return;
3552-
3553- if (message.ItsType() == Message::Type::kEvent) {
3554- if (delegate_)
3555- delegate_->OnUnsolicitedResponse(message);
3556- return;
3557- }
3558-
3559- if (!current_)
3560- return;
3561-
3562- if (current_->callback)
3563- current_->callback(message);
3564-
3565- delete current_;
3566- // This will unblock the queue and will allow us to send the next command
3567- current_ = nullptr;
3568-
3569- RestartQueue();
3570-}
3571-
3572-gboolean CommandQueue::OnRestartQueue(gpointer user_data) {
3573- auto inst = static_cast<CommandQueue*>(user_data);
3574- inst->idle_source_ = 0;
3575- inst->CheckRestartingQueue();
3576- return FALSE;
3577-}
3578-
3579-void CommandQueue::RestartQueue() {
3580- if (idle_source_ > 0)
3581- return;
3582-
3583- idle_source_ = g_idle_add(&CommandQueue::OnRestartQueue, this);
3584-}
3585-
3586-void CommandQueue::CheckRestartingQueue() {
3587- if (current_ != nullptr || queue_.size() == 0)
3588- return;
3589-
3590- WriteNextCommand();
3591- RestartQueue();
3592-}
3593-
3594-void CommandQueue::WriteNextCommand() {
3595- current_ = queue_.front();
3596- queue_.pop();
3597-
3598- if (!delegate_)
3599- return;
3600-
3601- if (!current_)
3602- return;
3603-
3604- current_->message.Seal();
3605-
3606- delegate_->OnWriteMessage(current_->message);
3607-
3608- if (!current_->callback) {
3609- delete current_;
3610- current_ = nullptr;
3611- }
3612-}
3613-}
3614
3615=== removed file 'src/w11t/commandqueue.h'
3616--- src/w11t/commandqueue.h 2015-12-18 17:15:31 +0000
3617+++ src/w11t/commandqueue.h 1970-01-01 00:00:00 +0000
3618@@ -1,63 +0,0 @@
3619-/*
3620- * Copyright (C) 2015 Canonical, Ltd.
3621- *
3622- * This program is free software: you can redistribute it and/or modify it
3623- * under the terms of the GNU General Public License version 3, as published
3624- * by the Free Software Foundation.
3625- *
3626- * This program is distributed in the hope that it will be useful, but
3627- * WITHOUT ANY WARRANTY; without even the implied warranties of
3628- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3629- * PURPOSE. See the GNU General Public License for more details.
3630- *
3631- * You should have received a copy of the GNU General Public License along
3632- * with this program. If not, see <http://www.gnu.org/licenses/>.
3633- *
3634- */
3635-
3636-#ifndef WPASUPPLICANTCOMMANDQUEUE_H_
3637-#define WPASUPPLICANTCOMMANDQUEUE_H_
3638-
3639-#include <boost/noncopyable.hpp>
3640-
3641-#include <string>
3642-#include <queue>
3643-
3644-#include <mcs/non_copyable.h>
3645-
3646-#include "command.h"
3647-
3648-namespace w11t {
3649-class CommandQueue {
3650-public:
3651- class Delegate : private mcs::NonCopyable {
3652- public:
3653- virtual void OnUnsolicitedResponse(Message message) = 0;
3654- virtual void OnWriteMessage(Message message) = 0;
3655-
3656- protected:
3657- Delegate() = default;
3658- };
3659-
3660- CommandQueue(Delegate *delegate);
3661- ~CommandQueue();
3662-
3663- void EnqueueCommand(const Message &message, Command::ResponseCallback callback = nullptr);
3664- void HandleMessage(Message message);
3665-
3666-private:
3667- void RestartQueue();
3668- void CheckRestartingQueue();
3669- void WriteNextCommand();
3670-
3671-private:
3672- static gboolean OnRestartQueue(gpointer user_data);
3673-
3674-private:
3675- Delegate *delegate_;
3676- Command *current_;
3677- std::queue<Command*> queue_;
3678- unsigned int idle_source_;
3679-};
3680-}
3681-#endif
3682
3683=== removed file 'src/w11t/dhcpclient.cpp'
3684--- src/w11t/dhcpclient.cpp 2015-12-18 17:15:31 +0000
3685+++ src/w11t/dhcpclient.cpp 1970-01-01 00:00:00 +0000
3686@@ -1,102 +0,0 @@
3687-/*
3688- * Copyright (C) 2015 Canonical, Ltd.
3689- *
3690- * This program is free software: you can redistribute it and/or modify it
3691- * under the terms of the GNU General Public License version 3, as published
3692- * by the Free Software Foundation.
3693- *
3694- * This program is distributed in the hope that it will be useful, but
3695- * WITHOUT ANY WARRANTY; without even the implied warranties of
3696- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3697- * PURPOSE. See the GNU General Public License for more details.
3698- *
3699- * You should have received a copy of the GNU General Public License along
3700- * with this program. If not, see <http://www.gnu.org/licenses/>.
3701- *
3702- */
3703-
3704-#include <asm/types.h>
3705-#include <linux/netlink.h>
3706-#include <linux/rtnetlink.h>
3707-#include <sys/socket.h>
3708-
3709-#include <mcs/logger.h>
3710-#include <mcs/networkutils.h>
3711-
3712-#include "dhcpclient.h"
3713-#include "gdhcp.h"
3714-
3715-namespace w11t {
3716-DhcpClient::DhcpClient(Delegate *delegate, const std::string &interface_name) :
3717- delegate_(delegate),
3718- interface_name_(interface_name) {
3719- interface_index_ = mcs::NetworkUtils::RetrieveInterfaceIndex(interface_name_.c_str());
3720- if (interface_index_ < 0)
3721- MCS_WARNING("Failed to determine index of network interface %s", interface_name_.c_str());
3722-}
3723-
3724-DhcpClient::~DhcpClient() {
3725-}
3726-
3727-void DhcpClient::OnLeaseAvailable(GDHCPClient *client, gpointer user_data) {
3728- auto inst = static_cast<DhcpClient*>(user_data);
3729-
3730- char *address = g_dhcp_client_get_address(inst->client_);
3731- char *netmask = g_dhcp_client_get_netmask(inst->client_);
3732-
3733- if (!address) {
3734- MCS_WARNING("Received invalid IP configuration over DHCP");
3735- return;
3736- }
3737-
3738- if (mcs::NetworkUtils::ModifyInterfaceAddress(RTM_NEWADDR, NLM_F_REPLACE | NLM_F_ACK, inst->interface_index_,
3739- AF_INET, address,
3740- NULL, 24, NULL) < 0) {
3741- MCS_WARNING("Failed to assign network address for %s", inst->interface_name_.c_str());
3742- return;
3743- }
3744-
3745- inst->local_address_ = mcs::IpV4Address::from_string(address);
3746-
3747- if (netmask)
3748- inst->netmask_.assign(netmask);
3749-
3750- inst->delegate_->OnAddressAssigned(inst->local_address_);
3751-}
3752-
3753-void DhcpClient::OnClientDebug(const char *str, gpointer user_data) {
3754- MCS_DEBUG("DHCP: %s", str);
3755-}
3756-
3757-mcs::IpV4Address DhcpClient::LocalAddress() const {
3758- return local_address_;
3759-}
3760-
3761-bool DhcpClient::Start() {
3762- GDHCPClientError error;
3763- client_ = g_dhcp_client_new(G_DHCP_IPV4, interface_index_, &error);
3764- if (!client_) {
3765- MCS_ERROR("Failed to setup DHCP client: %s", g_dhcp_client_error_to_string(error));
3766- return false;
3767- }
3768-
3769- g_dhcp_client_set_debug(client_, &DhcpClient::OnClientDebug, this);
3770- g_dhcp_client_register_event(client_, G_DHCP_CLIENT_EVENT_LEASE_AVAILABLE, &DhcpClient::OnLeaseAvailable, this);
3771- g_dhcp_client_start(client_, NULL);
3772-
3773- return true;
3774-}
3775-
3776-void DhcpClient::Stop() {
3777- if (!client_)
3778- return;
3779-
3780- g_dhcp_client_stop(client_);
3781- g_dhcp_client_unref(client_);
3782-
3783- local_address_ = mcs::IpV4Address{};
3784- netmask_ = "";
3785-
3786- mcs::NetworkUtils::ResetInterface(interface_index_);
3787-}
3788-}
3789
3790=== removed file 'src/w11t/dhcpserver.cpp'
3791--- src/w11t/dhcpserver.cpp 2015-12-18 17:15:31 +0000
3792+++ src/w11t/dhcpserver.cpp 1970-01-01 00:00:00 +0000
3793@@ -1,99 +0,0 @@
3794-/*
3795- * Copyright (C) 2015 Canonical, Ltd.
3796- *
3797- * This program is free software: you can redistribute it and/or modify it
3798- * under the terms of the GNU General Public License version 3, as published
3799- * by the Free Software Foundation.
3800- *
3801- * This program is distributed in the hope that it will be useful, but
3802- * WITHOUT ANY WARRANTY; without even the implied warranties of
3803- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3804- * PURPOSE. See the GNU General Public License for more details.
3805- *
3806- * You should have received a copy of the GNU General Public License along
3807- * with this program. If not, see <http://www.gnu.org/licenses/>.
3808- *
3809- */
3810-
3811-#include <asm/types.h>
3812-#include <linux/netlink.h>
3813-#include <linux/rtnetlink.h>
3814-#include <sys/socket.h>
3815-
3816-#include <mcs/logger.h>
3817-#include <mcs/networkutils.h>
3818-
3819-#include "dhcpserver.h"
3820-
3821-namespace w11t {
3822-DhcpServer::DhcpServer(Delegate *delegate, const std::string &interface_name) :
3823- interface_name_(interface_name) {
3824- interface_index_ = mcs::NetworkUtils::RetrieveInterfaceIndex(interface_name_.c_str());
3825- if (interface_index_ < 0)
3826- MCS_ERROR("Failed to determine index of network interface: %s", interface_name_);
3827-}
3828-
3829-DhcpServer::~DhcpServer() {
3830- if (server_)
3831- g_dhcp_server_unref(server_);
3832-}
3833-
3834-mcs::IpV4Address DhcpServer::LocalAddress() const {
3835- // FIXME this should be stored somewhere else
3836- return mcs::IpV4Address::from_string("192.168.7.1");
3837-}
3838-
3839-void DhcpServer::OnDebug(const char *str, gpointer user_data) {
3840- MCS_DEBUG("DHCP: %s", str);
3841-}
3842-
3843-bool DhcpServer::Start() {
3844- MCS_DEBUG("Starting up DHCP server");
3845-
3846- // FIXME store those defaults somewhere else
3847- const char *address = "192.168.7.1";
3848- const char *subnet = "255.255.255.0";
3849- const char *broadcast = "192.168.7.255";
3850- unsigned char prefixlen = 24;
3851-
3852- if (mcs::NetworkUtils::ModifyInterfaceAddress(RTM_NEWADDR, NLM_F_REPLACE | NLM_F_ACK, interface_index_,
3853- AF_INET, address,
3854- NULL, prefixlen, broadcast) < 0) {
3855- MCS_ERROR("Failed to assign network address for %s", interface_name_);
3856- return false;
3857- }
3858-
3859- GDHCPServerError error;
3860- server_ = g_dhcp_server_new(G_DHCP_IPV4, interface_index_, &error);
3861- if (!server_) {
3862- MCS_ERROR("Failed to setup DHCP server: %s", g_dhcp_server_error_to_string(error));
3863- return false;
3864- }
3865-
3866- g_dhcp_server_set_lease_time(server_, 3600);
3867- g_dhcp_server_set_option(server_, G_DHCP_SUBNET, subnet);
3868- g_dhcp_server_set_option(server_, G_DHCP_ROUTER, LocalAddress().to_string().c_str());
3869- g_dhcp_server_set_option(server_, G_DHCP_DNS_SERVER, NULL);
3870- g_dhcp_server_set_ip_range(server_, "192.168.7.5", "192.168.7.100");
3871-
3872- g_dhcp_server_set_debug(server_, &DhcpServer::OnDebug, this);
3873-
3874- if(g_dhcp_server_start(server_) < 0) {
3875- MCS_ERROR("Failed to start DHCP server");
3876- g_dhcp_server_unref(server_);
3877- return false;
3878- }
3879-
3880- return true;
3881-}
3882-
3883-void DhcpServer::Stop() {
3884- if (!server_)
3885- return;
3886-
3887- g_dhcp_server_stop(server_);
3888- g_dhcp_server_unref(server_);
3889-
3890- mcs::NetworkUtils::ResetInterface(interface_index_);
3891-}
3892-}
3893
3894=== removed directory 'src/w11t/gdhcp'
3895=== removed file 'src/w11t/gdhcp/client.c'
3896--- src/w11t/gdhcp/client.c 2015-12-09 16:07:13 +0000
3897+++ src/w11t/gdhcp/client.c 1970-01-01 00:00:00 +0000
3898@@ -1,3282 +0,0 @@
3899-/*
3900- *
3901- * DHCP client library with GLib integration
3902- *
3903- * Copyright (C) 2009-2014 Intel Corporation. All rights reserved.
3904- *
3905- * This program is free software; you can redistribute it and/or modify
3906- * it under the terms of the GNU General Public License version 2 as
3907- * published by the Free Software Foundation.
3908- *
3909- * This program is distributed in the hope that it will be useful,
3910- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3911- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3912- * GNU General Public License for more details.
3913- *
3914- * You should have received a copy of the GNU General Public License
3915- * along with this program; if not, write to the Free Software
3916- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
3917- *
3918- */
3919-
3920-#ifdef HAVE_CONFIG_H
3921-#include <config.h>
3922-#endif
3923-
3924-#define _GNU_SOURCE
3925-#include <stdio.h>
3926-#include <errno.h>
3927-#include <unistd.h>
3928-#include <stdlib.h>
3929-#include <string.h>
3930-#include <sys/ioctl.h>
3931-#include <arpa/inet.h>
3932-#include <sys/time.h>
3933-#include <resolv.h>
3934-
3935-#include <netpacket/packet.h>
3936-#include <netinet/if_ether.h>
3937-#include <net/ethernet.h>
3938-
3939-#include <linux/if.h>
3940-#include <linux/filter.h>
3941-
3942-#include <glib.h>
3943-
3944-#include "gdhcp.h"
3945-#include "common.h"
3946-#include "ipv4ll.h"
3947-
3948-#define DISCOVER_TIMEOUT 5
3949-#define DISCOVER_RETRIES 6
3950-
3951-#define REQUEST_TIMEOUT 5
3952-#define REQUEST_RETRIES 3
3953-
3954-typedef enum _listen_mode {
3955- L_NONE,
3956- L2,
3957- L3,
3958- L_ARP,
3959-} ListenMode;
3960-
3961-typedef enum _dhcp_client_state {
3962- INIT_SELECTING,
3963- REBOOTING,
3964- REQUESTING,
3965- BOUND,
3966- RENEWING,
3967- REBINDING,
3968- RELEASED,
3969- IPV4LL_PROBE,
3970- IPV4LL_ANNOUNCE,
3971- IPV4LL_MONITOR,
3972- IPV4LL_DEFEND,
3973- INFORMATION_REQ,
3974- SOLICITATION,
3975- REQUEST,
3976- CONFIRM,
3977- RENEW,
3978- REBIND,
3979- RELEASE,
3980- DECLINE,
3981-} ClientState;
3982-
3983-struct _GDHCPClient {
3984- int ref_count;
3985- GDHCPType type;
3986- ClientState state;
3987- int ifindex;
3988- char *interface;
3989- uint8_t mac_address[6];
3990- uint32_t xid;
3991- uint32_t server_ip;
3992- uint32_t requested_ip;
3993- char *assigned_ip;
3994- time_t start;
3995- uint32_t lease_seconds;
3996- ListenMode listen_mode;
3997- int listener_sockfd;
3998- uint8_t retry_times;
3999- uint8_t ack_retry_times;
4000- uint8_t conflicts;
4001- guint timeout;
4002- guint t1_timeout;
4003- guint t2_timeout;
4004- guint lease_timeout;
4005- guint listener_watch;
4006- GList *require_list;
4007- GList *request_list;
4008- GHashTable *code_value_hash;
4009- GHashTable *send_value_hash;
4010- GDHCPClientEventFunc lease_available_cb;
4011- gpointer lease_available_data;
4012- GDHCPClientEventFunc ipv4ll_available_cb;
4013- gpointer ipv4ll_available_data;
4014- GDHCPClientEventFunc no_lease_cb;
4015- gpointer no_lease_data;
4016- GDHCPClientEventFunc lease_lost_cb;
4017- gpointer lease_lost_data;
4018- GDHCPClientEventFunc ipv4ll_lost_cb;
4019- gpointer ipv4ll_lost_data;
4020- GDHCPClientEventFunc address_conflict_cb;
4021- gpointer address_conflict_data;
4022- GDHCPDebugFunc debug_func;
4023- gpointer debug_data;
4024- GDHCPClientEventFunc information_req_cb;
4025- gpointer information_req_data;
4026- GDHCPClientEventFunc solicitation_cb;
4027- gpointer solicitation_data;
4028- GDHCPClientEventFunc advertise_cb;
4029- gpointer advertise_data;
4030- GDHCPClientEventFunc request_cb;
4031- gpointer request_data;
4032- GDHCPClientEventFunc renew_cb;
4033- gpointer renew_data;
4034- GDHCPClientEventFunc rebind_cb;
4035- gpointer rebind_data;
4036- GDHCPClientEventFunc release_cb;
4037- gpointer release_data;
4038- GDHCPClientEventFunc confirm_cb;
4039- gpointer confirm_data;
4040- GDHCPClientEventFunc decline_cb;
4041- gpointer decline_data;
4042- char *last_address;
4043- unsigned char *duid;
4044- int duid_len;
4045- unsigned char *server_duid;
4046- int server_duid_len;
4047- uint16_t status_code;
4048- uint32_t iaid;
4049- uint32_t T1, T2;
4050- struct in6_addr ia_na;
4051- struct in6_addr ia_ta;
4052- time_t last_request;
4053- uint32_t expire;
4054- bool retransmit;
4055- struct timeval start_time;
4056- bool request_bcast;
4057-};
4058-
4059-const char *g_dhcp_client_error_to_string(GDHCPClientError error) {
4060- switch (error) {
4061- case G_DHCP_CLIENT_ERROR_NONE:
4062- return "None";
4063- case G_DHCP_CLIENT_ERROR_INTERFACE_UNAVAILABLE:
4064- return "Interface unavailable";
4065- case G_DHCP_CLIENT_ERROR_INTERFACE_IN_USE:
4066- return "Interface in use";
4067- case G_DHCP_CLIENT_ERROR_INTERFACE_DOWN:
4068- return "Interface down";
4069- case G_DHCP_CLIENT_ERROR_NOMEM:
4070- return "No memory";
4071- case G_DHCP_CLIENT_ERROR_INVALID_INDEX:
4072- return "Invalid index";
4073- case G_DHCP_CLIENT_ERROR_INVALID_OPTION:
4074- return "Invalid option";
4075- default:
4076- break;
4077- }
4078-
4079- return "";
4080-}
4081-
4082-static inline void debug(GDHCPClient *client, const char *format, ...)
4083-{
4084- char str[256];
4085- va_list ap;
4086-
4087- if (!client->debug_func)
4088- return;
4089-
4090- va_start(ap, format);
4091-
4092- if (vsnprintf(str, sizeof(str), format, ap) > 0)
4093- client->debug_func(str, client->debug_data);
4094-
4095- va_end(ap);
4096-}
4097-
4098-/* Initialize the packet with the proper defaults */
4099-static void init_packet(GDHCPClient *dhcp_client, gpointer pkt, char type)
4100-{
4101- if (dhcp_client->type == G_DHCP_IPV6)
4102- dhcpv6_init_header(pkt, type);
4103- else {
4104- struct dhcp_packet *packet = pkt;
4105-
4106- dhcp_init_header(packet, type);
4107- memcpy(packet->chaddr, dhcp_client->mac_address, 6);
4108- }
4109-}
4110-
4111-static void add_request_options(GDHCPClient *dhcp_client,
4112- struct dhcp_packet *packet)
4113-{
4114- int len = 0;
4115- GList *list;
4116- uint8_t code;
4117- int end = dhcp_end_option(packet->options);
4118-
4119- for (list = dhcp_client->request_list; list; list = list->next) {
4120- code = (uint8_t) GPOINTER_TO_INT(list->data);
4121-
4122- packet->options[end + OPT_DATA + len] = code;
4123- len++;
4124- }
4125-
4126- if (len) {
4127- packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
4128- packet->options[end + OPT_LEN] = len;
4129- packet->options[end + OPT_DATA + len] = DHCP_END;
4130- }
4131-}
4132-
4133-struct hash_params {
4134- unsigned char *buf;
4135- int max_buf;
4136- unsigned char **ptr_buf;
4137-};
4138-
4139-static void add_dhcpv6_binary_option(gpointer key, gpointer value,
4140- gpointer user_data)
4141-{
4142- uint8_t *option = value;
4143- uint16_t len;
4144- struct hash_params *params = user_data;
4145-
4146- /* option[0][1] contains option code */
4147- len = option[2] << 8 | option[3];
4148-
4149- if ((*params->ptr_buf + len + 2 + 2) > (params->buf + params->max_buf))
4150- return;
4151-
4152- memcpy(*params->ptr_buf, option, len + 2 + 2);
4153- (*params->ptr_buf) += len + 2 + 2;
4154-}
4155-
4156-static void add_dhcpv6_send_options(GDHCPClient *dhcp_client,
4157- unsigned char *buf, int max_buf,
4158- unsigned char **ptr_buf)
4159-{
4160- struct hash_params params = {
4161- .buf = buf,
4162- .max_buf = max_buf,
4163- .ptr_buf = ptr_buf
4164- };
4165-
4166- if (dhcp_client->type != G_DHCP_IPV6)
4167- return;
4168-
4169- g_hash_table_foreach(dhcp_client->send_value_hash,
4170- add_dhcpv6_binary_option, &params);
4171-
4172- *ptr_buf = *params.ptr_buf;
4173-}
4174-
4175-static void copy_option(uint8_t *buf, uint16_t code, uint16_t len,
4176- uint8_t *msg)
4177-{
4178- buf[0] = code >> 8;
4179- buf[1] = code & 0xff;
4180- buf[2] = len >> 8;
4181- buf[3] = len & 0xff;
4182- if (len > 0 && msg)
4183- memcpy(&buf[4], msg, len);
4184-}
4185-
4186-static int32_t get_time_diff(struct timeval *tv)
4187-{
4188- struct timeval now;
4189- int32_t hsec;
4190-
4191- gettimeofday(&now, NULL);
4192-
4193- hsec = (now.tv_sec - tv->tv_sec) * 100;
4194- hsec += (now.tv_usec - tv->tv_usec) / 10000;
4195-
4196- return hsec;
4197-}
4198-
4199-static void remove_timeouts(GDHCPClient *dhcp_client)
4200-{
4201-
4202- if (dhcp_client->timeout > 0)
4203- g_source_remove(dhcp_client->timeout);
4204- if (dhcp_client->t1_timeout > 0)
4205- g_source_remove(dhcp_client->t1_timeout);
4206- if (dhcp_client->t2_timeout > 0)
4207- g_source_remove(dhcp_client->t2_timeout);
4208- if (dhcp_client->lease_timeout > 0)
4209- g_source_remove(dhcp_client->lease_timeout);
4210-
4211- dhcp_client->timeout = 0;
4212- dhcp_client->t1_timeout = 0;
4213- dhcp_client->t2_timeout = 0;
4214- dhcp_client->lease_timeout = 0;
4215-
4216-}
4217-
4218-static void add_dhcpv6_request_options(GDHCPClient *dhcp_client,
4219- struct dhcpv6_packet *packet,
4220- unsigned char *buf, int max_buf,
4221- unsigned char **ptr_buf)
4222-{
4223- GList *list;
4224- uint16_t code, value;
4225- bool added;
4226- int32_t diff;
4227- int len;
4228-
4229- if (dhcp_client->type != G_DHCP_IPV6)
4230- return;
4231-
4232- for (list = dhcp_client->request_list; list; list = list->next) {
4233- code = (uint16_t) GPOINTER_TO_INT(list->data);
4234- added = false;
4235-
4236- switch (code) {
4237- case G_DHCPV6_CLIENTID:
4238- if (!dhcp_client->duid)
4239- return;
4240-
4241- len = 2 + 2 + dhcp_client->duid_len;
4242- if ((*ptr_buf + len) > (buf + max_buf)) {
4243- debug(dhcp_client, "Too long dhcpv6 message "
4244- "when writing client id option");
4245- return;
4246- }
4247-
4248- copy_option(*ptr_buf, G_DHCPV6_CLIENTID,
4249- dhcp_client->duid_len, dhcp_client->duid);
4250- (*ptr_buf) += len;
4251- added = true;
4252- break;
4253-
4254- case G_DHCPV6_SERVERID:
4255- if (!dhcp_client->server_duid)
4256- break;
4257-
4258- len = 2 + 2 + dhcp_client->server_duid_len;
4259- if ((*ptr_buf + len) > (buf + max_buf)) {
4260- debug(dhcp_client, "Too long dhcpv6 message "
4261- "when writing server id option");
4262- return;
4263- }
4264-
4265- copy_option(*ptr_buf, G_DHCPV6_SERVERID,
4266- dhcp_client->server_duid_len,
4267- dhcp_client->server_duid);
4268- (*ptr_buf) += len;
4269- added = true;
4270- break;
4271-
4272- case G_DHCPV6_RAPID_COMMIT:
4273- len = 2 + 2;
4274- if ((*ptr_buf + len) > (buf + max_buf)) {
4275- debug(dhcp_client, "Too long dhcpv6 message "
4276- "when writing rapid commit option");
4277- return;
4278- }
4279-
4280- copy_option(*ptr_buf, G_DHCPV6_RAPID_COMMIT, 0, 0);
4281- (*ptr_buf) += len;
4282- added = true;
4283- break;
4284-
4285- case G_DHCPV6_ORO:
4286- break;
4287-
4288- case G_DHCPV6_ELAPSED_TIME:
4289- if (!dhcp_client->retransmit) {
4290- /*
4291- * Initial message, elapsed time is 0.
4292- */
4293- diff = 0;
4294- } else {
4295- diff = get_time_diff(&dhcp_client->start_time);
4296- if (diff < 0 || diff > 0xffff)
4297- diff = 0xffff;
4298- }
4299-
4300- len = 2 + 2 + 2;
4301- if ((*ptr_buf + len) > (buf + max_buf)) {
4302- debug(dhcp_client, "Too long dhcpv6 message "
4303- "when writing elapsed time option");
4304- return;
4305- }
4306-
4307- value = htons((uint16_t)diff);
4308- copy_option(*ptr_buf, G_DHCPV6_ELAPSED_TIME,
4309- 2, (uint8_t *)&value);
4310- (*ptr_buf) += len;
4311- added = true;
4312- break;
4313-
4314- case G_DHCPV6_DNS_SERVERS:
4315- break;
4316-
4317- case G_DHCPV6_DOMAIN_LIST:
4318- break;
4319-
4320- case G_DHCPV6_SNTP_SERVERS:
4321- break;
4322-
4323- default:
4324- break;
4325- }
4326-
4327- if (added)
4328- debug(dhcp_client, "option %d len %d added", code, len);
4329- }
4330-}
4331-
4332-static void add_binary_option(gpointer key, gpointer value, gpointer user_data)
4333-{
4334- uint8_t *option = value;
4335- struct dhcp_packet *packet = user_data;
4336-
4337- dhcp_add_binary_option(packet, option);
4338-}
4339-
4340-static void add_send_options(GDHCPClient *dhcp_client,
4341- struct dhcp_packet *packet)
4342-{
4343- g_hash_table_foreach(dhcp_client->send_value_hash,
4344- add_binary_option, packet);
4345-}
4346-
4347-/*
4348- * Return an RFC 951- and 2131-complaint BOOTP 'secs' value that
4349- * represents the number of seconds elapsed from the start of
4350- * attempting DHCP to satisfy some DHCP servers that allow for an
4351- * "authoritative" reply before responding.
4352- */
4353-static uint16_t dhcp_attempt_secs(GDHCPClient *dhcp_client)
4354-{
4355- return htons(MIN(time(NULL) - dhcp_client->start, UINT16_MAX));
4356-}
4357-
4358-static int send_discover(GDHCPClient *dhcp_client, uint32_t requested)
4359-{
4360- struct dhcp_packet packet;
4361-
4362- debug(dhcp_client, "sending DHCP discover request");
4363-
4364- init_packet(dhcp_client, &packet, DHCPDISCOVER);
4365-
4366- packet.xid = dhcp_client->xid;
4367- packet.secs = dhcp_attempt_secs(dhcp_client);
4368-
4369- if (requested)
4370- dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP, requested);
4371-
4372- /* Explicitly saying that we want RFC-compliant packets helps
4373- * some buggy DHCP servers to NOT send bigger packets */
4374- dhcp_add_option_uint16(&packet, DHCP_MAX_SIZE, 576);
4375-
4376- add_request_options(dhcp_client, &packet);
4377-
4378- add_send_options(dhcp_client, &packet);
4379-
4380- /*
4381- * If we do not get a reply to DISCOVER packet, then we try with
4382- * broadcast flag set. So first packet is sent without broadcast flag,
4383- * first retry is with broadcast flag, second retry is without it etc.
4384- * Reason is various buggy routers/AP that either eat the other or vice
4385- * versa. In the receiving side we then find out what kind of packet
4386- * the server can send.
4387- */
4388- return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
4389- INADDR_BROADCAST, SERVER_PORT,
4390- MAC_BCAST_ADDR, dhcp_client->ifindex,
4391- dhcp_client->retry_times % 2);
4392-}
4393-
4394-static int send_request(GDHCPClient *dhcp_client)
4395-{
4396- struct dhcp_packet packet;
4397-
4398- debug(dhcp_client, "sending DHCP request (state %d)",
4399- dhcp_client->state);
4400-
4401- init_packet(dhcp_client, &packet, DHCPREQUEST);
4402-
4403- packet.xid = dhcp_client->xid;
4404- packet.secs = dhcp_attempt_secs(dhcp_client);
4405-
4406- if (dhcp_client->state == REQUESTING || dhcp_client->state == REBOOTING)
4407- dhcp_add_option_uint32(&packet, DHCP_REQUESTED_IP,
4408- dhcp_client->requested_ip);
4409-
4410- if (dhcp_client->state == REQUESTING)
4411- dhcp_add_option_uint32(&packet, DHCP_SERVER_ID,
4412- dhcp_client->server_ip);
4413-
4414- dhcp_add_option_uint16(&packet, DHCP_MAX_SIZE, 576);
4415-
4416- add_request_options(dhcp_client, &packet);
4417-
4418- add_send_options(dhcp_client, &packet);
4419-
4420- if (dhcp_client->state == RENEWING || dhcp_client->state == REBINDING)
4421- packet.ciaddr = htonl(dhcp_client->requested_ip);
4422-
4423- if (dhcp_client->state == RENEWING)
4424- return dhcp_send_kernel_packet(&packet,
4425- dhcp_client->requested_ip, CLIENT_PORT,
4426- dhcp_client->server_ip, SERVER_PORT);
4427-
4428- return dhcp_send_raw_packet(&packet, INADDR_ANY, CLIENT_PORT,
4429- INADDR_BROADCAST, SERVER_PORT,
4430- MAC_BCAST_ADDR, dhcp_client->ifindex,
4431- dhcp_client->request_bcast);
4432-}
4433-
4434-static int send_release(GDHCPClient *dhcp_client,
4435- uint32_t server, uint32_t ciaddr)
4436-{
4437- struct dhcp_packet packet;
4438- uint64_t rand;
4439-
4440- debug(dhcp_client, "sending DHCP release request");
4441-
4442- init_packet(dhcp_client, &packet, DHCPRELEASE);
4443- dhcp_get_random(&rand);
4444- packet.xid = rand;
4445- packet.ciaddr = htonl(ciaddr);
4446-
4447- dhcp_add_option_uint32(&packet, DHCP_SERVER_ID, server);
4448-
4449- return dhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT,
4450- server, SERVER_PORT);
4451-}
4452-
4453-static gboolean ipv4ll_probe_timeout(gpointer dhcp_data);
4454-static int switch_listening_mode(GDHCPClient *dhcp_client,
4455- ListenMode listen_mode);
4456-
4457-static gboolean send_probe_packet(gpointer dhcp_data)
4458-{
4459- GDHCPClient *dhcp_client;
4460- guint timeout;
4461-
4462- dhcp_client = dhcp_data;
4463- /* if requested_ip is not valid, pick a new address*/
4464- if (dhcp_client->requested_ip == 0) {
4465- debug(dhcp_client, "pick a new random address");
4466- dhcp_client->requested_ip = ipv4ll_random_ip();
4467- }
4468-
4469- debug(dhcp_client, "sending IPV4LL probe request");
4470-
4471- if (dhcp_client->retry_times == 1) {
4472- dhcp_client->state = IPV4LL_PROBE;
4473- switch_listening_mode(dhcp_client, L_ARP);
4474- }
4475- ipv4ll_send_arp_packet(dhcp_client->mac_address, 0,
4476- dhcp_client->requested_ip, dhcp_client->ifindex);
4477-
4478- if (dhcp_client->retry_times < PROBE_NUM) {
4479- /*add a random timeout in range of PROBE_MIN to PROBE_MAX*/
4480- timeout = ipv4ll_random_delay_ms(PROBE_MAX-PROBE_MIN);
4481- timeout += PROBE_MIN*1000;
4482- } else
4483- timeout = (ANNOUNCE_WAIT * 1000);
4484-
4485- dhcp_client->timeout = g_timeout_add_full(G_PRIORITY_HIGH,
4486- timeout,
4487- ipv4ll_probe_timeout,
4488- dhcp_client,
4489- NULL);
4490- return FALSE;
4491-}
4492-
4493-static gboolean ipv4ll_announce_timeout(gpointer dhcp_data);
4494-static gboolean ipv4ll_defend_timeout(gpointer dhcp_data);
4495-
4496-static gboolean send_announce_packet(gpointer dhcp_data)
4497-{
4498- GDHCPClient *dhcp_client;
4499-
4500- dhcp_client = dhcp_data;
4501-
4502- debug(dhcp_client, "sending IPV4LL announce request");
4503-
4504- ipv4ll_send_arp_packet(dhcp_client->mac_address,
4505- dhcp_client->requested_ip,
4506- dhcp_client->requested_ip,
4507- dhcp_client->ifindex);
4508-
4509- remove_timeouts(dhcp_client);
4510-
4511- if (dhcp_client->state == IPV4LL_DEFEND) {
4512- dhcp_client->timeout =
4513- g_timeout_add_seconds_full(G_PRIORITY_HIGH,
4514- DEFEND_INTERVAL,
4515- ipv4ll_defend_timeout,
4516- dhcp_client,
4517- NULL);
4518- return TRUE;
4519- } else
4520- dhcp_client->timeout =
4521- g_timeout_add_seconds_full(G_PRIORITY_HIGH,
4522- ANNOUNCE_INTERVAL,
4523- ipv4ll_announce_timeout,
4524- dhcp_client,
4525- NULL);
4526- return TRUE;
4527-}
4528-
4529-static void get_interface_mac_address(int index, uint8_t *mac_address)
4530-{
4531- struct ifreq ifr;
4532- int sk, err;
4533-
4534- sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
4535- if (sk < 0) {
4536- perror("Open socket error");
4537- return;
4538- }
4539-
4540- memset(&ifr, 0, sizeof(ifr));
4541- ifr.ifr_ifindex = index;
4542-
4543- err = ioctl(sk, SIOCGIFNAME, &ifr);
4544- if (err < 0) {
4545- perror("Get interface name error");
4546- goto done;
4547- }
4548-
4549- err = ioctl(sk, SIOCGIFHWADDR, &ifr);
4550- if (err < 0) {
4551- perror("Get mac address error");
4552- goto done;
4553- }
4554-
4555- memcpy(mac_address, ifr.ifr_hwaddr.sa_data, 6);
4556-
4557-done:
4558- close(sk);
4559-}
4560-
4561-void g_dhcpv6_client_set_retransmit(GDHCPClient *dhcp_client)
4562-{
4563- if (!dhcp_client)
4564- return;
4565-
4566- dhcp_client->retransmit = true;
4567-}
4568-
4569-void g_dhcpv6_client_clear_retransmit(GDHCPClient *dhcp_client)
4570-{
4571- if (!dhcp_client)
4572- return;
4573-
4574- dhcp_client->retransmit = false;
4575-}
4576-
4577-int g_dhcpv6_create_duid(GDHCPDuidType duid_type, int index, int type,
4578- unsigned char **duid, int *duid_len)
4579-{
4580- time_t duid_time;
4581-
4582- switch (duid_type) {
4583- case G_DHCPV6_DUID_LLT:
4584- *duid_len = 2 + 2 + 4 + ETH_ALEN;
4585- *duid = g_try_malloc(*duid_len);
4586- if (!*duid)
4587- return -ENOMEM;
4588-
4589- (*duid)[0] = 0;
4590- (*duid)[1] = 1;
4591- get_interface_mac_address(index, &(*duid)[2 + 2 + 4]);
4592- (*duid)[2] = 0;
4593- (*duid)[3] = type;
4594- duid_time = time(NULL) - DUID_TIME_EPOCH;
4595- (*duid)[4] = duid_time >> 24;
4596- (*duid)[5] = duid_time >> 16;
4597- (*duid)[6] = duid_time >> 8;
4598- (*duid)[7] = duid_time & 0xff;
4599- break;
4600- case G_DHCPV6_DUID_EN:
4601- return -EINVAL;
4602- case G_DHCPV6_DUID_LL:
4603- *duid_len = 2 + 2 + ETH_ALEN;
4604- *duid = g_try_malloc(*duid_len);
4605- if (!*duid)
4606- return -ENOMEM;
4607-
4608- (*duid)[0] = 0;
4609- (*duid)[1] = 3;
4610- get_interface_mac_address(index, &(*duid)[2 + 2]);
4611- (*duid)[2] = 0;
4612- (*duid)[3] = type;
4613- break;
4614- }
4615-
4616- return 0;
4617-}
4618-
4619-static gchar *convert_to_hex(unsigned char *buf, int len)
4620-{
4621- gchar *ret = g_try_malloc(len * 2 + 1);
4622- int i;
4623-
4624- for (i = 0; ret && i < len; i++)
4625- g_snprintf(ret + i * 2, 3, "%02x", buf[i]);
4626-
4627- return ret;
4628-}
4629-
4630-int g_dhcpv6_client_set_duid(GDHCPClient *dhcp_client, unsigned char *duid,
4631- int duid_len)
4632-{
4633- if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6)
4634- return -EINVAL;
4635-
4636- g_free(dhcp_client->duid);
4637-
4638- dhcp_client->duid = duid;
4639- dhcp_client->duid_len = duid_len;
4640-
4641- if (dhcp_client->debug_func) {
4642- gchar *hex = convert_to_hex(duid, duid_len);
4643- debug(dhcp_client, "DUID(%d) %s", duid_len, hex);
4644- g_free(hex);
4645- }
4646-
4647- return 0;
4648-}
4649-
4650-int g_dhcpv6_client_set_pd(GDHCPClient *dhcp_client, uint32_t *T1,
4651- uint32_t *T2, GSList *prefixes)
4652-{
4653- uint8_t options[1452];
4654- unsigned int max_buf = sizeof(options);
4655- int len, count = g_slist_length(prefixes);
4656-
4657- if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6)
4658- return -EINVAL;
4659-
4660- g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_PD);
4661-
4662- memset(options, 0, sizeof(options));
4663-
4664- options[0] = dhcp_client->iaid >> 24;
4665- options[1] = dhcp_client->iaid >> 16;
4666- options[2] = dhcp_client->iaid >> 8;
4667- options[3] = dhcp_client->iaid;
4668-
4669- if (T1) {
4670- uint32_t t = htonl(*T1);
4671- memcpy(&options[4], &t, 4);
4672- }
4673-
4674- if (T2) {
4675- uint32_t t = htonl(*T2);
4676- memcpy(&options[8], &t, 4);
4677- }
4678-
4679- len = 12;
4680-
4681- if (count > 0) {
4682- GSList *list;
4683-
4684- for (list = prefixes; list; list = list->next) {
4685- GDHCPIAPrefix *prefix = list->data;
4686- uint8_t sub_option[4+4+1+16];
4687-
4688- if ((len + 2 + 2 + sizeof(sub_option)) >= max_buf) {
4689- debug(dhcp_client,
4690- "Too long dhcpv6 message "
4691- "when writing IA prefix option");
4692- return -EINVAL;
4693- }
4694-
4695- memset(&sub_option, 0, sizeof(sub_option));
4696-
4697- /* preferred and validity time are left zero */
4698-
4699- sub_option[8] = prefix->prefixlen;
4700- memcpy(&sub_option[9], &prefix->prefix, 16);
4701-
4702- copy_option(&options[len], G_DHCPV6_IA_PREFIX,
4703- sizeof(sub_option), sub_option);
4704- len += 2 + 2 + sizeof(sub_option);
4705- }
4706- }
4707-
4708- g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_PD,
4709- options, len);
4710-
4711- return 0;
4712-}
4713-
4714-uint32_t g_dhcpv6_client_get_iaid(GDHCPClient *dhcp_client)
4715-{
4716- if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6)
4717- return 0;
4718-
4719- return dhcp_client->iaid;
4720-}
4721-
4722-void g_dhcpv6_client_set_iaid(GDHCPClient *dhcp_client, uint32_t iaid)
4723-{
4724- if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6)
4725- return;
4726-
4727- dhcp_client->iaid = iaid;
4728-}
4729-
4730-void g_dhcpv6_client_create_iaid(GDHCPClient *dhcp_client, int index,
4731- unsigned char *iaid)
4732-{
4733- uint8_t buf[6] = { };
4734-
4735- get_interface_mac_address(index, buf);
4736-
4737- memcpy(iaid, &buf[2], 4);
4738- dhcp_client->iaid = iaid[0] << 24 |
4739- iaid[1] << 16 | iaid[2] << 8 | iaid[3];
4740-}
4741-
4742-int g_dhcpv6_client_get_timeouts(GDHCPClient *dhcp_client,
4743- uint32_t *T1, uint32_t *T2,
4744- time_t *started,
4745- time_t *expire)
4746-{
4747- if (!dhcp_client || dhcp_client->type != G_DHCP_IPV6)
4748- return -EINVAL;
4749-
4750- if (T1)
4751- *T1 = dhcp_client->T1;
4752-
4753- if (T2)
4754- *T2 = dhcp_client->T2;
4755-
4756- if (started)
4757- *started = dhcp_client->last_request;
4758-
4759- if (expire)
4760- *expire = dhcp_client->last_request + dhcp_client->expire;
4761-
4762- return 0;
4763-}
4764-
4765-static uint8_t *create_iaaddr(GDHCPClient *dhcp_client, uint8_t *buf,
4766- uint16_t len)
4767-{
4768- buf[0] = 0;
4769- buf[1] = G_DHCPV6_IAADDR;
4770- buf[2] = 0;
4771- buf[3] = len;
4772- memcpy(&buf[4], &dhcp_client->ia_na, 16);
4773- memset(&buf[20], 0, 4); /* preferred */
4774- memset(&buf[24], 0, 4); /* valid */
4775- return buf;
4776-}
4777-
4778-static uint8_t *append_iaaddr(GDHCPClient *dhcp_client, uint8_t *buf,
4779- const char *address)
4780-{
4781- struct in6_addr addr;
4782-
4783- if (inet_pton(AF_INET6, address, &addr) != 1)
4784- return NULL;
4785-
4786- buf[0] = 0;
4787- buf[1] = G_DHCPV6_IAADDR;
4788- buf[2] = 0;
4789- buf[3] = 24;
4790- memcpy(&buf[4], &addr, 16);
4791- memset(&buf[20], 0, 4); /* preferred */
4792- memset(&buf[24], 0, 4); /* valid */
4793- return &buf[28];
4794-}
4795-
4796-static void put_iaid(GDHCPClient *dhcp_client, int index, uint8_t *buf)
4797-{
4798- uint32_t iaid;
4799-
4800- iaid = g_dhcpv6_client_get_iaid(dhcp_client);
4801- if (iaid == 0) {
4802- g_dhcpv6_client_create_iaid(dhcp_client, index, buf);
4803- return;
4804- }
4805-
4806- buf[0] = iaid >> 24;
4807- buf[1] = iaid >> 16;
4808- buf[2] = iaid >> 8;
4809- buf[3] = iaid;
4810-}
4811-
4812-int g_dhcpv6_client_set_ia(GDHCPClient *dhcp_client, int index,
4813- int code, uint32_t *T1, uint32_t *T2,
4814- bool add_iaaddr, const char *ia_na)
4815-{
4816- if (code == G_DHCPV6_IA_TA) {
4817- uint8_t ia_options[4];
4818-
4819- put_iaid(dhcp_client, index, ia_options);
4820-
4821- g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_TA);
4822- g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_TA,
4823- ia_options, sizeof(ia_options));
4824-
4825- } else if (code == G_DHCPV6_IA_NA) {
4826- struct in6_addr addr;
4827-
4828- g_dhcp_client_set_request(dhcp_client, G_DHCPV6_IA_NA);
4829-
4830- /*
4831- * If caller has specified the IPv6 address it wishes to
4832- * to use (ia_na != NULL and address is valid), then send
4833- * the address to server.
4834- * If caller did not specify the address (ia_na == NULL) and
4835- * if the current address is not set, then we should not send
4836- * the address sub-option.
4837- */
4838- if (add_iaaddr && ((!ia_na &&
4839- !IN6_IS_ADDR_UNSPECIFIED(&dhcp_client->ia_na))
4840- || (ia_na &&
4841- inet_pton(AF_INET6, ia_na, &addr) == 1))) {
4842-#define IAADDR_LEN (16+4+4)
4843- uint8_t ia_options[4+4+4+2+2+IAADDR_LEN];
4844-
4845- if (ia_na)
4846- memcpy(&dhcp_client->ia_na, &addr,
4847- sizeof(struct in6_addr));
4848-
4849- put_iaid(dhcp_client, index, ia_options);
4850-
4851- if (T1) {
4852- ia_options[4] = *T1 >> 24;
4853- ia_options[5] = *T1 >> 16;
4854- ia_options[6] = *T1 >> 8;
4855- ia_options[7] = *T1;
4856- } else
4857- memset(&ia_options[4], 0x00, 4);
4858-
4859- if (T2) {
4860- ia_options[8] = *T2 >> 24;
4861- ia_options[9] = *T2 >> 16;
4862- ia_options[10] = *T2 >> 8;
4863- ia_options[11] = *T2;
4864- } else
4865- memset(&ia_options[8], 0x00, 4);
4866-
4867- create_iaaddr(dhcp_client, &ia_options[12],
4868- IAADDR_LEN);
4869-
4870- g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_NA,
4871- ia_options, sizeof(ia_options));
4872- } else {
4873- uint8_t ia_options[4+4+4];
4874-
4875- put_iaid(dhcp_client, index, ia_options);
4876-
4877- memset(&ia_options[4], 0x00, 4); /* T1 (4 bytes) */
4878- memset(&ia_options[8], 0x00, 4); /* T2 (4 bytes) */
4879-
4880- g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_IA_NA,
4881- ia_options, sizeof(ia_options));
4882- }
4883-
4884- } else
4885- return -EINVAL;
4886-
4887- return 0;
4888-}
4889-
4890-int g_dhcpv6_client_set_ias(GDHCPClient *dhcp_client, int index,
4891- int code, uint32_t *T1, uint32_t *T2,
4892- GSList *addresses)
4893-{
4894- GSList *list;
4895- uint8_t *ia_options, *pos;
4896- int len, count, total_len;
4897-
4898- count = g_slist_length(addresses);
4899- if (count == 0)
4900- return -EINVAL;
4901-
4902- g_dhcp_client_set_request(dhcp_client, code);
4903-
4904- if (code == G_DHCPV6_IA_TA)
4905- len = 4; /* IAID */
4906- else if (code == G_DHCPV6_IA_NA)
4907- len = 4 + 4 + 4; /* IAID + T1 + T2 */
4908- else
4909- return -EINVAL;
4910-
4911- total_len = len + count * (2 + 2 + 16 + 4 + 4);
4912- ia_options = g_try_malloc0(total_len);
4913- if (!ia_options)
4914- return -ENOMEM;
4915-
4916- put_iaid(dhcp_client, index, ia_options);
4917-
4918- pos = &ia_options[len]; /* skip the IA_NA or IA_TA */
4919-
4920- for (list = addresses; list; list = list->next) {
4921- pos = append_iaaddr(dhcp_client, pos, list->data);
4922- if (!pos)
4923- break;
4924- }
4925-
4926- if (code == G_DHCPV6_IA_NA) {
4927- if (T1) {
4928- ia_options[4] = *T1 >> 24;
4929- ia_options[5] = *T1 >> 16;
4930- ia_options[6] = *T1 >> 8;
4931- ia_options[7] = *T1;
4932- } else
4933- memset(&ia_options[4], 0x00, 4);
4934-
4935- if (T2) {
4936- ia_options[8] = *T2 >> 24;
4937- ia_options[9] = *T2 >> 16;
4938- ia_options[10] = *T2 >> 8;
4939- ia_options[11] = *T2;
4940- } else
4941- memset(&ia_options[8], 0x00, 4);
4942- }
4943-
4944- g_dhcpv6_client_set_send(dhcp_client, code, ia_options, total_len);
4945-
4946- g_free(ia_options);
4947-
4948- return 0;
4949-}
4950-
4951-int g_dhcpv6_client_set_oro(GDHCPClient *dhcp_client, int args, ...)
4952-{
4953- va_list va;
4954- int i, j, len = sizeof(uint16_t) * args;
4955- uint8_t *values;
4956-
4957- values = g_try_malloc(len);
4958- if (!values)
4959- return -ENOMEM;
4960-
4961- va_start(va, args);
4962- for (i = 0, j = 0; i < args; i++) {
4963- uint16_t value = va_arg(va, int);
4964- values[j++] = value >> 8;
4965- values[j++] = value & 0xff;
4966- }
4967- va_end(va);
4968-
4969- g_dhcpv6_client_set_send(dhcp_client, G_DHCPV6_ORO, values, len);
4970-
4971- g_free(values);
4972-
4973- return 0;
4974-}
4975-
4976-static int send_dhcpv6_msg(GDHCPClient *dhcp_client, int type, char *msg)
4977-{
4978- struct dhcpv6_packet *packet;
4979- uint8_t buf[MAX_DHCPV6_PKT_SIZE];
4980- unsigned char *ptr;
4981- int ret, max_buf;
4982-
4983- memset(buf, 0, sizeof(buf));
4984- packet = (struct dhcpv6_packet *)&buf[0];
4985- ptr = buf + sizeof(struct dhcpv6_packet);
4986-
4987- init_packet(dhcp_client, packet, type);
4988-
4989- if (!dhcp_client->retransmit) {
4990- dhcp_client->xid = packet->transaction_id[0] << 16 |
4991- packet->transaction_id[1] << 8 |
4992- packet->transaction_id[2];
4993- gettimeofday(&dhcp_client->start_time, NULL);
4994- } else {
4995- packet->transaction_id[0] = dhcp_client->xid >> 16;
4996- packet->transaction_id[1] = dhcp_client->xid >> 8 ;
4997- packet->transaction_id[2] = dhcp_client->xid;
4998- }
4999-
5000- g_dhcp_client_set_request(dhcp_client, G_DHCPV6_ELAPSED_TIME);
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: