L ỜI NÓI ĐẦU
4.2. Thiết kế chương trình server trên máy tính
4.2.2. Lập trình tạo Socket trên C#
Ta sẽ sử dụng các hàm mà C# đã hỗ trợ săn dùng cho việc tạo kết nối socket như:
IPAddress: Địa chỉ giao tiếp của một IP trên mạng.
Socket: là lớp cũng cấp nhiều phương thức và thuộc tính để giao tiếp mạng.
TcpListener: dùng để lắng nghe kết nối từ những máy trong mạng. Thiết lập miền địa chỉ IP và cổng để lắng nghe. Gọi phương thức Start() để có thể ắt đầu lắng nghe. AcceptSocket() là phương thức lắng nghe kết nối trả về. Khi đó đã kết nối được và có thể gửi và nhận dữ liệu.
Ví dụ: Đoạn chương trình mơ tả việc máy tính (có địa chỉ IP là x.x.x.x) nắng nghe kết nối tới máy khác (có cổng là Port_Number)
m_endpoint = new IPEndPoint(IPAddress.Parse(strIPAdress), Port); m_tcpip = new TcpListener(m_endpoint);
TcpClient client = m_tcpip.AcceptTcpClient();
4.2.3. Chương trình ghi dữ liệu từ mic
Lưu đồ thuật tốn chương trình ghi dữ liệu từ mic:
Ở đây ta sử dụng thư viện WinSound để thu âm thanh : private void StartRecordingFromSounddevice_Server() {
//Khởi tạo ghi âm
m_Recorder_Server = new WinSound.Recorder(); //Gọi sự kiện lấy dữ liệu và xử lí m_Recorder_Server.DataRecorded += new WinSound.Recorder.DelegateDataRecorded(OnDataReceivedFr omSoundcard_Server); m_Recorder_Server.Start(Config.SoundInputDeviceNameServe r, Config.SamplesPerSecondServer, Config.BitsPerSampleServer, Config.ChannelsServer, m_SoundBufferCount, bufferSize) m_JitterBufferServerRecording.Start(); }
Với xử lí âm thanh và đẩy vào buffer bằng hàmOnDataReceivedFromSoundcard_Server() :
private void OnDataReceivedFromSoundcard_Server(Byte[] data) { //Chia nhỏ dữ liệu int bytesPerInterval = WinSound.Utils.GetBytesPerInterval((uint) m_Config.SamplesPerSecondServer, m_Config.BitsPerSampleServer, m_Config.ChannelsServer); int count = data.Length / bytesPerInterval;
for (int i = 0; i < count; i++) {
Byte[] partBytes = new Byte[bytesPerInterval]; Array.Copy(data, currentPos, partBytes, 0, bytesPerInterval);
currentPos += bytesPerInterval;
WinSound.RTPPacket rtp = ToRTPPacket(partBytes, m_Config.BitsPerSampleServer,
m_Config.ChannelsServer);
// Đưa dữ liệu vào bộđệm JitterBuffer:
m_JitterBufferServerRecording.AddData(rtp); }
}
Khi tạo gói RTP, hầu hết các thông tin như CSRC Count hoặc Version đều giống nhau. Sau mỗi gói RTP được gửi chỉ phải
tăng SequenceNumber và Timestamp. Trước đó, ta nén dữ liệu tuyến tính sang định dạng U-Law để giảm kích thước gói tin:
private WinSound.RTPPacket ToRTPPacket(Byte[] linearData, int bitsPerSample, int channels)
{
//Nén dữ liệu
Byte[] mulaws = WinSound.Utils.LinearToMulaw(linearData, bitsPerSample, channels);
//Tạo gói RTP
WinSound.RTPPacket rtp = new WinSound.RTPPacket(); rtp.Data = mulaws;
rtp.CSRCCount = m_CSRCCount; rtp.Extension = m_Extension; rtp.HeaderLength = WinSound.RTPPacket.MinHeaderLength; rtp.Marker = m_Marker; rtp.Padding = m_Padding; rtp.PayloadType = m_PayloadType; rtp.Version = m_Version; rtp.SourceId = m_SourceId;
//Tăng SequenceNumber và Timestamp sau mỗi gói tin try { rtp.SequenceNumber = Convert.ToUInt16(m_SequenceNumber); m_SequenceNumber++; } catch (Exception) { m_SequenceNumber = 0; } try { rtp.Timestamp = Convert.ToUInt32(m_TimeStamp); m_TimeStamp += mulaws.Length; } catch (Exception)
{
m_TimeStamp = 0; }
return rtp; }
Để gửi dữ liệu đi mà đảm bảo các gói tin gửi đi cách nhau một khoảng thời gian đều nhau, ta sử dụng thêm bộđệm JitterBuffer. Bộđệm JitterBuffer sẽđảm bảo các gói tin truyền đi với khoảng cách đều nhau, sau đây và tiến trình cài đặt bộđệm JitterBuffer và thêm sự kiện gửi gói tin:
m_JitterBufferServerRecording = new WinSound.JitterBuffer(null, RecordingJitterBufferCount, 20);
m_JitterBufferServerRecording.DataAvailable += new
WinSound.JitterBuffer.DelegateDataAvailable(OnJitterBufferServerD ataAvailable);