當前位置:首頁 » 存儲配置 » webrtc視頻存儲伺服器

webrtc視頻存儲伺服器

發布時間: 2023-02-24 22:37:21

A. webrtc哪些程序放在伺服器

一) sipdroid
1)架構
sip協議棧使用java實現,音頻Codec使用skype的silk(Silk編解碼是Skype向第三方開發人員和硬體製造商提供免版稅認證(RF)的Silk寬頻音頻編碼器)實現。NAT傳輸支持stun server.
2)優缺點:
NAT方面只支持STUN,無ICE框架,如需要完全實現P2P視頻通話需要實現符合ICE標準的客戶端,音頻方面沒看到AEC等技術,視頻方面還不是太完善,目前只看到調用的是系統自帶的MediaRecorder,並沒有自己的第三方音視頻編解碼庫。
3)實際測試:
基於sipdroid架構的話,我們要做的工作會比較多,(ICE支持,添加迴音消除,NetEQ等gips音頻技術,添加視頻硬體編解碼codec.),所以就不做測試了。

二) imsdroid
1)架構:
基於doubango(Doubango 是一個基於3GPP IMS/RCS 並能用於嵌入式和桌面系統的開源框架。該框架使用ANSCI-C編寫,具有很好的可移植性。並且已經被設計成非常輕便且能有效的工作在低內存和低處理能力的嵌入式系統上。蘋果系統上的idoubs功能就是基於此框架編寫) .音視頻編碼格式大部分都支持(H264(video),VP8(video),iLBC(audio),PCMA,PCMU,G722,G729)。NAT支持ICE(stun+turn)
2)效果實測
測試環境:公司區域網內兩台機器互通,伺服器走外網sip2sip
音頻質量可以,但是AEC打開了還是有點迴音(應該可以修復)。視頻馬賽克比較嚴重,延遲1秒左右。
3)優缺點
imsdroid目前來說還是算比較全面的,包括音視頻編解碼,傳輸(RTSP,ICE),音頻處理技術等都有涉獵。doubango使用了webrtc的AEC技術,但是其調用webrtc部分沒有開源,是用的編譯出來的webrtc的庫。如果要改善音頻的話不太方便,Demo的音頻效果可以,視頻效果還是不太理想。

三)csipsimple
1)sip協議棧用的是pjsip,音視頻編解碼用到的第三方庫有ffmpeg(video),silk(audio),webrtc.默認使用了webrtc的回聲演算法。支持ICE協議。
2)優缺點:
csipsimple架構比較清晰,sip協議由C實現,java通過JNI調用,SIP協議這一塊會比較高效。其VOIP各個功能也都具備,包括NAT傳輸,音視頻編解碼。並且該項目跟進新技術比較快,官方活躍程度也比較高。如果做二次開發可以推薦這個。
3)實測效果
測試環境:公司區域網內兩台機器互通,伺服器走外網sip2sip
音頻質量可以,無明顯迴音,視頻需要下插件,馬賽克比imsdroid更嚴重。

四)Linphone

這個是老牌的sip,支持平台廣泛 windows, mac,ios,android,linux,技術會比較成熟。但是據玩過的同事說linphone在Android上的bug有點多,由於其代碼實在龐大,所以我暫時放棄考慮Linphone.不過如果誰有跨平台的需要,可以考慮Linphone或者imsdroid和下面的webrtc.。。。好像現在開源軟體都跨平台了。。。

五) webrtc

imsdroid,csipsimple,linphone都想法設法調用webrtc的音頻技術,本人也測試過Android端的webrtc內網視頻通話,效果比較滿意。但是要把webrtc做成一個移動端的IM軟體的話還有一些路要走,不過webrtc基本技術都已經有了,包括p2p傳輸,音視頻codec,音頻處理技術。不過其因為目前僅支持VP8的視頻編碼格式(QQ也是)想做高清視頻通話的要注意了。VP8在移動端的硬體編解碼支持的平台沒幾個(RK可以支持VP8硬體編解碼)。不過webrtc代碼里看到可以使用外部codec,這個還是有希望調到H264的。

