Advertisement
Guest User

Untitled

a guest
Jul 1st, 2017
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.54 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. #
  3. # papyon - a python client library for Msn
  4. #
  5. # Copyright (C) 2009 Collabora Ltd.
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation; either version 2 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20.  
  21. from papyon.media import *
  22. from papyon.event.media import *
  23.  
  24. import pygst
  25. pygst.require('0.10')
  26.  
  27. import farsight
  28. import gobject
  29. import gst
  30. import logging
  31. import sys
  32.  
  33. logger = logging.getLogger("papylib.conference")
  34.  
  35. codecs_definitions = {
  36. "audio" : [
  37. (114, "x-msrta", farsight.MEDIA_TYPE_AUDIO, 16000),
  38. (111, "SIREN", farsight.MEDIA_TYPE_AUDIO, 16000),
  39. (112, "G7221", farsight.MEDIA_TYPE_AUDIO, 16000),
  40. (115, "x-msrta", farsight.MEDIA_TYPE_AUDIO, 8000),
  41. (116, "SIREN", farsight.MEDIA_TYPE_AUDIO, 8000),
  42. (4, "G723", farsight.MEDIA_TYPE_AUDIO, 8000),
  43. (8, "PCMA", farsight.MEDIA_TYPE_AUDIO, 8000),
  44. (0, "PCMU", farsight.MEDIA_TYPE_AUDIO, 8000),
  45. (97, "RED", farsight.MEDIA_TYPE_AUDIO, 8000),
  46. (101, "telephone-event", farsight.MEDIA_TYPE_AUDIO, 8000)
  47. ],
  48. "video" : [
  49. (121, "x-rtvc1", farsight.MEDIA_TYPE_VIDEO, 90000),
  50. (34, "H263", farsight.MEDIA_TYPE_VIDEO, 90000)
  51. ]
  52. }
  53.  
  54. types = {
  55. 0 : None,
  56. farsight.CANDIDATE_TYPE_HOST : "host",
  57. farsight.CANDIDATE_TYPE_SRFLX : "srflx",
  58. farsight.CANDIDATE_TYPE_PRFLX : "prflx",
  59. farsight.CANDIDATE_TYPE_RELAY : "relay"
  60. }
  61.  
  62. protos = {
  63. farsight.NETWORK_PROTOCOL_TCP : "TCP",
  64. farsight.NETWORK_PROTOCOL_UDP : "UDP"
  65. }
  66.  
  67. media_names = {
  68. farsight.MEDIA_TYPE_AUDIO : "audio",
  69. farsight.MEDIA_TYPE_VIDEO : "video"
  70. }
  71.  
  72. media_types = {
  73. "audio" : farsight.MEDIA_TYPE_AUDIO,
  74. "video" : farsight.MEDIA_TYPE_VIDEO
  75. }
  76.  
  77.  
  78. class Conference(gobject.GObject):
  79.  
  80. def __init__(self):
  81. gobject.GObject.__init__(self)
  82.  
  83. def set_source(self, source):
  84. pass
  85.  
  86.  
  87. class MediaSessionHandler(MediaSessionEventInterface):
  88.  
  89. def __init__(self, session, surface_buddy=None, surface_self=None):
  90. MediaSessionEventInterface.__init__(self, session)
  91. self.surface_buddy = surface_buddy
  92. self.surface_self = surface_self
  93.  
  94. self._conference = None
  95. self._handlers = []
  96. self._setup()
  97. for stream in session.streams:
  98. self.on_stream_added(stream)
  99.  
  100. def _setup(self):
  101. self._pipeline = gst.Pipeline()
  102. bus = self._pipeline.get_bus()
  103. bus.add_signal_watch()
  104. bus.connect("message", self.on_bus_message)
  105. if self._session.type is MediaSessionType.WEBCAM_RECV:
  106. name = "fsmsncamrecvconference"
  107. elif self._session.type is MediaSessionType.WEBCAM_SEND:
  108. name = "fsmsncamsendconference"
  109. else:
  110. name = "fsrtpconference"
  111. self._conference = gst.element_factory_make(name)
  112. self._participant = self._conference.new_participant("")
  113. self._pipeline.add(self._conference)
  114. self._pipeline.set_state(gst.STATE_PLAYING)
  115. #FIXME Create FsElementAddedNotifier
  116.  
  117. def on_stream_added(self, stream):
  118. logger.debug("Stream \"%s\" added" % stream.name)
  119. handler = MediaStreamHandler(stream, self.surface_buddy, self.surface_self)
  120. handler.setup(self._conference, self._pipeline, self._participant,
  121. self._session.type)
  122. self._handlers.append(handler)
  123. if self._session.type is MediaSessionType.WEBCAM_RECV or\
  124. self._session.type is MediaSessionType.WEBCAM_SEND:
  125. stream.set_local_codecs([])
  126.  
  127. def on_bus_message(self, bus, msg):
  128. ret = gst.BUS_PASS
  129. if msg.type == gst.MESSAGE_ELEMENT:
  130. s = msg.structure
  131. if s.has_name("prepare-xwindow-id"):
  132. # Sets buddy's xid in our nice window.
  133. msg.src.set_xwindow_id(self.surface_buddy)
  134. if s.has_name("farsight-error"):
  135. logger.error("Farsight error : %s" % s['error-msg'])
  136. if s.has_name("farsight-codecs-changed"):
  137. logger.debug("Farsight codecs changed")
  138. ret = gst.BUS_DROP
  139. ready = s["session"].get_property("codecs-ready")
  140. if ready:
  141. codecs = s["session"].get_property("codecs")
  142. name = media_names[s["session"].get_property("media-type")]
  143. stream = self._session.get_stream(name)
  144. stream.set_local_codecs(convert_fs_codecs(codecs))
  145. if s.has_name("farsight-new-local-candidate"):
  146. logger.debug("New local candidate")
  147. ret = gst.BUS_DROP
  148. name = media_names[s["stream"].get_property("session").get_property("media-type")]
  149. candidate = convert_fs_candidate(s["candidate"])
  150. stream = self._session.get_stream(name)
  151. stream.new_local_candidate(candidate)
  152. if s.has_name("farsight-local-candidates-prepared"):
  153. logger.debug("Local candidates are prepared")
  154. ret = gst.BUS_DROP
  155. type = s["stream"].get_property("session").get_property("media-type")
  156. name = media_names[type]
  157. stream = self._session.get_stream(name)
  158. stream.local_candidates_prepared()
  159. if s.has_name("farsight-new-active-candidate-pair"):
  160. logger.debug("New active candidate pair")
  161. ret = gst.BUS_DROP
  162. type = s["stream"].get_property("session").get_property("media-type")
  163. name = media_names[type]
  164. stream = self._session.get_stream(name)
  165. local = s["local-candidate"]
  166. remote = s["remote-candidate"]
  167. local = convert_fs_candidate(local)
  168. remote = convert_fs_candidate(remote)
  169. stream.new_active_candidate_pair(local, remote)
  170. return ret
  171.  
  172.  
  173. class MediaStreamHandler(MediaStreamEventInterface):
  174.  
  175. def __init__(self, stream, surface_buddy=None, surface_self=None):
  176. MediaStreamEventInterface.__init__(self, stream)
  177.  
  178. self.surface_buddy = surface_buddy
  179. self.surface_self = surface_self
  180.  
  181. def setup(self, conference, pipeline, participant, type):
  182. relays = []
  183. for r in self._stream.relays:
  184. relay = gst.Structure("relay")
  185. relay.set_value("username", r.username)
  186. relay.set_value("password", r.password)
  187. relay.set_value("ip", r.ip)
  188. relay.set_value("port", r.port, "uint")
  189. relays.append(relay)
  190.  
  191. if type in (MediaSessionType.SIP, MediaSessionType.TUNNELED_SIP):
  192. if type is MediaSessionType.TUNNELED_SIP:
  193. compatibility_mode = 3
  194. else:
  195. compatibility_mode = 2
  196. params = {"stun-ip" : "64.14.48.28", "stun-port" : 3478,
  197. "compatibility-mode" : compatibility_mode,
  198. "controlling-mode": self._stream.created_locally,
  199. "relay-info": relays}
  200. else:
  201. params = {}
  202. media_type = media_types[self._stream.name]
  203. self.fssession = conference.new_session(media_type)
  204. self.fssession.set_codec_preferences(build_codecs(self._stream.name))
  205. self.fsstream = self.fssession.new_stream(participant,
  206. self._stream.direction, "nice", params)
  207. self.fsstream.connect("src-pad-added", self.on_src_pad_added, pipeline)
  208. if self._stream.name == 'video':
  209. source = VideoSourceBin()
  210. spad = source.get_request_pad("src%d")
  211. elif self._stream.name == 'audio':
  212. source = make_audio_source()
  213. spad = source.get_pad("src")
  214. else:
  215. raise "Unknown source type"
  216. pipeline.add(source)
  217. pad = self.fssession.get_property("sink-pad")
  218. spad.link(pad)
  219. source.set_state(gst.STATE_PLAYING)
  220. #pipeline.set_state(gst.STATE_PLAYING)
  221.  
  222. def on_stream_closed(self):
  223. del self.fsstream
  224.  
  225. def on_remote_candidates_received(self, candidates):
  226. candidates = filter(lambda x: x.transport == "UDP", candidates)
  227. candidates = convert_media_candidates(candidates)
  228. self.fsstream.set_remote_candidates(candidates)
  229.  
  230. def on_remote_codecs_received(self, codecs):
  231. codecs = convert_media_codecs(codecs, self._stream.name)
  232. self.fsstream.set_remote_codecs(codecs)
  233.  
  234. def on_src_pad_added(self, stream, pad, codec, pipeline):
  235. sink = make_sink(self._stream.name)
  236. pipeline.add(sink)
  237. sink.set_state(gst.STATE_PLAYING)
  238. pad.link(sink.get_pad("sink"))
  239.  
  240.  
  241. # Farsight utility functions
  242.  
  243. def create_notifier(pipeline, filename):
  244. notifier = farsight.ElementAddedNotifier()
  245. notifier.add(pipeline)
  246. notifier.set_properties_from_file(filename)
  247. return notifier
  248.  
  249. def convert_fs_candidate(fscandidate):
  250. candidate = MediaCandidate()
  251. candidate.ip = fscandidate.ip
  252. candidate.port = fscandidate.port
  253. candidate.foundation = fscandidate.foundation
  254. candidate.component_id = fscandidate.component_id
  255. candidate.transport = protos[fscandidate.proto]
  256. candidate.priority = int(fscandidate.priority)
  257. candidate.username = fscandidate.username
  258. candidate.password = fscandidate.password
  259. candidate.type = types[fscandidate.type]
  260. candidate.base_ip = fscandidate.base_ip
  261. candidate.base_port = fscandidate.base_port
  262. return candidate
  263.  
  264. def convert_media_candidates(candidates):
  265. fscandidates = []
  266. for candidate in candidates:
  267. proto = farsight.NETWORK_PROTOCOL_TCP
  268. if candidate.transport == "UDP":
  269. proto = farsight.NETWORK_PROTOCOL_UDP
  270. type = 0
  271. for k,v in types.iteritems():
  272. if v == candidate.type:
  273. type = k
  274. fscandidate = farsight.Candidate()
  275. fscandidate.foundation = candidate.foundation
  276. fscandidate.ip = candidate.ip
  277. fscandidate.port = candidate.port
  278. fscandidate.component_id = candidate.component_id
  279. fscandidate.proto = proto
  280. fscandidate.type = type
  281. fscandidate.username = candidate.username
  282. fscandidate.password = candidate.password
  283. fscandidate.priority = int(candidate.priority)
  284. fscandidates.append(fscandidate)
  285. return fscandidates
  286.  
  287. def build_codecs(type):
  288. codecs = []
  289. for args in codecs_definitions[type]:
  290. codec = farsight.Codec(*args)
  291. codecs.append(codec)
  292. return codecs
  293.  
  294. def convert_fs_codecs(fscodecs):
  295. codecs = []
  296. for fscodec in fscodecs:
  297. codec = MediaCodec()
  298. codec.payload = fscodec.id
  299. codec.encoding = fscodec.encoding_name
  300. codec.clockrate = fscodec.clock_rate
  301. codec.params = dict(fscodec.optional_params)
  302. codecs.append(codec)
  303. return codecs
  304.  
  305. def convert_media_codecs(codecs, name):
  306. fscodecs = []
  307. media_type = media_types[name]
  308. for codec in codecs:
  309. fscodec = farsight.Codec(
  310. codec.payload,
  311. codec.encoding,
  312. media_type,
  313. codec.clockrate)
  314. fscodec.optional_params = codec.params.items()
  315. fscodecs.append(fscodec)
  316. return fscodecs
  317.  
  318.  
  319. # GStreamer utility functions
  320.  
  321. def make_source(media_name):
  322. func = globals()["make_%s_source" % media_name]
  323. return func()
  324.  
  325. def make_sink(media_name):
  326. func = globals()["make_%s_sink" % media_name]
  327. return func()
  328.  
  329. def make_audio_source_test(name="audiotestsrc"):
  330. element = gst.element_factory_make(name)
  331. element.set_property("is-live", True)
  332. return element
  333.  
  334. def make_audio_sink(async=False):
  335. return gst.element_factory_make("autoaudiosink")
  336.  
  337. def make_video_source_test(name="videotestsrc"):
  338. "Make a bin with a video source in it, defaulting to first webcamera "
  339. bin = gst.Bin("videosrc")
  340. src = gst.element_factory_make(name, name)
  341. src.set_property("is-live", True)
  342. src.set_property("pattern", 0)
  343. bin.add(src)
  344. filter = gst.element_factory_make("capsfilter")
  345. filter.set_property("caps", gst.Caps("video/x-raw-yuv , width=[300,500] , height=[200,500], framerate=[20/1,30/1]"))
  346. bin.add(filter)
  347. src.link(filter)
  348. videoscale = gst.element_factory_make("videoscale")
  349. bin.add(videoscale)
  350. filter.link(videoscale)
  351. bin.add_pad(gst.GhostPad("src", videoscale.get_pad("src")))
  352. return bin
  353.  
  354. def make_video_sink(async=False):
  355. "Make a bin with a video sink in it, that will be displayed on xid."
  356. bin = gst.Bin("videosink")
  357. sink = gst.element_factory_make("ximagesink", "imagesink")
  358. sink.set_property("sync", async)
  359. sink.set_property("async", async)
  360. bin.add(sink)
  361. colorspace = gst.element_factory_make("ffmpegcolorspace")
  362. bin.add(colorspace)
  363. videoscale = gst.element_factory_make("videoscale")
  364. bin.add(videoscale)
  365. videoscale.link(colorspace)
  366. colorspace.link(sink)
  367. bin.add_pad(gst.GhostPad("sink", videoscale.get_pad("sink")))
  368.  
  369. return bin
  370.  
  371. import os
  372. def make_audio_source():
  373. bin=gst.Bin()
  374. if not os.environ.has_key("TESTAUDIO"):
  375. source = gst.element_factory_make("audiotestsrc")
  376. source.set_property("is-live", True)
  377. else:
  378. source = gst.element_factory_make("gconfaudiosrc")
  379. bin.add(source)
  380. pad = gst.GhostPad("src", source.get_pad("src"))
  381. bin.add_pad(pad)
  382. return bin
  383.  
  384. class VideoSourceBin(gst.Bin):
  385. def __init__ (self, name = None):
  386. gst.Bin.__init__(self, name)
  387.  
  388. if os.environ.has_key("VIDEO_DEVICE"):
  389. source = gst.element_factory_make("v4l2src")
  390. source.set_property("device", os.environ["VIDEO_DEVICE"])
  391. print source.get_property("device")
  392. else:
  393. source = gst.element_factory_make("videotestsrc")
  394. source.set_property("is-live", True)
  395.  
  396. self.add(source)
  397.  
  398. colorspace = gst.element_factory_make("ffmpegcolorspace")
  399. self.add(colorspace)
  400. source.link(colorspace)
  401.  
  402. rate = gst.element_factory_make("videorate", "sourcerate")
  403. self.add(rate)
  404. colorspace.link(rate)
  405.  
  406. filter = gst.element_factory_make("capsfilter")
  407. filter.set_property("caps",
  408. gst.Caps("video/x-raw-yuv,width=[320,352],height=[240,288]," + \
  409. "framerate=(fraction)15/1,format=(fourcc)I420"))
  410.  
  411. self.add(filter)
  412. rate.link(filter)
  413.  
  414. tee = gst.element_factory_make("tee")
  415. self.tee = tee
  416. self.add(tee)
  417.  
  418. filter.link(tee)
  419.  
  420. def get_request_pad(self, name):
  421. pad = self.tee.get_request_pad(name)
  422.  
  423. queue = gst.element_factory_make("queue")
  424. self.add(queue)
  425. queue.sync_state_with_parent()
  426. pad.link(queue.get_pad("sink"))
  427.  
  428. ghost = gst.GhostPad(pad.get_name(), queue.get_pad("src"))
  429. #ghost = gst.GhostPad(pad.get_name(), pad)
  430. ghost.set_active (True)
  431. self.add_pad (ghost)
  432. return ghost
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement