From 3ddb9e51a7d11a69849ff427d38642d4f7d24f5e Mon Sep 17 00:00:00 2001 From: Michael Feurstein Date: Sun, 30 Oct 2011 22:27:46 +0100 Subject: [PATCH] qtsound: added audio capture functionality for MAC OS X Tested with Built-in Input, Built-in Microphone and Griffin iMic USB system Usage: qtsound://"Built-In Input" or qtsound://"iMic USB audio system" Modified-by: Jean-Baptiste Kempf Signed-off-by: Jean-Baptiste Kempf --- configure.ac | 17 +- modules/access/Modules.am | 18 +- modules/access/qtsound.m | 606 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 630 insertions(+), 11 deletions(-) create mode 100644 modules/access/qtsound.m diff --git a/configure.ac b/configure.ac index 8f631c4295..9db6f6abba 100644 --- a/configure.ac +++ b/configure.ac @@ -2101,19 +2101,16 @@ then fi dnl -dnl QTCapture -AC_ARG_ENABLE(macosx-qtcapture, - [ --enable-macosx-qtcapture Mac OS X qtcapture (iSight) module (default enabled on Mac OS X)]) -if test "x${enable_macosx_qtcapture}" != "xno" && - (test "${SYS}" = "darwin" || test "${enable_macosx_qtcapture}" = "yes") +dnl QTKit +AC_ARG_ENABLE(macosx-qtkit, + [ --enable-macosx-qtkit Mac OS X qtcapture (video) and qtsound (audio) module (default enabled on Mac OS X)]) +if test "x${enable_macosx_qtkit}" != "xno" && + (test "${SYS}" = "darwin" || test "${enable_macosx_qtkit}" = "yes") then - VLC_ADD_LIBS([qtcapture], [-Wl,-framework,Cocoa]) - VLC_ADD_LIBS([qtcapture], [-Wl,-framework,QTKit]) - VLC_ADD_LIBS([qtcapture], [-Wl,-framework,CoreAudio]) - VLC_ADD_LIBS([qtcapture], [-Wl,-framework,QuartzCore]) - VLC_ADD_LIBS([qtcapture], [-Wl,-framework,CoreVideo]) VLC_ADD_PLUGIN([qtcapture]) + VLC_ADD_PLUGIN([qtsound]) fi +AM_CONDITIONAL(HAVE_QTKIT, [test "${SYS}" = "darwin" && "x${enable_macosx_qtkit}" != "xno"]) dnl diff --git a/modules/access/Modules.am b/modules/access/Modules.am index 45b6499d9f..81d8e78edc 100644 --- a/modules/access/Modules.am +++ b/modules/access/Modules.am @@ -55,7 +55,6 @@ SOURCES_dvdnav = dvdnav.c SOURCES_dvdread = dvdread.c SOURCES_dc1394 = dc1394.c SOURCES_pvr = pvr.c -SOURCES_qtcapture = qtcapture.m SOURCES_linsys_sdi = linsys/linsys_sdi.c linsys/linsys_sdi.h SOURCES_linsys_hdsdi = \ linsys/linsys_hdsdi.c \ @@ -83,6 +82,23 @@ SOURCES_htcpcp = htcpcp.c SOURCES_access_rar = rar/rar.c rar/rar.h rar/access.c SOURCES_stream_filter_rar = rar/rar.c rar/rar.h rar/stream.c +if HAVE_QTKIT +libqtcapture_plugin_la_SOURCES = qtcapture.m +libqtcapture_plugin_la_LIBADDD = $(AM_LIBADD) +libqtcapture_plugin_la_LDFLAGS = -Wl,-framework,Cocoa -Wl,-framework,QTKit -Wl,-framework,CoreVideo -Wl,-framework,QuartzCore +libqtcapture_plugin_la_DEPENDENCIES = + +libqtsound_plugin_la_SOURCES = qtsound.m +libqtsound_plugin_la_LIBADD = $(AM_LIBADD) +libqtsound_plugin_la_LDFLAGS = -Wl,-framework,Cocoa -Wl,-framework,QTKit -Wl,-framework,CoreAudio +libqtsound_plugin_la_DEPENDENCIES = + +libvlc_LTLIBRARIES += \ + libqtcapture_plugin.la \ + libqtsound_plugin.la \ + $(NULL) +endif + libaccess_rtmp_plugin_la_SOURCES = \ rtmp/access.c \ rtmp/rtmp_amf_flv.c \ diff --git a/modules/access/qtsound.m b/modules/access/qtsound.m new file mode 100644 index 0000000000..75a8ef7cbd --- /dev/null +++ b/modules/access/qtsound.m @@ -0,0 +1,606 @@ +/***************************************************************************** +* qtsound.m: qtkit (Mac OS X) based audio capture module +***************************************************************************** +* Copyright © 2011 VLC authors and VideoLAN +* +* Authors: Pierre d'Herbemont +* Gustaf Neumann +* Michael S. Feurstein +* +***************************************************************************** +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public License +* as published by the Free Software Foundation; either version 2.1 +* of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA +* +*****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#include +#include + +#import + +/***************************************************************************** + * Local prototypes. + *****************************************************************************/ +static int Open( vlc_object_t *p_this ); +static void Close( vlc_object_t *p_this ); +static int Demux( demux_t *p_demux ); +static int Control( demux_t *, int, va_list ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ + +vlc_module_begin() +set_shortname( N_("QTSound") ) +set_description( N_("QuickTime Sound Capture") ) +set_category( CAT_INPUT ) +set_subcategory( SUBCAT_INPUT_ACCESS ) +add_shortcut( "qtsound" ) +set_capability( "access_demux", 0 ) +set_callbacks( Open, Close ) +vlc_module_end () + + +/***************************************************************************** + * QTKit Bridge + *****************************************************************************/ +@interface VLCDecompressedAudioOutput : QTCaptureDecompressedAudioOutput +{ + demux_t *p_qtsound; + AudioBuffer *currentAudioBuffer; + UInt32 numberOfSamples; + date_t date; + mtime_t currentPts; + mtime_t previousPts; +} +- (id)initWithDemux:(demux_t *)p_demux; +- (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection; +- (BOOL)checkCurrentAudioBuffer; +- (mtime_t)getCurrentPts; +- (void *)getCurrentAudioBufferData; +- (UInt32)getCurrentTotalDataSize; +- (UInt32)getNumberOfSamples; + +@end + +@implementation VLCDecompressedAudioOutput : QTCaptureDecompressedAudioOutput +- (id)initWithDemux:(demux_t *)p_demux +{ + if( self = [super init] ) + { + p_qtsound = p_demux; + currentAudioBuffer = nil; + date_Init(&date, 44100, 1); + date_Set(&date,0); + currentPts = 0; + previousPts = 0; + } + return self; +} +- (void)dealloc +{ + @synchronized (self) + { + free(currentAudioBuffer); + currentAudioBuffer = nil; + } + [super dealloc]; +} + +- (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection +{ + AudioBufferList *tempAudioBufferList; + block_t *rawAudioData; + UInt32 totalDataSize = 0; + UInt32 count = 0; + + @synchronized (self) + { + numberOfSamples = [sampleBuffer numberOfSamples]; + date_Increment(&date,numberOfSamples); + currentPts = date_Get(&date); + + tempAudioBufferList = [sampleBuffer audioBufferListWithOptions:0]; + if (tempAudioBufferList->mNumberBuffers == 2) + { + /* + * Compute totalDataSize as sum of all data blocks in the + * audio buffer list: + */ + for ( count = 0; count < tempAudioBufferList->mNumberBuffers; count++ ) + { + totalDataSize += tempAudioBufferList->mBuffers[count].mDataByteSize; + } + /* + * Allocate storage for the interleaved audio data + */ + rawAudioData = block_Alloc(totalDataSize * sizeof(float)); + if (NULL == rawAudioData) + { + msg_Err( p_qtsound, "Raw audiodata could not be allocated" ); + return; + } + } + else + { + msg_Err( p_qtsound, "Too many or only one channel found." ); + return; + } + + /* + * Interleave raw data (provided in two separate channels as + * F32L) with 2 samples per frame + */ + if ( totalDataSize ) + { + unsigned short i; + const float *b1Ptr, *b2Ptr; + float *uPtr; + + for (i = 0, + uPtr = (float *)rawAudioData, + b1Ptr = (const float *) tempAudioBufferList->mBuffers[0].mData, + b2Ptr = (const float *) tempAudioBufferList->mBuffers[1].mData; + i < numberOfSamples; i++) + { + *uPtr = *b1Ptr; + uPtr ++; + b1Ptr ++; + *uPtr = *b2Ptr; + uPtr ++; + b2Ptr ++; + } + + if (currentAudioBuffer == nil) + { + currentAudioBuffer = (AudioBuffer *)malloc(sizeof(AudioBuffer)); + if (NULL == currentAudioBuffer) + { + msg_Err( p_qtsound, "AudioBuffer could not be allocated." ); + return; + } + } + currentAudioBuffer->mNumberChannels = 2; + currentAudioBuffer->mDataByteSize = totalDataSize; + currentAudioBuffer->mData = rawAudioData; + } + free(rawAudioData); + } +} + +- (BOOL)checkCurrentAudioBuffer +{ + return (currentAudioBuffer) ? 1 : 0; +} + +- (mtime_t)getCurrentPts +{ + /* FIXME: can this getter be minimized? */ + mtime_t pts; + + if( !currentAudioBuffer || currentPts == previousPts ) + { + return 0; + } + + @synchronized (self) + { + pts = previousPts = currentPts; + } + + return (currentAudioBuffer->mData) ? currentPts : 0; +} + +- (void *)getCurrentAudioBufferData +{ + return currentAudioBuffer->mData; +} + +- (UInt32)getCurrentTotalDataSize +{ + return currentAudioBuffer->mDataByteSize; +} + +- (UInt32)getNumberOfSamples +{ + return numberOfSamples; +} + +@end + +/***************************************************************************** + * Struct + *****************************************************************************/ + +struct demux_sys_t { + QTCaptureSession * session; + QTCaptureDevice * audiodevice; + VLCDecompressedAudioOutput * audiooutput; + es_out_id_t *p_es_audio; + int i_audio_max_buffer_size; +}; + +/***************************************************************************** + * Open: initialize interface + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + demux_t *p_demux = (demux_t*)p_this; + demux_sys_t *p_sys; + es_format_t audiofmt; + char *psz_uid = NULL; + int audiocodec; + bool success; + NSString *qtk_curraudiodevice_uid; + NSAutoreleasePool *pool; + NSArray *myAudioDevices, *audioformat_array; + QTFormatDescription *audio_format; + QTCaptureDeviceInput *audioInput; + NSError *o_returnedAudioError; + + if( p_demux->psz_location && *p_demux->psz_location ) + { + psz_uid = p_demux->psz_location; + } + msg_Dbg( p_demux, "qtsound uid = %s", psz_uid ); + qtk_curraudiodevice_uid = [[NSString alloc] initWithFormat:@"%s", psz_uid]; + + pool = [[NSAutoreleasePool alloc] init]; + + p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) ); + if( !p_sys ) + return VLC_ENOMEM; + + msg_Dbg( p_demux, "qtsound : uid = %s", [qtk_curraudiodevice_uid UTF8String]); + myAudioDevices = [[[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeSound] arrayByAddingObjectsFromArray:[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeMuxed]] retain]; + if([myAudioDevices count] == 0) + { + dialog_FatalWait( p_demux, _("No Audio Input device found"), + _("Your Mac does not seem to be equipped with a suitable audio input device." + "Please check your connectors and drivers.") ); + msg_Err( p_demux, "Can't find any Audio device" ); + + goto error; + } + int iaudio; + for(iaudio = 0; iaudio < [myAudioDevices count]; iaudio++){ + QTCaptureDevice *qtk_audioDevice; + qtk_audioDevice = [myAudioDevices objectAtIndex:iaudio]; + msg_Dbg( p_demux, "qtsound audio %d/%d localizedDisplayName: %s uniqueID: %s", iaudio, [myAudioDevices count], [[qtk_audioDevice localizedDisplayName] UTF8String], [[qtk_audioDevice uniqueID] UTF8String]); + if([[[qtk_audioDevice localizedDisplayName]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:qtk_curraudiodevice_uid]){ + msg_Dbg( p_demux, "Device found" ); + break; + } + } + + audioInput = nil; + if(iaudio < [myAudioDevices count]){ + p_sys->audiodevice = [myAudioDevices objectAtIndex:iaudio]; + } + else + { + /* cannot find designated audio device, fall back to open default audio device */ + msg_Dbg(p_demux, "Cannot find designated uid audio device as %s. Fall back to open default audio device.", [qtk_curraudiodevice_uid UTF8String]); + p_sys->audiodevice = [QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeSound]; + } + if( !p_sys->audiodevice ) + { + dialog_FatalWait( p_demux, _("No audio input device found"), + _("Your Mac does not seem to be equipped with a suitable audio input device." + "Please check your connectors and drivers.") ); + msg_Err( p_demux, "Can't find any Audio device" ); + + goto error; + } + + if( ![p_sys->audiodevice open: &o_returnedAudioError] ) + { + msg_Err( p_demux, "Unable to open the audio capture device (%d)", [o_returnedAudioError code] ); + goto error; + } + + if( [p_sys->audiodevice isInUseByAnotherApplication] == YES ) + { + msg_Err( p_demux, "default audio capture device is exclusively in use by another application" ); + goto error; + } + audioInput = [[QTCaptureDeviceInput alloc] initWithDevice: p_sys->audiodevice]; + if( !audioInput ) + { + msg_Err( p_demux, "can't create a valid audio capture input facility" ); + goto error; + } else { + msg_Dbg( p_demux, "created valid audio capture input facility" ); + } + + p_sys->audiooutput = [[VLCDecompressedAudioOutput alloc] initWithDemux:p_demux]; + msg_Dbg ( p_demux, "initialized audio output" ); + + /* Get the formats */ + /* + FIXME: the format description gathered here does not seem to be the same + in comparison to the format description collected from the actual sampleBuffer. + This information needs to be updated some other place. For the time being this shall suffice. + + The following verbose output is an example of what is read from the input device during the below block + [0x3042138] qtsound demux debug: Audio localized format summary: Linear PCM, 24 bit little-endian signed integer, 2 channels, 44100 Hz + [0x3042138] qtsound demux debug: Sample Rate: 44100; Format ID: lpcm; Format Flags: 00000004; Bytes per Packet: 8; Frames per Packet: 1; Bytes per Frame: 8; Channels per Frame: 2; Bits per Channel: 24 + [0x3042138] qtsound demux debug: Flag float 0 bigEndian 0 signedInt 1 packed 0 alignedHigh 0 non interleaved 0 non mixable 0 + canonical 0 nativeFloatPacked 0 nativeEndian 0 + + However when reading this information from the sampleBuffer during the delegate call from + - (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection; + the following data shows up + 2011-09-23 22:06:03.077 VLC[23070:f103] Audio localized format summary: Linear PCM, 32 bit little-endian floating point, 2 channels, 44100 Hz + 2011-09-23 22:06:03.078 VLC[23070:f103] Sample Rate: 44100; Format ID: lpcm; Format Flags: 00000029; Bytes per Packet: 4; Frames per Packet: 1; Bytes per Frame: 4; Channels per Frame: 2; Bits per Channel: 32 + 2011-09-23 22:06:03.078 VLC[23070:f103] Flag float 1 bigEndian 0 signedInt 0 packed 1 alignedHigh 0 non interleaved 1 non mixable 0 + canonical 1 nativeFloatPacked 1 nativeEndian 0 + + Note the differences + 24bit vs. 32bit + little-endian signed integer vs. little-endian floating point + format flag 00000004 vs. 00000029 + bytes per packet 8 vs. 4 + packed 0 vs. 1 + non interleaved 0 vs. 1 -> this makes a major difference when filling our own buffer + canonical 0 vs. 1 + nativeFloatPacked 0 vs. 1 + + One would assume we'd need to feed the (es_format_t)audiofmt with the data collected here. + This is not the case. Audio will be transmitted in artefacts, due to wrong information. + + At the moment this data is set manually, however one should consider trying to set this data dynamically + */ + audioformat_array = [p_sys->audiodevice formatDescriptions]; + audio_format = NULL; + for( int k = 0; k < [audioformat_array count]; k++ ) + { + audio_format = (QTFormatDescription *)[audioformat_array objectAtIndex: k]; + + msg_Dbg( p_demux, "Audio localized format summary: %s", [[audio_format localizedFormatSummary] UTF8String]); + msg_Dbg( p_demux, "Audio format description attributes: %s",[[[audio_format formatDescriptionAttributes] description] UTF8String]); + + AudioStreamBasicDescription asbd = {0}; + NSValue *asbdValue = [audio_format attributeForKey:QTFormatDescriptionAudioStreamBasicDescriptionAttribute]; + [asbdValue getValue:&asbd]; + + char formatIDString[5]; + UInt32 formatID = CFSwapInt32HostToBig (asbd.mFormatID); + bcopy (&formatID, formatIDString, 4); + formatIDString[4] = '\0'; + + /* kept for development purposes */ +#if 0 + msg_Dbg( p_demux, "Sample Rate: %.0lf; Format ID: %s; Format Flags: %.8x; Bytes per Packet: %d; Frames per Packet: %d; Bytes per Frame: %d; Channels per Frame: %d; Bits per Channel: %d", + asbd.mSampleRate, + formatIDString, + asbd.mFormatFlags, + asbd.mBytesPerPacket, + asbd.mFramesPerPacket, + asbd.mBytesPerFrame, + asbd.mChannelsPerFrame, + asbd.mBitsPerChannel); + + msg_Dbg( p_demux, "Flag float %d bigEndian %d signedInt %d packed %d alignedHigh %d non interleaved %d non mixable %d\ncanonical %d nativeFloatPacked %d nativeEndian %d", + (asbd.mFormatFlags & kAudioFormatFlagIsFloat) != 0, + (asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0, + (asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0, + (asbd.mFormatFlags & kAudioFormatFlagIsPacked) != 0, + (asbd.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0, + (asbd.mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0, + (asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) != 0, + + (asbd.mFormatFlags & kAudioFormatFlagsCanonical) != 0, + (asbd.mFormatFlags & kAudioFormatFlagsNativeFloatPacked) != 0, + (asbd.mFormatFlags & kAudioFormatFlagsNativeEndian) != 0 + ); +#endif + } + + if( [audioformat_array count] ) + audio_format = [audioformat_array objectAtIndex: 0]; + else goto error; + + /* Now we can init */ + audiocodec = VLC_CODEC_FL32; + es_format_Init( &audiofmt, AUDIO_ES, audiocodec); + + audiofmt.audio.i_format = audiocodec; + audiofmt.audio.i_rate = 44100; + /* + * i_physical_channels Describes the channels configuration of the + * samples (ie. number of channels which are available in the + * buffer, and positions). + */ + audiofmt.audio.i_physical_channels = AOUT_CHAN_RIGHT | AOUT_CHAN_LEFT; + /* + * i_original_channels Describes from which original channels, + * before downmixing, the buffer is derived. + */ + audiofmt.audio.i_original_channels = AOUT_CHAN_RIGHT | AOUT_CHAN_LEFT; + /* + * i_bytes_per_frame Optional - for A/52, SPDIF and DTS types: + * Bytes used by one compressed frame, depends on bitrate. + */ + audiofmt.audio.i_bytes_per_frame = 4; + /* + * Number of sampleframes contained in one compressed frame. + */ + audiofmt.audio.i_frame_length = 1; + /* + * Please note that it may be completely arbitrary - buffers are not + * obliged to contain a integral number of so-called "frames". It's + * just here for the division: + * buffer_size = i_nb_samples * i_bytes_per_frame / i_frame_length + */ + audiofmt.audio.i_bitspersample = 32; + audiofmt.audio.i_channels = 2; + audiofmt.audio.i_blockalign = audiofmt.audio.i_channels * audiofmt.audio.i_bitspersample / 16; + audiofmt.i_bitrate = audiofmt.audio.i_channels * audiofmt.audio.i_rate * audiofmt.audio.i_bitspersample; + p_sys->i_audio_max_buffer_size = 4096; + + p_sys->session = [[QTCaptureSession alloc] init]; + + success = [p_sys->session addInput:audioInput error: &o_returnedAudioError]; + if( !success ) + { + msg_Err( p_demux, "the audio capture device could not be added to capture session (%d)", [o_returnedAudioError code] ); + goto error; + } + + success = [p_sys->session addOutput:p_sys->audiooutput error: &o_returnedAudioError]; + if( !success ) + { + msg_Err( p_demux, "audio output could not be added to capture session (%d)", [o_returnedAudioError code] ); + goto error; + } + + [p_sys->session startRunning]; + + /* Set up p_demux */ + p_demux->pf_demux = Demux; + p_demux->pf_control = Control; + p_demux->info.i_update = 0; + p_demux->info.i_title = 0; + p_demux->info.i_seekpoint = 0; + + msg_Dbg( p_demux, "New audio es %d channels %dHz", + audiofmt.audio.i_channels, audiofmt.audio.i_rate ); + + p_sys->p_es_audio = es_out_Add( p_demux->out, &audiofmt ); + + [audioInput release]; + [pool release]; + + msg_Dbg( p_demux, "QTSound: We have an audio device ready!" ); + + return VLC_SUCCESS; +error: + [audioInput release]; + [pool release]; + + free( p_sys ); + + return VLC_EGENERIC; +} + +/***************************************************************************** + * Close: destroy interface + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + demux_t *p_demux = (demux_t*)p_this; + demux_sys_t *p_sys = p_demux->p_sys; + + [p_sys->session performSelectorOnMainThread:@selector(stopRunning) withObject:nil waitUntilDone:NO]; + [p_sys->audiooutput performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; + [p_sys->session performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO]; + + free( p_sys ); + + [pool release]; +} + +/***************************************************************************** + * Demux: + *****************************************************************************/ +static int Demux( demux_t *p_demux ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + block_t *p_blocka; + NSAutoreleasePool *pool; + + p_blocka = block_New( p_demux, p_sys->i_audio_max_buffer_size ); + + if( !p_blocka ) + { + msg_Err( p_demux, "cannot get audio block" ); + return 0; + } + + pool = [[NSAutoreleasePool alloc] init]; + + @synchronized (p_sys->audiooutput) + { + if ( [p_sys->audiooutput checkCurrentAudioBuffer] ) + { + p_blocka->i_pts = [p_sys->audiooutput getCurrentPts]; + p_blocka->p_buffer = [p_sys->audiooutput getCurrentAudioBufferData]; + p_blocka->i_nb_samples = [p_sys->audiooutput getNumberOfSamples]; + p_blocka->i_buffer = [p_sys->audiooutput getCurrentTotalDataSize]; + } + } + + if( !p_blocka->i_pts ) + { + // Nothing to transfer yet, just forget + block_Release( p_blocka ); + [pool release]; + msleep( 10000 ); + return 1; + } + + [pool release]; + + if( p_blocka ) + { + es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_blocka->i_pts ); + es_out_Send( p_demux->out, p_sys->p_es_audio, p_blocka ); + } + + return 1; +} + +/***************************************************************************** + * Control: + *****************************************************************************/ +static int Control( demux_t *p_demux, int i_query, va_list args ) +{ + bool *pb; + int64_t *pi64; + + switch( i_query ) + { + /* Special for access_demux */ + case DEMUX_CAN_PAUSE: + case DEMUX_CAN_SEEK: + case DEMUX_SET_PAUSE_STATE: + case DEMUX_CAN_CONTROL_PACE: + pb = (bool*)va_arg( args, bool * ); + *pb = false; + return VLC_SUCCESS; + + case DEMUX_GET_PTS_DELAY: + pi64 = (int64_t*)va_arg( args, int64_t * ); + *pi64 = INT64_C(1000) * var_InheritInteger( p_demux, "live-caching" ); + return VLC_SUCCESS; + + default: + return VLC_EGENERIC; + } + return VLC_EGENERIC; +} -- 2.39.2