Uso de entrada de audio comprimido con códec

Tanto el SDK de Voz como la CLI de Voz pueden aceptar formatos de audio comprimidos mediante GStreamer. GStreamer descomprime el audio antes de enviarlo mediante la conexión del servicio de Voz como PCM sin procesar.

Plataforma Idiomas Versión de GStreamer compatible
Linux C++, C#, Java, Python y Go Distribuciones y arquitecturas de destino de Linux admitidas
Windows (excepto UWP) C++, C#, Java, Python 1.18.3
Android Java 1.18.3

Instalación de GStreamer en Linux

Para más información, consulte las instrucciones de instalación de Linux.

sudo apt install libgstreamer1.0-0 \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly

Instalación de GStreamer en Windows

Para más información, consulte las instrucciones de instalación de Windows.

  • Cree la carpeta c:\gstreamer.
  • Descargue el instalador.
  • Copie el instalador en c:\gstreamer.
  • Abra PowerShell como administrador.
  • Ejecute el siguiente comando en PowerShell:
cd c:\gstreamer
msiexec /passive INSTALLLEVEL=1000 INSTALLDIR=C:\gstreamer /i gstreamer-1.0-msvc-x86_64-1.18.3.msi
  • Agregue las variables del sistema GST_PLUGIN_PATH con el valor C:\gstreamer\1.0\msvc_x86_64\lib\gstreamer-1.0.
  • Agregue las variables del sistema GSTREAMER_ROOT_X86_64 con el valor C:\gstreamer\1.0\msvc_x86_64.
  • Agregue otra entrada en la variable path como C:\gstreamer\1.0\msvc_x86_64\bin.
  • Reinicie el equipo

Uso de GStreamer en Android

En la pestaña Java anterior encontrará información sobre la compilación de libgstreamer_android.so

Para más información, consulte las instrucciones de instalación de Android.

Versión del SDK de voz necesaria para la entrada de audio comprimido

  • Se requiere el SDK de Voz, versión 1.10.0 o posteriores, para RHEL 8 y CentOS 8.
  • Se requiere el SDK de Voz, versión 1.11.0 o posteriores, para Windows.
  • SDK de Voz, versión 1.16.0 o posteriores, para la versión más reciente de GStreamer en Windows y Android.

El formato de streaming de audio predeterminado es WAV (16 KHz o 8 KHz, 16 bits y PCM mono). Aparte de WAV y PCM, también se admiten con GStreamer los formatos de entrada comprimida que se enumeran a continuación.

  • MP3
  • OPUS/OGG
  • FLAC
  • ALAW en el contenedor WAV
  • MULAW en el contenedor WAV
  • ANY (para el escenario en el que no se conoce el formato de los elementos multimedia)

GStreamer necesario para controlar el audio comprimido

El control del audio comprimido se implementa mediante GStreamer. Por motivos de licencia, los binarios de GStreamer no se compilan ni se vinculan con el SDK de Voz. Los desarrolladores deben instalar varias dependencias y complementos; consulte Instalación en Windows o Instalación en Linux. Los archivos binarios de GStreamer deben estar en la ruta de acceso del sistema, con el fin de que el SDK de Voz pueda cargarlos en tiempo de ejecución. Por ejemplo, en Windows, si el SDK de Voz es capaz de encontrar libgstreamer-1.0-0.dll o gstreamer-1.0-0.dll (en la versión más reciente de GStreamer) durante el tiempo de ejecución, significa que los archivos binarios de GStreamer se encuentran en la ruta de acceso del sistema.

El control del audio comprimido se implementa mediante GStreamer. Por motivos de licencia, los binarios de GStreamer no se compilan ni se vinculan con el SDK de Voz. Los desarrolladores deben instalar varias dependencias y complementos.

Nota

Para obtener información sobre una configuración general obligatoria en Linux, consulte los requisitos del sistema y las instrucciones de configuración.

sudo apt install libgstreamer1.0-0 \
gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good \
gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly

El control del audio comprimido se implementa mediante GStreamer. Por motivos de licencia, los binarios de GStreamer no se compilan ni se vinculan con el SDK de Voz. En su lugar, tiene que usar los binarios compilados previamente para Android. Para descargar las bibliotecas compiladas previamente, vea Instalación para desarrollo de Android.