總結:sipdroid比較輕量級,著重基於java開發(音頻codec除外),由於其音視頻編碼以及P2P傳輸這一塊略顯不足,不太好做定製化開發和優化。imsdroid,遺憾就是直接調用webrtc的庫,而最近webrtc更新的比較頻繁,開發比較活躍。如果要自己在imsdroid上更新webrtc擔心兼容性問題,希望imsdroid可以直接把需要的webrtc相關源碼包進去。csipsimple的話,都是圍繞pjsip的,webrtc等都是以pjsip插件形式擴充的,類似gstreamer. webrtc如果有技術實力的開發公司個人還是覺得可以選擇這個來做,一個是google的原因,一個是其視頻通話相關關鍵技術都比較成熟的原因。個人覺得如果能做出來,效果會不錯的。

B. webrtc伺服器需要多少帶寬

webrtc中的帶寬自適應演算法分為兩種:
1,發端帶寬控制,原理是由rtcp中的丟包統計來動態的增加或減少帶寬,在減少帶寬時使用TFRC演算法來增加平滑度。
2,收端帶寬估算,原理是並由收到rtp數據,估出帶寬;用卡爾曼濾波,對每一幀的發送時間和接收時間進行分析,從而得出網路帶寬利用情況,修正估出的帶寬。

兩種演算法相輔相成,收端將估算的帶寬發送給發端,發端結合收到的帶寬以及丟包率,調整發送的帶寬。

下面具體分析兩種演算法:

2, 接收端帶寬估算演算法分析
結合文檔http://tools.ietf.org/html/draft-alvestrand-rtcweb-congestion-02以及源碼webrtc/moles/remote_bitrate_estimator/overuse_detector.cc進行分析
帶寬估算模型: d(i) = dL(i) / c + w(i) d(i)兩幀數據的網路傳輸時間差,dL(i)兩幀數據的大小差, c為網路傳輸能力, w(i)是我們關注的重點, 它主要由三個因素決定:發送速率, 網路路由能力, 以及網路傳輸能力。w(i)符合高斯分布, 有如下結論:當w(i)增加是,佔用過多帶寬(over-using);當w(i)減少時,佔用較少帶寬(under-using);為0時,用到恰好的帶寬。所以,只要我們能計算出w(i),即能判斷目前的網路使用情況,從而增加或減少發送的速率。

演算法原理:即應用kalman-filters
theta_hat(i) = [1/C_hat(i) m_hat(i)]^T // i時間點的狀態由C, m共同表示,theta_hat(i)即此時的估算值
z(i) = d(i) - h_bar(i)^T * theta_hat(i-1) //d(i)為測試值,可以很容易計算出, 後面的可以認為是d(i-1)的估算值, 因此z(i)就是d(i)的偏差,即resial
theta_hat(i) = theta_hat(i-1) + z(i) * k_bar(i) //好了,這個就是我們要的結果,關鍵是k值的選取,下面兩個公式即是取k值的,具體推導見後繼博文。
E(i-1) * h_bar(i)
k_bar(i) = --------------------------------------------
var_v_hat + h_bar(i)^T * E(i-1) * h_bar(i)
E(i) = (I - K_bar(i) * h_bar(i)^T) * E(i-1) + Q(i) // h_bar(i)由幀的數據包大小算出
由此可見,我們只需要知道當前幀的長度,發送時間,接收時間以及前一幀的狀態,就可以計算出網路使用情況。
接下來具體看一下代碼:

[cpp] view
plain

