Wwise SDK 2024.1.0
|
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를 시작해 보세요