using NAudio.Wave; using SIPSorcery.Media; using SIPSorcery.SIP; using SIPSorcery.SIP.App; using SIPSorceryMedia.Abstractions; using System.Net; namespace DigitalSystem.Servicios { class ContestadorClase { public void Contestar() { var sipTransport = new SIPTransport(); sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, 5060))); var registrationUserAgent = new SIPRegistrationUserAgent( sipTransport, "132", // tu usuario SIP "123.Gruas2024_", // tu contraseña SIP "nano18.citro.com.mx:36985", // dominio SIP o IP del servidor 3600 // tiempo de expiración ); registrationUserAgent.Start(); var userAgent = new SIPUserAgent(sipTransport, null, true); userAgent.OnIncomingCall += async (ua, req) => { var audioSource = new AudioSource("C:\\Users\\DESARROLLO\\Documents\\Audacity\\SPAFND1_0051.wav"); var endpoints = new MediaEndPoints { AudioSource = audioSource }; var mediaSession = new VoIPMediaSession(endpoints); var uas = ua.AcceptCall(req); await userAgent.Answer(uas, mediaSession); await audioSource.StartAudio(); }; } } public class AudioSink : IAudioSink { private BufferedWaveProvider _waveProvider; private WaveOutEvent _waveOut; public event SourceErrorDelegate OnAudioSinkError; // Métodos obligatorios para IAudioSink public Task StartAudio() { var waveFormat = new NAudio.Wave.WaveFormat(8000, 16, 1); _waveProvider = new BufferedWaveProvider(waveFormat) { BufferDuration = TimeSpan.FromSeconds(5), DiscardOnBufferOverflow = true }; _waveOut = new WaveOutEvent(); _waveOut.Init(_waveProvider); _waveOut.Play(); return Task.CompletedTask; } public void GotAudioSample(short[] sample, AudioSamplingRatesEnum samplingRate, int channels) { if (_waveProvider == null) return; byte[] byteBuffer = new byte[sample.Length * 2]; Buffer.BlockCopy(sample, 0, byteBuffer, 0, byteBuffer.Length); _waveProvider.AddSamples(byteBuffer, 0, byteBuffer.Length); } public Task CloseAudio() { _waveOut?.Stop(); _waveOut?.Dispose(); _waveOut = null; _waveProvider = null; return Task.CompletedTask; } public Task PauseAudio() => Task.CompletedTask; public Task ResumeAudio() => Task.CompletedTask; public bool IsAudioSinkPaused() => false; public void SetAudioSinkFormat(AudioFormat audioFormat) { } public List GetAudioSinkFormats() => new List { new AudioFormat(SDPWellKnownMediaFormatsEnum.PCMU) }; // Métodos adicionales que pide la interfaz extendida (implementa para evitar errores) public void GotAudioRtp(IPEndPoint remoteEndPoint, uint ssrc, uint seqnum, uint timestamp, int payloadID, bool marker, byte[] payload) { // Puedes dejar vacío o implementar si procesas RTP directamente } public void GotEncodedMediaFrame(EncodedAudioFrame encodedMediaFrame) { // Opcional, implementa si manejas frames codificados directamente } public void RestrictFormats(Func filter) { // Opcional, implementar si necesitas filtrar formatos } public Task PauseAudioSink() => Task.CompletedTask; public Task ResumeAudioSink() => Task.CompletedTask; public Task StartAudioSink() => StartAudio(); public Task CloseAudioSink() => CloseAudio(); } public class AudioSource : IAudioSource { public event EncodedSampleDelegate OnAudioSourceEncodedSample; public event Action OnAudioSourceEncodedFrameReady; public event RawAudioSampleDelegate OnAudioSourceRawSample; public event SourceErrorDelegate OnAudioSourceError; private byte[] audioData; private int playbackIndex; private System.Timers.Timer timer; public AudioSource(string wavFilePath) { audioData = File.ReadAllBytes(wavFilePath); playbackIndex = 44; // Saltar encabezado WAV estándar } public Task StartAudio() { timer = new System.Timers.Timer(20); // Cada 20ms (160 muestras a 8kHz) timer.Elapsed += (s, e) => StreamChunk(); timer.Start(); return Task.CompletedTask; } private void StreamChunk() { /*if (playbackIndex >= audioData.Length) { try { timer?.Stop(); timer?.Dispose(); timer = null; return; } catch { return; } }*/ int chunkSize = 160 * 2; // 160 muestras * 2 bytes por muestra (16-bit) int remaining = audioData.Length - playbackIndex; int bytesToCopy = Math.Min(chunkSize, remaining); byte[] chunk = new byte[bytesToCopy]; Array.Copy(audioData, playbackIndex, chunk, 0, bytesToCopy); playbackIndex += bytesToCopy; OnAudioSourceRawSample?.Invoke(AudioSamplingRatesEnum.Rate8KHz, 20, BytesToShorts(chunk)); } private short[] BytesToShorts(byte[] buffer) { short[] samples = new short[buffer.Length / 2]; for (int i = 0; i < samples.Length; i++) { samples[i] = BitConverter.ToInt16(buffer, i * 2); } return samples; } public List GetAudioSourceFormats() => new List { new AudioFormat(SDPWellKnownMediaFormatsEnum.PCMU) }; public Task CloseAudio() { timer?.Stop(); timer?.Dispose(); timer = null; return Task.CompletedTask; } public Task PauseAudio() => Task.CompletedTask; public Task ResumeAudio() => Task.CompletedTask; public bool HasEncodedAudioSubscribers() => false; public bool IsAudioSourcePaused() => false; public void RestrictFormats(Func filter) { } public void SetAudioSourceFormat(AudioFormat audioFormat) { } public void ExternalAudioSourceRawSample(AudioSamplingRatesEnum samplingRate, uint durationMilliseconds, short[] sample) { } } }