libgstreamer_android.so es obligatorio. Asegúrese de que todos los complementos de GStreamer (del archivo Android.mk siguiente) estén vinculados en libgstreamer_android.so. Cuando se usa el último SDK de voz (1.16 y versiones posteriores) con la versión de GStreamer 1.18.3, también es necesario que libc++_shared.so esté presente en el NDK de Android.

GSTREAMER_PLUGINS := coreelements app audioconvert mpg123 \
    audioresample audioparsers ogg opusparse \
    opus wavparse alaw mulaw flac

A continuación se proporciona un ejemplo de archivo Android.mk y Application.mk. Siga estos pasos para crear el objeto compartido de gstreamer: libgstreamer_android.so.

# Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := dummy
LOCAL_SHARED_LIBRARIES := gstreamer_android
include $(BUILD_SHARED_LIBRARY)

ifndef GSTREAMER_ROOT_ANDROID
$(error GSTREAMER_ROOT_ANDROID is not defined!)
endif

ifndef APP_BUILD_SCRIPT
$(error APP_BUILD_SCRIPT is not defined!)
endif

ifndef TARGET_ARCH_ABI
$(error TARGET_ARCH_ABI is not defined!)
endif

ifeq ($(TARGET_ARCH_ABI),armeabi)
GSTREAMER_ROOT        := $(GSTREAMER_ROOT_ANDROID)/arm
else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
GSTREAMER_ROOT        := $(GSTREAMER_ROOT_ANDROID)/armv7
else ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
GSTREAMER_ROOT        := $(GSTREAMER_ROOT_ANDROID)/arm64
else ifeq ($(TARGET_ARCH_ABI),x86)
GSTREAMER_ROOT        := $(GSTREAMER_ROOT_ANDROID)/x86
else ifeq ($(TARGET_ARCH_ABI),x86_64)
GSTREAMER_ROOT        := $(GSTREAMER_ROOT_ANDROID)/x86_64
else
$(error Target arch ABI not supported: $(TARGET_ARCH_ABI))
endif

GSTREAMER_NDK_BUILD_PATH  := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/
include $(GSTREAMER_NDK_BUILD_PATH)/plugins.mk
GSTREAMER_PLUGINS         :=  $(GSTREAMER_PLUGINS_CORE) \ 
                              $(GSTREAMER_PLUGINS_CODECS) \ 
                              $(GSTREAMER_PLUGINS_PLAYBACK) \
                              $(GSTREAMER_PLUGINS_CODECS_GPL) \
                              $(GSTREAMER_PLUGINS_CODECS_RESTRICTED)
GSTREAMER_EXTRA_LIBS      := -liconv -lgstbase-1.0 -lGLESv2 -lEGL
include $(GSTREAMER_NDK_BUILD_PATH)/gstreamer-1.0.mk
# Application.mk
APP_STL = c++_shared
APP_PLATFORM = android-21
APP_BUILD_SCRIPT = Android.mk

Puede compilar libgstreamer_android.so con el siguiente comando en Ubuntu 18.04 o 20.04. Las siguientes líneas de comandos solo se han probado para la versión GStreamer de Android 1.14.4 con Android NDK b16b.

# Assuming wget and unzip already installed on the system
mkdir buildLibGstreamer
cd buildLibGstreamer
wget https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip
unzip -q -o android-ndk-r16b-linux-x86_64.zip
export PATH=$PATH:$(pwd)/android-ndk-r16b
export NDK_PROJECT_PATH=$(pwd)/android-ndk-r16b
wget https://gstreamer.freedesktop.org/data/pkg/android/1.14.4/gstreamer-1.0-android-universal-1.14.4.tar.bz2
mkdir gstreamer_android
tar -xjf gstreamer-1.0-android-universal-1.14.4.tar.bz2 -C $(pwd)/gstreamer_android/
export GSTREAMER_ROOT_ANDROID=$(pwd)/gstreamer_android

mkdir gstreamer
# Copy the Application.mk and Android.mk from the documentation above and put it inside $(pwd)/gstreamer

# Enable only one of the following at one time to create the shared object for the targeted ABI
echo "building for armeabi-v7a. libgstreamer_android.so will be placed in $(pwd)/armeabi-v7a"
ndk-build -C $(pwd)/gstreamer "NDK_APPLICATION_MK=Application.mk" APP_ABI=armeabi-v7a NDK_LIBS_OUT=$(pwd)

