Skip to content

RTCAudioSource kCustom 自定义音频流没有效果 #137

@110jiangnan

Description

@110jiangnan

#ifndef SYS_AUDIO_SOURCE_HXX
#define SYS_AUDIO_SOURCE_HXX

#include
#include "rtc_audio_source.h"
#include "rtc_peerconnection_factory.h"

#include
#include
#include

#if defined(_WIN32) || defined(WINDOWS)
#include "win_sys_audio_capturer.h"
#elif defined(linux) || defined(LINUX)
#include "linux_sys_audio_capturer.h"
#else
#pragma message("SysAudioSource is only available on Windows and Linux (stub)")
#endif

namespace flutter_webrtc_plugin {

using namespace libwebrtc;

#if defined(_WIN32) || defined(WINDOWS)
using PlatformSysAudioCapturer = WinSysAudioCapturer;
#elif defined(linux) || defined(LINUX)
using PlatformSysAudioCapturer = LinuxSysAudioCapturer;
#endif

class SysAudioSource : public RTCAudioSource {
public:
SysAudioSource(scoped_refptr factory,
const std::string& audio_source_label = "sys_audio_input");

~SysAudioSource() override;

bool Initialize(const std::string& device_id = "");

bool StartCapture();

void StopCapture();

bool IsCapturing() const;

void CaptureFrame(const void* audio_data, int bits_per_sample,
int sample_rate, size_t number_of_channels,
size_t number_of_frames) override {
if (enable_pcm_recording_ && pcm_file_.is_open()) {
pcm_file_.write(static_cast<const char*>(audio_data),
bits_per_sample / 8 * number_of_channels * number_of_frames);
pcm_file_.flush();
total_frames_recorded_ += number_of_frames;
}

if (rtc_audio_source_) {

// std::cout << "sink size:" << rtc_audio_source_->GetSinkSize() << std::endl;
// std::cout << bits_per_sample << " " << sample_rate << " " << number_of_channels << " " << number_of_frames << std::endl;
rtc_audio_source_->CaptureFrame(audio_data, bits_per_sample, sample_rate,
number_of_channels, number_of_frames);
} else {
std::cout << "rtc_audio_source_ is null" << std::endl;
}
}

SourceType GetSourceType() const override {
return SourceType::kCustom;
}

scoped_refptr rtc_audio_source() {
return rtc_audio_source_;
}

int GetSinkSize() override {
return rtc_audio_source_->GetSinkSize();
}

void EnablePcmRecording(bool enable, const std::string& file_path) {
if (enable) {
pcm_file_.open(file_path, std::ios::binary);
if (pcm_file_.is_open()) {
enable_pcm_recording_ = true;
total_frames_recorded_ = 0;
std::cout << "PCM recording started: " << file_path << std::endl;
} else {
std::cout << "Failed to open PCM file: " << file_path << std::endl;
}
} else {
enable_pcm_recording_ = false;
if (pcm_file_.is_open()) {
pcm_file_.close();
std::cout << "PCM recording stopped. Total frames: "
<< total_frames_recorded_ << std::endl;
}
}
}

bool IsPcmRecordingEnabled() const {
return enable_pcm_recording_;
}

private:
static void OnAudioDataCallback(const void* audio_data,
int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames,
void* user_data);

std::unique_ptr capturer_;

scoped_refptr factory_;
scoped_refptr rtc_audio_source_;
std::string audio_source_label_;

bool enable_pcm_recording_ = false;
std::ofstream pcm_file_;
size_t total_frames_recorded_ = 0;
};

} // namespace flutter_webrtc_plugin

#endif // SYS_AUDIO_SOURCE_HXX

#include "sys_audio_source.h"
#include