void OveruseDetector::UpdateKalman(int64_t t_delta,
double ts_delta,
uint32_t frame_size,
uint32_t prev_frame_size) {
const double min_frame_period = UpdateMinFramePeriod(ts_delta);
const double drift = CurrentDrift();
// Compensate for drift
const double t_ts_delta = t_delta - ts_delta / drift; //即d(i)
double fs_delta = static_cast<double>(frame_size) - prev_frame_size;

// Update the Kalman filter
const double scale_factor = min_frame_period / (1000.0 / 30.0);
E_[0][0] += process_noise_[0] * scale_factor;
E_[1][1] += process_noise_[1] * scale_factor;

if ((hypothesis_ == kBwOverusing && offset_ < prev_offset_) ||
(hypothesis_ == kBwUnderusing && offset_ > prev_offset_)) {
E_[1][1] += 10 * process_noise_[1] * scale_factor;
}

const double h[2] = {fs_delta, 1.0}; //即h_bar
const double Eh[2] = {E_[0][0]*h[0] + E_[0][1]*h[1],
E_[1][0]*h[0] + E_[1][1]*h[1]};

const double resial = t_ts_delta - slope_*h[0] - offset_; //即z(i), slope為1/C

const bool stable_state =
(BWE_MIN(num_of_deltas_, 60) * fabsf(offset_) < threshold_);
// We try to filter out very late frames. For instance periodic key
// frames doesn't fit the Gaussian model well.
if (fabsf(resial) < 3 * sqrt(var_noise_)) {
UpdateNoiseEstimate(resial, min_frame_period, stable_state);
} else {
UpdateNoiseEstimate(3 * sqrt(var_noise_), min_frame_period, stable_state);
}

const double denom = var_noise_ + h[0]*Eh[0] + h[1]*Eh[1];

const double K[2] = {Eh[0] / denom,
Eh[1] / denom}; //即k_bar

const double IKh[2][2] = {{1.0 - K[0]*h[0], -K[0]*h[1]},
{-K[1]*h[0], 1.0 - K[1]*h[1]}};
const double e00 = E_[0][0];
const double e01 = E_[0][1];

// Update state
E_[0][0] = e00 * IKh[0][0] + E_[1][0] * IKh[0][1];
E_[0][1] = e01 * IKh[0][0] + E_[1][1] * IKh[0][1];
E_[1][0] = e00 * IKh[1][0] + E_[1][0] * IKh[1][1];
E_[1][1] = e01 * IKh[1][0] + E_[1][1] * IKh[1][1];

// Covariance matrix, must be positive semi-definite
assert(E_[0][0] + E_[1][1] >= 0 &&
E_[0][0] * E_[1][1] - E_[0][1] * E_[1][0] >= 0 &&
E_[0][0] >= 0);

slope_ = slope_ + K[0] * resial; //1/C
prev_offset_ = offset_;
offset_ = offset_ + K[1] * resial; //theta_hat(i)

Detect(ts_delta);
}

[cpp] view
plain

BandwidthUsage OveruseDetector::Detect(double ts_delta) {
if (num_of_deltas_ < 2) {
return kBwNormal;
}
const double T = BWE_MIN(num_of_deltas_, 60) * offset_; //即gamma_1
if (fabsf(T) > threshold_) {
if (offset_ > 0) {
if (time_over_using_ == -1) {
// Initialize the timer. Assume that we've been
// over-using half of the time since the previous
// sample.
time_over_using_ = ts_delta / 2;
} else {
// Increment timer
time_over_using_ += ts_delta;
}
over_use_counter_++;
if (time_over_using_ > kOverUsingTimeThreshold //kOverUsingTimeThreshold是gamma_2, gamama_3=1
&& over_use_counter_ > 1) {
if (offset_ >= prev_offset_) {
time_over_using_ = 0;
over_use_counter_ = 0;
hypothesis_ = kBwOverusing;
}
}
} else {
time_over_using_ = -1;
over_use_counter_ = 0;
hypothesis_ = kBwUnderusing;
}
} else {
time_over_using_ = -1;
over_use_counter_ = 0;
hypothesis_ = kBwNormal;
}
return hypothesis_;
}

