

# IVS-Broadcast-SDK: Benutzerdefinierte Audio-Quellen \| Echtzeit-Streaming
<a name="broadcast-custom-audio-sources"></a>

**Hinweis:** Diese Anleitung führt Sie durch die Schritte zum Einstieg in das Android Broadcast-SDK für IVS-Streaming. Informationen für die iOS- und Web-SDKs werden zukünftig veröffentlicht.

Benutzerdefinierte Audioeingangsquellen ermöglichen es einer Anwendung, ihre eigenen Audioeingänge an das Broadcast-SDK zu liefern, anstatt auf das integrierte Mikrofon des Geräts beschränkt zu sein. Eine benutzerdefinierte Audioquelle ermöglicht es Anwendungen, verarbeitetes Audio mit Effekten zu streamen, mehrere Audiostreams zu mischen oder in Audioverarbeitungsbibliotheken von Drittanbietern zu integrieren.

Beachten Sie, dass das Broadcast-SDK nicht mehr für die Verwaltung der Kamera verantwortlich ist, wenn Sie eine benutzerdefinierte Bildeingabequelle zur benutzerdefinierten Steuerung der Kamera verwenden. Stattdessen ist Ihre Anwendung für die Erfassung, Verarbeitung und Übertragung von Audiodaten an die benutzerdefinierte Quelle verantwortlich.

Der Arbeitsablauf für benutzerdefinierte Audioquellen folgt diesen Schritten:

1. Audioeingang – Erstellen Sie eine benutzerdefinierte Audioquelle mit einem bestimmten Audioformat (Samplerate, Kanäle, Format). 

1. Ihre Verarbeitung – Erfassen oder generieren Sie Audiodaten aus Ihrer Audioverarbeitungspipeline.

1. Benutzerdefinierte Audioquelle – Senden Sie Audiopuffer an die benutzerdefinierte Quelle mithilfe von`appendBuffer()`.

1. Stage – In `LocalStageStream` abschließen und über Ihre `StageStrategy` in der Stage veröffentlichen. 

1. Teilnehmer – Die Teilnehmer der Phase erhalten das bearbeitete Audio in Echtzeit.

## Android
<a name="custom-audio-sources-android"></a>

### Erstellen einer benutzerdefinierten Audioquelle
<a name="custom-audio-sources-android-creating-a-custom-audio-source"></a>

Erstellen Sie nach dem Erstellen einer `DeviceDiscovery`-Sitzung eine Audioeingabequelle:

```
DeviceDiscovery deviceDiscovery = new DeviceDiscovery(context); 
 
// Create custom audio source with specific format 
CustomAudioSource customAudioSource = deviceDiscovery.createAudioInputSource( 
   2,  // Number of channels (1 = mono, 2 = stereo) 
   BroadcastConfiguration.AudioSampleRate.RATE_48000,  // Sample rate 
   AudioDevice.Format.INT16  // Audio format (16-bit PCM) 
);
```

Diese Methode gibt eine `CustomAudioSource` zurück, die unformatierte PCM-Audiodaten akzeptiert. Die benutzerdefinierte Audioquelle muss mit demselben Audioformat konfiguriert sein, das Ihre Audioverarbeitungspipeline erzeugt.

#### Unterstützte Formate
<a name="custom-audio-sources-android-submitting-audio-data-supportedi-audio-formats"></a>


| Parameter | Optionen | Beschreibung | 
| --- | --- | --- | 
| Kanäle | 1 (Mono), 2 (Stereo) | Die Anzahl der Audiokanäle. | 
| Abtastrate | RATE\_16000, RATE\_44100, RATE\_48000 | Audio-Abtastrate in Hz. Für hohe Qualität werden 48 kHz empfohlen. | 
| Format | INT16, FLOAT32 | Format der Hörprobe. INT16 ist 16-Bit-Festkomma-PCM, FLOAT32 ist 32-Bit-Gleitkomma-PCM. Es sind sowohl verschachtelte als auch planare Formate verfügbar. | 

### Audioeinstellungen
<a name="custom-audio-sources-android-submitting-audio-data"></a>

Verwenden Sie die Methode `appendBuffer()`, um Audiodaten an die benutzerdefinierte Quelle zu senden:

