self.parent_session = None # type: Optional[VideoroomSessionInfo] # for subscribers this is their main session (the one used to join), for publishers is None
self.publisher_id = None # janus publisher ID for publishers / publisher session ID for subscribers
self.slow_download = False
self.slow_upload = False
self.feeds = PublisherFeedContainer() # keeps references to all the other participant's publisher feeds that we subscribed to
self.log.debug('subscribe to {account} in room {session.room.uri} {feeds}'.format(account=publisher_session.account.id, session=videoroom_session, feeds=len(base_session.feeds)))
raise APIError('Unknown room session to detach: {request.feed}'.format(request=request))
if videoroom_session.parent_session.id != request.session:
raise APIError('{request.feed} is not an attached feed of {request.session}'.format(request=request))
videoroom_session.janus_handle.feed_detach()
# safety net in case we do not get any answer for the feed_detach request
# todo: to be adjusted later after pseudo-synchronous communication with janus is implemented
self.log.debug('unsubscribe from {account} in room {session.room.uri}'.format(account=videoroom_session.room[videoroom_session.publisher_id].account.id, session=videoroom_session))
modified = ', '.join('{}={}'.format(key, options[key]) for key in options)
media = 'video'
try:
has_video = options['video']
except KeyError:
pass
else:
if not has_video:
media = 'audio only'
self.log.info('switched to {media} media to {account} in room {session.room.uri}'.format(account=videoroom_session.room[videoroom_session.publisher_id].account.id, session=videoroom_session, media=media))
body = cpim_message.content if isinstance(cpim_message.content, str) else cpim_message.content.decode()
content_type = cpim_message.content_type
sender = cpim_message.sender or FromHeader(SIPURI.parse('{}'.format(data.sender)), data.displayname)
disposition = next(([item.strip() for item in header.value.split(',')] for header in cpim_message.additional_headers if header.name == 'Disposition-Notification'), None)
message_id = next((header.value for header in cpim_message.additional_headers if header.name == 'Message-ID'), None)
content = message.content if isinstance(message.content, str) else message.content.decode('latin1') # preserve binary data for transmitting over JSON
if any(header.name == 'Message-Type' and header.value == 'status' and header.namespace == 'urn:ag-projects:xml:ns:cpim' for header in message.additional_headers):
body = CPIMPayload.decode(notification.sender.body)
reason = data.reason.decode() if isinstance(data.reason, bytes) else data.reason
callid = data.headers.get('Call-ID', Null).body if hasattr(data, 'headers') else None
self.log.warning('could not deliver message to %s: %d %s (%s)' % (', '.join(([str(item.uri) for item in body.recipients])), data.code, reason, callid))
message_id = next((header.value for header in body.additional_headers if header.name == 'Message-ID'), None)
raise DNSLookupError('DNS lookup error: no results found')
route = random.choice([r for r in routes if r.transport == routes[0].transport])
log.debug('DNS lookup for SIP message proxy for {} yielded {}'.format(uri, route))
return route
def _parse_message(self):
cpim_message = None
if self.content_type == "message/cpim":
cpim_message = CPIMPayload.decode(self.body)
body = cpim_message.content if isinstance(cpim_message.content, str) else cpim_message.content.decode()
content_type = cpim_message.content_type
sender = cpim_message.sender or self.from_header
disposition = next(([item.strip() for item in header.value.split(',')] for header in cpim_message.additional_headers if header.name == 'Disposition-Notification'), None)
message_id = next((header.value for header in cpim_message.additional_headers if header.name == 'Message-ID'), str(uuid.uuid4()))
else:
body = self.body.decode('utf-8')
sender = self.from_header
disposition = None
message_id = str(uuid.uuid4())
content_type = str(self.content_type)
timestamp = str(cpim_message.timestamp) if cpim_message is not None and cpim_message.timestamp is not None else str(ISOTimestamp.now())
if self.parsed_message.content_type in ignored_content_types:
return
log.info('storing {content_type} message for account {originator} to {destination.uri}'.format(content_type=self.parsed_message.content_type, originator=account.account, destination=self.parsed_message.destination))
log.info('storing {content_type} message from {originator.uri} for account {account}'.format(content_type=self.parsed_message.content_type, originator=self.parsed_message.sender, account=account.account))