C. 使用WebRTC搭建前端視頻聊天室——點對點通信篇

WebRTC給我們帶來了瀏覽器中的視頻、音頻聊天體驗。但個人認為,它最實用的特性莫過於DataChannel——在瀏覽器之間建立一個點對點的數據通道。在DataChannel之前,瀏覽器到瀏覽器的數據傳遞通常是這樣一個流程:瀏覽器1發送數據給伺服器,伺服器處理,伺服器再轉發給瀏覽器2。這三個過程都會帶來相應的消耗,佔用伺服器帶寬不說,還減緩了消息從發送到接收的時間。其實最理想的方式就是瀏覽器1直接與瀏覽2進行通信,伺服器不需要參與其中。WebRTC DataChannel就提供了這樣一種方式。

如果對WebRTC和DataChannel不太了解的同學,可以先閱讀如下文章:

- WebRTC的RTCDataChannel

- 使用WebRTC搭建前端視頻聊天室——信令篇

- 使用WebRTC搭建前端視頻聊天室——入門篇

當然伺服器完全不參與其中,顯然是不可能的,用戶需要通過伺服器上存儲的信息,才能確定需要和誰建立連接。這里通過一個故事來講述建立連接的過程:

不如釣魚去

一些背景:

現在,老劉聽說老姚釣魚技術高超,想和老姚討論釣魚技巧。只要老劉和老姚相互之間知道對方的門牌號以及憑證,就可以串門了:

老劉和老姚相互之間知道了對方的門牌號和小區出入憑證,他們相互之間有什麼需要交流的直接串門就行了,消息不再需要門衛老大爺來代為傳達了

換個角度

我們把角色做一個映射:

於是乎故事就變成了這樣:

這樣,就建立了一個點對點的信道,流程如下所示:

故事

老劉和老姚已經可以相互串門了,經過一段時間的交流感情越來越深。老姚的親友送了20斤葡萄給老姚,老姚決定送10斤給老劉。老姚畢竟年事已高,不可能一次帶10斤。於是乎,老姚將葡萄分成了10份,每次去老劉家串門就送一份過去。

這里可以做如下類比:

這其實就是通過datachannel傳輸文件的方式,首先將文件分片,然後逐個發送,最後再統一的進行組合成一個新的文件

分片

通過HTML5的File API可以將type為file的input選中的文件讀取出來,並轉換成data url字元串。這也就為我們提供了很方便的分片方式:

組合

通過datachannel發送的分片數據,我們需要將其進行組合,由於是data url字元串,在接收到所有包之後進行拼接就可以了。拼接完成後就得到了一個文件完整的data url字元串,那麼我們如何將這個字元串轉換成文件呢?

方案一:直接跳轉下載

既然是個dataurl,我們直接將其賦值給window.location.href自然可以下載,但是這樣下載是沒法設定下載後的文件名的,這想一想都蛋疼

方案二:通過a標簽下載

這個原理和跳轉下載類似,都是使用dataurl本身的特性,通過創建一個a標簽,將dataurl字元串賦值給href屬性,然後使用download確定下載後的文件名,就可以完成下載了。但是很快又有新問題了,稍微大一點的文件下載的時候頁面崩潰了。這是因為dataurl有大小限制

方案三:blob

其實可以通過給a標簽創建blob url的方式來進行下載,這個沒有大小限制。但是我們手上是dataurl,所以需要先進行轉換:

獲得blob後,我們就可以通過URL API來下載了:

這里有幾個點:

1. datachannel其實是可以直接傳送blob的,但是只有ff支持,所以傳data url

2. chrome下載是直接觸發的,不會進行詢問,firefox會先詢問後下載,在詢問過程中如果執行了revokeObjectURL,下載就會取消,囧

升級

