Example #1
0
/*
    ExampleHostProcessingLoop() illustrates the kind of processing which may
    occur in a host implementation.
 
*/
static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
{
    PaSkeletonStream *stream = (PaSkeletonStream*)userData;
    PaTimestamp outTime = 0; /* IMPLEMENT ME */
    int callbackResult;
    unsigned long framesProcessed;
    
    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
    
    /*
        IMPLEMENT ME:
            - generate timing information
            - handle buffer slips
    */

    /*
        If you need to byte swap or shift inputBuffer to convert it into a
        portaudio format, do it here.
    */



    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, outTime );

    /*
        depending on whether the host buffers are interleaved, non-interleaved
        or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
        PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
    */
    
    PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
    PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
            0, /* first channel of inputBuffer is channel 0 */
            inputBuffer,
            0 ); /* 0 - use numInputChannels passed to init buffer processor */

    PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
    PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
            0, /* first channel of outputBuffer is channel 0 */
            outputBuffer,
            0 ); /* 0 - use numOutputChannels passed to init buffer processor */

    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );

    
    /*
        If you need to byte swap or shift outputBuffer to convert it to
        host format, do it here.
    */

    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );


    if( callbackResult == paContinue )
    {
        /* nothing special to do */
    }
    else if( callbackResult == paAbort )
    {
        /* IMPLEMENT ME - finish playback immediately  */
    }
    else
    {
        /* User callback has asked us to stop with paComplete or other non-zero value */

        /* IMPLEMENT ME - finish playback once currently queued audio has completed  */
    }
}
Example #2
0
/*
    ExampleHostProcessingLoop() illustrates the kind of processing which may
    occur in a host implementation.
 
*/
static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
{
    PaSkeletonStream *stream = (PaSkeletonStream*)userData;
    PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
    int callbackResult;
    unsigned long framesProcessed;
    
    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
    
    /*
        IMPLEMENT ME:
            - generate timing information
            - handle buffer slips
    */

    /*
        If you need to byte swap or shift inputBuffer to convert it into a
        portaudio format, do it here.
    */



    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );

    /*
        depending on whether the host buffers are interleaved, non-interleaved
        or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
        PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
    */
    
    PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
    PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
            0, /* first channel of inputBuffer is channel 0 */
            inputBuffer,
            0 ); /* 0 - use inputChannelCount passed to init buffer processor */

    PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
    PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
            0, /* first channel of outputBuffer is channel 0 */
            outputBuffer,
            0 ); /* 0 - use outputChannelCount passed to init buffer processor */

    /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
        in general you would pass paContinue for normal operation, and
        paComplete to drain the buffer processor's internal output buffer.
        You can check whether the buffer processor's output buffer is empty
        using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
    */
    callbackResult = paContinue;
    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );

    
    /*
        If you need to byte swap or shift outputBuffer to convert it to
        host format, do it here.
    */

    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );


    if( callbackResult == paContinue )
    {
        /* nothing special to do */
    }
    else if( callbackResult == paAbort )
    {
        /* IMPLEMENT ME - finish playback immediately  */

        /* once finished, call the finished callback */
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
    }
    else
    {
        /* User callback has asked us to stop with paComplete or other non-zero value */

        /* IMPLEMENT ME - finish playback once currently queued audio has completed  */

        /* once finished, call the finished callback */
        if( stream->streamRepresentation.streamFinishedCallback != 0 )
            stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
    }
}
Example #3
0
void *CallbackThread( void *userData )
{
    PaAlsaStream *stream = (PaAlsaStream*)userData;
    pthread_cleanup_push( &Stop, stream );   // Execute Stop on exit

    if( stream->pcm_playback )
        snd_pcm_start( stream->pcm_playback );
    else if( stream->pcm_capture )
        snd_pcm_start( stream->pcm_capture );

    while(1)
    {
        int frames_avail;
        int frames_got;

        PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
        int callbackResult;
        int framesProcessed;

        pthread_testcancel();
        {
            /* calculate time info */
            snd_timestamp_t capture_timestamp;
            snd_timestamp_t playback_timestamp;
            snd_pcm_status_t *capture_status;
            snd_pcm_status_t *playback_status;
            snd_pcm_status_alloca( &capture_status );
            snd_pcm_status_alloca( &playback_status );

            if( stream->pcm_capture )
            {
                snd_pcm_status( stream->pcm_capture, capture_status );
                snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
            }
            if( stream->pcm_playback )
            {
                snd_pcm_status( stream->pcm_playback, playback_status );
                snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
            }

            /* Hmm, we potentially have both a playback and a capture timestamp.
             * Hopefully they are the same... */
            if( stream->pcm_capture && stream->pcm_playback )
            {
                float capture_time = capture_timestamp.tv_sec +
                                     ((float)capture_timestamp.tv_usec/1000000);
                float playback_time= playback_timestamp.tv_sec +
                                     ((float)playback_timestamp.tv_usec/1000000);
                if( fabsf(capture_time-playback_time) > 0.01 )
                    PA_DEBUG(("Capture time and playback time differ by %f\n", fabsf(capture_time-playback_time)));
                timeInfo.currentTime = capture_time;
            }
            else if( stream->pcm_playback )
            {
                timeInfo.currentTime = playback_timestamp.tv_sec +
                                       ((float)playback_timestamp.tv_usec/1000000);
            }
            else
            {
                timeInfo.currentTime = capture_timestamp.tv_sec +
                                       ((float)capture_timestamp.tv_usec/1000000);
            }

            if( stream->pcm_capture )
            {
                snd_pcm_sframes_t capture_delay = snd_pcm_status_get_delay( capture_status );
                timeInfo.inputBufferAdcTime = timeInfo.currentTime -
                    (float)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
            }

            if( stream->pcm_playback )
            {
                snd_pcm_sframes_t playback_delay = snd_pcm_status_get_delay( playback_status );
                timeInfo.outputBufferDacTime = timeInfo.currentTime +
                    (float)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
            }
        }


        /*
            IMPLEMENT ME:
                - handle buffer slips
        */

        /*
            depending on whether the host buffers are interleaved, non-interleaved
            or a mixture, you will want to call PaUtil_ProcessInterleavedBuffers(),
            PaUtil_ProcessNonInterleavedBuffers() or PaUtil_ProcessBuffers() here.
        */

        framesProcessed = frames_avail = wait( stream );

        while( frames_avail > 0 )
        {
            //PA_DEBUG(( "%d frames available\n", frames_avail ));

            /* Now we know the soundcard is ready to produce/receive at least
             * one period.  We just need to get the buffers for the client
             * to read/write. */
            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
                    0 /* @todo pass underflow/overflow flags when necessary */ );

            frames_got = setup_buffers( stream, frames_avail );


            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

            callbackResult = paContinue;

            /* this calls the callback */

            framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
                                                          &callbackResult );

            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );

            /* inform ALSA how many frames we wrote */

            if( stream->pcm_capture )
                snd_pcm_mmap_commit( stream->pcm_capture, stream->capture_offset, frames_got );

            if( stream->pcm_playback )
                snd_pcm_mmap_commit( stream->pcm_playback, stream->playback_offset, frames_got );

            if( callbackResult != paContinue )
                break;

            frames_avail -= frames_got;
        }


        /*
            If you need to byte swap outputBuffer, you can do it here using
            routines in pa_byteswappers.h
        */

        if( callbackResult != paContinue )
        {
            stream->callback_finished = 1;
            stream->callbackAbort = (callbackResult == paAbort);

            pthread_exit( NULL );
        }
    }

    /* This code is unreachable, but important to include regardless because it
     * is possibly a macro with a closing brace to match the opening brace in
     * pthread_cleanup_push() above.  The documentation states that they must
     * always occur in pairs. */

    pthread_cleanup_pop( 1 );
}
Example #4
0
/*
 * I/O loop for callback interface
 */
