private static unsafe void AllocateAndPrimeBuffers(AudioStream *pThis) { OSStatus status = API.AudioQueueAllocateBufferWithPacketDescriptions(pThis->Queue, pThis->BufferByteSize, pThis->NumPacketsToRead, &pThis->Buffer0); API.CheckStatus(status); status = API.AudioQueueAllocateBufferWithPacketDescriptions(pThis->Queue, pThis->BufferByteSize, pThis->NumPacketsToRead, &pThis->Buffer1); API.CheckStatus(status); status = API.AudioQueueAllocateBufferWithPacketDescriptions(pThis->Queue, pThis->BufferByteSize, pThis->NumPacketsToRead, &pThis->Buffer2); API.CheckStatus(status); pThis->IsRunning = true; if (pThis->Buffer0 == null) { Console.WriteLine("AudioQueueAllocateBufferWithPacketDescriptions failed to allocate buffer0 of size " + pThis->BufferByteSize); } if (pThis->Buffer1 == null) { Console.WriteLine("AudioQueueAllocateBufferWithPacketDescriptions failed to allocate buffer0 of size " + pThis->BufferByteSize); } if (pThis->Buffer2 == null) { Console.WriteLine("AudioQueueAllocateBufferWithPacketDescriptions failed to allocate buffer0 of size " + pThis->BufferByteSize); } ReadBufferProc(pThis, pThis->Queue, pThis->Buffer0); ReadBufferProc(pThis, pThis->Queue, pThis->Buffer1); ReadBufferProc(pThis, pThis->Queue, pThis->Buffer2); }
internal static void Play(AudioStream *pThis) { // start the queue OSStatus status = API.AudioQueueStart(pThis->Queue, null); API.CheckStatus(status); }
static unsafe void PropertyChangeInternal(void *pUserData, AudioQueue *pQueue, AudioQueueProperty id) { AudioStream *pThis = (AudioStream *)pUserData; if (pThis == null) { Console.WriteLine("PropertyChangeProc: pThis is null"); } if (pQueue == null) { Console.WriteLine("PropertyChangeProc: pQueue is null"); } int size = sizeof(uint); uint iIsRunning = 0; OSStatus status = API.AudioQueueGetProperty(pQueue, AudioQueueProperty.IsRunning, &iIsRunning, &size); API.CheckStatus(status); bool isRunning = iIsRunning != 0; if (status == 0) { if (pThis->IsRunning && !isRunning) { AudioStream.Stop(pThis); } } }
public unsafe static AudioStream *AllocateStream() { AudioStream *pThis = (AudioStream *)Marshal.AllocHGlobal(sizeof(AudioStream)); API.ZeroMemory(pThis, sizeof(AudioStream)); return(pThis); }
private static unsafe void OpenFileAndCreateStream(AudioStream *pThis, string url) { using (NSUrl nsUrl = new NSUrl(url)) { OSStatus status = API.AudioFileOpenURL(nsUrl.Handle, AudioFilePermissions.Read, 0, &pThis->AudioFile); API.CheckStatus(status); } }
public unsafe static void Create(AudioStream *pThis, string url) { OpenFileAndCreateStream(pThis, url); CreateQueue(pThis); CopyPropertyFromFileToQueue(pThis, AudioFileProperty.MagicCookieData, AudioQueueProperty.MagicCookie); CopyPropertyFromFileToQueue(pThis, AudioFileProperty.ChannelLayout, AudioQueueProperty.ChannelLayout); API.AudioQueueAddPropertyListener(pThis->Queue, AudioQueueProperty.IsRunning, OnPropertyChange, pThis); AllocateAndPrimeBuffers(pThis); }
internal static void Stop(AudioStream *pThis) { lock (API.StopLock) { OSStatus status = API.AudioQueueDispose(pThis->Queue, 1); API.CheckStatus(status); status = API.AudioFileClose(pThis->AudioFile); API.CheckStatus(status); Marshal.FreeHGlobal((IntPtr)pThis); Sound.OnDisposeStream(pThis); } }
private static unsafe void CopyPropertyFromFileToQueue(AudioStream *pThis, AudioFileProperty fileProp, AudioQueueProperty queueProp) { int size = sizeof(uint); OSStatus status = API.AudioFileGetPropertyInfo(pThis->AudioFile, fileProp, &size, null); if (status == 0 && size > 0) { void *pData = (void *)Marshal.AllocHGlobal(size); API.AudioFileGetProperty(pThis->AudioFile, fileProp, &size, pData); API.AudioQueueSetProperty(pThis->Queue, queueProp, pData, size); Marshal.FreeHGlobal((IntPtr)pData); } }
internal static void OnDisposeStream(AudioStream *pStream) { lock (Sound.Map) { Sound sound = null; bool exists = Sound.Map.TryGetValue((IntPtr)pStream, out sound); if (exists) { Sound.Map.Remove((IntPtr)pStream); if (sound != null) { sound.Stream = null; } } } }
private static unsafe void CreateQueue(AudioStream *pThis) { int dataFormatSize = sizeof(AudioStreamBasicDescription); AudioStreamBasicDescription *pDataFormat = &pThis->DataFormat; OSStatus status = API.AudioFileGetProperty(pThis->AudioFile, AudioFileProperty.DataFormat, &dataFormatSize, pDataFormat); API.CheckStatus(status); status = API.AudioQueueNewOutput(pDataFormat, OnReadBuffer, pThis, null, null, 0, &pThis->Queue); API.CheckStatus(status); dataFormatSize = sizeof(int); int *pMaxPacketSize = &pThis->MaxPacketSize; status = API.AudioFileGetProperty(pThis->AudioFile, AudioFileProperty.PacketSizeUpperBound, &dataFormatSize, pMaxPacketSize); API.CheckStatus(status); DeriveBufferSize(&pThis->DataFormat, pThis->MaxPacketSize, 0.5, &pThis->BufferByteSize, &pThis->NumPacketsToRead); }
private Sound(AudioStream *stream) { this.Stream = stream; }
internal static unsafe void SetVolume(AudioStream *pThis, float volume) { OSStatus status = API.AudioQueueSetParameter(pThis->Queue, AudioQueueParameter.Volume, volume); API.CheckStatus(status); }
static unsafe void ReadBufferInternal(void *pUserData, AudioQueue *pQueue, AudioQueueBuffer *pBuffer) { AudioStream *pThis = (AudioStream *)pUserData; if (pThis == null) { Console.WriteLine("ReadBufferProc: pThis is null"); } if (!pThis->IsRunning) { return; } if (pQueue == null) { Console.WriteLine("ReadBufferProc: pQueue is null"); } if (pBuffer == null) { Console.WriteLine("ReadBufferProc: pBuffer is null"); } if (pBuffer->AudioData == null) { Console.WriteLine("ReadBufferProc: pBuffer->AudioData is null"); } if (pBuffer->PacketDescriptors == null) { Console.WriteLine("ReadBufferProc: pBuffer->PacketDescriptors is null"); } if (pThis->AudioFile == null) { Console.WriteLine("ReadBufferProc: pThis->AudioFile is null"); } int numPacketsReadFromFile = pThis->NumPacketsToRead; int numBytesReadFromFile = 0; OSStatus status = API.AudioFileReadPackets(pThis->AudioFile, 0, &numBytesReadFromFile, pBuffer->PacketDescriptors, pThis->CurrentPacket, &numPacketsReadFromFile, pBuffer->AudioData); API.CheckStatus(status); if (status == 0 && numPacketsReadFromFile == 0 && pThis->Looping) { // we ran out of packets and they are // asking to loop, so try and reset pThis->CurrentPacket = 0; numPacketsReadFromFile = pThis->NumPacketsToRead; numBytesReadFromFile = 0; status = API.AudioFileReadPackets(pThis->AudioFile, 0, &numBytesReadFromFile, pBuffer->PacketDescriptors, pThis->CurrentPacket, &numPacketsReadFromFile, pBuffer->AudioData); API.CheckStatus(status); } if (numPacketsReadFromFile > 0) { pBuffer->AudioDataByteSize = numBytesReadFromFile; pBuffer->PacketDescriptorCount = numPacketsReadFromFile; status = API.AudioQueueEnqueueBuffer(pThis->Queue, pBuffer, (pBuffer->PacketDescriptors != null ? pBuffer->PacketDescriptorCount : 0), pBuffer->PacketDescriptors); API.CheckStatus(status); pThis->CurrentPacket += numPacketsReadFromFile; } else { status = API.AudioQueueStop(pThis->Queue, 0); API.CheckStatus(status); } }