Spring Boot向Angular发送音频字节数组并实现播放的方法
Let's walk through this end-to-end, from polishing your Spring Boot backend to building the Angular frontend playback logic.
Step 1: Complete the Spring Boot Backend
First, let's finish your generateVoice method and expose a REST endpoint that returns the audio bytes with the correct HTTP headers.
1.1 Polish the Audio Generation Method
Make sure your generateVoice method properly handles exceptions and converts the AudioInputStream to a byte array. Here's a complete, error-handled version:
import marytts.LocalMaryInterface; import marytts.exceptions.MaryConfigurationException; import marytts.exceptions.SynthesisException; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @RestController @CrossOrigin(origins = "http://localhost:4200") // Allow your Angular app's default origin public class TextToSpeechController { public byte[] generateVoice(String text) throws MaryConfigurationException, SynthesisException, IOException { LocalMaryInterface maryInterface = new LocalMaryInterface(); // Optional: Set a specific voice or output format (default is WAV) // maryInterface.setVoice("cmu-slt-hsmm"); InputStream audioStream = maryInterface.generateAudio(text); // Convert InputStream to byte array ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = audioStream.read(buffer)) != -1) { baos.write(buffer, 0, bytesRead); } audioStream.close(); return baos.toByteArray(); } @GetMapping("/api/tts/generate") public ResponseEntity<byte[]> getAudio(@RequestParam String text) { try { byte[] audioBytes = generateVoice(text); // Return with correct audio content type (adjust if you use MP3 or another format) return ResponseEntity.ok() .contentType(MediaType.parseMediaType("audio/wav")) .body(audioBytes); } catch (Exception e) { e.printStackTrace(); return ResponseEntity.internalServerError().build(); } } }
- Notes:
- The
@CrossOriginannotation lets your Angular app (running on port 4200 by default) access the endpoint. For production, restrict this to your frontend's actual domain. - We use
audio/wavas the Content-Type since MaryTTS defaults to WAV format. Update this if you configure MaryTTS to output MP3 or another format. - The endpoint accepts a
textquery parameter to support dynamic input.
- The
Step 2: Build the Angular Frontend
Now let's create the service and component to fetch the audio blob and play it in the browser.
2.1 Create a TTS Service
Generate a service to handle the HTTP request to your backend:
// src/app/services/tts.service.ts import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class TtsService { private apiUrl = 'http://localhost:8080/api/tts/generate'; constructor(private http: HttpClient) { } getAudio(text: string): Observable<Blob> { return this.http.get(`${this.apiUrl}?text=${encodeURIComponent(text)}`, { responseType: 'blob' }); } }
- We set
responseType: 'blob'to tell Angular to parse the binary audio response as a Blob, which is ideal for media playback. encodeURIComponent(text)ensures special characters in the input text are handled correctly in the URL.
2.2 Create a Playback Component
Build a component with an input field, play button, and audio player:
// src/app/tts-player/tts-player.component.ts import { Component, OnDestroy, ViewChild, ElementRef } from '@angular/core'; import { TtsService } from '../services/tts.service'; @Component({ selector: 'app-tts-player', template: ` <div class="tts-container"> <input type="text" [(ngModel)]="inputText" placeholder="Enter text to speak..." class="text-input" > <button (click)="playAudio()" [disabled]="!inputText" class="play-btn"> Play Audio </button> <audio #audioElement controls class="audio-player"></audio> </div> `, styles: [` .tts-container { margin: 2rem; display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; } .text-input { padding: 0.5rem; width: 300px; border: 1px solid #ddd; border-radius: 4px; } .play-btn { padding: 0.5rem 1rem; background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; } .play-btn:disabled { background: #ccc; cursor: not-allowed; } .audio-player { margin-top: 1rem; width: 100%; } `] }) export class TtsPlayerComponent implements OnDestroy { inputText = ''; private audioUrl: string | null = null; @ViewChild('audioElement') audioElement!: ElementRef<HTMLAudioElement>; constructor(private ttsService: TtsService) { } playAudio() { if (!this.inputText) return; this.ttsService.getAudio(this.inputText).subscribe({ next: (blob) => { // Clean up old URL to prevent memory leaks if (this.audioUrl) { URL.revokeObjectURL(this.audioUrl); } // Create a temporary URL for the audio blob this.audioUrl = URL.createObjectURL(blob); // Update the audio element's source and play const audio = this.audioElement.nativeElement; audio.src = this.audioUrl; audio.play().catch(err => console.error('Playback failed:', err)); }, error: (err) => { console.error('Failed to fetch audio:', err); } }); } ngOnDestroy() { // Clean up the object URL when the component is destroyed if (this.audioUrl) { URL.revokeObjectURL(this.audioUrl); } } }
- Key Points:
- We use
@ViewChildto directly access the<audio>element instead of querying the DOM. URL.createObjectURL(blob)creates a temporary URL that the audio element can use as its source.- We revoke the object URL in
ngOnDestroyto free up memory—this is critical to avoid memory leaks. - We handle playback errors (like browser autoplay restrictions) with
.catch()onaudio.play().
- We use
2.3 Add Required Modules
Don't forget to import HttpClientModule and FormsModule in your AppModule to enable HTTP requests and two-way binding:
// src/app/app.module.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpClientModule } from '@angular/common/http'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { TtsPlayerComponent } from './tts-player/tts-player.component'; @NgModule({ declarations: [AppComponent, TtsPlayerComponent], imports: [BrowserModule, HttpClientModule, FormsModule], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Final Checks
- Ensure MaryTTS dependencies are properly added to your Spring Boot project (via
pom.xmlorbuild.gradle). - Start your Spring Boot backend (default port 8080) and Angular frontend (
ng serve, default port 4200). - Enter text in the input field, click "Play Audio"—you should hear the generated MaryTTS audio!
内容的提问来源于stack exchange,提问作者brahim belkhiria

