WebRTC中RTP/RTCP協(xié)議實(shí)現(xiàn)分析

課程地址:零聲學(xué)院 WebRTC入門與提高 https://ke.qq.com/course/435382?tuin=137bb271

技術(shù)支持QQ群:782508536

webrtc時(shí)序圖.png

本文主要介紹WebRTC中的RTP/RTCP協(xié)議,作者:weizhenwei 试和,文章最早發(fā)表在編風(fēng)網(wǎng)阱飘,微信ID:befoio

支持原創(chuàng)窘游,轉(zhuǎn)載必須注明出處语婴,歡迎關(guān)注我的微信公眾號(hào)blacker(微信ID:blackerteam 或 webrtcorgcn)榜田。

一 前言

RTP/RTCP協(xié)議是流媒體通信的基石填大。RTP協(xié)議定義流媒體數(shù)據(jù)在互聯(lián)網(wǎng)上傳輸?shù)臄?shù)據(jù)包格式,而RTCP協(xié)議則負(fù)責(zé)可靠傳輸燕垃、流量控制和擁塞控制等服務(wù)質(zhì)量保證枢劝。在WebRTC項(xiàng)目中,RTP/RTCP模塊作為傳輸模塊的一部分卜壕,負(fù)責(zé)對(duì)發(fā)送端采集到的媒體數(shù)據(jù)進(jìn)行進(jìn)行封包您旁,然后交給上層網(wǎng)絡(luò)模塊發(fā)送;在接收端RTP/RTCP模塊收到上層模塊的數(shù)據(jù)包后轴捎,進(jìn)行解包操作鹤盒,最后把負(fù)載發(fā)送到解碼模塊蚕脏。因此,RTP/RTCP 模塊在WebRTC通信中發(fā)揮非常重要的作用侦锯。

本文在深入研究WebRTC源代碼的基礎(chǔ)上驼鞭,以Video數(shù)據(jù)的發(fā)送和接收為例,力求用簡潔語言描述RTP/RTCP模塊的實(shí)現(xiàn)細(xì)節(jié)尺碰,為進(jìn)一步深入掌握WebRTC打下良好基礎(chǔ)挣棕。

二 RTP/RTCP協(xié)議概述

RTP協(xié)議是Internet上針對(duì)流媒體傳輸?shù)幕A(chǔ)協(xié)議,該協(xié)議詳細(xì)說明在互聯(lián)網(wǎng)上傳輸音視頻的標(biāo)準(zhǔn)數(shù)據(jù)包格式亲桥。RTP協(xié)議本身只保證實(shí)時(shí)數(shù)據(jù)的傳輸洛心,RTCP協(xié)議則負(fù)責(zé)流媒體的傳輸質(zhì)量保證,提供流量控制和擁塞控制等服務(wù)题篷。在RTP會(huì)話期間词身,各參與者周期性彼此發(fā)送RTCP報(bào)文。報(bào)文中包含各參與者數(shù)據(jù)發(fā)送和接收等統(tǒng)計(jì)信息番枚,參與者可以據(jù)此動(dòng)態(tài)控制流媒體傳輸質(zhì)量法严。

RFC3550 [1]定義RTP/RTCP協(xié)議的基本內(nèi)容,包括報(bào)文格式户辫、傳輸規(guī)則等渐夸。除此之外嗤锉,IETF還定義一系列擴(kuò)展協(xié)議渔欢,包括RTP協(xié)議基于檔次的擴(kuò)展,和RTCP協(xié)議基于報(bào)文類型的擴(kuò)展瘟忱,等等奥额。詳細(xì)內(nèi)容可參考文獻(xiàn)[2]。

三 WebRTC線程關(guān)系和數(shù)據(jù)流

WebRTC對(duì)外提供兩個(gè)線程:Signal和Worker访诱,前者負(fù)責(zé)信令數(shù)據(jù)的處理和傳輸垫挨,后者負(fù)責(zé)媒體數(shù)據(jù)的處理和傳輸。在WebRTC內(nèi)部触菜,有一系列線程各司其職九榔,相互協(xié)作完成數(shù)據(jù)流管線。下面以Video數(shù)據(jù)的處理流程為例涡相,說明WebRTC內(nèi)部的線程合作關(guān)系哲泊。

image