namespace flutter_webrtc_plugin {

SysAudioSource::SysAudioSource(
scoped_refptr factory,
const std::string& audio_source_label)
: factory_(factory), audio_source_label_(audio_source_label) {
std::cout << "Creating SysAudioSource: " << audio_source_label;

RTCAudioOptions options;
options.echo_cancellation = false;
options.noise_suppression = false;
options.auto_gain_control = false;
options.highpass_filter = false;

rtc_audio_source_ = factory_->CreateAudioSource(
audio_source_label.c_str(),
RTCAudioSource::SourceType::kCustom,
options);

if (rtc_audio_source_) {
capturer_ = std::make_unique();

capturer_->SetCallback(&SysAudioSource::OnAudioDataCallback, this);

std::cout << "SysAudioSource created successfully";

} else {
std::cout << "Failed to create RTCAudioSource";
}
}

SysAudioSource::~SysAudioSource() {
std::cout << "Destroying SysAudioSource";
StopCapture();
rtc_audio_source_ = nullptr;
}

bool SysAudioSource::Initialize(const std::string& device_id) {
if (!capturer_) {
std::cout << "Capturer not initialized";
return false;
}

bool result = capturer_->Initialize(device_id);
if (result) {
std::cout << "SysAudioSource initialized with device: "
<< (device_id.empty() ? "default" : device_id);
} else {
std::cout << "Failed to initialize SysAudioSource (platform may not support it)";
}

return result;
}

bool SysAudioSource::StartCapture() {
if (!capturer_) {
std::cout << "Cannot start capture - capturer is null";
return false;
}

if (capturer_->IsCapturing()) {
std::cout << "Already capturing";
return true;
}

bool result = capturer_->StartCapture();
if (result) {
std::cout << "Started sys audio capture";
} else {
std::cout << "Failed to start sys audio capture (platform may not support it)";
}

return result;
}

void SysAudioSource::StopCapture() {
if (capturer_ && capturer_->IsCapturing()) {
capturer_->StopCapture();
std::cout << "Stopped sys audio capture";
}
}

bool SysAudioSource::IsCapturing() const {
return capturer_ ? capturer_->IsCapturing() : false;
}

void SysAudioSource::OnAudioDataCallback(const void* audio_data,
int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames,
void* user_data) {
SysAudioSource* self = static_cast<SysAudioSource*>(user_data);
if (self) {
self->CaptureFrame(audio_data, bits_per_sample, sample_rate,
number_of_channels, number_of_frames);
}
}

} // namespace flutter_webrtc_plugin

sink可以触发,向里面发送数据但是远程的peerconection无法接收到。

Image

