AudioCaptureService.java

package org.hammer.audio;

import javax.sound.sampled.AudioFormat;
import org.hammer.audio.buffer.AudioRingBuffer;
import org.hammer.audio.core.AudioBlock;
import org.hammer.audio.core.AudioFormatDescriptor;

/**
 * Service interface for audio capture and waveform data management.
 *
 * <p>This interface defines the contract for starting/stopping audio capture, retrieving the latest
 * waveform model snapshots, and adjusting capture parameters.
 *
 * <p>Thread-safety: Implementations must ensure thread-safe access to all methods. Model snapshots
 * returned by {@link #getLatestModel()} should be immutable or defensive copies to prevent
 * concurrent modification issues.
 *
 * @author refactoring
 */
public interface AudioCaptureService {

  /**
   * Start audio capture.
   *
   * <p>Initializes audio input device and begins capturing audio data in a background thread.
   *
   * @throws IllegalStateException if the service is already started or if the audio device cannot
   *     be initialized
   */
  void start();

  /**
   * Stop audio capture.
   *
   * <p>Gracefully stops the capture thread and releases audio device resources. This method should
   * be idempotent - calling it multiple times should be safe.
   */
  void stop();

  /**
   * Check if audio capture is currently running.
   *
   * @return true if capture is active, false otherwise
   */
  boolean isRunning();

  /**
   * Get the latest waveform model snapshot.
   *
   * <p>Returns an immutable snapshot of the current waveform data. This method must be thread-safe
   * and return defensive copies to prevent concurrent modification.
   *
   * @return the latest WaveformModel snapshot, never null
   */
  WaveformModel getLatestModel();

  /**
   * Get the audio format being used for capture.
   *
   * @return the AudioFormat, or null if not initialized
   */
  AudioFormat getFormat();

  /**
   * Set the divisor for buffer size calculation.
   *
   * <p>The divisor affects how much data is captured and displayed. Higher values mean smaller
   * buffers and less data per frame.
   *
   * @param divisor the divisor value (must be >= 1)
   * @throws IllegalArgumentException if divisor < 1
   */
  void setDivisor(int divisor);

  /**
   * Get the current divisor value.
   *
   * @return the current divisor
   */
  int getDivisor();

  /**
   * Recompute layout/coordinates based on current panel dimensions.
   *
   * <p>This should be called when the display panel is resized to adjust the x-coordinates of the
   * waveform points.
   *
   * @param width the panel width in pixels
   * @param height the panel height in pixels
   */
  void recomputeLayout(int width, int height);

  /**
   * @return the audio-domain format descriptor, or {@code null} if the service has not been started
   *     yet. Unlike {@link #getFormat()}, this is platform-internal and free of JavaSound types.
   */
  default AudioFormatDescriptor getDescriptor() {
    return null;
  }

  /**
   * @return the most recently captured {@link AudioBlock}, or {@code null} if no audio has been
   *     captured yet. The returned block is immutable and safe to share.
   */
  default AudioBlock getLatestBlock() {
    return null;
  }

  /**
   * @return the producer/consumer ring buffer fed by the capture thread, or {@code null} if the
   *     service has not been started yet. Downstream DSP and analysis modules consume blocks from
   *     this buffer.
   */
  default AudioRingBuffer<AudioBlock> getRingBuffer() {
    return null;
  }
}