如圖1所示,Capture線程從攝像頭采集原始數(shù)據(jù)催蝗,得到VideoFrame切威;Capture線程是系統(tǒng)相關(guān)的,在Linux系統(tǒng)上可能是調(diào)用V4L2接口的線程丙号,而在Mac系統(tǒng)上可能是調(diào)用AVFoundation框架的接口先朦。接下來原始數(shù)據(jù)VideoFrame從Capture線程到達(dá)Worker線程缰冤,Worker線程起搬運(yùn)工的作用,沒有對(duì)數(shù)據(jù)做特別處理喳魏,而是轉(zhuǎn)發(fā)到Encoder線程棉浸。Encoder線程調(diào)用具體的編碼器(如VP8, H264)對(duì)原始數(shù)據(jù)VideoFrame進(jìn)行編碼,編碼后的輸出進(jìn)一步進(jìn)行RTP封包形成RTP數(shù)據(jù)包刺彩。然后RTP數(shù)據(jù)包發(fā)送到Pacer線程進(jìn)行平滑發(fā)送涮拗,Pacer線程會(huì)把RTP數(shù)據(jù)包推送到Network線程。最終Network線程調(diào)用傳輸層系統(tǒng)函數(shù)把數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)迂苛。

在接收端三热,Network線程從網(wǎng)絡(luò)接收字節(jié)流,接著Worker線程反序列化為RTP數(shù)據(jù)包三幻,并在VCM模塊進(jìn)行組幀操作就漾。Decoder線程對(duì)組幀完成的數(shù)據(jù)幀進(jìn)行解碼操作,解碼后的原始數(shù)據(jù)VideoFrame會(huì)推送到IncomingVideoStream線程念搬,該線程把VideoStream投放到render進(jìn)行渲染顯示抑堡。至此,一幀視頻數(shù)據(jù)完成從采集到顯示的完整過程朗徊。

在上述過程中首妖,RTP數(shù)據(jù)包產(chǎn)生在發(fā)送端編碼完成后,其編碼輸出被封裝為RTP報(bào)文爷恳,然后經(jīng)序列化發(fā)送到網(wǎng)絡(luò)有缆。在接收端由網(wǎng)絡(luò)線程收到網(wǎng)絡(luò)數(shù)據(jù)包后,經(jīng)過反序列化還原成RTP報(bào)文温亲,然后經(jīng)過解包得到媒體數(shù)據(jù)負(fù)載棚壁,供解碼器進(jìn)行解碼。RTP報(bào)文在發(fā)送和接收過程中栈虚,會(huì)執(zhí)行一系列統(tǒng)計(jì)操作袖外,統(tǒng)計(jì)結(jié)果作為數(shù)據(jù)源供構(gòu)造RTCP報(bào)文之用。RTP報(bào)文構(gòu)造魂务、發(fā)送/接收統(tǒng)計(jì)和RTCP報(bào)文構(gòu)造曼验、解析反饋,是接下來分析的重點(diǎn)粘姜。

四 RTP報(bào)文發(fā)送和接收

RTP報(bào)文的構(gòu)造和發(fā)送發(fā)生在編碼器編碼之后鬓照、網(wǎng)絡(luò)層發(fā)送數(shù)據(jù)包之前,而接收和解包發(fā)生在網(wǎng)絡(luò)層接收數(shù)據(jù)之后相艇、解碼器編碼之前颖杏。本節(jié)詳細(xì)分析這兩部分的內(nèi)容。

4.1 RTP報(bào)文構(gòu)造和發(fā)送

圖2描述發(fā)送端編碼之后RTP報(bào)文的構(gòu)造和發(fā)送過程坛芽,涉及三個(gè)線程:Encoder留储、Pacer和Network翼抠,分別負(fù)責(zé)編碼和構(gòu)造RTP報(bào)文,平滑發(fā)送和傳輸層發(fā)送获讳。下面詳細(xì)描述這三個(gè)線程的協(xié)同工作過程阴颖。

image

圖2 RTP報(bào)文構(gòu)造和發(fā)送

Encode線程調(diào)用編碼器(比如VP8)對(duì)采集到的Raw VideoFrame進(jìn)行編碼,編碼完成以后丐膝,其輸出EncodedImage通過回調(diào)到達(dá)VideoSendStream::Encoded()函數(shù)量愧,進(jìn)而通過PayloadRouter路由到ModuleRtpRtcpImpl::SendOutgoingData()。接下來帅矗,該函數(shù)向下調(diào)用RtpSender::SendOutgoingData()偎肃,進(jìn)而調(diào)用RtpSenderVideo::SendVideo()。該函數(shù)對(duì)EncodedImage進(jìn)行打包浑此,然后填充RTP頭部構(gòu)造RTP報(bào)文累颂;如果配置了FEC,則進(jìn)一步封裝為FEC報(bào)文凛俱。最后返回RtpSender::SendToNetwork()進(jìn)行下一步發(fā)送紊馏。