```
// Prepare audio data in a ByteBuffer 
ByteBuffer audioBuffer = ByteBuffer.allocateDirect(bufferSize); 
audioBuffer.put(pcmAudioData);  // Your processed audio data 
 
// Calculate the number of bytes 
long byteCount = pcmAudioData.length; 
 
// Submit audio to the custom source 
// presentationTimeUs should be generated by and come from your audio source
int samplesProcessed = customAudioSource.appendBuffer( 
   audioBuffer, 
   byteCount, 
   presentationTimeUs 
); 
 
if (samplesProcessed > 0) { 
   Log.d(TAG, "Successfully submitted " + samplesProcessed + " samples"); 
} else { 
   Log.w(TAG, "Failed to submit audio samples"); 
} 
 
// Clear buffer for reuse 
audioBuffer.clear();
```

**Wichtige Überlegungen:**
+ Audiodaten müssen in dem Format vorliegen, das bei der Erstellung der benutzerdefinierten Quelle angegeben wurde.
+ Die Zeitstempel sollten monoton ansteigend sein und von Ihrer Audioquelle bereitgestellt werden, um eine reibungslose Audiowiedergabe zu gewährleisten.
+ Reichen Sie regelmäßig Audiodateien ein, um Lücken im Stream zu vermeiden.
+ Die Methode gibt die Anzahl der verarbeiteten Samples zurück (0 bedeutet Fehler). 

### In einer Stage veröffentlichen
<a name="custom-audio-sources-android-publishing-to-a-stage"></a>

Die `CustomAudioSource` in einem `AudioLocalStageStream` abschließen und von Ihrer `StageStrategy` zurücksenden:

```
// Create the audio stream from custom source 
AudioLocalStageStream audioStream = new AudioLocalStageStream(customAudioSource); 
 
// Define your stage strategy 
Strategy stageStrategy = new Strategy() { 
   @NonNull 
   @Override 
   public List<LocalStageStream> stageStreamsToPublishForParticipant( 
         @NonNull Stage stage, 
         @NonNull ParticipantInfo participantInfo) { 
      List<LocalStageStream> streams = new ArrayList<>(); 
      streams.add(audioStream);  // Publish custom audio 
      return streams; 
   } 
 
   @Override 
   public boolean shouldPublishFromParticipant( 
         @NonNull Stage stage, 
         @NonNull ParticipantInfo participantInfo) { 
      return true;  // Control when to publish 
   } 
 
   @Override 
   public Stage.SubscribeType shouldSubscribeToParticipant( 
         @NonNull Stage stage, 
         @NonNull ParticipantInfo participantInfo) { 
      return Stage.SubscribeType.AUDIO_VIDEO; 
   } 
}; 
 
// Create and join the stage 
Stage stage = new Stage(context, stageToken, stageStrategy);
```

### Vollständiges Beispiel: Integration der Audioverarbeitung
<a name="custom-audio-sources-android-complete-example"></a>

Hier ist ein vollständiges Beispiel, das die Integration mit einem Audioverarbeitungs-SDK zeigt:

