Repository: flutter
Issue: [pigeon] support for multiple input files.
Labels: c: new feature,package,c: proposal,team-ecosystem,p: pigeon,P3,triaged-ecosystem

I'm experimenting with pigeon and have created my first interface.

I started structuring my code into three dart file.

hostapi
flutterapi
shared classes.

When trying to  generate the pigeon code I found the --input flag only takes one file.

So I tried to run pigeon once for each file.

This however didn't work as it appears that pigeon is using the name of the first class it visits (this isn't clear) despite placing a configPigeon declaration in each file.

So  I assume that pigeon currently only supports a single input file.
Whilst this is probably suitable from an minimum release it would be nice if it would support multiple input files to allow for better structuring of the code base.

For the record here are the input files I created

<details>

sounds_shared_api_classes.dart
```dart
/// classes that are shared between the 'to' and 'from' platform apis.abstract
///
///
///
import 'package:pigeon/pigeon.dart';

class SoundPlayer {}

class Track {}

class Request {
  String uuid;
}

class Response {
  bool success;
  int errorCode;
  String error;
}

void configurePigeon(PigeonOptions opts) {
  opts.dartOut =
      '../sounds_platform_interface/lib/sounds_shared_api_classes.dart';
  opts.objcHeaderOut = 'ios/Classes/sounds_shared_api_classes.h';
  opts.objcSourceOut = 'ios/Classes/sounds_shared_api_classes.m';
  opts.objcOptions.prefix = 'FLT';
  opts.javaOut =
      'android/src/main/java/com/bsutton/sounds/SoundsSharedApiClasses.java';
  opts.javaOptions.package = 'com.bsutton.sounds';
}


```
sounds_from_platform_api.dart
```dart
import 'package:pigeon/pigeon.dart';

import 'sounds_shared_api_classes.dart';

/// Defines the set of methods that the platform can used
/// to call into the dart code.
///

/// This enum reflects an enum of the same name
/// in BackgroundAudioServices.java
/// and the two enums MUST be kept in sync.
///
/// The order of these enums is CRITICAL!
enum SystemPlaybackState {
  /// The OS Media Player has started playing
  playing,

  /// The OS Media Player has been paused
  paused,

  /// The OS Media Player has been stopped
  stopped
}

/// The collection of method calls the platform can
/// use to call back into the dart code.
@FlutterApi()
abstract class SoundsFromPlatformApi {
  /// Called in response to an [initialisePlayer] call.
  ///
  /// If the player was already initialised then the platform MUST
  /// set [success] to false and [error] to 'Already initialised'.
  ///
  /// If the initialisation suceeded then [success] is
  /// set to true and [error] is ignored.
  ///
  /// If the initialisation failed [success] is set to false
  /// and [error] contains an appropriate message.
  void onInitialiseCompleted(
      SoundPlayer player, bool success, int errorCode, String error);

  /// Called by the platform to indicate
  /// that a call to [releasePlayer] has completed.
  ///
  /// If the player was already released (an unknown player is passed)
  /// then the platform MUST
  /// set [success] to false and [error] to 'Already released'.
  ///
  /// If the player was released successfully then [success] is set to true.
  ///
  /// If the player failed to start then [success] is set to false
  /// and [error] contains an appropriate error message.
  ///
  /// Even if the release failed the Dart system will assume
  /// that the release was successful and take no further action.
  /// i.e. it will make no attempts to do any further cleanup.
  /// It is the platforms responsibilty to clean up the resources
  /// as much as possible before calling this method.
  ///
  void onReleaseCompleted(
      SoundPlayer player, bool success, int errorCode, String error);

  /// Called by the platform to indicate
  /// that a call to [startPlayer] has completed.
  ///
  /// If the player was already started then the platform MUST
  /// set [success] to false and [error] to 'Already playing'.
  ///
  /// If the player started then [success] is set to true.
  ///
  /// If the player failed to start then [success] is set to false
  /// and [error] contains an appropriate error message.
  ///
  void onStartCompleted(
      SoundPlayer player, bool success, int errorCode, String error);

  /// Called by the platform to indicate
  /// that a call to [stopPlayer] has completed.
  ///
  /// If the player was already stopped then the platform MUST
  /// set [success] to false and [error] to 'Already stopped'.
  ///
  /// If the player stopped then [success] is set to true.
  ///
  /// If the player failed to stop then [success] is set to false
  /// and [error] contains an appropriate error message.
  ///
  void onStopCompleted(
      SoundPlayer player, bool success, int errorCode, String error);

  /// Called by the platform to indicate
  /// that a call to [pausePlayer] has completed.
  ///
  /// If the player was already paused then the platform MUST
  /// set success to false and set error to 'Already paused'.
  ///
  /// If the player paused then [success] is set to true.
  ///
  /// If the player failed to pause then [success] is set to false
  /// and [error] contains an appropriate error message.
  ///
  void onPauseCompleted(
      SoundPlayer player, bool success, int errorCode, String error);

  /// Called by the platform to indicate
  /// that a call to [resumelayer] has completed.
  ///
  /// If the player was already playing then the platform MUST
  /// set success to false and set error to 'Already playing'.
  ///
  /// If the player resumed then [success] is set to true.
  ///
  /// If the player failed to resume then [success] is set to false
  /// and [error] contains an appropriate error message.
  ///
  void onResumeCompleted(
      SoundPlayer player, bool success, int errorCode, String error);

  /// Called by the platform to indicate
  /// that a call to [getDuration] has completed.
  ///
  /// The [milliseconds] represents the duration of the recording
  /// in milliseconds.
  ///
  /// If the duration was calculated then [success] is set to true.
  ///
  /// If the passed coded could not be calculated
  /// If the player failed to resume then [success] is set to false
  /// and [error] contains an appropriate error message.
  ///
  void onGetDurationCompleted(SoundPlayer player, Track track, int milliseconds,
      bool success, int errorCode, String error);

  /// The platform must emmit calls to this method whenever
  /// audio is playing.
  ///
  /// The [duration] is the total duration of the track currently playing in
  /// milliseconds. This value may change if the audio is being streamed.
  ///
  /// The [position] is the current playback position measured as the no.
  /// of milliseconds from the start of the track. This value will change
  /// as playback occurs.
  ///
  /// The interval between calls to this method is set by a call to
  /// [setProgressInterval]. If not call to [setProgressInterval] has
  /// been set then the default interval MUST be 100ms.
  void onUpdateProgress(
      SoundPlayer player, Track track, int duration, int position);

  /// The platform MUST emit this method whenever audio finishes playing and
  /// is non resumable for any reason.
  ///
  /// e.g. a call to [pause] would not normally result in this method being
  /// called.
  ///
  /// The following circumstances are noted but may not be exhaustive.
  ///  - [onStopped] was called.
  ///  - the audio played to completion.
  ///  - the user skipped to another track.
  ///  - the sound player is released.
  ///  - an error occurs that causes the track to stop playing.
  ///  - playback was stopped due to the app being sent to the background.
  ///  - playback was stopped (as apposed to paused) via the shade
  void onAudioPlayerFinished(
      SoundPlayer player, Track track, int duration, int position);

  /// The platform MUST emit this method when the OS Media Player
  /// is used to skip forward to the next track.
  ///
  /// [track] represents the current track that was playing when the
  /// user initialied the skip.
  void onSystemSkipForward(SoundPlayer player, Track track);

  /// The platform MUST emit this method when the OS Media Player
  /// is used to skip backward to the next track.
  ///
  /// [track] represents the current track that was playing when the
  /// user initialied the skip.
  void onSystemSkipBackward(SoundPlayer player, Track track);

  /// I think we will deprecate this api as we should now have
  /// reliable state visiblity from the individual events that will
  /// be emitted as noted above.
  /// The platform MUST emit this method when the OS Media Player
  /// is used to skip backward to the next track.
  ///
  /// [track] represents the current track that was playing when the
  /// user initialied the skip.
//void onSystemUpdatePlaybackState

}

void configurePigeon(PigeonOptions opts) {
  opts.dartOut =
      '../sounds_platform_interface/lib/sounds_from_platform_api.dart';
  opts.objcHeaderOut = 'ios/Classes/sounds_from_platform_api.h';
  opts.objcSourceOut = 'ios/Classes/sounds_from_platform_api.m';
  opts.objcOptions.prefix = 'FLT';
  opts.javaOut =
      'android/src/main/java/com/bsutton/sounds/SoundsFromPlatformApi.java';
  opts.javaOptions.package = 'com.bsutton.sounds';
}


```
sounds_to_platform_api.dart
```dart
/// Defines the platform agnosistic interface for calls from flutter to the
///  underlaying platform code.
///
import 'package:pigeon/pigeon.dart';
import 'package:sounds/src/audio_focus.dart';

import 'sounds_shared_api_classes.dart';

/// The collection of methods we use to call into the platform code.
@HostApi()
abstract class SoundsToPlatformApi {
  /// The list of specific errors that can be passed from the platform to dart.
  static const errnoGeneral = 1;
  static const errnoUnsupportedCodec = 2;

  /// Each Player must be initialized and registered before
  /// any other calls can be made.
  ///
  /// This platform MUST return immediately and MUST
  /// the platform MUST call [onInitialiseCompleted] once
  /// the operation completes or an error occurs.
  @async
  Response initializePlayer(SoundPlayer player);

  /// Releases the slot used by the connector.
  /// To use a plugin you start by calling [register]
  /// and finish by calling [release].
  /// Instructs the platform to release the player and
  /// free any resources associated with the player.
  ///
  /// The platform MUST  return immediately and the platform must
  /// emmit a call to [onReleaseCompleted] once the player has actually been
  /// released.
  @async
  Response releasePlayer(SoundPlayer player);

  /// Call this method to start playing the given track.
  ///
  /// The platform MUST return immediately and
  /// MUST call [onStartCompleted] once the
  /// track starts playing or if an error occurs.
  ///
  /// Once the audio start playing the platform MUST
  @async
  Response startPlayer(SoundPlayer player, Track track);

  /// Instructs the player to stop playing.
  ///
  /// The call MUST return immediately and the platform must
  /// emmit a call to [onStopCompleted] once the player has actually stopped
  /// playing.
  @async
  Response stopPlayer(SoundPlayer player);

  /// Instructs the player to pause.
  ///
  /// The call should return immediately and the platform must
  /// emmit a call to [onPauseCompleted] once the player has actually stopped
  /// playing.
  ///
  @async
  Response pausePlayer(SoundPlayer player);

  /// Instructs the player to resume.
  ///
  /// The call MUST return immediately and the platform must
  /// emmit a call to [onResumeCompleted] once the player has actually stopped
  /// playing.
  @async
  Response resumePlayer(SoundPlayer player);

  /// seek the currently playing track to the position [milliseconds]
  /// from the start.
  ///
  /// It is not valid to attempt to seek if the player is not currently
  /// playing.
  ///
  /// It is expect that we may see race conditions (as pause/seek overlapping)
  /// in which case the platform will return an error if the player
  /// isn't playing. It is up to the dart code to manage these race conditions.
  ///
  /// The call MUST return immediately and the platform must
  /// emmit a call to [onSeekCompleted] once the player has actually stopped
  /// playing.
  @async
  Response seekToPlayer(SoundPlayer player, int milliseconds);

  /// Get the duration of an audio file located at [path].
  ///
  /// Depending on the size of the file and the codec this may be a lengthy
  /// operation.
  ///
  /// The platform MUST return immediately  and MUST call
  /// [getDurationCompleted] once the duration is calculated or an error occurs.
  ///
  /// If the Track's codec is not supported then [getDurationCompleted]
  /// must return with [success] = false and an error of the form:
  /// 'The codec $codec is not supported'.
  @async
  Response getDuration(SoundPlayer player, Track track);

  ///
  /// Sets the volume between 0 and 100.
  ///
  /// On android this will need to be scaled to a value between 0 and 1.
  @async
  Response setVolume(SoundPlayer player, double volume);

  /// Sets the interval between progress messages being generated from
  /// the platform code.
  @async
  Response setProgressInterval(SoundPlayer player, int milliseconds);

  /// Requests the audio focus setting the mode and gain.
  ///
  /// Was setActive(bool)
  /// - combines
  ///   ioSetCategory
  ///   androidAudioFocusRequest
  ///   setActive
  ///
  @async
  Response requestAudioFocus(SoundPlayer player, AudioFocus mode);

  /// Release the audio focus.
  /// The affect on other media players will a result of a prior
  /// call to [requestAudioFocus] and the [AudioFocus] mode that was passed.
  /// was setActive(false)
  @async
  Response releaseAudioFocus(SoundPlayer player);
}

void configurePigeon(PigeonOptions opts) {
  opts.dartOut = '../sounds_platform_interface/lib/sounds_to_platform_api.dart';
  opts.objcHeaderOut = 'ios/Classes/sounds_to_platform_api.h';
  opts.objcSourceOut = 'ios/Classes/sounds_to_platform_api.m';
  opts.objcOptions.prefix = 'FLT';
  opts.javaOut =
      'android/src/main/java/com/bsutton/sounds/SoundsToPlatformApi.java';
  opts.javaOptions.package = 'com.bsutton.sounds';
}


```

</details>