diff --git a/.gitignore b/.gitignore
index ab53353..1aebf98 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,9 @@
 
 /app/demo/push_rtmp_hook
 /app/demo/parse_ts/
+/app/demo/tytsp/
+/app/demo/parse_mp4/
+/app/demo/udp_server/
 
 /windows
 
diff --git a/pkg/base/t_http_an__.go b/pkg/base/t_http_an__.go
index b9c1b3b..f7121aa 100644
--- a/pkg/base/t_http_an__.go
+++ b/pkg/base/t_http_an__.go
@@ -51,6 +51,8 @@ type StatGroup struct {
 	StatSubs    []StatSub `json:"subs"` // TODO(chef): [opt] 增加数量字段,因为这里不一定全部放入
 	StatPull    StatPull  `json:"pull"`
 
+	// TODO: [opt] 增加字段,最近1秒,5秒,10秒等时间段的fps 202408
+	// TODO: [opt] 考虑和bitrate等字段语义统一,详细的数据可以是detail样式的字段 202408
 	Fps []RecordPerSec `json:"in_frame_per_sec"`
 }
 
@@ -89,7 +91,7 @@ type StatPull struct {
 }
 
 type PeriodRecord struct {
-	mu sync.Mutex
+	mu      sync.Mutex
 	ringBuf []RecordPerSec
 	//nRecord int
 }
