void PA_AudioIO_ALSA::enableRealTimeScheduling(bool enable){ PaAlsa_EnableRealtimeScheduling(m_Stream, enable); m_isRealTime = enable; if(m_isRealTime){ std::cout << "Real time scheduling is enabled." << std::endl; } else{ std::cout << "Real time scheduling is disabled." << std::endl; } }
int run_filter(AudioOptions audio_options) { PaStreamParameters input_parameters, output_parameters; PaStream *input_stream = NULL, *output_stream = NULL; PaError err = paNoError; CircularBuffer * output_buffer = CircularBuffer_create(audio_options.buffer_size); CircularBuffer * input_buffer = NULL; CircularBuffer * decoder_input = NULL; DecodingBuffer * decoder_buffer = NULL; int live_stream = !audio_options.wav_path || !strlen(audio_options.wav_path); OSFilter * filter = OSFilter_create( audio_options.filters, audio_options.num_filters, 2, audio_options.filter_size, audio_options.conv_multiple * (audio_options.filter_size - 1), audio_options.input_scale ); if (!filter) { goto done; } if ((err = Pa_Initialize()) != paNoError) { goto done; } int step_size = audio_options.filter_size - 1; RecordCallbackMetadata record_data = { NULL, 0, 0, audio_options.number_of_channels, audio_options.enabled_channels, 0 }; { int num_enabled_channels = 0; for (int i = 0; i < audio_options.number_of_channels; ++i) { if (audio_options.enabled_channels & (1 << i)) { num_enabled_channels++; } } if (num_enabled_channels != audio_options.enabled_channels) { record_data.stripe_input = 1; } if (num_enabled_channels == 0) { record_data.stripe_input = 0; } } if (record_data.stripe_input) { printf("striping record_data: %d channels with %d enabled flag\n", record_data.number_of_channels, record_data.enabled_channels ); } else { printf("NOT striping record_data: %d channels with %d enabled flag\n", record_data.number_of_channels, record_data.enabled_channels ); } if (live_stream) { input_buffer = CircularBuffer_create(audio_options.buffer_size); if (audio_options.decode_input) { decoder_input = CircularBuffer_create(audio_options.buffer_size); decoder_buffer = Decoding_new(decoder_input, input_buffer); record_data.buffer = decoder_input; if (!Decoding_start_ac3(decoder_buffer)) { printf("Failed to start ac3 decoder thread.\n"); goto done; } } else { record_data.buffer = input_buffer; } input_parameters.device = audio_options.input_device; input_parameters.channelCount = 2; input_parameters.sampleFormat = PA_SAMPLE_TYPE; input_parameters.suggestedLatency = Pa_GetDeviceInfo(input_parameters.device)->defaultHighInputLatency; input_parameters.hostApiSpecificStreamInfo = NULL; err = Pa_OpenStream( &input_stream, &input_parameters, NULL, audio_options.sample_rate, step_size, paNoFlag, recordCallback, &record_data ); if (err != paNoError) { goto done; } record_data.start_time = currentTimeMillis(); #ifdef LINUX_ALSA PaAlsa_EnableRealtimeScheduling(input_stream, 1); #endif if ((err = Pa_StartStream(input_stream)) != paNoError) { goto done; } } else { input_buffer = __read_audio_file(audio_options); } output_parameters.device = audio_options.output_device; if (audio_options.output_channels >= 6) { output_parameters.channelCount = audio_options.output_channels + 2; } else { output_parameters.channelCount = audio_options.output_channels; } output_parameters.sampleFormat = PA_SAMPLE_TYPE; output_parameters.suggestedLatency = Pa_GetDeviceInfo(output_parameters.device)->defaultLowOutputLatency; output_parameters.hostApiSpecificStreamInfo = NULL; PlaybackCallbackData playback_data = { output_buffer, output_parameters.channelCount }; printf("output channels: %d\n", output_parameters.channelCount); err = Pa_OpenStream( &output_stream, NULL, &output_parameters, audio_options.sample_rate, step_size, paNoFlag, playCallback, &playback_data ); if (err != paNoError) { goto done; } #ifdef LINUX_ALSA PaAlsa_EnableRealtimeScheduling(output_stream, 1); #endif if ((err = Pa_StartStream(output_stream)) != paNoError) { goto done; } int output_scale = output_parameters.channelCount / 2; int frame_print_interval = DEBUG_PRINT_INTERVAL_MILLIS * audio_options.sample_rate / 1000; int current_frame = 0; while (true) { if ((err = Pa_IsStreamActive(output_stream)) != 1) { break; } if (input_stream && (err = Pa_IsStreamActive(input_stream)) != 1) { break; } current_frame += OSFilter_execute(filter, input_buffer, output_buffer); if (audio_options.print_debug && current_frame > frame_print_interval) { current_frame -= frame_print_interval; if (!is_parent_running(audio_options.parent_thread_ident)) { printf("Parent thread is dead. Shutting down now.\n"); fflush(stdout); goto done; } if (!audio_options.print_debug) { continue; } long frame_difference = (CircularBuffer_lag(input_buffer) + CircularBuffer_lag(output_buffer) / output_scale) / 2; float lag = (float)(frame_difference) / audio_options.sample_rate * 1000; printf("%lu\t%lu\t%lu\t%fms\n", input_buffer->offset_producer, output_buffer->offset_consumer / output_scale, frame_difference, lag ); if (live_stream && (lag > audio_options.lag_reset_limit * 1000)) { printf("Resetting to latest due to high lag.\n"); CircularBuffer_fastforward(input_buffer, audio_options.filter_size * 2); CircularBuffer_fastforward(output_buffer, 0); } fflush(stdout); } } if (err < 0) { goto done; } done: if (output_stream) { Pa_CloseStream(output_stream); } if (input_stream) { Pa_CloseStream(input_stream); } Pa_Terminate(); if (input_buffer) { CircularBuffer_destroy(input_buffer); } CircularBuffer_destroy(output_buffer); if (decoder_input) { CircularBuffer_destroy(decoder_input); } if (decoder_buffer) { Decoding_free(decoder_buffer); } OSFilter_destroy(filter); if (err != paNoError) { fprintf(stdout, "An error occured while using the portaudio stream\n"); fprintf(stdout, "Error number: %d\n", err); fprintf(stdout, "Error message: %s\n", Pa_GetErrorText(err)); fflush(stdout); err = 1; } return err; }
PaError OpenStream(PaStream **mStream, PaDeviceIndex Device, double Rate, void* Sound, double &dLatency, PaStreamCallback Callback) { PaStreamParameters outputParams; outputParams.device = Device; outputParams.channelCount = 2; outputParams.sampleFormat = paFloat32; if (!Configuration::GetConfigf("UseHighLatency", "Audio")) outputParams.suggestedLatency = Pa_GetDeviceInfo(outputParams.device)->defaultLowOutputLatency; else outputParams.suggestedLatency = Pa_GetDeviceInfo(outputParams.device)->defaultHighOutputLatency; #ifndef WIN32 outputParams.hostApiSpecificStreamInfo = NULL; #else PaWasapiStreamInfo StreamInfo; PaWinDirectSoundStreamInfo DSStreamInfo; if (UseWasapi) { outputParams.hostApiSpecificStreamInfo = &StreamInfo; StreamInfo.hostApiType = paWASAPI; StreamInfo.size = sizeof(PaWasapiStreamInfo); StreamInfo.version = 1; if (!Configuration::GetConfigf("WasapiDontUseExclusiveMode", "Audio")) { StreamInfo.threadPriority = eThreadPriorityProAudio; StreamInfo.flags = paWinWasapiExclusive; } else { StreamInfo.threadPriority = eThreadPriorityAudio; StreamInfo.flags = 0; } StreamInfo.hostProcessorOutput = NULL; StreamInfo.hostProcessorInput = NULL; } else { outputParams.hostApiSpecificStreamInfo = &DSStreamInfo; DSStreamInfo.size = sizeof(PaWinDirectSoundStreamInfo); DSStreamInfo.hostApiType = paDirectSound; DSStreamInfo.version = 2; DSStreamInfo.flags = 0; } #endif dLatency = outputParams.suggestedLatency; // fire up portaudio PaError Err = Pa_OpenStream(mStream, NULL, &outputParams, Rate, 0, paClipOff, Callback, (void*)Sound); if (Err) { Log::Logf("%ls\n", Utility::Widen(Pa_GetErrorText(Err)).c_str()); Log::Logf("Device Selected %d\n", Device); } #ifdef LINUX else { Log::Logf("Audio: Enabling real time scheduling\n"); PaAlsa_EnableRealtimeScheduling( mStream, true ); } #endif return Err; }