RtpSender::SendToNetwork()函數(shù)把報(bào)文存儲(chǔ)到RTPPacketHistory結(jié)構(gòu)中進(jìn)行緩存。接下來如果開啟PacedSending蒲犬,則構(gòu)造Packe發(fā)送到PacedSender進(jìn)行排隊(duì)朱监,否則直接發(fā)送到網(wǎng)絡(luò)層。

Pacer線程周期性從隊(duì)列中獲取Packet原叮,然后調(diào)用PacedSender::SendPacket()進(jìn)行發(fā)送赫编,接下來經(jīng)過ModuleRtpRtcpImpl到達(dá)RtpSender::TimeToSendPacket()。該函數(shù)首先從RtpPacketHistory緩存中拿到Packet的負(fù)載篇裁,然后調(diào)用PrepareAndSendPacket()函數(shù):更新RtpHeader的相關(guān)域沛慢,統(tǒng)計(jì)延遲和數(shù)據(jù)包赡若,調(diào)用SendPacketToNetwork()把報(bào)文發(fā)送到傳輸模塊达布。

Network線程則調(diào)用傳輸層套接字執(zhí)行數(shù)據(jù)發(fā)送操作。至此逾冬,發(fā)送端的RTP構(gòu)造和發(fā)送流程完成黍聂。需要注意的是,在RtpSender中進(jìn)行Rtp發(fā)送后身腻,會(huì)統(tǒng)計(jì)RTP報(bào)文相關(guān)信息产还。這些信息作為RTCP構(gòu)造SR/RR報(bào)文的數(shù)據(jù)來源,因此非常重要嘀趟。

4.2 RTP報(bào)文接收和解析

在接收端脐区,RTP報(bào)文的接收和解包操作主要在Worker線程中執(zhí)行,RTP報(bào)文從Network線程拿到后她按,進(jìn)入Worker線程牛隅,經(jīng)過解包操作炕柔,進(jìn)入VCM模塊,由Decode線程進(jìn)行解碼媒佣,最終由Render線程進(jìn)行渲染匕累。下圖3描述RTP報(bào)文在Worker線程中的處理流程。

image

圖3 RTP報(bào)文接收和解析

RTP數(shù)據(jù)包經(jīng)網(wǎng)絡(luò)層到達(dá)Call對(duì)象默伍,根據(jù)其SSRC找到對(duì)應(yīng)的VideoReceiveStream欢嘿,通過調(diào)用其DeliverRtp()函數(shù)到RtpStreamReceiver::DeliverRtp()。該函數(shù)首先解析數(shù)據(jù)包得到RTP頭部信息也糊,接下來執(zhí)行三個(gè)操作:1.碼率估計(jì)炼蹦;2.繼續(xù)發(fā)送數(shù)據(jù)包;3.接收統(tǒng)計(jì)狸剃。碼率估計(jì)模塊使用GCC算法估計(jì)碼率框弛,構(gòu)造REMB報(bào)文,交給RtpRtcp模塊發(fā)送回發(fā)送端捕捂。而接收統(tǒng)計(jì)則統(tǒng)計(jì)RTP接收信息瑟枫,這些信息作為RTCP RR報(bào)文的數(shù)據(jù)來源。下面重點(diǎn)分析接下來的數(shù)據(jù)包發(fā)送流程指攒。

RtpStreamReceiver::ReceivePacket()首先判斷數(shù)據(jù)包是否是FEC報(bào)文慷妙,如果是則調(diào)用FecReceiver進(jìn)行解包,否則直接調(diào)用RtpReceiver::IncomingRtpPacket()允悦。該函數(shù)分析RTP報(bào)文得到通用的RTP頭部描述結(jié)構(gòu)膝擂,然后調(diào)用RtpReceiverVideo::ParseRtpPacket()進(jìn)一步得到Video相關(guān)信息和負(fù)載,接著經(jīng)過回調(diào)返回RtpStreamReceiver對(duì)象隙弛。該對(duì)象把Rtp描述信息和負(fù)載發(fā)送到VCM模塊架馋,繼續(xù)接下來的JitterBuffer緩存和解碼渲染操作。

RTP報(bào)文解包過程是封包的逆過程全闷,重要的輸出信息是RTP頭部描述和媒體負(fù)載叉寂,這些信息是下一步JitterBuffer緩存和解碼的基礎(chǔ)。另外對(duì)RTP報(bào)文進(jìn)行統(tǒng)計(jì)得到的信息則是RTCP RR報(bào)文的數(shù)據(jù)來源总珠。

五 RTCP報(bào)文發(fā)送和接收

