Problem with recording audio

Discussion in 'Mac Programming' started by spt, Sep 3, 2012.

  1. spt, Sep 3, 2012
    Last edited: Sep 3, 2012

    spt macrumors member

    Joined:
    Oct 27, 2009
    #1
    Hello,

    I would like to make a command line program that is able to record audio using the internal mike of my MBP. I've done some experimenting, but the problem is that as soon as a leave out the GUI the program won't run properly. It seems as if the program is 'waiting' for something. I've tried to run things in separate threats, which seems to help, as the code below works well.

    However, as soon as I leave out starting NSApplicationMain, it stops working properly.

    Any ideas on what I might have done wrong?

    Code:
    
    #import <Cocoa/Cocoa.h>
    #import <QTKit/QTkit.h>
    #import <pthread.h>
    
    QTCaptureSession            *mCaptureSession;
    QTCaptureMovieFileOutput    *mCaptureMovieFileOutput;
    QTCaptureDeviceInput        *mCaptureAudioDeviceInput;
    
    pthread_t *t_cap, *t_stop;
    
    void capture_tread(void *arch);
    void capture_stop(void *arch);
    
    int main(int argc, char *argv[])
    {
        pthread_create(&t_cap, NULL, capture_tread, NULL);
        pthread_create(&t_stop, NULL, capture_stop, NULL);
        printf("Starting threads...\n");
    
       // As soon as I leave out this part (and add pthreads_join to ensure the main thread doesn't exit premature), no errors occur but sound will never be written to a file...
        return NSApplicationMain(argc,  (const char **) argv);
    }
    
    void capture_tread(void *arch)
    {    
        printf("Start capture thread\n");
        
        // Create the capture session
    	mCaptureSession = [[QTCaptureSession alloc] init];
        
        // Connect inputs and outputs to the session	
    	BOOL success = NO;
    	NSError *error;
    	
        QTCaptureDevice *audioDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeSound];
        success = [audioDevice open:&error];
        
        if (!success) {
            audioDevice = nil;
            // Handle error
        }
        
        if (audioDevice) {
            mCaptureAudioDeviceInput = [[QTCaptureDeviceInput alloc] initWithDevice:audioDevice];
            
            success = [mCaptureSession addInput:mCaptureAudioDeviceInput error:&error];
            if (!success) {
                // Handle error
            }
        }
        
        // Create the audi file output and add it to the session
        mCaptureMovieFileOutput = [[QTCaptureMovieFileOutput alloc] init];
        success = [mCaptureSession addOutput:mCaptureMovieFileOutput error:&error];
        if (!success) {
            // Handle error
        }
        
        //[mCaptureMovieFileOutput setDelegate:0];
        
        // Set the compression for the audio/video that is recorded to the hard disk
    	NSEnumerator *connectionEnumerator = [[mCaptureMovieFileOutput connections] objectEnumerator];
    	QTCaptureConnection *connection;
    	
    	// iterate over each output connection for the capture session and specify the desired compression
    	while ((connection = [connectionEnumerator nextObject])) {
    		NSString *mediaType = [connection mediaType];
    		QTCompressionOptions *compressionOptions = nil;
    		// specify the audio compression options
            if ([mediaType isEqualToString:QTMediaTypeSound]) {
    			// use AAC Audio
    			compressionOptions = [QTCompressionOptions compressionOptionsWithIdentifier:@"QTCompressionOptionsHighQualityAACAudio"];
    		}
    		
    		// set the compression options for the movie file output
    		[mCaptureMovieFileOutput setCompressionOptions:compressionOptions forConnection:connection];
    	} 
        
        [mCaptureSession startRunning];
        
        [mCaptureMovieFileOutput recordToOutputFileURL:[NSURL fileURLWithPath:@"/Users/shared/test.mov"]];
        
    }
    
    void capture_stop(void *arch)
    {
        printf("Pausing...\n");
        sleep(5);
        [mCaptureMovieFileOutput recordToOutputFileURL:[NSURL fileURLWithPath:nil]];
        printf("Stop capturing\n");
    }
    
     
  2. mfram macrumors 65816

    Joined:
    Jan 23, 2010
    Location:
    San Diego, CA USA
    #2
    Well, I can think of a couple issues. First, it's my understanding that separate threads should have their own autorelease pools. You should create separate autorelease pools for each thread.

    Second, if any of the classes you are using use NSTimers internally then then timers won't work unless there's a run loop created. A GUI program gets a run loop created automatically. Maybe that's the magic that the GUI program is giving you.
     
  3. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #3
    The main() function must not return until everything else is completed. When main() returns, the exit() function is called. That will exit the program, regardless of any other threads that might be running. That's pretty much standard Posix behavior, too, so it shouldn't be surprising.

    The main thread, which runs the main() function, needs to run its run-loop, which will do its normal event handling. That's what NSApplicationMain() does for your, because that's what its reference doc says it does.

    This is also worth reading:
    http://cocoawithlove.com/2009/01/demystifying-nsapplication-by.html

    And instead of pthreads, it might be better to use NSThread. That's what I've done before when I had a command-line tool that needed threading. I also implemented a main-thread run-loop, which was pretty easy to do with NSRunLoop.
     
  4. spt thread starter macrumors member

    Joined:
    Oct 27, 2009
    #4
    I know, that's why I added pthread_join in that case.

    This may be useful, as the problem indeed occurs when the main thread is sleeping.

    ----------

    This did the trick.

    Everything worked after simply adding
    Code:
        [[NSRunLoop currentRunLoop] run];
    
    in the main loop.

    Thanks!
     

Share This Page