|
Wwise SDK 2024.1.9
|
Stream Manager는 Wwise 사운드 엔진에서 사운드뱅크를 로드하고 스트리밍된 오디오 파일을 읽을 때 사용합니다. 뿐만 아니라 I/O 관리자가 따로 없는 경우, 모든 게임 I/O에 대해 사용해도 됩니다. Stream Manager를 클라이언트로서 직접 사용하지 않을 경우 이번 장 전체를 건너뛰고 단순히 하위 레벨 I/O 연결을 구현해 Wwise I/O를 자신의 게임에 통합하기만 하면 됩니다.
Stream Manager의 주요 인터페이스는 AK::IAkStreamMgr 에 의해 정의되며, 이는 간단히 말해 스트리밍 오브젝트의 팩토리입니다.
Stream Manager를 사용하기 전에 먼저 인스턴스화해줘야 합니다.
| Default Streaming Manager Information Stream Manager 인스턴스화는 구현에 따라 달라집니다. 따라서 Stream Manager의 Audiokinetic 기본 구현 팩토리 함수는 AkStreamMgrModule.h: AK::StreamMgr::Create() 에서 정의됩니다. 이를 구현별 설정으로 전달해야 합니다 (초기화 설정에 대한 설명은 Audiokinetic Stream Manager 초기화 설정 츷 참고하세요). |
| Default Streaming Manager Information 스트림 오브젝트를 생성하고 사용하기 전에 상위 레벨 스트리밍 장치를 생성해야 합니다. 이 방식은 Adiokinetic의 Stream Maanger 기본 구현에 특화돼있습니다. 상위 레벨 스트리밍 장치는 근본적으로 I/O 스케줄러를 구현함으로서, 자신의 스레드에서 작동하여 연관된 스트림 오브젝트를 집중화해 데이터 전송 요청을 Low-Level I/O로 전달합니다. 상위 레벨 장치는 일반적으로 그냥 '장치'로 통칭됩니다. 하나 또는 여러 개의 장치가 게임에 의해 생성되며, 대부분 초기화 때에 특정 플래그와 설정으로 생성됩니다. 초기화 설정과 관련한 더 자세한 정보는 Audiokinetic Stream Manager 초기화 설정 를 참고하세요. AK::StreamMgr::CreateDevice() 가 장치 ID를 반환하며, Low-Level I/O가 파일 위치 및 장치 할당을 위해 이를 보관합니다. (더 많은 정보는 파일 위치 결정 섹션을 참고하세요. ) 이 장치 ID는 올바른 종료 처리를 위해 AK::StreamMgr::DestroyDevice() 로 전달돼야 합니다. 모든 구현 함수에 대해, AK::StreamMgr::CreateDevice() 와 AK::StreamMgr::DestroyDevice() 가 AkStreamMgrModule.h 헤더에 정의됩니다. |
Stream Manager 주요 API의 상당수는 스트림 팩토리 메소드 세트입니다. 파일 식별자와 설정을 통해 스트림 오브젝트를 생성하고 해당 스트림으로 인터페이스를 반환합니다. 모든 스트림 작업은 이 인터페이스를 통해 실행됩니다. In this API, it is possible to identify a stream file either by file name (string) or by file ID (integer). This choice is wrapped into the structure AkFileOpenData. Only one method should be used to designate a file. If both are used, the string method will be preferred.
![]() | 참고: Low-Level I/O 인터페이스의 Open() 메소드는 파일 식별자로부터 파일 설명자를 생성합니다. |
파일 식별자와 함께, 스트림 생성 메소드는 파일 위치 플래그가 들어있는 AkFileSystemFlags 구조체를 가리키는 포인터를 받습니다.
| Default Streaming Manager Information 이 포인터는 있는 그대로 Low-Level I/O로 전달됩니다. AkFileSystemFlags 와 사운드 엔진이 이를 어떻게 사용하는 지에 대한 더 자세한 정보는 SoundBank 와 스트리밍된 오디오 파일 , 기본 파일 위치 섹션을 참고하세요. |
스트림 생성 메소드에는 in_bSyncOpen 라는 또 추가 인자가 있습니다. 호출되는 동안 스트림 오브젝트로 감싼 파일 핸들을 열어야 할 때 사용자(예: 사운드 엔진)가 true를 전달합니다. 만약 사용자가 false를 전달하면, Stream Manager가 파일 열기를 지연키는 것을 허용한다는 뜻입니다. 이는 지연을 할 수도 있고 하지 않을 수도 있습니다. 만약 지연시킨 후 파일 열기가 실패할 경우, 다음 호출인 AK::IAkStdStream::Read() 나 AK::IAkAutoStream::GetBuffer() 가 AK_Fail을 반환합니다.
![]() | 참고: 이는 치명적인 오류에 해당됩니다. 사운드 엔진이 스트리밍된 오디오 파일에 대해 false를 전달합니다. GetBuffer() 가 false를 반환할 경우, 사운드 엔진이 이를 I/O 오류로 받아들여 스트림을 삭제합니다. |
| Default Streaming Manager Information Argument in_bSyncOpen 은 Low-Level I/O로 직접 전달됩니다. Low-Level I/O에서 이 플래그의 역할에 대한 자세한 내용은 지연 열기 을 참고하세요. |
AK::IAkStreamMgr::CreateStd() 는 표준 스트림을 생성하고, AK::IAkStreamMgr::CreateAuto() 는 자동 스트림을 생성합니다. 다음 섹션은 이 두 스트림 타입에 대한 설명입니다.
두 유형의 스트림 오브젝트 모두 Destroy() 메소드를 정의합니다. 이 스트림이 사용하는 리소스를 제거하기 위해서는 메소드를 호출해야 합니다. 그런 다음 해당 오브젝트를 다시 사용하면 안 됩니다.
Default Streaming Manager Information 소멸이 예정된 스트림 오브젝트는 I/O 스레드에 신호를 보내 Low-Level I/O에서 지연되고 있는 I/O 전송이 더 이상 없으면 즉시 제거될 수 있도록 합니다. 스트림 프로파일링이 발생하면, I/O 스레드는 스트림 오브젝트를 배치하기 전에 모니터링 스레드가 승인을 내리기를 기다립니다. 모니터링 스레드는 매 200 ms마다 프로파일링 전달을 실행합니다. |
AK::IAkStreamMgr::CreateStd() 를 호출하면 반환된 AK::IAkStdStream 인터페이스를 통해 표준 스트림 오브젝트를 생성합니다.
표준 스트림(standard stream)은 I/O 작업을 통제할 때 기본 읽기/쓰기 체계를 사용합니다. AK::IAkStdStream::Read() 나 AK::IAkStdStream::Write() 가 호출되면, I/O 요청이 스케줄러의 큐에 담기고 스트림의 상태를 AK_StmStatusPending 으로 설정합니다. 사용자는 요청된 전송 크기와 버퍼의 주소를 전달합니다. 작업이 완료되면, 스트림 상태를 AK_StmStatusCompleted 나 AK_StmStatusError 중 하나로 설정합니다. 해당 위치는 전송된 실제 크기에 따라 증가되어, 다음 작업이 새로운 위치에서 발생하게 됩니다. 다른 위치를 강제로 지정하려면 사용자는 새로운 전송을 시작하기 전에 AK::IAkStdStream::SetPosition() 메소드를 사용해야 합니다.
I/O 작업은 한 번에 하나만 발생할 수 있습니다. 그 다음 작업은 AK::IAkStdStream::Read() 나 AK::IAkStdStream::Write() 를 호출하여 명시적으로 시작됩니다. 사용자가 스트림을 이용해 작업을 끝냈을 경우, AK::IAkStdStream::Destroy() 가 호출돼야 합니다. 그러면 해당 인터페이스가 유효하지 않게 됩니다.
| Default Streaming Manager Information 읽기나 쓰기 호출은 Low-Level I/O의 I/O 전송으로 처리됩니다. 클라이언트 단에서 요청된 크기가 스트리밍 장치의 단위(AkDeviceSettings::uGranularity)보다 클 경우, 해당 전송은 작게 쪼개집니다. 스트림은 전체 전송이 완료되거나 파일 끝 상태가 발생할 때까지 AK_StmStatusPending 이나 AK_StmStatusIdle 상태로 남아있습니다. |
인터페이스는 설정 쿼리, 현재 상태나 위치에 접근, 이전 작업에 제공된 버퍼에 접근, 등과 같은 다른 메소드를 보여줍니다.
표준 스트림 작업을 실행하는 방법은 두 가지입니다.
AK::IAkStdStream::Read() 나 AK::IAkStdStream::Write() 의 in_bWait 매개 변수가 true이면, 해당 메소드는 모든 I/O가 완료될 때까지 즉각적으로 차단합니다.AK::IAkStdStream::Read() 나 AK::IAkStdStream::Write() 의 in_bWait 매개 변수가 false면, 해당 메소드는 I/O가 완료되기 전에 반환되고, 나머지 작업은 비동기식으로 완료됩니다. 스트림 상태는 AK_StmStatusCompleted 가 반환될 때까지 AK::IAkStdStream::GetStatus() 호출로 폴링되거나, AK::IAkStdStream::WaitForPendingOperation() 를 호출해 비동기 작업이 완료될 때까지 차단 대기를 할 수 있습니다. 그런 다음 읽기 작업을 위해 AK::IAkStdStream::GetData() 를 호출하거나 AK::IAkStdStream::Read() 초기 호출 동안 제공된 버퍼를 읽어 데이터에 안전하게 접근합니다.표준 스트림 생성할 때에는 열기 모드 (AkOpenMode)를 지정해줘야 합니다. 열기 모드는, 스트림을 읽기에 사용할 수 있는지, 쓰기에 사용할 수 있는지, 또는 둘 다에 사용할 수 있는지를 지정합니다. 물론 읽기 전용으로만 열려있는 스트림에 대해 AK::IAkStdStream::Write() 를 호출하면 실패합니다.
또한 AK::IAkStdStream::SetStreamName() 을 이용해 스트림 이름을 지정할 수도 있습니다. 해당 문자열은 스트림 오브젝트에 복사되며, AK::IAkStdStream::GetInfo() 로 쿼리될 수 있습니다.
| Default Streaming Manager Information 스트림 이름은 Wwise Advanced Profiler의 streaming 탭에 나타납니다. |
표준 스트림의 휴리스틱은 개별 작업별로 지정됩니다.
AK::IAkStdStream::Read() 와 AK::IAkStdStream::Write() 는 작업의 우선순위와 작업 시간(밀리세컨드 단위)을 필요로 합니다. 일반적으로 Stream Manager는 작업 시간이 짧은 작업부터 처리합니다. 애플리케이션에 저장 장치보다 더 큰 I/O 대역폭이 필요할 때, Stream Manager는 높은 우선순위의 스트림을 먼저 처리합니다. 작업 시간을 0으로 지정하면 데이터가 지금 바로 필요하다는 뜻이므로 I/O는 이미 늦은 상황이 됩니다. 이럴 경우, 보다 낮은 우선 순위의 다른 스트림보다 먼저 처리됩니다.
![]() | 참고: 사운드 엔진의 Bank Manager는 표준 스트림의 사용자입니다. Bank Manager는 해당 버퍼에서 SoundBank 데이터를 읽고 파싱합니다. 메소드는 사운드 엔진 API에 나타나 평균 처리량과 뱅크 로딩 우선 순위를 지정합니다 ( AK::SoundEngine::SetBankLoadIOSettings() ). ( Wwise 사운드 엔진의 Banks를 참고하세요. ) Bank Manager는 AK::IAkStdStream::Read() 를 호출하고, 완료되면 데이터를 파싱하고 읽습니다. 이 때 해당 메소드의 인자로서 제공된 우선 순위를 사용합니다. Bank Manager는 사용자가 지정한 처리량으로부터 작업 시간을 계산합니다. fDeadline = uBufferSize / fUserSpecifiedThroughput;
표준 스트림의 작업 시간과 자동 스트림의 평균 처리량은 Stream Manager의 I/O 스케줄러와 동일한 역할을 합니다. 따라서 사운드 엔진 사용자는 오디오 스트림과 게임에서 다른 스트림으로 I/O의 뱅크 로딩 부담을 조절할 수 있습니다. |
읽기와 찾기 단위의 하위 레벨 제약과 버퍼 정렬을 Stream Manager 레벨에서 '블록 크기 (block size)'라고 부릅니다. 스트림 인터페이스의 AK::IAkStdStream::GetBlockSize() 메소드는 Low-Level I/O를 쿼리하고 이를 스트림과 연관된 파일 설명자로 전달해 호출자에게 그 값을 반환합니다. 파일 설명자와 AK::StreamMgr::IAkLowLevelIOHook::GetBlockSize() 메소드에 대한 자세한 설명은 Low-Level I/O 섹션을 참고하세요. 일부 저장 장치는 데이터 전송 크기에 제약이 있습니다. 예를 들어, Win32 플랫폼에서 FILE_FLAG_UNBUFFERED 플래그로 연 파일은 물리적 장치의 부분 크기의 배수로만 전송 크기를 허용합니다. 블록 크기의 배수가 아닌 전송 크기를 요청한 경우 읽기나 쓰기 작업이 실패합니다. 상위 레벨 인터페이스 사용자는 AK::IAkStdStream::GetBlockSize()로 반환된 값의 배수로 된 읽기 크기를 요청해야 합니다. AK::IAkStdStream::SetPosition() 또한 동일한 제약이 적용됩니다. 그러나 AK::IAkStdStream::SetPosition() 는 낮은 블록 한도로 자동 스냅한 후 실제 파일 위치 오프셋을 반환합니다.
일반적으로 게임 타이틀이 Stream Manager의 사용자입니다. 게임 타이틀 또한 Low-Level I/O 하위 모듈을 구현하므로 사용할 수 있는 전송 크기를 이미 인지하고 있습니다. 사운드 엔진은 저장 장치 제약에 대해 인지하지 못하고 있으므로 언제나 자체 표준 스트림 읽기 크기를 블록 크기 한도로 스냅합니다.
스트림이 AK_StmStatusPending 상태에 있을 때 AK::IAkStdStream::Read() 와 AK::IAkStdStream::Write() 를 호출하면 실패합니다. AK::IAkStdStream::GetPosition() 과 AK::IAkStdStream::SetPosition() 은 I/O 전송이 완료되기 전이나 후에 발생할 수 있으므로 분명하지 않은 결과를 산출합니다. 그러나 I/O에서 차단되지는 않습니다.
전송이 지연되는 동안 AK::IAkStdStream::Cancel() 를 사용할 수 있지만, 성능이 안 좋아질 수 있기 때문에 추천하지 않습니다. 이 메소드는 지연 중인 I/O가 없다는 사실을 호출에게 확인시켜 줍니다. Low-Level I/O로 요청이 전송되기 전에 호출이 실행되면 해당 과제는 큐에서 제거됩니다. 그러나 요청이 이미 Low-Level I/O로 발송됐다면 I/O가 완료될 때까지 호출자가 차단됩니다.
![]() | 작은 정보: 사용자는 스트림을 파기하기 전에 (AK::IAkStdStream::Destroy()) AK::IAkStdStream::Cancel() 를 명시적으로 호출하지 않아도 됩니다. 그러나 가장 좋은 성능을 내려면 사용자가 스트림이 AK_StmStatusPending 상태에 있지 않을 때에만 Destroy()를 호출하면 됩니다. |
AK::IAkStreamMgr::CreateAuto() 를 호출하면 반환된 AK::IAkAutoStream 인터페이스를 통해 자동 스트림 오브젝트를 생성합니다.
자동 스트림은 입력에만 사용되는 스트림입니다. 자동 스트림이라 불리는 이유는, 사용자의 명시적 함수 호출 없이 내부 처리 과정을 통해 I/O 요청이 Low-Level I/O로 전송되기 때문입니다. 스트리밍 메모리는 Stream Manager가 소유하며, 스트리밍 메모리 주소를 요청해 스트리밍된 데이터에 접근할 수 있습니다. 스트리밍 메모리 영역이 사용자에게 부여되면 명시적으로 해제될 때까지 잠긴 상태를 유지합니다. 한편 내부 스케줄러는 잠기지 않은 메모리에서 데이터 전송을 실행합니다. 스트림은 생성될 때 idle 상태입니다. I/O 요청의 자동 스케줄링은 사용자가 AK::IAkAutoStream::Start() 를 호출할 때 시작됩니다. AK::IAkAutoStream::Stop() 을 호출하면 멈추거나 일시 정지하고, AK::IAkAutoStream::Start() 를 호출하면 재개됩니다.
![]() | 경고: 스트림이 멈춰있는 동안 GetBuffer() 를 호출하지 마세요. 스트림으로부터 버퍼를 구하려고 하기 전에 항상 Start() 를 호출해야 합니다. |
데이터는 AK::IAkAutoStream::GetBuffer() 를 호출해 접근할 수 있습니다. 데이터가 Low-Level I/O로부터 이미 읽힌 경우, 메소드는 AK_DataReady, 해당 데이터가 포함된 버퍼의 주소, 그리고 그 크기를 반환합니다. 버퍼가 더 이상 필요하지 않게 되면, AK::IAkAutoStream::ReleaseBuffer() 를 호출하여 해제합니다. 그러면 해제된 버퍼의 크기만큼 사용자에게 보이는 스트림 위치가 증가됩니다. 사용자는 AK::IAkAutoStream::SetPosition() 을 호출해 새로운 위치를 강제로 지정할 수 있습니다. 다음 AK::IAkAutoStream::GetBuffer() 호출은 이 위치와 일치하게 됩니다.
스트림 위치를 변경하면 일부 데이터가 지워질 수 있습니다. 자동 스트림은 순차적인 접근에 최적화돼있습니다. 여기에는 반복 재생을 지정하는 휴리스틱이 있습니다. 이 휴리스틱은 Stream Manager가 스트리밍 메모리를 효율적으로 관리할 수 있도록 돕습니다. 더 자세한 정보는 일반적인 위험과 다른 고려 사항 섹션을 참고하세요.
![]() | 경고: Low-Level I/O가 오류를 보고하면 해당 스트림이 자체적으로 오류 모드로 들어갑니다. 자동 스트림은 오류 상태에서 복구할 수는 없으며, AK::IAkAutoStream::GetBuffer() 가 항상 AK_Fail을 반환하게 됩니다. |
자동 스트림의 데이터에 접근하는 방법은 두 가지입니다.
AK::IAkAutoStream::GetBuffer() 에 사용할 수 있는 반환 코드는 다음 네 가지입니다.
사용자에게 데이터로 채워진 버퍼가 부여되면, 메소드는 AK_DataReady 나 AK_NoMoreData 중 하나를 반환합니다. 만약 스트림 버퍼가 비어있을 경우, AK::IAkAutoStream::GetBuffer() 가 AK_NoDataReady 를 크기 0과 버퍼 주소 null로 반환합니다. Low-Level I/O가 오류를 보고하거나 메소드가 유효하지 않은 매개 변수로 호출되면 AK_Fail을 반환합니다.
파일의 마지막 버퍼가 부여될 때는 AK_DataReady 대신 AK_NoMoreData 가 반환됩니다. Stream Manager가 파일 설명자 구조체 멤버로서 Low-Level I/O가 제공한 파일 크기와 현재 위치(사용자에게 보이는)를 비교해 마지막 버퍼임을 평가합니다. 그 다음 호출인 AK::IAkAutoStream::GetBuffer() 는 AK_NoMoreData 를 크기 0으로 반환합니다.
각 AK::IAkAutoStream::GetBuffer() 호출은 새로운 버퍼를 제공합니다. 버퍼는 AK::IAkAutoStream::ReleaseBuffer() 를 호출해 명시적으로 해제해야 합니다. 이 버퍼들은 GetBuffer()에 의해 부여된 순서대로 해제됩니다. 버퍼가 해제되면 해당 주소는 유효하지 않게 됩니다. 클라이언트가 아무 버퍼도 갖고있지 않을 경우 ReleaseBuffer() 는 AK_Fail 을 반환합니다. 그러나 이를 치명적인 오류로 간주하지는 않습니다.
![]() | 작은 정보: 가능하다면 한 번에 버퍼 하나씩만 사용하세요. 이렇게 하면 Stream Manager가 I/O를 실행할 공간이 더 생깁니다. 한 번에 버퍼를 둘 이상 사용하는 경우는 주로 링 버퍼나 이중 버퍼에 접근해야 하는 하드웨어나 다른 인터페이스에만 해당됩니다. 한 스트림에 대해 한 번에 둘 이상의 버퍼를 사용할 경우, 적합한 휴리스틱을 전달해 알려줘야 합니다 (AkAutoStmHeuristics::uMinNumBuffers). |
![]() | 경고: 자동 스트림을 사용할 때 가장 흔히 하는 실수는 ReleaseBuffer() 를 호출을 잊어버리는 것입니다. |
성공적인 GetBuffer() 호출에 의해 부여된 버퍼 크기는 Stream Manager에 의해 결정됩니다. 그래도 근본 파일의 끝에 도달하지 않는 한 버퍼 크기는 블록 크기의 배수여야 합니다. 버퍼링 제약을 이용하는 (AkAutoStmBufSettings 참고) GetBuffer() 에 의해 반환된 크기를 강제로 지정해 생성 시간에 전달할 수도 있습니다.
![]() | 경고: 버퍼 크기를 강제로 지정하면 스트리밍 메모리나 대역폭이 낭비될 수 있기 때문에 최적의 성능을 내지 못할 수 있습니다. 또한, 사용자가 지정한 제약은 지원하지 않습니다. IAkStreamMgr::CreateAuto() 는 AK_Fail 을 반환하게 됩니다. |
| Default Streaming Manager Information 이 크기는 스트림이 끝에 도달한 경우를 제외하고는 주로 상위 레벨 장치 생성 설정에 지정된 단위와 일치합니다. |
True로 설정된 in_bWait 플래그로 AK::IAkAutoStream::GetBuffer() 를 호출하면 데이터가 준비될 때까지 사용자를 차단합니다. 따라서 메소드가 AK_NoDataReady 를 반환할 수 없습니다. 마지막 버퍼가 이미 부여됐거나 해제된 경우, 메소드는 바로 AK_NoMoreData를 크기 0으로 반환합니다.
사용자는, in_bWait 플래그를 False로 설정하여 호출된 AK::IAkAutoStream::GetBuffer() 가 반환한 코드를 평가해 데이터를 구할 수 있습니다. 만약 AK_NoDataReady 인 경우, 사용자는 다른 과제를 실행하고 나중에 다시 시도해야 합니다.
자동 스트림은 표준 스트림보다 더 다양한 설정으로 인스턴스화됩니다. 그중에는 휴리스틱과 버퍼 크기 제약이 있습니다. 이 설정들은 Stream Manager가 최적의 메모리 양을 할당하고 데이터 전송 요청의 우선 순위를 정하는 것을 돕습니다.
일부 설정은 사용자가 지정한 메모리 연관 제약들입니다. 이 때 버퍼 크기는 직접 지정할 수 있습니다. Stream Manager가 일정한 한도 내에서 버퍼 크기를 선택하게 하고 싶다면 최소 버퍼 크기나 블록 크기를 지정하면 됩니다. 버퍼 크기는 블록 크기의 배수가 됩니다.
![]() | 작은 정보: 버퍼 제약은 선택 사항이며, Stream Manager가 스트리밍 메모리를 선택적으로 관리할 수 있도록 일반적으로 사용해서는 안 됩니다. 사운드 엔진은 일부 플랫폼에서 디코딩 파드웨어를 사용할 때 버퍼 제약을 사용합니다. 이 디코더는 주로, 특정한 바이트 정렬(블록 크기)과 최소 버퍼 크기로 한 번에 두 버퍼로 접근해야 합니다. |
Default Streaming Manager Information |
휴리스틱은 Stream Manager의 스케줄링과 메모리 할당 작업을 돕습니다. 자동 스트림 휴리스틱은 생성 시간에 스트림별로 지정되며 최적의 동작을 내기 위해 매우 중요합니다. 자동 스트림 휴리스틱은 AK::IAkAutoStream::GetHeuristics() 와 AK::IAkAutoStream::SetHeuristics() 를 통해 아무 때나 쿼리되거나 변경될 수 있습니다.
Stream Manager는 항상 버퍼 크기를 결정하기 전에 파일의 블록 크기를 Low-Level I/O로 쿼리해 버퍼 크기가 블록 크기의 배수가 되도록 합니다. 따라서 자동 스트림 사용자는, 스트림을 다른 위치로 강제 지정하지 않는 한 Low-Level 블록 크기에 대해 신경 쓰지 않아도 됩니다. 이 경우, 블록 크기를 AK::IAkAutoStream::GetBlockSize() 에서 가져온 것으로 감안하거나, AK::IAkAutoStream::SetPosition() 에서 반환된 실제 절대 상쇄값으로 간주합니다.
Stream 위치는 사용자 시점에서 평가되며, Get/SetPosition() 메소드로 쿼리되고 설정됩니다. Low-Level I/O로부터 Stream Manager의 버퍼로 전송 받은 데이터는 위치를 계산할 때 포함하지 않습니다. Stream 위치는 사용자에 의해 버퍼가 해제될 때 업데이트됩니다. AK::IAkAutoStream::SetPosition() 가 호출됐을 때 일부 데이터가 이미 Low-Level I/O로부터 전송됐을 경우, 해당 데이터는 일반적으로 지워집니다.
![]() | 참고: 사용자는 가능하면 항상 AK::IAkAutoStream::SetPosition() 호출을 피해야 합니다. 반드시 사용해야 할 때에는, 최대한 일찍 호출해야 합니다. 예를 들어, 사운드 엔진에서 반복 재생 음원이 Stream Manager로부터 버퍼를 가져올 때 반복 재생의 끝이 그 버퍼에 들어있는지를 확인합니다. 만약 들어있다면, 곧바로 AK::IAkAutoStream::SetPosition() 가 호출되고 (즉, ReleaseBuffer() 한참 전에 호출됨), 그에 따라 필요 없는 데이터의 스트리밍이 발생할 위험을 최소화합니다. 또한 반복 재생 휴리스틱을 지정하면 내부 스케줄러가 Low-Level I/O에 보낼 요청과 관련해 더 나은 결정을 내릴 수 있도록 돕습니다. |
![]() | 작은 정보: 버퍼를 차단하든 차단하지 않든 AK::IAkAutoStream::SetPosition() 를 호출할 수 있지만, 불필요한 스트리밍 데이터가 발생할 위험을 최소화하려면 최대한 일찍 위치를 변경하는 것이 좋습니다. 스트리밍을 적절하게 중지하는 것은 대역폭 낭비를 최소화하는 데에도 도움이 됩니다. AK::IAkAutoStream::SetPosition() 는 클라이언트가 갖고있는 버퍼를 해제하지 않습니다. 클라이언트는 ReleaseBuffer() 를 명시적으로 호출해 버퍼가 언제 해제될지를 결정합니다. AK::IAkAutoStream::SetPosition() 는 사실상 클라이언트가 GetBuffer() 의 호출 다음으로 기대하는 위치를 나타냅니다. AK::IAkAutoStream::GetPosition() 는 현재 클라이언트가 갖고있는 첫 번째 버퍼의 위치를 반환합니다. 만약 클라이언트가 아무 버퍼도 갖고있지 않다면 GetBuffer() 의 다음 호출에 부여될 버퍼의 위치를 반환합니다. |
AK::IAkAutoStream::GetBuffer() 의 AK_NoMoreData 반환 코드는 스트림 위치로부터 결정됩니다. AK::IAkAutoStream::GetPosition() 에 의해 반환되는 out_bEndOfStream 선택적 플래그도 스트림 위치에 따라 달라집니다. 이는 다음 경우에 한해 True를 반환합니다.
자동 스트림 API는 AK::IAkAutoStream::GetBuffer() 호출 차단을 제외하고는 지연되는 Low-Level I/O 처리를 사용자가 절대 차단하지 않도록 설계되었습니다. AK::IAkAutoStream::Destroy() 도 차단해서는 안 됩니다. 일반적으로 한 스트림이 파기될 때 아직 Low-Level I/O와 상호 작용중이라면 이 스트림은 Low-Level I/O과의 현재 전송이 완료될 때까지 내부적으로 활성화돼있습니다.
전체 Stream Manager를 오버라이드하기 위해서는 게임 타이틀이 IAkStreamMgr.h 에 정의돼있는 모든 인터페이스를 구현해야 합니다. 이 구현은 이 섹션의 다른 곳에서 설명한 규칙을 따라야합니다.
정적 라이브러리 AkStreamMgr.lib를 게임 자체의 정적 라이브러리로 교체해도 됩니다. Low-Level I/O API와 같이 다른 구현 전용 설정과 정의 및 생성 함수는 AkStreamMgrModule.h 에 위치하고 있으며 Stream Manager에 속해있지 않습니다.
사운드 엔진은 인라인 정적 AK::IAkStreamMgr::Get() 메소드를 호출해 Stream Manager에 접근하며, 이는 AK::IAkStreamMgr 의 protected 멤버로 정의된 AK::IAkStreamMgr 인터페이스를 가리키는 포인터를 반환합니다. 커스텀 구현은 반드시 하나의 변수(AK::IAkStreamMgr::m_pStreamMgr)만 선언해야 하며, 연결은 자동으로 됩니다. Stream Manager와 사운드 엔진이 같은 실행 파일이나 DLL에서 연결돼있지 않은 경우 AK::IAkStreamMgr::m_pStreamMgr 에 __dllexport 속성이 있어야 합니다. 커스텀 Stream Manager 라이브러리의 컴파일러 설정에서 정의된 AKSTREAMMGR_EXPORTS로 AKSTREAMMGR_API 매크로를 사용할 수 있습니다.
사운드 엔진의 non-AK_OPTIMIZED 버전과 연결하기 위해 프로파일링 인터페이스도 구현돼야 합니다. 인터페이스는 따로 설명이 필요 없을 정도로 명백합니다. 이를 구현하면 Wwise 내 프로파일링을 활성화시킵니다. 프로파일링이 필요 없을 경우, AK::IAkStreamMgr::GetStreamMgrProfile() 이 NULL을 반환하고, 해당 인터페이스는 텅 빈 코드로 구현될 수 있습니다. 이 경우, Wwise에서 아무런 프로파일링 정보도 나타나지 않습니다.
다음 몇 가지 고려해야 할 사항들은 글로 된 설명보다는 아래 나온 코드를 보면 이해가 더 쉽습니다. Stream Manager의 구현을 오버라이드하거나 변경할 때 특히 유용합니다. 이 코드는 특별한 주의가 필요한 내용을 담고 있기 때문에 의도적으로 코드 양이 많습니다.
프로젝트를 등록하세요. 아무런 조건이나 의무 사항 없이 빠른 시작을 도와드리겠습니다.
Wwise를 시작해 보세요