RTCP協(xié)議是RTP協(xié)議的控制下可以屏鳍,負(fù)責(zé)流媒體的服務(wù)質(zhì)量保證。比較常用的RTCP報(bào)文由發(fā)送端報(bào)告SR和接收端報(bào)告RR局服,分別包含數(shù)據(jù)發(fā)送統(tǒng)計(jì)信息和數(shù)據(jù)接收信息钓瞭。這些信息對(duì)于流媒體質(zhì)量保證非常重要,比如碼率控制淫奔、負(fù)載反饋山涡,等等。其他RTCP報(bào)文還有諸如SDES、BYE鸭丛、SDES等霍殴,RFC3550對(duì)此有詳細(xì)定義。

本節(jié)重點(diǎn)分析WebRTC內(nèi)部RTCP報(bào)文的構(gòu)造系吩、發(fā)送来庭、接收、解析穿挨、反饋等流程月弛。需要再次強(qiáng)調(diào)的是,RTCP報(bào)文的數(shù)據(jù)源來自RTP報(bào)文發(fā)送和接收時(shí)的統(tǒng)計(jì)信息科盛。在WebRTC內(nèi)部帽衙,RTCP報(bào)文的發(fā)送采取周期性發(fā)送和及時(shí)發(fā)送相結(jié)合的策略:ModuleProcess線程周期性發(fā)送RTCP報(bào)文;而RtpSender則在每次發(fā)送RTP報(bào)文之前都判斷是否需要發(fā)送RTCP報(bào)文贞绵;另外在接收端碼率估計(jì)模塊構(gòu)造出REMB報(bào)文后厉萝,通過設(shè)置超時(shí)讓ModuleProcess模塊立即發(fā)送RTCP報(bào)文。

5.1 RTCP報(bào)文構(gòu)造和發(fā)送

在發(fā)送端榨崩,RTCP以周期性發(fā)送為基準(zhǔn)谴垫,輔以RTP報(bào)文發(fā)送時(shí)的及時(shí)發(fā)送和REMB報(bào)文的立即發(fā)送。發(fā)送過程主要包括Feedback信息獲取母蛛、RTCP報(bào)文構(gòu)造翩剪、序列化和發(fā)送。圖4描述了RTCP報(bào)文的構(gòu)造和發(fā)送過程彩郊。

image

圖4 RTCP報(bào)文構(gòu)造和發(fā)送

ModuleProcess線程周期性調(diào)用ModuleRtpRtcpImpl::Process()函數(shù)前弯,該函數(shù)通過RTCPSender::TimeToSendRtcpReport()函數(shù)確定當(dāng)前是否需要立即發(fā)送RTCP報(bào)文。若是秫逝,則首先從RTPSender::GetDataCounters()獲取RTP發(fā)送統(tǒng)計(jì)信息恕出,然后調(diào)用RTCPSender::SendRTCP(),接著是SendCompoundRTCP()發(fā)送RTCP組合報(bào)文违帆。關(guān)于RTCP組合報(bào)文的定義浙巫,請(qǐng)參考文獻(xiàn)[1]。

在SendCompoundRTCP()函數(shù)中前方,首先通過PrepareReport()確定將要發(fā)送何種類型的RTCP報(bào)文狈醉。然后針對(duì)每一種報(bào)文,調(diào)用其構(gòu)造函數(shù)(如構(gòu)造SR報(bào)文為BuildSR()函數(shù))惠险,構(gòu)造好的報(bào)文存儲(chǔ)在PacketContainer容器中。最后調(diào)用SendPackets()進(jìn)行發(fā)送抒线。

接下來每種RTCP報(bào)文都會(huì)調(diào)用各自的序列化函數(shù)班巩,把報(bào)文序列化為網(wǎng)絡(luò)字節(jié)流。最后通過回調(diào)到達(dá)PacketContainer::OnPacketReady(),最終把字節(jié)流發(fā)送到傳輸層模塊:即通過TransportAdapter到達(dá)BaseChannel抱慌,Network線程調(diào)用傳輸層套接字API發(fā)送數(shù)據(jù)到網(wǎng)絡(luò)逊桦。

RTCP報(bào)文的構(gòu)造和發(fā)送過程總體不是很復(fù)雜,最核心的操作就是獲取數(shù)據(jù)源抑进、構(gòu)造報(bào)文强经、序列化和發(fā)送。相對(duì)來說構(gòu)造報(bào)文和序列化比較繁瑣寺渗,基于RFC定義的細(xì)節(jié)進(jìn)行匿情。

5.2 RTCP報(bào)文接收和解析

接收端的RTCP報(bào)文接收和解析過程如圖5所示。