如我們所知,WebRTC最有特點的地方其實是可以傳輸getUserMedia獲得的視頻、音頻流,來實現視頻聊天。但事實上我們的使用習慣來看,一般人不會一開始就打開視頻聊天,而且視頻聊天時很消耗內存的(32位機上一個連接至少20M左右好像,也有可能有出入)。所以常見的需求是,先建立一個包含datachannel的連接用於傳輸數據,然後在需要時升級成可以傳輸視頻、音頻。

看看我們之前傳輸的session description,它其實來自Session Description Protocol。可以看到wiki上的介紹:

這意味著什麼呢?我們之前建立datachannel是沒有加視頻、音頻流的,而這個流的描述是寫在SDP裡面的。現在我們需要傳輸視頻、音頻,就需要添加這些描述。所以就得重新獲得SDP,然後構建offer和answer再傳輸一次。傳輸的流程和之前一樣,沒什麼區別。但這一次,我們不需要傳輸任何的ice candidate,這里我曾經遇到了坑,經過國外大大的點撥才明白過來。

Peertc

我將datachannel和websocket組合,實現了一個構建點對點連接的庫Peertc,它提供非常簡潔的方式來建立連接和發送數據、文件和視頻/音頻流,詳情見github。走過路過的記得star一下哦,有什麼bug也非常希望能夠提出來。

最後

WebRTC的點對點方式能夠運用在很多場景:

- 如web qq這種Web IM工具,這就不說了

- 如象棋這種雙人對戰 游戲 ,每一步的數據伺服器時不關心的,所以完全可以點對點發送

- 一對一在線面試、在線教育,這其實是即時通信的一個業務方向

D. 用SRS搭建WebRTC流媒體伺服器實戰

WebRTC經過這么多年的發展,目前已經比較成熟的協議之一,播放也比較穩定,協議也已經成為了RFC,相應的開源項目也越來越多,但是基於WebRTC協議的部署簡單,性能強悍,功能強大流媒體伺服器的項目還比較稀少。之前了解到的伺服器比如Mediasoup,Janus,Medooze ,要麼就是設計復雜,接入成本要,要麼就是性能較差,還就是多種語言結合,學習成本較高。 而SRS聚焦視頻相關,功能專一,語言使用了高性能的c++,並且支持Rtmp轉Webrtc等其他強大的功能的媒體伺服器。

1.源碼編譯安裝運行SRS

使用這個命令開啟RTC支持

2.SRS常用命令

3.配置nginx代理
若不需要瀏覽器推流,可以不用設置nginx代理,使用localhost訪問

注意:your 代表需要配置你自己的域名信息,由於使用瀏覽器推流必須使用https協議,所以我這邊配置了證書
4.訪問配置的域名
訪問nginx配置的網址 https://webrtc.yourhost.com/
出現如下內容,則服務端架設成功

雖然整片文章看起來不復雜,流程很簡單。但是官網的文檔中的知識點比較分散,所以大家要想快速的搭建的話就參考我這篇文章

熱點內容
電腦我的世界伺服器地址怎麼輸 發布:2025-07-08 04:28:33 瀏覽:646
js裁剪上傳 發布:2025-07-08 04:27:51 瀏覽:507
怎麼復制密碼欄的密碼安卓 發布:2025-07-08 04:27:47 瀏覽:9
jquery上傳多張圖片 發布:2025-07-08 04:26:44 瀏覽:824
python是腳本語言主要用作 發布:2025-07-08 04:25:54 瀏覽:761
安卓怎麼傳視頻 發布:2025-07-08 04:03:26 瀏覽:914
oracle測試sql 發布:2025-07-08 03:16:54 瀏覽:974
php壁紙源碼 發布:2025-07-08 03:04:26 瀏覽:321
android應用層 發布:2025-07-08 02:42:32 瀏覽:301
大唐存儲銷量 發布:2025-07-08 02:41:11 瀏覽:582