#echo "building for arm64-v8a. libgstreamer_android.so will be placed in $(pwd)/arm64-v8a"
#ndk-build -C $(pwd)/gstreamer "NDK_APPLICATION_MK=Application.mk" APP_ABI=arm64-v8a NDK_LIBS_OUT=$(pwd)

#echo "building for x86_64. libgstreamer_android.so will be placed in $(pwd)/x86_64"
#ndk-build -C $(pwd)/gstreamer "NDK_APPLICATION_MK=Application.mk" APP_ABI=x86_64 NDK_LIBS_OUT=$(pwd)

#echo "building for x86. libgstreamer_android.so will be placed in $(pwd)/x86"
#ndk-build -C $(pwd)/gstreamer "NDK_APPLICATION_MK=Application.mk" APP_ABI=x86 NDK_LIBS_OUT=$(pwd)

Una vez que el objeto compartido (libgstreamer_android.so) está compilado, el desarrollador de aplicaciones debe colocarlo en la aplicación de Android para que el SDK de voz pueda cargarlo.

El control del audio comprimido se implementa mediante GStreamer. Por motivos de licencia, los binarios de GStreamer no se compilan ni se vinculan con el SDK de Voz. Los desarrolladores deben instalar varias dependencias y complementos; consulte Instalación en Windows o Instalación en Linux. Los archivos binarios de GStreamer deben estar en la ruta de acceso del sistema, con el fin de que el SDK de Voz pueda cargarlos en tiempo de ejecución. Por ejemplo, en Windows, si el SDK de Voz es capaz de encontrar libgstreamer-1.0-0.dll en tiempo de ejecución, significa que los archivos binarios de GStreamer se encuentran en la ruta de acceso del sistema.

El SDK de Voz puede usar GStreamer para controlar el audio comprimido. No obstante, por motivos de licencia, los binarios de GStreamer no se compilan ni se vinculan con el SDK de Voz. Los desarrolladores deben instalar varias dependencias y complementos; consulte Instalación en Linux. El lenguaje Go solo se admite en el SDK de Voz en la plataforma Linux. Consulte SDK de Voz para Go para empezar a trabajar con el SDK de Voz de Microsoft en Go.

Ejemplo de código que usa una entrada de audio comprimido con códec

Para configurar el SDK de Voz para que acepte entradas de audio comprimidas, cree PullAudioInputStream o PushAudioInputStream. A continuación, cree un objeto AudioConfig a partir de una instancia de la clase de secuencia, especificando el formato de compresión de la secuencia. Busque fragmentos de código de ejemplo relacionados en Acerca de Audio Input Stream API del SDK de Voz.

Supongamos que tiene una clase de flujo de entrada llamada pullStream y que usa OPUS/OGG. El aspecto del código sería el siguiente:

using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;

// ... omitted for brevity

var speechConfig =
    SpeechConfig.FromSubscription(
        "YourSubscriptionKey",
        "YourServiceRegion");

// Create an audio config specifying the compressed
// audio format and the instance of your input stream class.
var audioFormat =
    AudioStreamFormat.GetCompressedFormat(
        AudioStreamContainerFormat.OGG_OPUS);
var audioConfig =
    AudioConfig.FromStreamInput(
        pullStream,
        audioFormat);

using var recognizer = new SpeechRecognizer(speechConfig, audioConfig);
var result = await recognizer.RecognizeOnceAsync();

var text = result.Text;

Para configurar el SDK de Voz para que acepte entradas de audio comprimidas, cree PullAudioInputStream o PushAudioInputStream. A continuación, cree un objeto AudioConfig a partir de una instancia de la clase de secuencia, especificando el formato de compresión de la secuencia. Busque código de ejemplo relacionado en Ejemplos del SDK de Voz.

Supongamos que tiene una clase de flujo de entrada llamada pushStream y que usa OPUS/OGG. El aspecto del código sería el siguiente:

using namespace Microsoft::CognitiveServices::Speech;
using namespace Microsoft::CognitiveServices::Speech::Audio;

// ... omitted for brevity

 auto config =
    SpeechConfig::FromSubscription(
        "YourSubscriptionKey",
        "YourServiceRegion"
    );