image

圖5 RTCP報(bào)文接收和解析

在接收端信殊,RTCP報(bào)文的接收流程和RTP一樣炬称,經(jīng)過網(wǎng)絡(luò)接收之后到達(dá)Call對(duì)象,進(jìn)而通過SSRC找到VideoReceiveStream涡拘,繼而到達(dá)RtpStreamReceiver玲躯。接下來RTCP報(bào)文的解析和反饋操作都在ModuleRtpRtcpImpl::IncomingRtcpPacket()函數(shù)中完成。該函數(shù)首先調(diào)用RTCPReceiver::IncomingRtcpPacket()解析RTCP報(bào)文鳄乏,得到RTCPPacketInformation對(duì)象跷车,然后調(diào)用 TriggerCallbacksFromRTCPPacket(),觸發(fā)注冊(cè)在此處的各路觀察者執(zhí)行回調(diào)操作橱野。

RTCPReceiver::IncomingRtcpPacket()使用RTCPParser解析組合報(bào)文姓赤,針對(duì)每一種報(bào)文類型,調(diào)用對(duì)應(yīng)的處理函數(shù)(如處理SDES的HandleSDES函數(shù))仲吏,反序列化后拿到報(bào)文的描述結(jié)構(gòu)不铆。最后所有報(bào)文綜合在一起形成RTCPPacketInformation對(duì)象。該對(duì)象接下來作為參數(shù)調(diào)用TriggerCallbacksFromRTCPPacket()函數(shù)觸發(fā)回調(diào)操作裹唆,如處理NACK的回調(diào)誓斥,處理SLI的回調(diào),處理REMB的回調(diào)许帐,等等劳坑。這些回調(diào)在各自模塊控制流媒體數(shù)據(jù)的編碼、發(fā)送成畦、碼率等服務(wù)質(zhì)量保證距芬,這也是RTCP報(bào)文最終起作用的地方。

至此循帐,我們分析了RTCP報(bào)文發(fā)送和接收的整個(gè)流程框仔。

六 總結(jié)

本文在深入分析WebRTC源代碼的基礎(chǔ)上,結(jié)合流程圖描述出RTP/RTCP模塊的實(shí)現(xiàn)流程拄养,在關(guān)鍵問題上(如RTCP報(bào)文的數(shù)據(jù)來源)進(jìn)行深入細(xì)致的研究离斩。為進(jìn)一步深入掌握WebRTC的實(shí)現(xiàn)原理和細(xì)節(jié)打下良好基礎(chǔ)。

參考文獻(xiàn)

[1] RFC3550 - RTP: A Transport Protocol for Real-Time Applications
https://www.ietf.org/rfc/rfc3550.txt

[2] 超越RFC3550 - RTP/RTCP協(xié)議族分析 : http://www.reibang.com/p/e5e21aeb219f

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市跛梗,隨后出現(xiàn)的幾起案子寻馏,更是在濱河造成了極大的恐慌,老刑警劉巖核偿,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诚欠,死亡現(xiàn)場離奇詭異,居然都是意外死亡漾岳,警方通過查閱死者的電腦和手機(jī)轰绵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝗羊,“玉大人藏澳,你說我怎么就攤上這事∫遥” “怎么了翔悠?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長野芒。 經(jīng)常有香客問我蓄愁,道長,這世上最難降的妖魔是什么狞悲? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任撮抓,我火速辦了婚禮,結(jié)果婚禮上摇锋,老公的妹妹穿的比我還像新娘丹拯。我一直安慰自己,他們只是感情好荸恕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布乖酬。 她就那樣靜靜地躺著,像睡著了一般融求。 火紅的嫁衣襯著肌膚如雪咬像。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天生宛,我揣著相機(jī)與錄音县昂,去河邊找鬼。 笑死陷舅,一個(gè)胖子當(dāng)著我的面吹牛倒彰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔑赘,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼狸驳,長吁一口氣:“原來是場噩夢啊……” “哼预明!你這毒婦竟也來了缩赛?” 一聲冷哼從身側(cè)響起耙箍,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎酥馍,沒想到半個(gè)月后辩昆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旨袒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年汁针,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砚尽。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡施无,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出必孤,到底是詐尸還是另有隱情猾骡,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布敷搪,位于F島的核電站兴想,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏赡勘。R本人自食惡果不足惜嫂便,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望闸与。 院中可真熱鬧毙替,春花似錦、人聲如沸践樱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽映胁。三九已至木羹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間解孙,已是汗流浹背坑填。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弛姜,地道東北人脐瑰。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像廷臼,于是被迫代替她去往敵國和親苍在。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绝页,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容