webrtc58 中的音訊採集
關於webrtc中的音訊採集,當然和是各個平臺採集具體實現,上層封裝統一介面;
從資料來源來看,音訊資料來自於class AudioDeviceModule;
然後檢視:
virtual int32_t RegisterAudioCallback(AudioTransport* audioCallback) = 0;
class AudioTransport {
public:
virtual int32_t RecordedDataIsAvailable(const void* audioSamples,
const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
const uint32_t totalDelayMS,
const int32_t clockDrift,
const uint32_t currentMicLevel,
const bool keyPressed,
uint32_t& newMicLevel) = 0;
virtual int32_t NeedMorePlayData(const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
void* audioSamples,
size_t& nSamplesOut,
int64_t* elapsed_time_ms,
int64_t* ntp_time_ms) = 0;
// Method to push the captured audio data to the specific VoE channel.
// The data will not undergo audio processing.
// |voe_channel| is the id of the VoE channel which is the sink to the
// capture data.
// TODO(bugs.webrtc.org/8659): Remove this method once clients updated.
RTC_DEPRECATED virtual void PushCaptureData(
int voe_channel,
const void* audio_data,
int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames) {
RTC_NOTREACHED();
}
// Method to pull mixed render audio data from all active VoE channels.
// The data will not be passed as reference for audio processing internally.
virtual void PullRenderData(int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames,
void* audio_data,
int64_t* elapsed_time_ms,
int64_t* ntp_time_ms) = 0;
protected:
virtual ~AudioTransport() {}
};
嗯,就是這了;
這裡除錯跟蹤的是Windows端的程式碼: 從下往上看,
VoEBaseImpl::RecordedDataIsAvailable(const void * audioSamples, const unsigned __int64 nSamples, const unsigned __int64 nBytesPerSample, const unsigned __int64 nChannels, const unsigned int samplesPerSec, const unsigned int totalDelayMS, const int clockDrift, const unsigned int currentMicLevel, const bool keyPressed, unsigned int & newMicLevel)
AudioTransportProxy::RecordedDataIsAvailable(const void * audioSamples, const unsigned __int64 nSamples, const unsigned __int64 nBytesPerSample, const unsigned __int64 nChannels, const unsigned int samplesPerSec, const unsigned int totalDelayMS, const int clockDrift, const unsigned int currentMicLevel, const bool keyPressed, unsigned int & newMicLevel)
AudioDeviceBuffer::DeliverRecordedData()
AudioDeviceWindowsCore::DoCaptureThread()
AudioDeviceWindowsCore::WSAPICaptureThread(void * context)
從上述程式碼流程可以看出,先從平臺相關實現獲取具體音訊PCM資料,然後經過傳送到VoEBaseImpl::RecordedDataIsAvailable;
這裡的資料採集為什麼說道這裡呢?因為:在VoEBaseImpl::RecordedDataIsAvailable函式中還執行了相關的一些資料函式;
所以,要獲取音訊資料,最好在ProcessRecordedDataWithAPM函式之後獲取音訊;
int32_t VoEBaseImpl::RecordedDataIsAvailable(const void* audioSamples,
const size_t nSamples,
const size_t nBytesPerSample,
const size_t nChannels,
const uint32_t samplesPerSec,
const uint32_t totalDelayMS,
const int32_t clockDrift,
const uint32_t currentMicLevel,
const bool keyPressed,
uint32_t& newMicLevel) {
newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM
nullptr, 0, audioSamples, samplesPerSec, nChannels, nSamples,
totalDelayMS, clockDrift, currentMicLevel, keyPressed));
}
寫在後面: 根據webrtc58版本中的示例,可以看出,已經預留了了音訊獲取的資料回撥函式介面OnData;
只不過在webrtc58版本中沒有實現完成,所以在後去版本中,應該會實現。
ProcessRecordedDataWithAPM 函式中實現了音訊的處理,encode,rtp打包,rtp 傳送等;內容比較多;
本來想單獨寫一遍文章,但是為了內容的連續性,就在這類繼續寫了;
//直接獲取音訊PCM編碼後的資料
encoded_info = encoder_stack_->Encode(
rtp_timestamp, rtc::ArrayView<const int16_t>(
input_data.audio, input_data.audio_channel *
input_data.length_per_channel),
&encode_buffer_);
AudioCodingModuleImpl::Encode(const webrtc::`anonymous-namespace'::AudioCodingModuleImpl::InputData & input_data)
AudioCodingModuleImpl::Add10MsData(const webrtc::AudioFrame & audio_frame)
voe::Channel::EncodeAndSend()
voe::TransmitMixer::EncodeAndSend()
VoEBaseImpl::ProcessRecordedDataWithAPM(const int * voe_channels, unsigned __int64 number_of_voe_channels, const void * audio_data, unsigned int sample_rate, unsigned __int64 number_of_channels, unsigned __int64 number_of_frames, unsigned int audio_delay_milliseconds, int clock_drift, unsigned int volume, bool key_pressed)
每次獲取10Ms的音訊資料,然後進行音訊資料的處理,然後進行編碼;
webrtc會將各類編碼具體實現,都具基礎實現 public AudioEncoder ;
如:
class AudioEncoderOpus final : public AudioEncoder
class AudioEncoderG722 final : public AudioEncoder
PCM編碼完成後,傳送資料,其實,就是進入了:int32_t Channel::SendData
if (packetization_callback_) {
packetization_callback_->SendData(
frame_type, encoded_info.payload_type, encoded_info.encoded_timestamp,
encode_buffer_.data(), encode_buffer_.size(),
my_fragmentation.fragmentationVectorSize > 0 ? &my_fragmentation
: nullptr);
然後:
// Push data from ACM to RTP/RTCP-module to deliver audio frame for
// packetization.
// This call will trigger Transport::SendPacket() from the RTP/RTCP module.
if (!_rtpRtcpModule->SendOutgoingData(
(FrameType&)frameType, payloadType, timeStamp,
// Leaving the time when this frame was
// received from the capture device as
// undefined for voice for now.
-1, payloadData, payloadSize, fragmentation, nullptr, nullptr)) {
_engineStatisticsPtr->SetLastError(
VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
"Channel::SendData() failed to send data to RTP/RTCP module");
return -1;
}
...
然後:
實現音訊資料的RTP打包,然後傳送,高優先順序;
bool RTPSenderAudio::SendAudio
bool send_result = rtp_sender_->SendToNetwork(
std::move(packet), kAllowRetransmission, RtpPacketSender::kHighPriority);
然後:
新增到傳送快取:
paced_sender_->InsertPacket(priority, ssrc, seq_no, corrected_time_ms,
payload_length, false);
//void PacedSender::InsertPacket //執行到這裡;
//這個類實現了平滑傳送資料,同時根據位元速率控制傳送資料;
class PacedSender : public Module, public RtpPacketSender
通過PacedSender::InsertPacket新增rtp packet, 新增到 packets_ 連結串列中;
通過 PacedSender::Process實現packets_ 連結串列中中的資料計算,傳送;通常這個函式會在一個單獨的執行緒中執行;
關於 PacedSender 可以檢視這篇文章:http://blog.csdn.net/qq_24283329/article/details/72899322 《傳送位元速率控制之PacedSender模組》
資料的傳送:
ricket::UDPPort::SendTo
ricket::ProxyConnection::Send
ricket::P2PTransportChannel::SendPacket
ricket::DtlsTransport::SendPacket
ricket::BaseChannel::SendPacket
ricket::BaseChannel::OnMessage
ricket::VideoChannel::OnMessage
tc::MessageQueue::Dispatch
tc::Thread::ProcessMessages
tc::Thread::Run
tc::Thread::PreRun
UDPPort::SendTo實現了的資料的真正傳送;
UDPPort中包含了webrtc中封裝的UDP類;
一個 ProxyConnection 對應 一個 UDPPort;
ProxyConnection::ProxyConnection的實現函式:
int ProxyConnection::Send(const void* data, size_t size, const rtc::PacketOptions& options) {
stats_.sent_total_packets++;
int sent = port_->SendTo(data, size, remote_candidate_.address(),
options, true);
if (sent <= 0) {
RTC_DCHECK(sent < 0);
error_ = port_->GetError();
stats_.sent_discarded_packets++;
} else {
send_rate_tracker_.AddSamples(sent);
}
return sent;
}
可清楚的看到,port_通過設定遠端的地址,通過UDP傳送資料到指定地址;
UDPPort中的socket建立函式:
bool UDPPort::Init() {
stun_keepalive_lifetime_ = GetStunKeepaliveLifetime();
if (!SharedSocket()) {
RTC_DCHECK(socket_ == NULL);
socket_ = socket_factory()->CreateUdpSocket(
rtc::SocketAddress(ip(), 0), min_port(), max_port());
if (!socket_) {
LOG_J(LS_WARNING, this) << "UDP socket creation failed";
return false;
}
socket_->SignalReadPacket.connect(this, &UDPPort::OnReadPacket);
}
socket_->SignalSentPacket.connect(this, &UDPPort::OnSentPacket);
socket_->SignalReadyToSend.connect(this, &UDPPort::OnReadyToSend);
socket_->SignalAddressReady.connect(this, &UDPPort::OnLocalAddressReady);
requests_.SignalSendPacket.connect(this, &UDPPort::OnSendPacket);
return true;
}
最近看見一個檔案:
audio_device_data_observer.h
// This interface will capture the raw PCM data of both the local captured as
// well as the mixed/rendered remote audio.
class AudioDeviceDataObserver {
public:
virtual void OnCaptureData(const void* audio_samples,
const size_t num_samples,
const size_t bytes_per_sample,
const size_t num_channels,
const uint32_t samples_per_sec) = 0;
virtual void OnRenderData(const void* audio_samples,
const size_t num_samples,
const size_t bytes_per_sample,
const size_t num_channels,
const uint32_t samples_per_sec) = 0;
AudioDeviceDataObserver() = default;
virtual ~AudioDeviceDataObserver() = default;
};
// Creates an ADM instance with AudioDeviceDataObserver registered.
rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceWithDataObserver(
const AudioDeviceModule::AudioLayer audio_layer,
AudioDeviceDataObserver* observer);
// TODO(bugs.webrtc.org/7306): deprecated.
rtc::scoped_refptr<AudioDeviceModule> CreateAudioDeviceWithDataObserver(
const int32_t id,
const AudioDeviceModule::AudioLayer audio_layer,
AudioDeviceDataObserver* observer);
} // namespace webrtc
看檔案的內容,應該可以更好的獲取音訊採集資料和播放資料;有時間在具體測試;
當然64版本已經有Ondata函式獲取本地採集資料了,可以簡單獲取採集資料;
還有ADMWrapper ,關於 ADMWrapper ,看我這篇文章:《webrtc中的音訊裝置 音訊採集 AudioDeviceModule》
相關推薦
webrtc58 中的音訊採集
關於webrtc中的音訊採集,當然和是各個平臺採集具體實現,上層封裝統一介面;從資料來源來看,音訊資料來自於class AudioDeviceModule;然後檢視: virtual int32_t RegisterAudioCallback(AudioTransport*
學習音訊之android中AudioRecord採集音訊的引數說明
在android中採集音訊的api是android.media.AudioRecord類 其中構造器的幾個引數就是標準的聲音採集引數 以下是引數的含義解釋 public AudioRecord (int audioSource, int sampleRateInH
android中AudioRecord採集音訊的引數說明以及audioTrack的播放
在android中採集音訊的api是android.media.AudioRecord類 在android中播放音訊也是從api中的類分析 其中構造器的幾個引數就是標準的聲音採集引數 以下是引數的含義解釋 1. public AudioRecord (int audioSource, int sampleR
webRTC中音訊相關的netEQ(五):DSP處理 webRTC中音訊相關的netEQ(四):控制命令決策 webRTC中音訊相關的netEQ(二):資料結構)
上篇(webRTC中音訊相關的netEQ(四):控制命令決策)講了MCU模組是怎麼根據網路延時、抖動緩衝延時和反饋報告等來決定給DSP模組發什麼控制命令的。DSP模組根據收到的命令進行相關處理,處理簡要流程圖如下。 從上圖看出如果有語音包從packet buffer裡取出來先要做解碼得到PC
Qt工程中音訊資原始檔的路徑報錯
void Player::play(QString filePath) { player->setMedia(QUrl(filePath)); player->play(); } Player *player=new Player();
音訊採集-AudioUnit
AudioUnit簡介 AudioUnit這個名字取得還是比較形象的,它的主體就是一系列的unit,不同unit能夠實現不同的功能,將一個或多個unit新增到AUGraph(Audio Processing Graph)中,並建立unit之間的連線,音訊資料順次通過各個
webRTC中音訊相關的netEQ(四):控制命令決策
上篇(webRTC中音訊相關的netEQ(三):存取包和延時計算)講了語音包的存取以及網路延時和抖動緩衝延時的計算,MCU也收到了DSP模組發來的反饋報告。本文講MCU模組如何根據網路延時、抖動緩衝延時和反饋報告等決定發給DSP模組的控制命令, 好讓DSP模組先對取出的語音包做解碼處理(如果有的話)以及根據這
pcm原始音訊採集率轉換
pcm介紹 pcm也被稱為 脈碼編碼調製,是音訊中沒經過壓縮的原始資料。 在聲音採集中經過抽樣,量化,最後編碼。 取樣:對聲音進行一定頻率的採集,頻率越高,間隔時間越小,聲音更接近真實。常用的取樣率有8khz,16khz,22.05KHz、44.1KHz、48KHz等。 量化就是對每個採
HI3521D外接audio codec轉I2S音訊採集
經過幾天的不斷的閱讀文件,問人,嘗試終於除錯成功。反過來一想,原來如此簡單。 1.硬體原理圖 a.外接codec部分 b.時鐘MCLK部分,由海思提供 c.海思對接codec部分 對原理圖的理解:外接codec通過由海思GPIO9_3/I2S2_
Windows下wave API 音訊採集
目的:Windows下wave API採集PCM 環境: 系統:Win10 環境:VS2015 64bit 操作步驟: 1. 匯入系統wave標頭檔案及庫 #include <mmsystem.h> #pragma com
C#音訊採集 (筆記)
using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Threading; using Microsoft.
alsa音訊採集和播放 (麥克風)
Alsa音訊採集 #include <stdio.h> #include <malloc.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include
iOS 實時音訊採集與播放
前言 在iOS中有很多方法可以進行音視訊採集。如 AVCaptureDevice, AudioQueue以及Audio Unit。其中 Audio Unit是最底層的介面,它的優點是功能強大,延遲低; 而缺點是學習成本高,難度大。對於一般的iOS應用程式,AV
Android開發之PCM音訊採集
通過ijkplayer播放視訊,需求:移動端實現實時對講。即pcm音訊錄製實時推送到裝置端,本篇主要記錄pcm音訊採集 為保證語音連續性,bufferSize 1m在網不好的情況下可能出現語音時斷時續,需要調小bufferSize 到最合適的值 impo
Android音訊採集、壓縮、傳送
基本的實現流程: 1、從手機麥中採集音訊資料;2、將PCM音訊資料編碼壓縮;3、將壓縮好的音訊通過無線網路傳送出去;4、其他手機接收音訊資料並解碼;5、將音訊資料寫入到音軌中播放。專案雖然簡單,但其中的一些小問題也折騰了我不少時間。 首先我們建立一個執行緒用來採
瀏覽器中音訊相容性問題(上)
參考文章:http://blog.csdn.net/www3300300/article/details/17709219 我參考了上面連結的文章,由於這篇文章寫於2013年,目前已經不能滿足需求了。 下面我將把我參考改進後的做法列出來: (由於我們公司只
淺談iOS中音訊的開發
我對音訊技術不是很精通,最近對這方面比較有興趣,公司以前的專案用到這方面的技術不多。我只是粗略的涉獵沒有深入研究。今天就研究一下寫一篇部落格。同時希望以後能做一個關於音訊的商業專案也期望能接觸到音
windows下簡單的音訊採集示例
最近需要在window下進行音訊採集,網上找了很久都沒找到win7下如何採集pcm資料的完整示例,經過一翻折騰後寫了一個很簡單的demo程式以供同行進行參考,如有不正確的地方請指正 本例是採用audio core進行音訊採集 程式碼塊 #include "
linux 音訊採集基礎知識普及
雖然目前Linux的優勢主要體現在網路服務方面,但事實上同樣也有著非常豐富的媒體功能,本文就是以多媒體應用中最基本的聲音為物件,介紹如何在Linux平臺下開發實際的音訊應用程式,同時還給出了一些常用的音訊程式設計框架。 一、數字音訊 音訊訊號是一種連
UE4 4.18關於視訊播放中音訊播放的變動
這個問題是我請教一個UE4開發好友解決的(當然是他告訴我的,外掛結構發生了變動) 他的聯絡方式,QQ:10235336 , email: [email protected] 具體視訊播放的變動日期不知道,但很可能在4.18.3。 該變動中是視訊播放的Media S