summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/portaudio/src/hostapi/pulseaudio/pa_linux_pulseaudio_block.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/portaudio/src/hostapi/pulseaudio/pa_linux_pulseaudio_block.c')
-rw-r--r--3rdparty/portaudio/src/hostapi/pulseaudio/pa_linux_pulseaudio_block.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/3rdparty/portaudio/src/hostapi/pulseaudio/pa_linux_pulseaudio_block.c b/3rdparty/portaudio/src/hostapi/pulseaudio/pa_linux_pulseaudio_block.c
new file mode 100644
index 00000000000..3ef9b458c87
--- /dev/null
+++ b/3rdparty/portaudio/src/hostapi/pulseaudio/pa_linux_pulseaudio_block.c
@@ -0,0 +1,197 @@
+
+/*
+ * PulseAudio host to play natively in Linux based systems without
+ * ALSA emulation
+ *
+ * Copyright (c) 2014-2023 Tuukka Pasanen <tuukka.pasanen@ilmi.fi>
+ * Copyright (c) 2016 Sqweek
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The text above constitutes the entire PortAudio license; however,
+ * the PortAudio community also makes the following non-binding requests:
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version. It is also
+ * requested that these non-binding requests be included along with the
+ * license above.
+ */
+
+/** @file
+ @ingroup common_src
+
+ @brief PulseAudio implementation of support for a host API.
+
+ This host API implements PulseAudio support for portaudio
+ it has callbackmode and normal write mode support
+*/
+
+#include "pa_linux_pulseaudio_block_internal.h"
+#include <unistd.h>
+
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+PaError PaPulseAudio_ReadStreamBlock( PaStream * s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaPulseAudio_Stream *pulseaudioStream = (PaPulseAudio_Stream *) s;
+ PaPulseAudio_HostApiRepresentation *pulseaudioHostApi =
+ pulseaudioStream->hostapi;
+ PaError ret = 0;
+ uint8_t *readableBuffer = (uint8_t *) buffer;
+ long bufferLeftToRead = (frames * pulseaudioStream->inputFrameSize);
+
+ while( bufferLeftToRead > 0 )
+ {
+ PA_PULSEAUDIO_IS_ERROR( pulseaudioStream, paStreamIsStopped )
+
+ PaPulseAudio_Lock( pulseaudioStream->mainloop );
+ long l_read = PaUtil_ReadRingBuffer( &pulseaudioStream->inputRing, readableBuffer,
+ bufferLeftToRead );
+ readableBuffer += l_read;
+ bufferLeftToRead -= l_read;
+ if( bufferLeftToRead > 0 )
+ pa_threaded_mainloop_wait( pulseaudioStream->mainloop );
+
+ PaPulseAudio_UnLock( pulseaudioStream->mainloop );
+
+ if( bufferLeftToRead > 0 )
+ {
+ /* Sleep small amount of time not burn CPU
+ * we block anyway so this is bearable
+ */
+ usleep(100);
+ }
+ }
+ return paNoError;
+}
+
+
+PaError PaPulseAudio_WriteStreamBlock( PaStream * s,
+ const void *buffer,
+ unsigned long frames )
+{
+ PaPulseAudio_Stream *pulseaudioStream = (PaPulseAudio_Stream *) s;
+ int ret = 0;
+ size_t pulseaudioWritable = 0;
+ uint8_t *writableBuffer = (uint8_t *) buffer;
+ long bufferLeftToWrite = (frames * pulseaudioStream->outputFrameSize);
+ pa_operation *pulseaudioOperation = NULL;
+
+ PaUtil_BeginCpuLoadMeasurement( &pulseaudioStream->cpuLoadMeasurer );
+
+ while( bufferLeftToWrite > 0)
+ {
+ PA_PULSEAUDIO_IS_ERROR( pulseaudioStream, paStreamIsStopped )
+
+ PaPulseAudio_Lock( pulseaudioStream->mainloop );
+ pulseaudioWritable = pa_stream_writable_size( pulseaudioStream->outputStream );
+ PaPulseAudio_UnLock( pulseaudioStream->mainloop );
+
+ if( pulseaudioWritable > 0 )
+ {
+ if( bufferLeftToWrite < pulseaudioWritable )
+ {
+ pulseaudioWritable = bufferLeftToWrite;
+ }
+ PaPulseAudio_Lock( pulseaudioStream->mainloop );
+ ret = pa_stream_write( pulseaudioStream->outputStream,
+ writableBuffer,
+ pulseaudioWritable,
+ NULL,
+ 0,
+ PA_SEEK_RELATIVE );
+
+ pulseaudioOperation = pa_stream_update_timing_info( pulseaudioStream->outputStream,
+ NULL,
+ NULL );
+ PaPulseAudio_UnLock( pulseaudioStream->mainloop );
+
+ ret = 0;
+
+ if( pulseaudioOperation == NULL )
+ {
+ return paInsufficientMemory;
+ }
+
+ while( pa_operation_get_state( pulseaudioOperation ) == PA_OPERATION_RUNNING )
+ {
+ ret ++;
+ PA_PULSEAUDIO_IS_ERROR( pulseaudioStream, paStreamIsStopped )
+
+ /* As this shouldn never happen it's error if it does */
+ if( ret >= 10000 )
+ {
+ return paStreamIsStopped;
+ }
+
+ usleep(100);
+ }
+
+ PaPulseAudio_Lock( pulseaudioStream->mainloop );
+
+ pa_operation_unref( pulseaudioOperation );
+ pulseaudioOperation = NULL;
+
+ PaPulseAudio_UnLock( pulseaudioStream->mainloop );
+
+ writableBuffer += pulseaudioWritable;
+ bufferLeftToWrite -= pulseaudioWritable;
+ }
+
+ if( bufferLeftToWrite > 0 )
+ {
+ /* Sleep small amount of time not burn CPU
+ * we block anyway so this is bearable
+ */
+ usleep(100);
+ }
+
+ }
+ PaUtil_EndCpuLoadMeasurement( &pulseaudioStream->cpuLoadMeasurer,
+ frames );
+
+ return paNoError;
+}
+
+
+signed long PaPulseAudio_GetStreamReadAvailableBlock( PaStream * s )
+{
+ PaPulseAudio_Stream *pulseaudioStream = (PaPulseAudio_Stream *) s;
+
+ if( pulseaudioStream->inputStream == NULL )
+ {
+ return 0;
+ }
+
+ return ( PaUtil_GetRingBufferReadAvailable( &pulseaudioStream->inputRing ) /
+ pulseaudioStream->inputFrameSize );
+}