flutter: report => {
flutter: id: T01,
flutter: type: transport,
flutter: timestamp: 1774874753187447.0,
flutter: values => {
flutter: bytesReceived : 721,
flutter: bytesSent : 698,
flutter: dtlsCipher : TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
flutter: dtlsRole : client,
flutter: dtlsState : connected,
flutter: iceLocalUsernameFragment : Aq26,
flutter: iceRole : controlled,
flutter: iceState : connected,
flutter: localCertificateId : CF3C:1A:91:3D:2C:C7:4E:71:B6:79:72:75:B9:E6:CD:FC:33:A9:03:4F:70:BA:33:6B:41:9B:15:F3:4C:09:1E:5D,
flutter: packetsReceived : 2,
flutter: packetsSent : 2,
flutter: remoteCertificateId : CF8D:2D:B5:B8:AD:27:B2:F7:8D:E2:10:DA:04:FE:B6:4B:01:13:26:BC:DC:35:9E:68:2F:A4:24:C1:87:74:55:99,
flutter: selectedCandidatePairChanges : 1,
flutter: selectedCandidatePairId : CPKxHVStaL_cIePVcEY,
flutter: srtpCipher : AES_CM_128_HMAC_SHA1_80,
flutter: tlsVersion : FEFD,
flutter: }
flutter: }
flutter: report => {
flutter: id: CF3C:1A:91:3D:2C:C7:4E:71:B6:79:72:75:B9:E6:CD:FC:33:A9:03:4F:70:BA:33:6B:41:9B:15:F3:4C:09:1E:5D,
flutter: type: certificate,
flutter: timestamp: 1774874754187561.0,
flutter: values => {
flutter: base64Certificate : MIIBFTCBvaADAgECAgkAxLzdGpK1SoQwCgYIKoZIzj0EAwIwETEPMA0GA1UEAwwGV2ViUlRDMB4XDTI2MDMyOTEyNDUwNFoXDTI2MDQyOTEyNDUwNFowETEPMA0GA1UEAwwGV2ViUlRDMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESl+GWmPHfWGcotiy2c1NvxvPM9ahDIOXkzyW4nwx06c+BW3vJv1xVKu5488BdQVQVkld+tHugkBf7gL3A0zCyDAKBggqhkjOPQQDAgNHADBEAiB8viLhWqrVzQk983MOMc1yuTZ4GaRUVwLIJ7TgKpgyCwIgScdrM6/zKrvGwlwMJ3rp4QZHJBS9+nbW2gv/vVIMRx8=,
flutter: fingerprint : 3C:1A:91:3D:2C:C7:4E:71:B6:79:72:75:B9:E6:CD:FC:33:A9:03:4F:70:BA:33:6B:41:9B:15:F3:4C:09:1E:5D,
flutter: fingerprintAlgorithm : sha-256,
flutter: }
flutter: }
flutter: report => {
flutter: id: CF8D:2D:B5:B8:AD:27:B2:F7:8D:E2:10:DA:04:FE:B6:4B:01:13:26:BC:DC:35:9E:68:2F:A4:24:C1:87:74:55:99,
flutter: type: certificate,
flutter: timestamp: 1774874754187561.0,
flutter: values => {
flutter: base64Certificate : MIIBFjCBvKADAgECAggDOiiGHpaqXjAKBggqhkjOPQQDAjARMQ8wDQYDVQQDDAZXZWJSVEMwHhcNMjYwMzI5MTI0NTA0WhcNMjYwNDI5MTI0NTA0WjARMQ8wDQYDVQQDDAZXZWJSVEMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATxCKelMmxcjXOjbLbfvyKR2kzJz1uO/5yOdho8sUcgCsWdC3zJYgupb8CqsHUqhFY5EI15SYw5PxFd7ssSKuY8MAoGCCqGSM49BAMCA0kAMEYCIQD4gf2AfJBo0l+pdNTLDdZZ+/QxXWpkAkQWncothgcLiwIhAM7p4AbvM6agIHau45c3ve+o5o5EN8vMXPFDq6RS6Xqo,
flutter: fingerprint : 8D:2D:B5:B8:AD:27:B2:F7:8D:E2:10:DA:04:FE:B6:4B:01:13:26:BC:DC:35:9E:68:2F:A4:24:C1:87:74:55:99,
flutter: fingerprintAlgorithm : sha-256,
flutter: }
flutter: }
flutter: report => {
flutter: id: CPKxHVStaL_cIePVcEY,
flutter: type: candidate-pair,
flutter: timestamp: 1774874754187561.0,
flutter: values => {
flutter: availableOutgoingBitrate : 2000000.0,
flutter: bytesDiscardedOnSend : 0,
flutter: bytesReceived : 721,
flutter: bytesSent : 698,
flutter: consentRequestsSent : 21,
flutter: currentRoundTripTime : 0.0,
flutter: lastPacketReceivedTimestamp : 1774874707186.0,
flutter: lastPacketSentTimestamp : 1774874707182.0,
flutter: localCandidateId : IKxHVStaL,
flutter: nominated : true,
flutter: packetsDiscardedOnSend : 0,
flutter: packetsReceived : 2,
flutter: packetsSent : 2,
flutter: priority : 9114756780654345726,
flutter: remoteCandidateId : IcIePVcEY,
flutter: requestsReceived : 22,
flutter: requestsSent : 22,
flutter: responsesReceived : 22,
flutter: responsesSent : 22,
flutter: state : succeeded,
flutter: totalRoundTripTime : 0.004,
flutter: transportId : T01,
flutter: writable : true,
flutter: }
flutter: }
flutter: report => {
flutter: id: IKxHVStaL,
flutter: type: local-candidate,
flutter: timestamp: 1774874754187561.0,
flutter: values => {
flutter: address : 10.1.2.211,
flutter: candidateType : host,
flutter: foundation : 3460999637,
flutter: ip : 10.1.2.211,
flutter: isRemote : false,
flutter: networkAdapterType : wifi,
flutter: networkType : wifi,
flutter: port : 64627,
flutter: priority : 2122194687,
flutter: protocol : udp,
flutter: transportId : T01,
flutter: usernameFragment : Aq26,
flutter: vpn : false,
flutter: }
flutter: }
flutter: report => {
flutter: id: IT01A296816917,
flutter: type: inbound-rtp,
flutter: timestamp: 1774874754187561.0,
flutter: values => {
flutter: audioLevel : 0.0,
flutter: bytesReceived : 0,
flutter: concealedSamples : 0,
flutter: concealmentEvents : 0,
flutter: delayedPacketOutageSamples : 0,
flutter: fecPacketsDiscarded : 0,
flutter: fecPacketsReceived : 0,
flutter: headerBytesReceived : 0,
flutter: insertedSamplesForDeceleration : 0,
flutter: interruptionCount : 0,
flutter: jitter : 0.0,
flutter: jitterBufferDelay : 0.0,
flutter: jitterBufferEmittedCount : 0,
flutter: jitterBufferFlushes : 0,
flutter: jitterBufferMinimumDelay : 0.0,
flutter: jitterBufferTargetDelay : 0.0,
flutter: kind : audio,
flutter: mid : 0,
flutter: packetsDiscarded : 0,
flutter: packetsLost : 0,
flutter: packetsReceived : 0,
flutter: relativePacketArrivalDelay : 0.0,
flutter: removedSamplesForAcceleration : 0,
flutter: silentConcealedSamples : 0,
flutter: ssrc : 296816917,
flutter: totalAudioEnergy : 0.0,
flutter: totalInterruptionDuration : 0.0,
flutter: totalProcessingDelay : 0.0,
flutter: totalSamplesDuration : 47.019999999999214,
flutter: totalSamplesReceived : 0,
flutter: trackIdentifier : 6dada39b-21bc-4597-9fd4-4e88382ac1a4,
flutter: transportId : T01,
flutter: }
flutter: }
flutter: report => {
flutter: id: IcIePVcEY,
flutter: type: remote-candidate,
flutter: timestamp: 1774874754187561.0,
flutter: values => {
flutter: address : 10.1.2.211,
flutter: candidateType : host,
flutter: foundation : 1706040316,
flutter: ip : 10.1.2.211,
flutter: isRemote : true,
flutter: port : 65133,
flutter: priority : 2122194687,
flutter: protocol : udp,
flutter: transportId : T01,
flutter: usernameFragment : DiET,
flutter: }
flutter: }
flutter: report => {
flutter: id: T01,
flutter: type: transport,
flutter: timestamp: 1774874754187561.0,
flutter: values => {
flutter: bytesReceived : 721,
flutter: bytesSent : 698,
flutter: dtlsCipher : TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
flutter: dtlsRole : client,
flutter: dtlsState : connected,
flutter: iceLocalUsernameFragment : Aq26,
flutter: iceRole : controlled,
flutter: iceState : connected,
flutter: localCertificateId : CF3C:1A:91:3D:2C:C7:4E:71:B6:79:72:75:B9:E6:CD:FC:33:A9:03:4F:70:BA:33:6B:41:9B:15:F3:4C:09:1E:5D,
flutter: packetsReceived : 2,
flutter: packetsSent : 2,
flutter: remoteCertificateId : CF8D:2D:B5:B8:AD:27:B2:F7:8D:E2:10:DA:04:FE:B6:4B:01:13:26:BC:DC:35:9E:68:2F:A4:24:C1:87:74:55:99,
flutter: selectedCandidatePairChanges : 1,
flutter: selectedCandidatePairId : CPKxHVStaL_cIePVcEY,
flutter: srtpCipher : AES_CM_128_HMAC_SHA1_80,
flutter: tlsVersion : FEFD,
flutter: }
flutter: }
flutter: Have a Sender of kind:audio
flutter: Setting direction and replacing track with null
flutter: LocalRenegotiationNeeded
LocalAudioSource RemoveSink1
MediaStreamForId: b4edfbb4-cce1-4d9f-aa60-8dc0958ab556
flutter: local pc: onSignalingState(RTCSignalingState.RTCSignalingStateHaveLocalOffer), state2(RTCSignalingState.RTCSignalingStateHaveLocalOffer)
flutter: remote pc: onSignalingState(RTCSignalingState.RTCSignalingStateHaveRemoteOffer), state2(RTCSignalingState.RTCSignalingStateHaveRemoteOffer)
flutter: remote pc: onSignalingState(RTCSignalingState.RTCSignalingStateStable), state2(RTCSignalingState.RTCSignalingStateStable)
MediaStreamForId: b4edfbb4-cce1-4d9f-aa60-8dc0958ab556

bytesReceived 的值没有什么变化,表示远端没有接收到数据(我可以保证是一直发送数据的 ondata方法一直被调用)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions