"""Normalized authored RTSP2 single-media state model; not wire parser/server/RTP capture."""
import copy,json,platform
class SessionModel:
 def __init__(self):self.state='Init';self.session=None;self.transport=None;self.received=[];self.log=[]
 def request(self,method,session=None,transport=None):
  before=(self.state,self.session,self.transport,copy.deepcopy(self.received));status=200
  if method=='SETUP':
   if self.state!='Init':status=455
   elif transport not in ['RTP/AVP/UDP','RTP/AVP/TCP']:status=461
   else:self.state='Ready';self.session='AUTHORED-S1';self.transport=transport
  elif method in ['PLAY','PAUSE','TEARDOWN']:
   if self.session is None or session!=self.session:status=454
   elif method=='PLAY':self.state='Play'
   elif method=='PAUSE':self.state='Ready'
   else:self.state='Init';self.session=None;self.transport=None
  else:raise ValueError('unsupported model operation')
  if status!=200:assert before==(self.state,self.session,self.transport,self.received)
  out={'method':method,'status':status,'state':self.state,'session':self.session,'transport':self.transport,'received_media_records':len(self.received)};self.log.append(out);return out
 def observe_authored_packet(self,seq,timestamp,payload_bytes):
  if self.state!='Play':raise ValueError('fixture receive allowed only in Play')
  self.received.append({'sequence':seq,'rtp_timestamp_ticks':timestamp,'payload_bytes':payload_bytes})
def demo():
 m=SessionModel();assert m.request('PLAY','AUTHORED-S1')['status']==454
 assert m.request('SETUP',transport='unsupported')['status']==461
 assert m.request('SETUP',transport='RTP/AVP/TCP')['state']=='Ready'
 assert m.request('PLAY','WRONG')['status']==454
 assert m.request('PLAY','AUTHORED-S1')['received_media_records']==0
 m.observe_authored_packet(100,80000,160);m.observe_authored_packet(101,80160,160)
 assert m.received==[{'sequence':100,'rtp_timestamp_ticks':80000,'payload_bytes':160},{'sequence':101,'rtp_timestamp_ticks':80160,'payload_bytes':160}]
 assert m.request('PAUSE','AUTHORED-S1')['state']=='Ready'
 try:m.observe_authored_packet(102,80320,160)
 except ValueError:pause_rejected=True
 else:raise AssertionError('paused receive')
 assert m.request('PLAY','AUTHORED-S1')['state']=='Play'
 assert m.request('TEARDOWN','WRONG')['status']==454
 assert m.request('TEARDOWN','AUTHORED-S1')['session']is None
 assert m.request('PLAY','AUTHORED-S1')['status']==454
 return {'runtime':platform.python_version(),'model_scope':'Normalized selected RTSP2 single-media operations; SETUP reconfiguration/expiry/auth/wire parsing outside model','control_trace':m.log,'separate_authored_rtp_records':m.received,'rtp_tick_delta':160,'assumed_clock_hz_for_explanation':8000,'tick_delta_seconds':160/8000,'example_media_range':'npt=10-12','example_http_range':'bytes=10-12','pause_receive_fixture_rejected':pause_rejected,'actual_network_or_media_decode':False,'all_assertions_passed':True}
if __name__=='__main__':print(json.dumps(demo(),indent=2))
