| 506 | |
| 507 | // Feeds raw PCM from stdin into the session chunk by chunk, so nothing has to be buffered up |
| 508 | // front and transcription tracks the input as it arrives. |
| 509 | engine::runtime::TaskResult run_streaming_from_stdin( |
| 510 | const std::string & input_format, |
| 511 | engine::runtime::IStreamingVoiceTaskSession & streaming, |
| 512 | const engine::runtime::TaskRequest & request, |
| 513 | const minitts::app::StreamEventSink & sink) { |
| 514 | // build_request_from_cli fills audio_input with the declared format and no samples, which is |
| 515 | // also what prepare() consumes as its audio contract. |
| 516 | if (!request.audio_input.has_value()) { |
| 517 | throw std::runtime_error("streaming from stdin requires an audio format contract"); |
| 518 | } |
| 519 | const auto sample_format = minitts::app::parse_pcm_sample_format(input_format); |
| 520 | const minitts::app::AudioStreamFormat format{ |
| 521 | request.audio_input->sample_rate, |
| 522 | request.audio_input->channels, |
| 523 | }; |
| 524 | // A headerless stream cannot be checked against a header, so report how it was interpreted. |
| 525 | std::cout << "audio_input=stdin format=" << minitts::app::to_string(sample_format) |
| 526 | << " rate=" << format.sample_rate |
| 527 | << " channels=" << format.channels << "\n" |
| 528 | << std::flush; |
| 529 | const auto stream = minitts::app::make_stdin_pcm_stream(format, sample_format); |
| 530 | return minitts::app::run_streaming_task(streaming, request, sink, stream); |
| 531 | } |
| 532 | |
| 533 | void run_streaming( |
| 534 | int argc, |
| 535 | char ** argv, |
| 536 | engine::runtime::IStreamingVoiceTaskSession & streaming, |
| 537 | engine::runtime::IVoiceTaskSession & session, |
| 538 | engine::runtime::TaskRequest & request, |
| 539 | const minitts::app::FileOutputPolicy & outputs, |
| 540 | const std::string & input_format, |
| 541 | const std::optional<std::filesystem::path> & text_out) { |
| 542 | const auto & out_dir = outputs.output_dir; |
| 543 | minitts::cli::PartialTextRenderer partial_renderer(stdout_is_terminal()); |
| 544 | const minitts::app::StreamEventSink sink = |
| 545 | [&](const engine::runtime::StreamEvent & event) { |
| 546 | if (event.partial_text.has_value()) { |
| 547 | // Flushed so a live source's partials appear as they are produced rather than |
| 548 | // when the stdio buffer happens to fill. |
| 549 | std::cout << partial_renderer.render(event.partial_text->text) << std::flush; |
| 550 | } |
| 551 | engine::runtime::TaskResult event_result; |
| 552 | event_result.audio_output = event.audio_output; |
| 553 | event_result.named_audio_outputs = event.named_audio_outputs; |
| 554 | event_result.speaker_turns = event.speaker_turns; |
| 555 | event_result.word_timestamps = event.word_timestamps; |
| 556 | event_result.output_artifacts = event.output_artifacts; |
| 557 | minitts::app::emit_task_result( |
| 558 | event_result, |
| 559 | std::nullopt, |
| 560 | out_dir, |
| 561 | out_dir, |
| 562 | std::nullopt, |
| 563 | std::nullopt, |
| 564 | std::nullopt, |
| 565 | outputs.wav_options); |
nothing calls this directly
no test coverage detected