@@ -88,39 +88,50 @@ public async Task<TextToSpeechResponse> TextToSpeechAsync(TextToSpeechRequest re
8888 {
8989 const int chunkSize = 32768 ; // 32KB 청크 크기
9090 byte [ ] ? readBuffer = null ;
91- MemoryStream ? memoryStream = null ;
91+ IMemoryOwner < byte > ? owner = null ;
9292
9393 try
9494 {
9595 readBuffer = _arrayPool . Rent ( chunkSize ) ;
96- memoryStream = new MemoryStream ( ) ;
97-
9896 using var stream = await content . ReadAsStreamAsync ( ) ;
99- int bytesRead ;
10097
101- // 청크 단위로 데이터 읽어서 MemoryStream에 복사
102- while ( ( bytesRead = await stream . ReadAsync ( readBuffer , 0 , chunkSize ) ) > 0 )
98+ // 초기 버퍼 렌트(증분 확장 전략)
99+ owner = MemoryPool < byte > . Shared . Rent ( chunkSize ) ;
100+ int total = 0 ;
101+ while ( true )
103102 {
104- await memoryStream . WriteAsync ( readBuffer , 0 , bytesRead ) ;
105- }
106-
107- var totalSize = ( int ) memoryStream . Length ;
103+ // 여유 공간 없으면 확장
104+ if ( total == owner . Memory . Length )
105+ {
106+ var newOwner = MemoryPool < byte > . Shared . Rent ( Math . Min ( owner . Memory . Length * 2 , int . MaxValue ) ) ;
107+ owner . Memory . Span . Slice ( 0 , total ) . CopyTo ( newOwner . Memory . Span ) ;
108+ owner . Dispose ( ) ;
109+ owner = newOwner ;
110+ }
108111
109- // ArrayPool에서 최종 데이터 크기만큼 메모리 할당
110- var resultMemoryOwner = MemoryPool < byte > . Shared . Rent ( totalSize ) ;
112+ int toRead = Math . Min ( chunkSize , owner . Memory . Length - total ) ;
113+ int bytesRead = await stream . ReadAsync ( readBuffer , 0 , toRead ) ;
114+ if ( bytesRead == 0 ) break ;
115+ readBuffer . AsSpan ( 0 , bytesRead ) . CopyTo ( owner . Memory . Span . Slice ( total ) ) ;
116+ total += bytesRead ;
117+ }
111118
112- // MemoryStream에서 최종 메모리로 복사
113- memoryStream . Position = 0 ;
114- await memoryStream . ReadAsync ( resultMemoryOwner . Memory . Slice ( 0 , totalSize ) ) ;
119+ if ( total == 0 )
120+ {
121+ owner . Dispose ( ) ;
122+ _logger . LogDebug ( "[TTS][ArrayPool] 비어있는 오디오 스트림" ) ;
123+ return ( null , 0 ) ;
124+ }
115125
116126 _logger . LogDebug ( "[TTS][ArrayPool] 음성 데이터 읽기 완료: {Size} bytes, 청크 크기: {ChunkSize}" ,
117- totalSize , chunkSize ) ;
127+ total , chunkSize ) ;
118128
119- return ( resultMemoryOwner , totalSize ) ;
129+ return ( owner , total ) ;
120130 }
121131 catch ( Exception ex )
122132 {
123133 _logger . LogError ( ex , "[TTS][ArrayPool] 음성 데이터 읽기 실패" ) ;
134+ owner ? . Dispose ( ) ;
124135 return ( null , 0 ) ;
125136 }
126137 finally
@@ -129,7 +140,7 @@ public async Task<TextToSpeechResponse> TextToSpeechAsync(TextToSpeechRequest re
129140 {
130141 _arrayPool . Return ( readBuffer ) ;
131142 }
132- memoryStream ? . Dispose ( ) ;
143+ // owner는 정상 경로에서 호출자에게 반환됨. 예외 시 위에서 Dispose 처리.
133144 }
134145 }
135146
0 commit comments