Skip to content

Commit 1b0b130

Browse files
committed
R Refactoring, moved AAC-related code out of the RTSP Server, API changes
1 parent abb583e commit 1b0b130

9 files changed

Lines changed: 571 additions & 414 deletions

File tree

src/RTSPServerApp/Program.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
using System.Linq;
88
using System.Timers;
99

10-
const string userName = "admin";
11-
const string password = "password";
10+
// TODO config file
1211
const string hostName = "127.0.0.1";
13-
const string fileName = "frag_bunny.mp4";
1412
const ushort port = 8554;
13+
const string fileName = "frag_bunny.mp4";
14+
const string userName = "admin";
15+
const string password = "password";
1516

1617
using (var server = new RTSPServer(port, userName, password))
1718
{
@@ -99,7 +100,7 @@
99100
audioTimer = new Timer(audioSampleDuration * 1000 / audioSamplingRate);
100101
audioTimer.Elapsed += (s, e) =>
101102
{
102-
server.FeedInAudioPacket((uint)(audioIndex * audioSampleDuration), SharpRTSPServer.AACTrack.AppendAUHeader(audioTrack[0][audioIndex++ % audioTrack[0].Count]));
103+
server.FeedInAudioPacket((uint)(audioIndex * audioSampleDuration), audioTrack[0][audioIndex++ % audioTrack[0].Count]);
103104

104105
if (audioIndex % audioTrack[0].Count == 0)
105106
{
Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using System.Linq;
1+
using System;
2+
using System.Buffers;
3+
using System.Collections.Generic;
4+
using System.Linq;
25
using System.Text;
36

47
namespace SharpRTSPServer
@@ -31,6 +34,55 @@ public StringBuilder BuildSDP(StringBuilder sdp)
3134
return sdp;
3235
}
3336

37+
public (List<Memory<byte>>, List<IMemoryOwner<byte>>) PrepareRtpPackets(List<byte[]> samples, uint rtpTimestamp)
38+
{
39+
List<Memory<byte>> rtpPackets = new List<Memory<byte>>();
40+
List<IMemoryOwner<byte>> memoryOwners = new List<IMemoryOwner<byte>>();
41+
42+
for (int i = 0; i < samples.Count; i++)
43+
{
44+
// append AU header (required for AAC)
45+
var audioPacket = AppendAUHeader(samples[i]);
46+
47+
// Put the whole Audio Packet into one RTP packet.
48+
// 12 is header size when there are no CSRCs or extensions
49+
var size = 12 + audioPacket.Length;
50+
var owner = MemoryPool<byte>.Shared.Rent(size);
51+
memoryOwners.Add(owner);
52+
53+
var rtpPacket = owner.Memory.Slice(0, size);
54+
55+
const bool rtpPadding = false;
56+
const bool rtpHasExtension = false;
57+
int rtpCsrcCount = 0;
58+
const bool rtpMarker = true; // always 1 as this is the last (and only) RTP packet for this audio timestamp
59+
60+
RTPPacketUtil.WriteHeader(rtpPacket.Span,
61+
RTPPacketUtil.RTP_VERSION, rtpPadding, rtpHasExtension, rtpCsrcCount, rtpMarker, PayloadType);
62+
63+
// sequence number is set just before send
64+
RTPPacketUtil.WriteTS(rtpPacket.Span, rtpTimestamp);
65+
66+
// Now append the audio packet
67+
audioPacket.CopyTo(rtpPacket.Slice(12));
68+
69+
rtpPackets.Add(rtpPacket);
70+
}
71+
72+
return (rtpPackets, memoryOwners);
73+
}
74+
75+
private static byte[] AppendAUHeader(byte[] frame)
76+
{
77+
short frameLen = (short)(frame.Length << 3);
78+
byte[] header = new byte[4];
79+
header[0] = 0x00;
80+
header[1] = 0x10; // 16 bits size of the header
81+
header[2] = (byte)((frameLen >> 8) & 0xFF);
82+
header[3] = (byte)(frameLen & 0xFF);
83+
return header.Concat(frame).ToArray();
84+
}
85+
3486
private static int GetAACLevel(int samplingFrequency, int channelConfiguration)
3587
{
3688
if (samplingFrequency <= 24000)
@@ -110,17 +162,5 @@ private static int GetAACProfileLevel(int samplingFrequency, int channelConfigur
110162
return 1;
111163
}
112164
}
113-
114-
public static byte[] AppendAUHeader(byte[] frame)
115-
{
116-
// append AU header (required for AAC)
117-
short frameLen = (short)(frame.Length << 3);
118-
byte[] header = new byte[4];
119-
header[0] = 0x00;
120-
header[1] = 0x10; // 16 bits size of the header
121-
header[2] = (byte)((frameLen >> 8) & 0xFF);
122-
header[3] = (byte)(frameLen & 0xFF);
123-
return header.Concat(frame).ToArray();
124-
}
125165
}
126166
}

