You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot向Angular发送音频字节数组并实现播放的方法

Solution: Send MaryTTS Audio from Spring Boot to Angular & Play It

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 @CrossOrigin annotation 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/wav as 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 text query parameter to support dynamic input.

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 @ViewChild to 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 ngOnDestroy to free up memory—this is critical to avoid memory leaks.
    • We handle playback errors (like browser autoplay restrictions) with .catch() on audio.play().

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

  1. Ensure MaryTTS dependencies are properly added to your Spring Boot project (via pom.xml or build.gradle).
  2. Start your Spring Boot backend (default port 8080) and Angular frontend (ng serve, default port 4200).
  3. Enter text in the input field, click "Play Audio"—you should hear the generated MaryTTS audio!

内容的提问来源于stack exchange,提问作者brahim belkhiria

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:57:12