auto audioFormat =
    AudioStreamFormat::GetCompressedFormat(
        AudioStreamContainerFormat::OGG_OPUS
    );
auto audioConfig =
    AudioConfig::FromStreamInput(
        pushStream,
        audioFormat
    );

auto recognizer = SpeechRecognizer::FromConfig(config, audioConfig);
auto result = recognizer->RecognizeOnceAsync().get();

auto text = result->Text;

Para configurar el SDK de Voz para que acepte entradas de audio comprimidas, cree PullAudioInputStream o PushAudioInputStream. A continuación, cree un objeto AudioConfig a partir de una instancia de la clase de secuencia, especificando el formato de compresión de la secuencia. Busque código de ejemplo relacionado en Ejemplos del SDK de Voz.

Supongamos que tiene una clase de flujo de entrada llamada pullStream y que usa OPUS/OGG. El aspecto del código sería el siguiente:

import com.microsoft.cognitiveservices.speech.audio.AudioConfig;
import com.microsoft.cognitiveservices.speech.audio.AudioInputStream;
import com.microsoft.cognitiveservices.speech.audio.AudioStreamFormat;
import com.microsoft.cognitiveservices.speech.audio.PullAudioInputStream;
import com.microsoft.cognitiveservices.speech.internal.AudioStreamContainerFormat;

// ... omitted for brevity

SpeechConfig speechConfig =
    SpeechConfig.fromSubscription(
        "YourSubscriptionKey",
        "YourServiceRegion");

// Create an audio config specifying the compressed
// audio format and the instance of your input stream class.
AudioStreamFormat audioFormat = 
    AudioStreamFormat.getCompressedFormat(
        AudioStreamContainerFormat.OGG_OPUS);
AudioConfig audioConfig =
    AudioConfig.fromStreamInput(
        pullStream,
        audioFormat);

SpeechRecognizer recognizer = new SpeechRecognizer(speechConfig, audioConfig);
SpeechRecognitionResult result = recognizer.recognizeOnceAsync().get();

String text = result.getText();

Para configurar el SDK de Voz para que acepte entradas de audio comprimidas, cree PullAudioInputStream o PushAudioInputStream. A continuación, cree un objeto AudioConfig a partir de una instancia de la clase de secuencia, especificando el formato de compresión de la secuencia.

Supongamos que el caso de uso es usar PullStream para un archivo MP3. El aspecto del código sería el siguiente:


import azure.cognitiveservices.speech as speechsdk

class BinaryFileReaderCallback(speechsdk.audio.PullAudioInputStreamCallback):
    def __init__(self, filename: str):
        super().__init__()
        self._file_h = open(filename, "rb")

    def read(self, buffer: memoryview) -> int:
        print('trying to read {} frames'.format(buffer.nbytes))
        try:
            size = buffer.nbytes
            frames = self._file_h.read(size)

            buffer[:len(frames)] = frames
            print('read {} frames'.format(len(frames)))

            return len(frames)
        except Exception as ex:
            print('Exception in `read`: {}'.format(ex))
            raise

    def close(self) -> None:
        print('closing file')
        try:
            self._file_h.close()
        except Exception as ex:
            print('Exception in `close`: {}'.format(ex))
            raise

def compressed_stream_helper(compressed_format,
        mp3_file_path,
        default_speech_auth):
    callback = BinaryFileReaderCallback(mp3_file_path)
    stream = speechsdk.audio.PullAudioInputStream(stream_format=compressed_format, pull_stream_callback=callback)

    speech_config = speechsdk.SpeechConfig(**default_speech_auth)
    audio_config = speechsdk.audio.AudioConfig(stream=stream)

    speech_recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config, audio_config=audio_config)

    done = False

    def stop_cb(evt):
        """callback that signals to stop continuous recognition upon receiving an event `evt`"""
        print('CLOSING on {}'.format(evt))
        nonlocal done
        done = True

    # Connect callbacks to the events fired by the speech recognizer
    speech_recognizer.recognizing.connect(lambda evt: print('RECOGNIZING: {}'.format(evt)))
    speech_recognizer.recognized.connect(lambda evt: print('RECOGNIZED: {}'.format(evt)))
    speech_recognizer.session_started.connect(lambda evt: print('SESSION STARTED: {}'.format(evt)))
    speech_recognizer.session_stopped.connect(lambda evt: print('SESSION STOPPED {}'.format(evt)))
    speech_recognizer.canceled.connect(lambda evt: print('CANCELED {}'.format(evt)))
    # stop continuous recognition on either session stopped or canceled events
    speech_recognizer.session_stopped.connect(stop_cb)
    speech_recognizer.canceled.connect(stop_cb)

    # Start continuous speech recognition
    speech_recognizer.start_continuous_recognition()
    while not done:
        time.sleep(.5)

    speech_recognizer.stop_continuous_recognition()
    # </SpeechContinuousRecognitionWithFile>