src/SharpRTSPServer/G711.cs

Lines changed: 0 additions & 42 deletions
This file was deleted.

src/SharpRTSPServer/G711Track.cs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using System;
2+
using System.Buffers;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
6+
namespace SharpRTSPServer
7+
{
8+
public class PCMUTrack : ITrack
9+
{
10+
public int ID { get; set; } = 1;
11+
public int SamplingRate { get; } = 8000;
12+
public int Channels { get; } = 1;
13+
14+
public bool IsReady { get { return true; } }
15+
16+
public int PayloadType => 0;
17+
18+
public StringBuilder BuildSDP(StringBuilder sdp)
19+
{
20+
sdp.Append($"m=audio 0 RTP/AVP {PayloadType}\n"); // <---- Payload Type 0 means G711 ULAW
21+
sdp.Append($"a=control:trackID={ID}\n");
22+
sdp.Append($"a=rtpmap:{PayloadType} PCMU/{SamplingRate}\n");
23+
return sdp;
24+
}
25+
26+
public (List<Memory<byte>>, List<IMemoryOwner<byte>>) PrepareRtpPackets(List<byte[]> samples, uint rtpTimestamp)
27+
{
28+
List<Memory<byte>> rtpPackets = new List<Memory<byte>>();
29+
List<IMemoryOwner<byte>> memoryOwners = new List<IMemoryOwner<byte>>();
30+
31+
for (int i = 0; i < samples.Count; i++)
32+
{
33+
var audioPacket = samples[i];
34+
var size = 12 + audioPacket.Length;
35+
var owner = MemoryPool<byte>.Shared.Rent(size);
36+
memoryOwners.Add(owner);
37+
38+
var rtpPacket = owner.Memory.Slice(0, size);
39+
40+
const bool rtpPadding = false;
41+
const bool rtpHasExtension = false;
42+
int rtpCsrcCount = 0;
43+
const bool rtpMarker = true;
44+
45+
RTPPacketUtil.WriteHeader(rtpPacket.Span,
46+
RTPPacketUtil.RTP_VERSION, rtpPadding, rtpHasExtension, rtpCsrcCount, rtpMarker, PayloadType);
47+
48+
RTPPacketUtil.WriteTS(rtpPacket.Span, rtpTimestamp);
49+
audioPacket.CopyTo(rtpPacket.Slice(12));
50+
rtpPackets.Add(rtpPacket);
51+
}
52+
53+
return (rtpPackets, memoryOwners);
54+
}
55+
}
56+
57+
public class PCMATrack : ITrack
58+
{
59+
public int ID { get; set; } = 1;
60+
public int SamplingRate { get; } = 8000;
61+
public int Channels { get; } = 1;
62+
63+
public bool IsReady { get { return true; } }
64+
65+
public int PayloadType => 8;
66+
67+
public StringBuilder BuildSDP(StringBuilder sdp)
68+
{
69+
sdp.Append($"m=audio 0 RTP/AVP {PayloadType}\n"); // <---- Payload Type 8 means G711 ALAW
70+
sdp.Append($"a=control:trackID={ID}\n");
71+
sdp.Append($"a=rtpmap:{PayloadType} PCMA/{SamplingRate}\n");
72+
return sdp;
73+
}
74+
75+
public (List<Memory<byte>>, List<IMemoryOwner<byte>>) PrepareRtpPackets(List<byte[]> samples, uint rtpTimestamp)
76+
{
77+
List<Memory<byte>> rtpPackets = new List<Memory<byte>>();
78+
List<IMemoryOwner<byte>> memoryOwners = new List<IMemoryOwner<byte>>();
79+
80+
for (int i = 0; i < samples.Count; i++)
81+
{
82+
var audioPacket = samples[i];
83+
var size = 12 + audioPacket.Length;
84+
var owner = MemoryPool<byte>.Shared.Rent(size);
85+
memoryOwners.Add(owner);
86+
87+
var rtpPacket = owner.Memory.Slice(0, size);
88+
89+
const bool rtpPadding = false;
90+
const bool rtpHasExtension = false;
91+
int rtpCsrcCount = 0;
92+
const bool rtpMarker = true;
93+
94+
RTPPacketUtil.WriteHeader(rtpPacket.Span,
95+
RTPPacketUtil.RTP_VERSION, rtpPadding, rtpHasExtension, rtpCsrcCount, rtpMarker, PayloadType);
96+
97+
RTPPacketUtil.WriteTS(rtpPacket.Span, rtpTimestamp);
98+
audioPacket.CopyTo(rtpPacket.Slice(12));
99+
rtpPackets.Add(rtpPacket);
100+
}
101+
102+
return (rtpPackets, memoryOwners);
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)