```
public class AudioStreamingActivity extends AppCompatActivity { 
   private DeviceDiscovery deviceDiscovery; 
   private CustomAudioSource customAudioSource; 
   private AudioLocalStageStream audioStream; 
   private Stage stage; 
 
   @Override 
   protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
 
      // Configure audio manager 
      StageAudioManager.getInstance(this) 
         .setPreset(StageAudioManager.UseCasePreset.VIDEO_CHAT); 
 
      // Initialize IVS components 
      initializeIVSStage(); 
 
      // Initialize your audio processing SDK 
      initializeAudioProcessing(); 
   } 
 
   private void initializeIVSStage() { 
      deviceDiscovery = new DeviceDiscovery(this); 
 
      // Create custom audio source (48kHz stereo, 16-bit) 
      customAudioSource = deviceDiscovery.createAudioInputSource( 
         2,  // Stereo 
         BroadcastConfiguration.AudioSampleRate.RATE_48000, 
         AudioDevice.Format.INT16 
      ); 
 
      // Create audio stream 
      audioStream = new AudioLocalStageStream(customAudioSource); 
 
      // Create stage with strategy 
      Strategy strategy = new Strategy() { 
         @NonNull 
         @Override 
         public List<LocalStageStream> stageStreamsToPublishForParticipant( 
               @NonNull Stage stage, 
               @NonNull ParticipantInfo participantInfo) { 
            return Collections.singletonList(audioStream); 
         } 
 
         @Override 
         public boolean shouldPublishFromParticipant( 
               @NonNull Stage stage, 
               @NonNull ParticipantInfo participantInfo) { 
            return true; 
         } 
 
         @Override 
         public Stage.SubscribeType shouldSubscribeToParticipant( 
               @NonNull Stage stage, 
               @NonNull ParticipantInfo participantInfo) { 
            return Stage.SubscribeType.AUDIO_VIDEO; 
         } 
      }; 
 
      stage = new Stage(this, getStageToken(), strategy); 
   } 
 
   private void initializeAudioProcessing() { 
      // Initialize your audio processing SDK 
      // Set up callback to receive processed audio 
      yourAudioSDK.setAudioCallback(new AudioCallback() { 
         @Override 
         public void onProcessedAudio(byte[] audioData, int sampleRate, 
                                     int channels, long timestamp) { 
            // Submit processed audio to IVS Stage 
            submitAudioToStage(audioData, timestamp); 
         } 
      }); 
   } 
 
   // The timestamp is required to come from your audio source and you  
   // should not be generating one on your own, unless your audio source 
   // does not provide one. If that is the case, create your own epoch  
   // timestamp and manually calculate the duration between each sample  
   // using the number of frames and frame size. 

   private void submitAudioToStage(byte[] audioData, long timestamp) { 
      try { 
         // Allocate direct buffer 
         ByteBuffer buffer = ByteBuffer.allocateDirect(audioData.length); 
         buffer.put(audioData); 
 
         // Submit to custom audio source 
         int samplesProcessed = customAudioSource.appendBuffer( 
            buffer, 
            audioData.length, 
            timestamp > 0 ? timestamp : System.nanoTime() / 1000 
         ); 
 
         if (samplesProcessed <= 0) { 
            Log.w(TAG, "Failed to submit audio samples"); 
         } 
 
         buffer.clear(); 
      } catch (Exception e) { 
         Log.e(TAG, "Error submitting audio: " + e.getMessage(), e); 
      } 
   } 
 
   @Override 
   protected void onDestroy() { 
      super.onDestroy(); 
      if (stage != null) { 
          stage.release(); 
      } 
   } 
}
```

### Bewährte Methoden
<a name="custom-audio-sources-android-best-practices"></a>

#### Audioformatkonsistenz
<a name="custom-audio-sources-android-best-practices-audio-format-consistency"></a>

Stellen Sie sicher, dass das von Ihnen eingereichte Audioformat dem Format entspricht, das bei der Erstellung der benutzerdefinierten Quelle angegeben wurde:

```
// If you create with 48kHz stereo INT16 
customAudioSource = deviceDiscovery.createAudioInputSource( 
   2, RATE_48000, INT16 
); 
 
// Your audio data must be: 
// - 2 channels (stereo) 
// - 48000 Hz sample rate 
// - 16-bit interleaved PCM format
```

#### Pufferverwaltung
<a name="custom-audio-sources-android-best-practices-buffer-managemetn"></a>

Verwenden Sie direkte `ByteBuffers` und verwenden Sie sie erneut, um die Garbage Collection zu minimieren: 

```
// Allocate once 
private ByteBuffer audioBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE); 
 
// Reuse in callback 
public void onAudioData(byte[] data) { 
   audioBuffer.clear(); 
   audioBuffer.put(data); 
   customAudioSource.appendBuffer(audioBuffer, data.length, getTimestamp()); 
   audioBuffer.clear(); 
}
```

#### Timing und Synchronisation
<a name="custom-audio-sources-android-best-practices-timing-and-synchronization"></a>

Für eine reibungslose Audiowiedergabe müssen Sie die von Ihrer Audioquelle bereitgestellten Zeitstempel verwenden. Wenn Ihre Audioquelle keinen eigenen Zeitstempel hat, erstellen Sie Ihren eigenen Epochenzeitstempel und berechnen Sie die Dauer zwischen den einzelnen Samples manuell anhand der Anzahl der Frames und der Framegröße. 

```
// "audioFrameTimestamp" should be generated by your audio source
// Consult your audio source’s documentation for information on how to get this 
long timestamp = audioFrameTimestamp;
```

#### Fehlerbehandlung
<a name="custom-audio-sources-android-best-practices-error-handling"></a>

Überprüfen Sie immer den Rückgabewert von `appendBuffer()`: 

```
int samplesProcessed = customAudioSource.appendBuffer(buffer, count, timestamp); 
 
if (samplesProcessed <= 0) { 
   Log.w(TAG, "Audio submission failed - buffer may be full or format mismatch"); 
   // Handle error: check format, reduce submission rate, etc. 
}
```