static void *
sndioThread(void *arg)
{
	PaSndioStream *s = (PaSndioStream *)arg;
	PaStreamCallbackTimeInfo ti;
	unsigned char *data;
	unsigned todo, rblksz, wblksz;
	int n, result;
	
	rblksz = s->par.round * s->par.rchan * s->par.bps;
	wblksz = s->par.round * s->par.pchan * s->par.bps;
	
	DPR("sndioThread: mode = %x, round = %u, rblksz = %u, wblksz = %u\n",
	    s->mode, s->par.round, rblksz, wblksz);
	
	while (!s->stopped) {
		if (s->mode & SIO_REC) {
			todo = rblksz;
			data = s->rbuf;
			while (todo > 0) {
				n = sio_read(s->hdl, data, todo);
				if (n == 0) {
					DPR("sndioThread: sio_read failed\n");
					goto failed;
				}
				todo -= n;
				data += n;
			}
			s->rpos += s->par.round;
			ti.inputBufferAdcTime = 
			    (double)s->realpos / s->par.rate;
		}
		if (s->mode & SIO_PLAY) {
			ti.outputBufferDacTime =
			    (double)(s->realpos + s->par.bufsz) / s->par.rate;
		}
		ti.currentTime = s->realpos / (double)s->par.rate;
		PaUtil_BeginBufferProcessing(&s->bufproc, &ti, 0);
		if (s->mode & SIO_PLAY) {
			PaUtil_SetOutputFrameCount(&s->bufproc, s->par.round);
			PaUtil_SetInterleavedOutputChannels(&s->bufproc,
			    0, s->wbuf, s->par.pchan);
		}
		if (s->mode & SIO_REC) {
			PaUtil_SetInputFrameCount(&s->bufproc, s->par.round);
			PaUtil_SetInterleavedInputChannels(&s->bufproc,
			    0, s->rbuf, s->par.rchan);
		}
		result = paContinue;
		n = PaUtil_EndBufferProcessing(&s->bufproc, &result);
		if (n != s->par.round) {
			DPR("sndioThread: %d < %u frames, result = %d\n",
			    n, s->par.round, result);
		}
		if (result != paContinue) {
			break;
		}
		if (s->mode & SIO_PLAY) {
			n = sio_write(s->hdl, s->wbuf, wblksz);
			if (n < wblksz) {
				DPR("sndioThread: sio_write failed\n");
				goto failed;
			}
			s->wpos += s->par.round;
		}
	}
 failed:
	s->active = 0;
	DPR("sndioThread: done\n");
}
Example #5
0
static int JackCallback( jack_nframes_t frames, void *userData )
{
    PaJackStream *stream = (PaJackStream*)userData;
    PaStreamCallbackTimeInfo timeInfo;
    int callbackResult;
    int chn;
    int framesProcessed;

    /* TODO: make this a lot more accurate */
    PaTime now = GetStreamTime(stream);
    timeInfo.currentTime = now;
    timeInfo.outputBufferDacTime = now;
    timeInfo.inputBufferAdcTime = now;

    if( stream->t0 == -1 )
    {
        if( stream->num_outgoing_connections == 0 )
        {
            /* TODO: how to handle stream time for capture-only operation? */
        }
        else
        {
            /* the beginning time needs to be initialized */
            stream->t0 = jack_frame_time( stream->jack_client ) -
                         jack_frames_since_cycle_start( stream->jack_client) +
                         jack_port_get_total_latency( stream->jack_client,
                                                      stream->local_output_ports[0] );
        }
    }

    PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

    PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
            0 /* @todo pass underflow/overflow flags when necessary */ );

    for( chn = 0; chn < stream->num_incoming_connections; chn++ )
    {
        jack_default_audio_sample_t *channel_buf;
        channel_buf = (jack_default_audio_sample_t*)
            jack_port_get_buffer( stream->local_input_ports[chn],
                                  frames );

        PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
                                              chn,
                                              channel_buf );
    }

    for( chn = 0; chn < stream->num_outgoing_connections; chn++ )
    {
        jack_default_audio_sample_t *channel_buf;
        channel_buf = (jack_default_audio_sample_t*)
            jack_port_get_buffer( stream->local_output_ports[chn],
                                  frames );

        PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
                                               chn,
                                               channel_buf );
    }

    if( stream->num_incoming_connections > 0 )
        PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames );

    if( stream->num_outgoing_connections > 0 )
        PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames );

    callbackResult = paContinue;
    framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
                                                  &callbackResult );

    PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
    stream->total_frames_sent += frames;


    if( callbackResult == paContinue )
    {
        /* nothing special */
    }
    else if( callbackResult == paAbort )
    {
        /* finish playback immediately  */

        /* TODO: memset 0 the outgoing samples to "cancel" them */

        stream->is_active = FALSE;

        /* return nonzero so we get deactivated (and the callback won't
         * get called again) */
        return 1;
    }
    else
    {
        /* User callback has asked us to stop with paComplete or other non-zero value. */

        stream->is_active = FALSE;

        /* return nonzero so we get deactivated (and the callback won't
         * get called again) */
        return 1;
    }
    return 0;
}