def pull_audio_input_stream_compressed_mp3(mp3_file_path: str,
        default_speech_auth):
    # Create a compressed format
    compressed_format = speechsdk.audio.AudioStreamFormat(compressed_stream_format=speechsdk.AudioStreamContainerFormat.MP3)
    compressed_stream_helper(compressed_format, mp3_file_path, default_speech_auth)

Para configurar el SDK de Voz para que acepte entradas de audio comprimidas, cree PullAudioInputStream o PushAudioInputStream. A continuación, cree un objeto AudioConfig a partir de una instancia de la clase de secuencia, especificando el formato de compresión de la secuencia.

En el ejemplo siguiente supongamos que su caso de uso es la utilización de PushStream para un archivo comprimido.


package recognizer

import (
  "fmt"
  "time"
    "strings"

  "github.com/Microsoft/cognitive-services-speech-sdk-go/audio"
  "github.com/Microsoft/cognitive-services-speech-sdk-go/speech"
  "github.com/Microsoft/cognitive-services-speech-sdk-go/samples/helpers"
)

func RecognizeOnceFromCompressedFile(subscription string, region string, file string) {
  var containerFormat audio.AudioStreamContainerFormat
  if strings.Contains(file, ".mulaw") {
    containerFormat = audio.MULAW
  } else if strings.Contains(file, ".alaw") {
    containerFormat = audio.ALAW
  } else if strings.Contains(file, ".mp3") {
    containerFormat = audio.MP3
  } else if strings.Contains(file, ".flac") {
    containerFormat = audio.FLAC
  } else if strings.Contains(file, ".opus") {
    containerFormat = audio.OGGOPUS
  } else {
    containerFormat = audio.ANY
  }
  format, err := audio.GetCompressedFormat(containerFormat)
  if err != nil {
    fmt.Println("Got an error: ", err)
    return
  }
  defer format.Close()
  stream, err := audio.CreatePushAudioInputStreamFromFormat(format)
  if err != nil {
    fmt.Println("Got an error: ", err)
    return
  }
  defer stream.Close()
  audioConfig, err := audio.NewAudioConfigFromStreamInput(stream)
  if err != nil {
    fmt.Println("Got an error: ", err)
    return
  }
  defer audioConfig.Close()
  config, err := speech.NewSpeechConfigFromSubscription(subscription, region)
  if err != nil {
    fmt.Println("Got an error: ", err)
    return
  }
  defer config.Close()
  speechRecognizer, err := speech.NewSpeechRecognizerFromConfig(config, audioConfig)
  if err != nil {
    fmt.Println("Got an error: ", err)
    return
  }
  defer speechRecognizer.Close()
  speechRecognizer.SessionStarted(func(event speech.SessionEventArgs) {
    defer event.Close()
    fmt.Println("Session Started (ID=", event.SessionID, ")")
  })
  speechRecognizer.SessionStopped(func(event speech.SessionEventArgs) {
    defer event.Close()
    fmt.Println("Session Stopped (ID=", event.SessionID, ")")
  })
  helpers.PumpFileIntoStream(file, stream)
  task := speechRecognizer.RecognizeOnceAsync()
  var outcome speech.SpeechRecognitionOutcome
  select {
  case outcome = <-task:
  case <-time.After(40 * time.Second):
    fmt.Println("Timed out")
    return
  }
  defer outcome.Close()
  if outcome.Error != nil {
    fmt.Println("Got an error: ", outcome.Error)
  }
  fmt.Println("Got a recognition!")
  fmt.Println(outcome.Result.Text)
}

Pasos siguientes