]> git.sesse.net Git - vlc/blob - modules/access/qtsound.m
75a8ef7cbd4ce707a876319c9ebf7827df8633f1
[vlc] / modules / access / qtsound.m
1 /*****************************************************************************
2 * qtsound.m: qtkit (Mac OS X) based audio capture module
3 *****************************************************************************
4 * Copyright © 2011 VLC authors and VideoLAN
5 *
6 * Authors: Pierre d'Herbemont <pdherbemont@videolan.org>
7 *          Gustaf Neumann <neumann@wu.ac.at>
8 *          Michael S. Feurstein <michael.feurstein@wu.ac.at>
9 *
10 *****************************************************************************
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
24 *
25 *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_aout.h>
38
39 #include <vlc_demux.h>
40 #include <vlc_dialog.h>
41
42 #import <QTKit/QTKit.h>
43
44 /*****************************************************************************
45  * Local prototypes.
46  *****************************************************************************/
47 static int Open( vlc_object_t *p_this );
48 static void Close( vlc_object_t *p_this );
49 static int Demux( demux_t *p_demux );
50 static int Control( demux_t *, int, va_list );
51
52 /*****************************************************************************
53  * Module descriptor
54  *****************************************************************************/
55
56 vlc_module_begin()
57 set_shortname( N_("QTSound") )
58 set_description( N_("QuickTime Sound Capture") )
59 set_category( CAT_INPUT )
60 set_subcategory( SUBCAT_INPUT_ACCESS )
61 add_shortcut( "qtsound" )
62 set_capability( "access_demux", 0 )
63 set_callbacks( Open, Close )
64 vlc_module_end ()
65
66
67 /*****************************************************************************
68  * QTKit Bridge
69  *****************************************************************************/
70 @interface VLCDecompressedAudioOutput : QTCaptureDecompressedAudioOutput
71 {
72     demux_t *p_qtsound;
73     AudioBuffer *currentAudioBuffer;
74     UInt32 numberOfSamples;
75     date_t date;
76     mtime_t currentPts;
77     mtime_t previousPts;
78 }
79 - (id)initWithDemux:(demux_t *)p_demux;
80 - (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection;
81 - (BOOL)checkCurrentAudioBuffer;
82 - (mtime_t)getCurrentPts;
83 - (void *)getCurrentAudioBufferData;
84 - (UInt32)getCurrentTotalDataSize;
85 - (UInt32)getNumberOfSamples;
86
87 @end
88
89 @implementation VLCDecompressedAudioOutput : QTCaptureDecompressedAudioOutput
90 - (id)initWithDemux:(demux_t *)p_demux
91 {
92     if( self = [super init] )
93     {
94         p_qtsound = p_demux;
95         currentAudioBuffer = nil;
96         date_Init(&date, 44100, 1);
97         date_Set(&date,0);
98         currentPts = 0;
99         previousPts = 0;
100     }
101     return self;
102 }
103 - (void)dealloc
104 {
105     @synchronized (self)
106     {
107         free(currentAudioBuffer);
108         currentAudioBuffer = nil;
109     }
110     [super dealloc];
111 }
112
113 - (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection
114 {
115     AudioBufferList *tempAudioBufferList;
116     block_t *rawAudioData;
117     UInt32 totalDataSize = 0;
118     UInt32 count = 0;
119
120     @synchronized (self)
121     {
122         numberOfSamples = [sampleBuffer numberOfSamples];
123         date_Increment(&date,numberOfSamples);
124         currentPts = date_Get(&date);
125
126         tempAudioBufferList = [sampleBuffer audioBufferListWithOptions:0];
127         if (tempAudioBufferList->mNumberBuffers == 2)
128         {
129             /*
130              * Compute totalDataSize as sum of all data blocks in the
131              * audio buffer list:
132              */
133             for ( count = 0; count < tempAudioBufferList->mNumberBuffers; count++ )
134             {
135                 totalDataSize += tempAudioBufferList->mBuffers[count].mDataByteSize;
136             }
137             /*
138              * Allocate storage for the interleaved audio data
139              */
140             rawAudioData = block_Alloc(totalDataSize * sizeof(float));
141             if (NULL == rawAudioData)
142             {
143                 msg_Err( p_qtsound, "Raw audiodata could not be allocated" );
144                 return;
145             }
146         }
147         else
148         {
149             msg_Err( p_qtsound, "Too many or only one channel found." );
150             return;
151         }
152
153         /*
154          * Interleave raw data (provided in two separate channels as
155          * F32L) with 2 samples per frame
156          */
157         if ( totalDataSize )
158         {
159             unsigned short i;
160             const float *b1Ptr, *b2Ptr;
161             float *uPtr;
162
163             for (i = 0,
164                  uPtr = (float *)rawAudioData,
165                  b1Ptr = (const float *) tempAudioBufferList->mBuffers[0].mData,
166                  b2Ptr = (const float *) tempAudioBufferList->mBuffers[1].mData;
167                  i < numberOfSamples; i++)
168             {
169                 *uPtr = *b1Ptr;
170                 uPtr ++;
171                 b1Ptr ++;
172                 *uPtr = *b2Ptr;
173                 uPtr ++;
174                 b2Ptr ++;
175             }
176
177             if (currentAudioBuffer == nil)
178             {
179                 currentAudioBuffer = (AudioBuffer *)malloc(sizeof(AudioBuffer));
180                 if (NULL == currentAudioBuffer)
181                 {
182                     msg_Err( p_qtsound, "AudioBuffer could not be allocated." );
183                     return;
184                 }
185             }
186             currentAudioBuffer->mNumberChannels = 2;
187             currentAudioBuffer->mDataByteSize = totalDataSize;
188             currentAudioBuffer->mData = rawAudioData;
189         }
190         free(rawAudioData);
191     }
192 }
193
194 - (BOOL)checkCurrentAudioBuffer
195 {
196     return (currentAudioBuffer) ? 1 : 0;
197 }
198
199 - (mtime_t)getCurrentPts
200 {
201     /* FIXME: can this getter be minimized? */
202     mtime_t pts;
203
204     if( !currentAudioBuffer || currentPts == previousPts )
205     {
206         return 0;
207     }
208
209     @synchronized (self)
210     {
211         pts = previousPts = currentPts;
212     }
213
214     return (currentAudioBuffer->mData) ? currentPts : 0;
215 }
216
217 - (void *)getCurrentAudioBufferData
218 {
219     return currentAudioBuffer->mData;
220 }
221
222 - (UInt32)getCurrentTotalDataSize
223 {
224     return currentAudioBuffer->mDataByteSize;
225 }
226
227 - (UInt32)getNumberOfSamples
228 {
229     return numberOfSamples;
230 }
231
232 @end
233
234 /*****************************************************************************
235  * Struct
236  *****************************************************************************/
237
238 struct demux_sys_t {
239     QTCaptureSession * session;
240     QTCaptureDevice * audiodevice;
241     VLCDecompressedAudioOutput * audiooutput;
242     es_out_id_t *p_es_audio;
243     int i_audio_max_buffer_size;
244 };
245
246 /*****************************************************************************
247  * Open: initialize interface
248  *****************************************************************************/
249 static int Open( vlc_object_t *p_this )
250 {
251     demux_t *p_demux = (demux_t*)p_this;
252     demux_sys_t *p_sys;
253     es_format_t audiofmt;
254     char *psz_uid = NULL;
255     int audiocodec;
256     bool success;
257     NSString *qtk_curraudiodevice_uid;
258     NSAutoreleasePool *pool;
259     NSArray *myAudioDevices, *audioformat_array;
260     QTFormatDescription *audio_format;
261     QTCaptureDeviceInput *audioInput;
262     NSError *o_returnedAudioError;
263
264     if( p_demux->psz_location && *p_demux->psz_location )
265     {
266         psz_uid = p_demux->psz_location;
267     }
268     msg_Dbg( p_demux, "qtsound uid = %s", psz_uid );
269     qtk_curraudiodevice_uid = [[NSString alloc] initWithFormat:@"%s", psz_uid];
270
271     pool = [[NSAutoreleasePool alloc] init];
272
273     p_demux->p_sys = p_sys = calloc( 1, sizeof( demux_sys_t ) );
274     if( !p_sys )
275         return VLC_ENOMEM;
276
277     msg_Dbg( p_demux, "qtsound : uid = %s", [qtk_curraudiodevice_uid UTF8String]);
278     myAudioDevices = [[[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeSound] arrayByAddingObjectsFromArray:[QTCaptureDevice inputDevicesWithMediaType:QTMediaTypeMuxed]] retain];
279     if([myAudioDevices count] == 0)
280     {
281         dialog_FatalWait( p_demux, _("No Audio Input device found"),
282                          _("Your Mac does not seem to be equipped with a suitable audio input device."
283                      "Please check your connectors and drivers.") );
284         msg_Err( p_demux, "Can't find any Audio device" );
285
286         goto error;
287     }
288     int iaudio;
289     for(iaudio = 0; iaudio < [myAudioDevices count]; iaudio++){
290         QTCaptureDevice *qtk_audioDevice;
291         qtk_audioDevice = [myAudioDevices objectAtIndex:iaudio];
292         msg_Dbg( p_demux, "qtsound audio %d/%d localizedDisplayName: %s uniqueID: %s", iaudio, [myAudioDevices count], [[qtk_audioDevice localizedDisplayName] UTF8String], [[qtk_audioDevice uniqueID] UTF8String]);
293         if([[[qtk_audioDevice localizedDisplayName]stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:qtk_curraudiodevice_uid]){
294             msg_Dbg( p_demux, "Device found" );
295             break;
296         }
297     }
298
299     audioInput = nil;
300     if(iaudio < [myAudioDevices count]){
301         p_sys->audiodevice = [myAudioDevices objectAtIndex:iaudio];
302     }
303     else
304     {
305         /* cannot find designated audio device, fall back to open default audio device */
306         msg_Dbg(p_demux, "Cannot find designated uid audio device as %s. Fall back to open default audio device.", [qtk_curraudiodevice_uid UTF8String]);
307         p_sys->audiodevice = [QTCaptureDevice defaultInputDeviceWithMediaType: QTMediaTypeSound];
308     }
309     if( !p_sys->audiodevice )
310     {
311         dialog_FatalWait( p_demux, _("No audio input device found"),
312                          _("Your Mac does not seem to be equipped with a suitable audio input device."
313                      "Please check your connectors and drivers.") );
314         msg_Err( p_demux, "Can't find any Audio device" );
315
316         goto error;
317     }
318
319     if( ![p_sys->audiodevice open: &o_returnedAudioError] )
320     {
321         msg_Err( p_demux, "Unable to open the audio capture device (%d)", [o_returnedAudioError code] );
322         goto error;
323     }
324
325     if( [p_sys->audiodevice isInUseByAnotherApplication] == YES )
326     {
327         msg_Err( p_demux, "default audio capture device is exclusively in use by another application" );
328         goto error;
329     }
330     audioInput = [[QTCaptureDeviceInput alloc] initWithDevice: p_sys->audiodevice];
331     if( !audioInput )
332     {
333         msg_Err( p_demux, "can't create a valid audio capture input facility" );
334         goto error;
335     } else {
336         msg_Dbg( p_demux, "created valid audio capture input facility" );
337     }
338
339     p_sys->audiooutput = [[VLCDecompressedAudioOutput alloc] initWithDemux:p_demux];
340     msg_Dbg ( p_demux, "initialized audio output" );
341
342     /* Get the formats */
343     /*
344      FIXME: the format description gathered here does not seem to be the same
345      in comparison to the format description collected from the actual sampleBuffer.
346      This information needs to be updated some other place. For the time being this shall suffice.
347
348      The following verbose output is an example of what is read from the input device during the below block
349      [0x3042138] qtsound demux debug: Audio localized format summary: Linear PCM, 24 bit little-endian signed integer, 2 channels, 44100 Hz
350      [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
351      [0x3042138] qtsound demux debug: Flag float 0 bigEndian 0 signedInt 1 packed 0 alignedHigh 0 non interleaved 0 non mixable 0
352      canonical 0 nativeFloatPacked 0 nativeEndian 0
353
354      However when reading this information from the sampleBuffer during the delegate call from
355      - (void)outputAudioSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection;
356      the following data shows up
357      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
358      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
359      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
360      canonical 1 nativeFloatPacked 1 nativeEndian 0
361
362      Note the differences
363      24bit vs. 32bit
364      little-endian signed integer vs. little-endian floating point
365      format flag 00000004 vs. 00000029
366      bytes per packet 8 vs. 4
367      packed 0 vs. 1
368      non interleaved 0 vs. 1 -> this makes a major difference when filling our own buffer
369      canonical 0 vs. 1
370      nativeFloatPacked 0 vs. 1
371
372      One would assume we'd need to feed the (es_format_t)audiofmt with the data collected here.
373      This is not the case. Audio will be transmitted in artefacts, due to wrong information.
374
375      At the moment this data is set manually, however one should consider trying to set this data dynamically
376      */
377     audioformat_array = [p_sys->audiodevice formatDescriptions];
378     audio_format = NULL;
379     for( int k = 0; k < [audioformat_array count]; k++ )
380     {
381         audio_format = (QTFormatDescription *)[audioformat_array objectAtIndex: k];
382
383         msg_Dbg( p_demux, "Audio localized format summary: %s", [[audio_format localizedFormatSummary] UTF8String]);
384         msg_Dbg( p_demux, "Audio format description attributes: %s",[[[audio_format formatDescriptionAttributes] description] UTF8String]);
385
386         AudioStreamBasicDescription asbd = {0};
387         NSValue *asbdValue =  [audio_format attributeForKey:QTFormatDescriptionAudioStreamBasicDescriptionAttribute];
388         [asbdValue getValue:&asbd];
389
390         char formatIDString[5];
391         UInt32 formatID = CFSwapInt32HostToBig (asbd.mFormatID);
392         bcopy (&formatID, formatIDString, 4);
393         formatIDString[4] = '\0';
394
395         /* kept for development purposes */
396 #if 0
397         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",
398                 asbd.mSampleRate,
399                 formatIDString,
400                 asbd.mFormatFlags,
401                 asbd.mBytesPerPacket,
402                 asbd.mFramesPerPacket,
403                 asbd.mBytesPerFrame,
404                 asbd.mChannelsPerFrame,
405                 asbd.mBitsPerChannel);
406
407         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",
408                 (asbd.mFormatFlags & kAudioFormatFlagIsFloat) != 0,
409                 (asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0,
410                 (asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0,
411                 (asbd.mFormatFlags & kAudioFormatFlagIsPacked) != 0,
412                 (asbd.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0,
413                 (asbd.mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0,
414                 (asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) != 0,
415
416                 (asbd.mFormatFlags & kAudioFormatFlagsCanonical) != 0,
417                 (asbd.mFormatFlags & kAudioFormatFlagsNativeFloatPacked) != 0,
418                 (asbd.mFormatFlags & kAudioFormatFlagsNativeEndian) != 0
419                 );
420 #endif
421     }
422
423     if( [audioformat_array count] )
424         audio_format = [audioformat_array objectAtIndex: 0];
425     else goto error;
426
427     /* Now we can init */
428     audiocodec = VLC_CODEC_FL32;
429     es_format_Init( &audiofmt, AUDIO_ES, audiocodec);
430
431     audiofmt.audio.i_format = audiocodec;
432     audiofmt.audio.i_rate = 44100;
433     /*
434      * i_physical_channels Describes the channels configuration of the
435      * samples (ie. number of channels which are available in the
436      * buffer, and positions).
437      */
438     audiofmt.audio.i_physical_channels = AOUT_CHAN_RIGHT | AOUT_CHAN_LEFT;
439     /*
440      * i_original_channels Describes from which original channels,
441      * before downmixing, the buffer is derived.
442      */
443     audiofmt.audio.i_original_channels = AOUT_CHAN_RIGHT | AOUT_CHAN_LEFT;
444     /*
445      * i_bytes_per_frame Optional - for A/52, SPDIF and DTS types:
446      * Bytes used by one compressed frame, depends on bitrate.
447      */
448     audiofmt.audio.i_bytes_per_frame = 4;
449     /*
450      * Number of sampleframes contained in one compressed frame.
451      */
452     audiofmt.audio.i_frame_length = 1;
453     /*
454      * Please note that it may be completely arbitrary - buffers are not
455      * obliged to contain a integral number of so-called "frames". It's
456      * just here for the division:
457      * buffer_size = i_nb_samples * i_bytes_per_frame / i_frame_length
458      */
459     audiofmt.audio.i_bitspersample = 32;
460     audiofmt.audio.i_channels = 2;
461     audiofmt.audio.i_blockalign = audiofmt.audio.i_channels * audiofmt.audio.i_bitspersample / 16;
462     audiofmt.i_bitrate = audiofmt.audio.i_channels * audiofmt.audio.i_rate * audiofmt.audio.i_bitspersample;
463     p_sys->i_audio_max_buffer_size = 4096;
464
465     p_sys->session = [[QTCaptureSession alloc] init];
466
467     success = [p_sys->session addInput:audioInput error: &o_returnedAudioError];
468     if( !success )
469     {
470         msg_Err( p_demux, "the audio capture device could not be added to capture session (%d)", [o_returnedAudioError code] );
471         goto error;
472     }
473
474     success = [p_sys->session addOutput:p_sys->audiooutput error: &o_returnedAudioError];
475     if( !success )
476     {
477         msg_Err( p_demux, "audio output could not be added to capture session (%d)", [o_returnedAudioError code] );
478         goto error;
479     }
480
481     [p_sys->session startRunning];
482
483     /* Set up p_demux */
484     p_demux->pf_demux = Demux;
485     p_demux->pf_control = Control;
486     p_demux->info.i_update = 0;
487     p_demux->info.i_title = 0;
488     p_demux->info.i_seekpoint = 0;
489
490     msg_Dbg( p_demux, "New audio es %d channels %dHz",
491             audiofmt.audio.i_channels, audiofmt.audio.i_rate );
492
493     p_sys->p_es_audio = es_out_Add( p_demux->out, &audiofmt );
494
495     [audioInput release];
496     [pool release];
497
498     msg_Dbg( p_demux, "QTSound: We have an audio device ready!" );
499
500     return VLC_SUCCESS;
501 error:
502     [audioInput release];
503     [pool release];
504
505     free( p_sys );
506
507     return VLC_EGENERIC;
508 }
509
510 /*****************************************************************************
511  * Close: destroy interface
512  *****************************************************************************/
513 static void Close( vlc_object_t *p_this )
514 {
515     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
516     demux_t *p_demux = (demux_t*)p_this;
517     demux_sys_t *p_sys = p_demux->p_sys;
518
519     [p_sys->session performSelectorOnMainThread:@selector(stopRunning) withObject:nil waitUntilDone:NO];
520     [p_sys->audiooutput performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
521     [p_sys->session performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:NO];
522
523     free( p_sys );
524
525     [pool release];
526 }
527
528 /*****************************************************************************
529  * Demux:
530  *****************************************************************************/
531 static int Demux( demux_t *p_demux )
532 {
533     demux_sys_t *p_sys = p_demux->p_sys;
534     block_t *p_blocka;
535     NSAutoreleasePool *pool;
536
537     p_blocka = block_New( p_demux, p_sys->i_audio_max_buffer_size );
538
539     if( !p_blocka )
540     {
541         msg_Err( p_demux, "cannot get audio block" );
542         return 0;
543     }
544
545     pool = [[NSAutoreleasePool alloc] init];
546
547     @synchronized (p_sys->audiooutput)
548     {
549         if ( [p_sys->audiooutput checkCurrentAudioBuffer] )
550         {
551             p_blocka->i_pts = [p_sys->audiooutput getCurrentPts];
552             p_blocka->p_buffer = [p_sys->audiooutput getCurrentAudioBufferData];
553             p_blocka->i_nb_samples = [p_sys->audiooutput getNumberOfSamples];
554             p_blocka->i_buffer = [p_sys->audiooutput getCurrentTotalDataSize];
555         }
556     }
557
558     if( !p_blocka->i_pts )
559     {
560         // Nothing to transfer yet, just forget
561         block_Release( p_blocka );
562         [pool release];
563         msleep( 10000 );
564         return 1;
565     }
566
567     [pool release];
568
569     if( p_blocka )
570     {
571         es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_blocka->i_pts );
572         es_out_Send( p_demux->out, p_sys->p_es_audio, p_blocka );
573     }
574
575     return 1;
576 }
577
578 /*****************************************************************************
579  * Control:
580  *****************************************************************************/
581 static int Control( demux_t *p_demux, int i_query, va_list args )
582 {
583     bool *pb;
584     int64_t *pi64;
585
586     switch( i_query )
587     {
588             /* Special for access_demux */
589         case DEMUX_CAN_PAUSE:
590         case DEMUX_CAN_SEEK:
591         case DEMUX_SET_PAUSE_STATE:
592         case DEMUX_CAN_CONTROL_PACE:
593             pb = (bool*)va_arg( args, bool * );
594             *pb = false;
595             return VLC_SUCCESS;
596
597         case DEMUX_GET_PTS_DELAY:
598             pi64 = (int64_t*)va_arg( args, int64_t * );
599             *pi64 = INT64_C(1000) * var_InheritInteger( p_demux, "live-caching" );
600             return VLC_SUCCESS;
601
602         default:
603             return VLC_EGENERIC;
604     }
605     return VLC_EGENERIC;
606 }