@@ -116,47 +118,26 @@ func Session2StatPull(session ISession) StatPull {
 
 // GetFpsFrom
 //
-// @note result s.Fps is not ordered
+// s.Fps 是输出,p 是输入
 func (s *StatGroup) GetFpsFrom(p *PeriodRecord, nowUnixSec int64) {
-	// s.Fps 是输出,p 是输入
-	// p.nRecord 是有数据的元素个数,但是如果 nowUnixSec 和元素的 UnixSec 相等,那么这个元素的数据还没有完全记录,这个元素需要被忽略
-	// 当前的实现,把 p.nRecord 和 元素的 UnixSec 重置了,也就是被GetFpsFrom获取过的元素,下次将不被获取
-	//
-	// 新的要解决的问题:
-	// 1 获取过的,还可以再次获取 [DONE]
-	// 2.1 去除 nRecord 字段,避免竞态 [DONE]
-	// 2.2 加锁,保护 ringBuf [DONE]
-	// 2 数据是排序好的 [DONE]
-	// 3 增加字段,最近1秒,5秒,10秒等时间段的fps
-	// 4 考虑和bitrate等字段语义统一,详细的数据可以是detail样式的字段
-
 	p.mu.Lock()
 	defer p.mu.Unlock()
 
-	//if s.Fps == nil || cap(s.Fps) < p.nRecord {
-	//	s.Fps = make([]RecordPerSec, p.nRecord)
-	//} else {
-	//	s.Fps = s.Fps[0:p.nRecord]
-	//}
-
 	if s.Fps == nil || len(s.Fps) < len(p.ringBuf) {
 		s.Fps = make([]RecordPerSec, len(p.ringBuf))
 	}
 
 	nRecord := 0
-	//p.nRecord = 0
 	for _, record := range p.ringBuf {
 		if record.UnixSec == 0 {
 			continue
 		}
 		if record.UnixSec == nowUnixSec {
 			// value at nowUnixSec not completely recorded
-			//p.nRecord++
 			continue
 		}
 		s.Fps[nRecord] = record
 		nRecord++
-		//p.ringBuf[idx].UnixSec = 0
 	}
 	s.Fps = s.Fps[0:nRecord]
 
@@ -168,7 +149,6 @@ func (s *StatGroup) GetFpsFrom(p *PeriodRecord, nowUnixSec int64) {
 func NewPeriodRecord(bufSize int) PeriodRecord {
 	return PeriodRecord{
 		ringBuf: make([]RecordPerSec, bufSize),
-		//nRecord: 0,
 	}
 }
 
@@ -183,18 +163,8 @@ func (p *PeriodRecord) Add(unixSec int64, v uint32) {
 	if record.UnixSec == unixSec {
 		p.ringBuf[index].V = record.V + v
 	} else {
-		//if record.UnixSec == 0 {
-		//	p.nRecord++
-		//}
 		p.ringBuf[index].UnixSec = unixSec
 		p.ringBuf[index].V = v
 	}
 	return
 }
-
-//func (p *PeriodRecord) Clear() {
-//	for idx := range p.ringBuf {
-//		p.ringBuf[idx].UnixSec = 0
-//		p.ringBuf[idx].V = 0
-//	}
-//}
diff --git a/pkg/base/t_http_an__test.go b/pkg/base/t_http_an__test.go
index f64e5f3..be413a2 100644
--- a/pkg/base/t_http_an__test.go
+++ b/pkg/base/t_http_an__test.go
@@ -9,79 +9,56 @@
 package base
 
 import (
-	"fmt"
-	"strings"
+	"github.com/q191201771/naza/pkg/assert"
 	"testing"
 )
 
-func ringBufToStr(ringBuf []RecordPerSec) string {
-	var buf strings.Builder
-	for idx, record := range ringBuf {
-		if record.UnixSec == 0 {
-			continue
-		}
-		record_str := fmt.Sprintf(" [%d]:{%d,%d}", idx, record.UnixSec, record.V)
-		buf.WriteString(record_str)
-	}
-	return buf.String()
-}
+//func ringBufToStr(ringBuf []RecordPerSec) string {
+//	var buf strings.Builder
+//	for idx, record := range ringBuf {
+//		if record.UnixSec == 0 {
+//			continue
+//		}
+//		record_str := fmt.Sprintf(" [%d]:{%d,%d}", idx, record.UnixSec, record.V)
+//		buf.WriteString(record_str)
+//	}
+//	return buf.String()
+//}
 
 func TestPeriodRecord(t *testing.T) {
+	funCmpRecord := func(index int, record *RecordPerSec, expect *RecordPerSec) {
+		assert.Equal(t, record.UnixSec, expect.UnixSec)
+		assert.Equal(t, record.V, expect.V)
+	}
+
 	records := NewPeriodRecord(16)
+	statSess := StatGroup{}
 
 	expected_fps := []RecordPerSec{
 		{UnixSec: 1, V: 11},
 		{UnixSec: 3, V: 13},
 		{UnixSec: 9, V: 19},
 		{UnixSec: 16, V: 26},
-		{UnixSec: 17, V: 27}, // fpsRingBuf len 16, so replace 1
-		{UnixSec: 19, V: 29}, // replace 3
-		{UnixSec: 25, V: 35}, // replace 9
+		{UnixSec: 17, V: 27},
+		{UnixSec: 19, V: 29},
+		{UnixSec: 25, V: 35},
 		{UnixSec: 26, V: 36},
 	}
-	expected_n := 5
-
+	expected_n := 4
 	for _, record := range expected_fps {
 		records.Add(record.UnixSec, 1)
 		records.Add(record.UnixSec, 2)
 		records.Add(record.UnixSec, 3)
 		records.Add(record.UnixSec, record.V-6)
-		t.Logf("records.nRecord:%d", records.nRecord)
 	}
-
-	if records.nRecord != expected_n {
-		t.Fatalf("nFpsRecord not match, got:%d expect:%d, %s",
-			records.nRecord, expected_n, ringBufToStr(records.ringBuf))
-	}
-
 	nowUnixSec := int64(26)
-	expected_n = 4 // 26 not complete
-	statSess := StatGroup{}
 	statSess.GetFpsFrom(&records, nowUnixSec)
-	// { 16, 17, 19, 25 }
-	// 26 not complete
-	if len(statSess.Fps) != expected_n {
-		t.Fatalf("len(statSess.Fps) not match, got:%d expect:%d, %s",
-			len(statSess.Fps), expected_n, ringBufToStr(statSess.Fps))
-	}
-
-	funCmpRecord := func(index int, record *RecordPerSec, expect *RecordPerSec) {
-		if record.UnixSec != expect.UnixSec {
-			t.Fatalf("index:%d UnixSec not match, got:%d expect:%d",
-				index, record.UnixSec, expect.UnixSec)
-		}
-		if record.V != expect.V {
-			t.Fatalf("index:%d V not match, got:%d expect:%d", index, record.V, expect.V)
-		}
-	}
 
-	funCmpRecord(0, &statSess.Fps[0], &expected_fps[3])
-	funCmpRecord(1, &statSess.Fps[1], &expected_fps[4])
-	funCmpRecord(2, &statSess.Fps[2], &expected_fps[5])
-	funCmpRecord(3, &statSess.Fps[3], &expected_fps[6])
-	t.Log(ringBufToStr(statSess.Fps))
-
-	t.Log("2nd period record test")
+	assert.Equal(t, expected_n, len(statSess.Fps))
+	funCmpRecord(0, &statSess.Fps[0], &expected_fps[6])
+	funCmpRecord(1, &statSess.Fps[1], &expected_fps[5])
+	funCmpRecord(2, &statSess.Fps[2], &expected_fps[4])
+	funCmpRecord(3, &statSess.Fps[3], &expected_fps[3])
 
 	expected_fps_2nd := []RecordPerSec{
 		{UnixSec: 0 + 16*2, V: 10 + 16*2},
@@ -90,52 +67,36 @@ func TestPeriodRecord(t *testing.T) {
 		{UnixSec: 9 + 16*2, V: 9 + 16*2},
 		{UnixSec: 11 + 16*2, V: 11 + 16*2},
 	}
-	nowUnixSec = 11 + 16*2
 	expected_n = 5
-	// records = { 26 }
 	for _, record := range expected_fps_2nd {
 		records.Add(record.UnixSec, record.V)
 	}
+	nowUnixSec = 11 + 16*2
 	statSess.GetFpsFrom(&records, nowUnixSec)
 
-	// {32, 33, 35, 41, 26}
-	// 11 + 16*2 not complete
-	if len(statSess.Fps) != expected_n {
-		t.Fatalf("len(statSess.Fps) not match, got:%d expect:%d, %s",
-			len(statSess.Fps), expected_n, ringBufToStr(statSess.Fps))
-	}
-	funCmpRecord(0, &statSess.Fps[0], &expected_fps_2nd[0])
-	funCmpRecord(1, &statSess.Fps[1], &expected_fps_2nd[1])
-	funCmpRecord(2, &statSess.Fps[2], &expected_fps_2nd[2])
-	funCmpRecord(3, &statSess.Fps[3], &expected_fps_2nd[3])
+	assert.Equal(t, expected_n, len(statSess.Fps))
+	funCmpRecord(0, &statSess.Fps[0], &expected_fps_2nd[3])
+	funCmpRecord(1, &statSess.Fps[1], &expected_fps_2nd[2])
+	funCmpRecord(2, &statSess.Fps[2], &expected_fps_2nd[1])
+	funCmpRecord(3, &statSess.Fps[3], &expected_fps_2nd[0])
 	funCmpRecord(4, &statSess.Fps[4], &expected_fps[7])
 
-	t.Log(ringBufToStr(statSess.Fps))
-
-	t.Log("3rd period record test")
-
 	expected_fps = []RecordPerSec{
 		{UnixSec: 0 + 16*3, V: 10 + 16*3},
 		{UnixSec: 1 + 16*3, V: 11 + 16*3},
 		{UnixSec: 3 + 16*3, V: 13 + 16*3},
 	}
-	nowUnixSec = 3 + 16*3 + 1
-	expected_n = 4
-
-	// records = { 11 + 16*2 }
+	expected_n = 6
 	for _, record := range expected_fps {
 		records.Add(record.UnixSec, record.V)
 	}
+	nowUnixSec = 3 + 16*3 + 1
 	statSess.GetFpsFrom(&records, nowUnixSec)
 
-	if len(statSess.Fps) != expected_n {
-		t.Fatalf("len(statSess.Fps) not match, got:%d expect:%d, %s",
-			len(statSess.Fps), expected_n, ringBufToStr(statSess.Fps))
-	}
-
-	funCmpRecord(0, &statSess.Fps[0], &expected_fps[0])
+	assert.Equal(t, expected_n, len(statSess.Fps))
+	funCmpRecord(0, &statSess.Fps[0], &expected_fps[2])
 	funCmpRecord(1, &statSess.Fps[1], &expected_fps[1])
-	funCmpRecord(2, &statSess.Fps[2], &expected_fps[2])
+	funCmpRecord(2, &statSess.Fps[2], &expected_fps[0])
 	funCmpRecord(3, &statSess.Fps[3], &expected_fps_2nd[4])
-	t.Log(ringBufToStr(statSess.Fps))
+	funCmpRecord(3, &statSess.Fps[4], &expected_fps_2nd[3])
 }