Guest User

Untitled

a guest
Dec 8th, 2017
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.74 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.  
  32. logger = logging.getLogger("papylib.conference")
  33.  
  34. codecs_definitions = {
  35. "audio" : [
  36. (114, "x-msrta", farsight.MEDIA_TYPE_AUDIO, 16000),
  37. (111, "SIREN", farsight.MEDIA_TYPE_AUDIO, 16000),
  38. (112, "G7221", farsight.MEDIA_TYPE_AUDIO, 16000),
  39. (115, "x-msrta", farsight.MEDIA_TYPE_AUDIO, 8000),
  40. (116, "SIREN", farsight.MEDIA_TYPE_AUDIO, 8000),
  41. (4, "G723", farsight.MEDIA_TYPE_AUDIO, 8000),
  42. (8, "PCMA", farsight.MEDIA_TYPE_AUDIO, 8000),
  43. (0, "PCMU", farsight.MEDIA_TYPE_AUDIO, 8000),
  44. (97, "RED", farsight.MEDIA_TYPE_AUDIO, 8000),
  45. (101, "telephone-event", farsight.MEDIA_TYPE_AUDIO, 8000)
  46. ],
  47. "video" : [
  48. (121, "x-rtvc1", farsight.MEDIA_TYPE_VIDEO, 90000),
  49. (34, "H263", farsight.MEDIA_TYPE_VIDEO, 90000)
  50. ]
  51. }
  52.  
  53. types = {
  54. 0 : None,
  55. farsight.CANDIDATE_TYPE_HOST : "host",
  56. farsight.CANDIDATE_TYPE_SRFLX : "srflx",
  57. farsight.CANDIDATE_TYPE_PRFLX : "prflx",
  58. farsight.CANDIDATE_TYPE_RELAY : "relay"
  59. }
  60.  
  61. protos = {
  62. farsight.NETWORK_PROTOCOL_TCP : "TCP",
  63. farsight.NETWORK_PROTOCOL_UDP : "UDP"
  64. }
  65.  
  66. media_names = {
  67. farsight.MEDIA_TYPE_AUDIO : "audio",
  68. farsight.MEDIA_TYPE_VIDEO : "video"
  69. }
  70.  
  71. media_types = {
  72. "audio" : farsight.MEDIA_TYPE_AUDIO,
  73. "video" : farsight.MEDIA_TYPE_VIDEO
  74. }
  75.  
  76.  
  77. class Conference(gobject.GObject):
  78.  
  79. def __init__(self):
  80. gobject.GObject.__init__(self)
  81.  
  82. def set_source(self, source):
  83. pass
  84.  
  85.  
  86. class MediaSessionHandler(MediaSessionEventInterface):
  87.  
  88. def __init__(self, session, surface_buddy=None, surface_self=None):
  89. MediaSessionEventInterface.__init__(self, session)
  90. self.surface_buddy = surface_buddy
  91. self.surface_self = surface_self
  92.  
  93. self._conference = None
  94. self._handlers = []
  95. self._setup()
  96. for stream in session.streams:
  97. self.on_stream_added(stream)
  98.  
  99. def _setup(self):
  100. self._pipeline = gst.Pipeline()
  101. bus = self._pipeline.get_bus()
  102. bus.add_signal_watch()
  103. bus.connect("message", self.on_bus_message)
  104. if self._session.type is MediaSessionType.WEBCAM_RECV:
  105. name = "fsmsncamrecvconference"
  106. elif self._session.type is MediaSessionType.WEBCAM_SEND:
  107. name = "fsmsncamsendconference"
  108. else:
  109. name = "fsrtpconference"
  110. self._conference = gst.element_factory_make(name)
  111. self._participant = self._conference.new_participant("")
  112. self._pipeline.add(self._conference)
  113. self._pipeline.set_state(gst.STATE_PLAYING)
  114. #FIXME Create FsElementAddedNotifier
  115.  
  116. def on_stream_added(self, stream):
  117. logger.debug("Stream \"%s\" added" % stream.name)
  118. handler = MediaStreamHandler(stream, self.surface_buddy, self.surface_self)
  119. handler.setup(self._conference, self._pipeline, self._participant,
  120. self._session.type)
  121. self._handlers.append(handler)
  122. if self._session.type is MediaSessionType.WEBCAM_RECV or\
  123. self._session.type is MediaSessionType.WEBCAM_SEND:
  124. stream.set_local_codecs([])
  125.  
  126. def on_bus_message(self, bus, msg):
  127. ret = gst.BUS_PASS
  128. if msg.type == gst.MESSAGE_ELEMENT:
  129. s = msg.structure
  130. if s.has_name("prepare-xwindow-id"):
  131. # Sets buddy's xid in our nice window.
  132. msg.src.set_xwindow_id(self.surface_buddy)
  133. if s.has_name("farsight-error"):
  134. logger.error("Farsight error : %s" % s['error-msg'])
  135. if s.has_name("farsight-codecs-changed"):
  136. logger.debug("Farsight codecs changed")
  137. ret = gst.BUS_DROP
  138. ready = s["session"].get_property("codecs-ready")
  139. if ready:
  140. codecs = s["session"].get_property("codecs")
  141. name = media_names[s["session"].get_property("media-type")]
  142. stream = self._session.get_stream(name)
  143. stream.set_local_codecs(convert_fs_codecs(codecs))
  144. if s.has_name("farsight-new-local-candidate"):
  145. logger.debug("New local candidate")
  146. ret = gst.BUS_DROP
  147. name = media_names[s["stream"].get_property("session").get_property("media-type")]
  148. candidate = convert_fs_candidate(s["candidate"])
  149. stream = self._session.get_stream(name)
  150. stream.new_local_candidate(candidate)
  151. if s.has_name("farsight-local-candidates-prepared"):
  152. logger.debug("Local candidates are prepared")
  153. ret = gst.BUS_DROP
  154. type = s["stream"].get_property("session").get_property("media-type")
  155. name = media_names[type]
  156. stream = self._session.get_stream(name)
  157. stream.local_candidates_prepared()
  158. if s.has_name("farsight-new-active-candidate-pair"):
  159. logger.debug("New active candidate pair")
  160. ret = gst.BUS_DROP
  161. type = s["stream"].get_property("session").get_property("media-type")
  162. name = media_names[type]
  163. stream = self._session.get_stream(name)
  164. local = s["local-candidate"]
  165. remote = s["remote-candidate"]
  166. local = convert_fs_candidate(local)
  167. remote = convert_fs_candidate(remote)
  168. stream.new_active_candidate_pair(local, remote)
  169. return ret
  170.  
  171.  
  172. class MediaStreamHandler(MediaStreamEventInterface):
  173.  
  174. def __init__(self, stream, surface_buddy=None, surface_self=None):
  175. MediaStreamEventInterface.__init__(self, stream)
  176.  
  177. self.surface_buddy = surface_buddy
  178. self.surface_self = surface_self
  179.  
  180. def setup(self, conference, pipeline, participant, type):
  181. relays = []
  182. for r in self._stream.relays:
  183. relay = gst.Structure("relay")
  184. relay.set_value("username", r.username)
  185. relay.set_value("password", r.password)
  186. relay.set_value("ip", r.ip)
  187. relay.set_value("port", r.port, "uint")
  188. relays.append(relay)
  189.  
  190. if type in (MediaSessionType.SIP, MediaSessionType.TUNNELED_SIP):
  191. if type is MediaSessionType.TUNNELED_SIP:
  192. compatibility_mode = 3
  193. else:
  194. compatibility_mode = 2
  195. params = {"stun-ip" : "64.14.48.28", "stun-port" : 3478,
  196. "compatibility-mode" : compatibility_mode,
  197. "controlling-mode": self._stream.created_locally,
  198. "relay-info": relays}
  199. else:
  200. params = {}
  201. media_type = media_types[self._stream.name]
  202. self.fssession = conference.new_session(media_type)
  203. self.fssession.set_codec_preferences(build_codecs(self._stream.name))
  204. self.fsstream = self.fssession.new_stream(participant,
  205. self._stream.direction, "nice", params)
  206. self.fsstream.connect("src-pad-added", self.on_src_pad_added, pipeline)
  207. source = make_source(self._stream.name)
  208. pipeline.add(source)
  209.  
  210. def on_src_message(bus, msg):
  211. if msg.structure is None:
  212. return
  213. if msg.structure.get_name() == "prepare-xwindow-id":
  214. msg.src.set_xwindow_id(self.surface_self)
  215. print "XID222222"
  216.  
  217. #bus = pipeline.get_bus()
  218. #bus.add_signal_watch()
  219. #bus.enable_sync_message_emission()
  220. #bus.connect("sync-message::element", on_src_message)
  221.  
  222. source.get_pad("src").link(self.fssession.get_property("sink-pad"))
  223. pipeline.set_state(gst.STATE_PLAYING)
  224.  
  225. def on_stream_closed(self):
  226. del self.fsstream
  227.  
  228. def on_remote_candidates_received(self, candidates):
  229. candidates = filter(lambda x: x.transport == "UDP", candidates)
  230. candidates = convert_media_candidates(candidates)
  231. self.fsstream.set_remote_candidates(candidates)
  232.  
  233. def on_remote_codecs_received(self, codecs):
  234. codecs = convert_media_codecs(codecs, self._stream.name)
  235. self.fsstream.set_remote_codecs(codecs)
  236.  
  237. def on_src_pad_added(self, stream, pad, codec, pipeline):
  238. sink = make_sink(self._stream.name)
  239. pipeline.add(sink)
  240. sink.set_state(gst.STATE_PLAYING)
  241. pad.link(sink.get_pad("sink"))
  242.  
  243.  
  244. # Farsight utility functions
  245.  
  246. def create_notifier(pipeline, filename):
  247. notifier = farsight.ElementAddedNotifier()
  248. notifier.add(pipeline)
  249. notifier.set_properties_from_file(filename)
  250. return notifier
  251.  
  252. def convert_fs_candidate(fscandidate):
  253. candidate = MediaCandidate()
  254. candidate.ip = fscandidate.ip
  255. candidate.port = fscandidate.port
  256. candidate.foundation = fscandidate.foundation
  257. candidate.component_id = fscandidate.component_id
  258. candidate.transport = protos[fscandidate.proto]
  259. candidate.priority = int(fscandidate.priority)
  260. candidate.username = fscandidate.username
  261. candidate.password = fscandidate.password
  262. candidate.type = types[fscandidate.type]
  263. candidate.base_ip = fscandidate.base_ip
  264. candidate.base_port = fscandidate.base_port
  265. return candidate
  266.  
  267. def convert_media_candidates(candidates):
  268. fscandidates = []
  269. for candidate in candidates:
  270. proto = farsight.NETWORK_PROTOCOL_TCP
  271. if candidate.transport == "UDP":
  272. proto = farsight.NETWORK_PROTOCOL_UDP
  273. type = 0
  274. for k,v in types.iteritems():
  275. if v == candidate.type:
  276. type = k
  277. fscandidate = farsight.Candidate()
  278. fscandidate.foundation = candidate.foundation
  279. fscandidate.ip = candidate.ip
  280. fscandidate.port = candidate.port
  281. fscandidate.component_id = candidate.component_id
  282. fscandidate.proto = proto
  283. fscandidate.type = type
  284. fscandidate.username = candidate.username
  285. fscandidate.password = candidate.password
  286. fscandidate.priority = int(candidate.priority)
  287. fscandidates.append(fscandidate)
  288. return fscandidates
  289.  
  290. def build_codecs(type):
  291. codecs = []
  292. for args in codecs_definitions[type]:
  293. codec = farsight.Codec(*args)
  294. codecs.append(codec)
  295. return codecs
  296.  
  297. def convert_fs_codecs(fscodecs):
  298. codecs = []
  299. for fscodec in fscodecs:
  300. codec = MediaCodec()
  301. codec.payload = fscodec.id
  302. codec.encoding = fscodec.encoding_name
  303. codec.clockrate = fscodec.clock_rate
  304. codec.params = dict(fscodec.optional_params)
  305. codecs.append(codec)
  306. return codecs
  307.  
  308. def convert_media_codecs(codecs, name):
  309. fscodecs = []
  310. media_type = media_types[name]
  311. for codec in codecs:
  312. fscodec = farsight.Codec(
  313. codec.payload,
  314. codec.encoding,
  315. media_type,
  316. codec.clockrate)
  317. fscodec.optional_params = codec.params.items()
  318. fscodecs.append(fscodec)
  319. return fscodecs
  320.  
  321.  
  322. # GStreamer utility functions
  323.  
  324. def make_source(media_name):
  325. func = globals()["make_%s_source" % media_name]
  326. return func()
  327.  
  328. def make_sink(media_name):
  329. func = globals()["make_%s_sink" % media_name]
  330. return func()
  331.  
  332. # TODO: FIXME: Make this work, and then make a nice gui for configuration.
  333. def make_audio_source(name="pulsesrc"): #was: "audiotestsrc"
  334. element = gst.element_factory_make(name)
  335. #element.set_property("is-live", True)
  336. return element
  337.  
  338. def make_audio_sink(async=False):
  339. return gst.element_factory_make("autoaudiosink")
  340.  
  341. # TODO: FIXME: Make this work, and then make a nice gui for configuration.
  342. def make_video_source(name="autovideosrc"):
  343. "Make a bin with a video source in it, defaulting to first webcamera "
  344. bin = gst.Bin("videosrc")
  345. src = gst.element_factory_make(name, name)
  346. bin.add(src)
  347. filter = gst.element_factory_make("capsfilter")
  348. filter.set_property("caps", gst.Caps("video/x-raw-yuv , width=[300,1000] , height=[200,500], framerate=[20/1,100/1]"))
  349. bin.add(filter)
  350. src.link(filter)
  351. videoscale = gst.element_factory_make("videoscale")
  352. bin.add(videoscale)
  353. filter.link(videoscale)
  354. bin.add_pad(gst.GhostPad("src", videoscale.get_pad("src")))
  355. return bin
  356.  
  357. def make_video_sink(async=False):
  358. "Make a bin with a video sink in it, that will be displayed on xid."
  359. bin = gst.Bin("videosink")
  360. sink = gst.element_factory_make("autovideosink", "videosink")
  361. sink.set_property("sync", async)
  362. bin.add(sink)
  363. colorspace = gst.element_factory_make("ffmpegcolorspace")
  364. bin.add(colorspace)
  365. videoscale = gst.element_factory_make("videoscale")
  366. bin.add(videoscale)
  367. videoscale.link(colorspace)
  368. colorspace.link(sink)
  369. bin.add_pad(gst.GhostPad("sink", videoscale.get_pad("sink")))
  370.  
  371. return bin
Add Comment
Please, Sign In to add comment