Reproducir música (mp3, ogg, wav) en Java

Una de las formas más sencillas de reproducir música (wav, mp3, ogg) en Java, es haciendo uso de «Java Sound» y alguna librería de extensión.

En este caso usaremos la implementación Java Sound, «Tritonus» y la librería de reproducción de mp3 MP3SPI (en caso de querer reproducción OGG deberíamos incluir también VorbisSPI). Para simplificar el proceso, usaremos una librería que proporciona una API de alto nivel para no tener que programar las funciones básicas, BasicPlayer, que usa para ello JLayer.

Resumiendo, descargate jlGui y en el directorio lib tendrás todos los jar que necesitas ;)

Hagamos un ejemplo simple, una clase llamada «Reproductor» controlará la librería y la clase «Test» ordenará cosas a «Reproductor». En este supuesto solamente se podría escuchar una canción al mismo tiempo y no nos preocuparemos de fallos no relacionados directamente con el ejemplo.

En la clase Reproductor, deberíamos tener una variable de Clase de tipo «BasicPlayer» que instanciaremos en el constructor para trabajar con la API BasicPlayer:

private BasicPlayer basicPlayer;
public Reproductor() {
 basicPlayer = new BasicPlayer();
}

Deberíamos crear también métodos públicos para «Play», «Stop», «Pause» y «Resume» que seguirían todos la misma estructura:

 public void play() {
 try {
  basicPlayer.play();
 } catch (BasicPlayerException e) {
  // TODO Auto-generated catch block  e.printStackTrace();
 }
}

Además de lo anterior, deberemos crear un método para «abrir» el fichero:

public void loadFile(String ruta) throws BasicPlayerException {
 basicPlayer.open(new File(ruta));
}

Con esto, nuestra clase «Test» simplemente tendría que instanciar «Reproductor», llamar a «loadFile» pasándole la ruta a un fichero mp3, ogg o wav y a continuación hacer uso de «Play».

Ahora bien, es muy posible que queramos hacer una interfaz gráfica y añadir una barra de desplacamiento, es decir, saber en punto de la reproducción se encuentra el fichero.

Para ello deberemos implementar la interfaz «BasicPlayerListener» en la clase que elijamos. En el ejemplo la implementaremos en «Reproductor». Por tanto sería:

public class Player implements BasicPlayerListener {

Lo que nos obliga a implementar una serie de métodos, pero antes de implementarnos, en el contructor suscribiremos a la clase al reproductor BasicPlayer (recordad que en nuestro diseño solo hay un BasicPlayer al mismo tiempo, pero podría haber varios):

public Reproductor() {
 basicPlayer = new BasicPlayer();
 // Me suscribo al reproductor para obtener sus eventos.
 basicPlayer.addBasicPlayerListener(this);
}

Además, crearemos la variable de clase bytesLength de tipo double para almacenar el tamaño del fichero. Lo haremos porque BasicPlayer nos dice cuantos bytes ha reproducido hasta el momento.

Uno de los métodos que nos obliga a implementar la interfaz es «opened», que se ejecuta cuando BasicPlayer abre un fichero. Lo usaremos para leer en ese momento los bytes del fichero:

 /** * Necesario por implementar BasicPlayerListener. Es ejecutado una vez se
 * carga un fichero. En este caso, obtiene el tamaño en bytes del fichero. */
public void opened(Object arg0, Map arg1) {
 if (arg1.containsKey("audio.length.bytes")) {
  bytesLength = Double.parseDouble(arg1.get("audio.length.bytes").toString());
 }
}

El último método que nos interesa, es «progress», al cual BasicPlayer llama de forma automática varias veces por segundo durante la reproducción. Lo usaremos para obtener el progreso de la canción:

 /** * Necesario por implementar BasicPlayerListener. Según la documentación,
 * este método es llamado varias veces por segundo para informar del
 * progreso en la reproducción. */
public void progress(int bytesread, long microseconds, byte[] pcmdata,  Map properties) {
 float progressUpdate = (float) (bytesread * 1.0f / bytesLength * 1.0f);
 int progressNow = (int) (bytesLength * progressUpdate);
 // Descomentando la siguiente línea se mosrtaría el progreso
 // System.out.println(" -> " + progressNow);
}

Imaginad que queréis usarlo en un jSlider, solamente habría que fijar el máximo del slider en bytesLength y el valor actual en lo que diga progressNow ;)

En fin, espero que os haya sido útil. Si tenéis cualquier duda, ya sabéis que podéis dejar comentarios.

Por Carballude

Me llamo Pablo Carballude González, soy graduado en computación con master en HCI y Seguridad Informática. Actualmente trabajo para Amazon en Seattle como Software Developer Engineer. Soy de esas personas que no saben si los textos autobiográficos deben ser en primera o tercera persona. Lo intenté en segunda, pero no le entendí nada :P

74 comentarios

  1. ole men gracias por la ayuda intentare y te adare las congratu.. cuando lo lopgre hacer … tahito.. ingeniero en sistemas …. o esa es la idea

  2. Hola;
    Bueno decirte que tu entrada está muy bien y creo que me puede servir de mucho para un proyectillo de la uni. Pero tengo un problema; me descargo la libreria, la importo desde el sistema de archivos en el jBuilder 2007 turbo y cuando creo la variable de tipo BasicPlayer no me la reconoce….vamos que no debe importar bien…
    Tengo que escribir algún import de java??

    Muchas gracias.

  3. Hola Dundalk4ever,
    Hay otra persona que me ha reportado el mismo problema usando jBuilder 2007 turbo. La verdad es que no sé a qué puede deberse que no te lo reconozca.

    Por si sirve de algo, estos son los imports:
    import javazoom.jlgui.basicplayer.BasicPlayer;
    import javazoom.jlgui.basicplayer.BasicPlayerException;

    Y estos los jars necesarios:
    commons-logging-api
    basicplayer3.0
    jl1.0
    mp3spi1.9.4
    tritonus_share

    Todos ellos se encuentran dentro del directorio lib de jlGui.

    ¡Suerte!

  4. Hola! muy buen articulo!
    Yo uso el Eclipse en Ubuntu y queria saber exactamente el path donde descomprimir esos jars
    los quiero importar pero no los encuentra..
    Te agradezco mucho tu ayuda
    Saludos

  5. Gracias Carballude!! lo hice como explicaste y se cargaron todos los jars externos que necesito XD
    Me surgio un problema en tiempo de ejecucion justo en el momento en que se crea el BasicPlayer:
    basicPlayer = new BasicPlayer();

    es un ExceptionInInitializerError y estoy viendo a que se debe…

  6. Tocayo…. chapo!

    estoy haciendo un proyecto muy parecido al tuyo, en java tmb (bueno, d echo lo estoy empezando…. :P) y me esta sirviendo de mucho tus explicaciones xDDD si vas haciendo mas cosillas me gustaria que pudieras ir publicando como vas haciendo y tal. Cuando tenga más hecho y implemente alguna casa q no tuviera el tuyo ya te comentaria :)

    muchas gracias x todo ;)

  7. oye me puedes pasar el programa q llame un archivo de audio y lo reprodusca x fa lo nececito con urgencia grax

  8. hola.. hice lo q dijist y todo me sale bien, pero mi proyecto consiste en hacer un reproductor en netbeans y necesito colocar las rutas (url) en una jtable para poder tener una lista d reproduccion, quisiera saber cmo hago para cerrar el fichero, xq una vez abierto suena perfecto pero no me deja pasar a la siguient cancion xq obviamnt todavia sigue abierto el fichero anterior y quisiera saber cmo cerrarlo y abrir el siguiente ya q creo q ahi radica mi error. muchas gracias y espero q me puedas ayudar cn esto..

  9. Hola, que tal
    yo quiero hacer un programita para que solo me ejecute un archivo .mp3, sin interfaz ni nada, hice un codigo de prueba con las funciones que mensionas, y no me marca errores, pero no me ejecuta nada jeje, en consola me muestra lo siguiente:

    2/05/2009 06:13:53 PM javazoom.jlgui.basicplayer.BasicPlayer open
    INFO: open(C:\Documents and Settings\Garibay\Mis documentos\Mi m·sica\Musica\- c
    hiquitita.mp3)
    2/05/2009 06:13:53 PM javazoom.jlgui.basicplayer.BasicPlayer createLine
    INFO: Create Line
    2/05/2009 06:13:53 PM javazoom.jlgui.basicplayer.BasicPlayer createLine
    INFO: Create Line : Source format : MPEG1L3 44100.0 Hz, unknown bits per sample,
    stereo, unknown frame size, 38.28125 frames/second,
    2/05/2009 06:13:53 PM javazoom.jlgui.basicplayer.BasicPlayer createLine
    INFO: Create Line : Target format: PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 byte
    s/frame, little-endian
    2/05/2009 06:13:54 PM javazoom.jlgui.basicplayer.BasicPlayer createLine
    INFO: Line : com.sun.media.sound.DirectAudioDevice$DirectSDL@12498b5
    Press any key to continue…

    No se a que se deba =( si es micódigo o necesito alguna libreria más, o q jeje, te agradecería que me contestaras o alguien de ustedes x ahi jeje grax-

  10. hola necesito que m ayudés a hacer una cola y lista de reproducción, sq tengo q hacer un reproductor de música y video. por favor gracias!!!

  11. con esto solo reproduce mp3, wav y ogg verdad?
    sabes qué librerías tengo que añadir para reproducir otros formatos como midi, wma, etc…?

    Gracias jefe!

  12. @pere: Efectivamente, de la forma descrita en este artículo, únicamente puedes reproducir MP3, WAV y OGG. Para reproducir MIDI sólo tienes que importar el paquete «javax.sound.midi». Tienes un ejemplo en: http://tinyurl.com/pkv6mx

    Para reproducir WMA u otros formatos… me temo que Java no puede. Vas a tener que llamar a otro programa (no Java) para que lo reproduzca por ti. Hace algún tiempo hice eso mismo para C#, está en: http://www.carballude.es/Blog/?p=179

    @adriana: Seguramente puedas usar una LinkedList para eso. Intentaré hacer un artículo describiendo su uso esta semana.

  13. hola, ps amigos yo no soy siquiera novato en esto de java, pero tengo una idea y no se si ustedes puedan materializa, ps la idea es un reproductor mp3 que se enlace a mi cuenta de gmail y reproduzca en una lista de reproduccion los adjuntos.

    para que tengan una idea de como hacer para entrar a la cuenta gmail y enlazar los adjuntos vean un programa que se llama mailresender, con ese programa subo y bajo archivos a mi cuenta gmail y ps ya que gmail no tiene la opcion de reproducir los adjuntos uno detras de otro me surgio esa idea pero como no se nada de programación quisiera saber si alguno de ustedes podria desarrollar algo para esto.

    si algo escribanme a stoyjec@gmail.com.

    Gracias de antemano.

  14. hola, quisiera un reproductor en interfaz grafica, usando una lista que me almacene las canciones que voy agregando y las reproduzca..

  15. ola man disculpa estoi haciendo un proyecto de crear un reproductor de musica en java espero q me ayudes x fa ps!!
    mil gracias de antemano!

  16. Hola man, muchisimas gracias, logre que me lo reprodusca perfectamente, mi problema es el siguiente, me corre cualquier mp3 si le paso la direccion pero no puedo hacerlo correr con un mp3 interno al .jar, es q estas clases externas no lo permiten?, bueno solo eso , muchas gracias!

  17. Hola ya lo pude solucionar, otra pregunta, como puedo hacer para q lo reprodusca aleatoriamente?, te agradesco la respuesta, muchas gracias

  18. Hola yo estoy trabajando con el codigo que publicastes, que es bastante sencillo y facil de entender, sin embargo al hacer el reproductor con el jslider tambien deseo presentar el tiempo q transcurre de la cancion pero cuando adelanto o atrazo el tiempo(jslider) los microsegundos del metodo progress se borran y no puedo presentarlos y no puedo utilizar los bytes xq cada musica pesa distinto sin importar el tiempo que realmente tiene.
    si puedes ayudarme te lo agradeceria mucho.

  19. Hola Carballude, me estoy iniciando en java… y estoy haciendo un programa para un sorteo, asi tipo bingo, y quiero ponerle musica a mi programa, vi tu explicacion que me parece que esta muy bien, y la quise implementar. Hice la clase Reproductor tal cual como describes, e hice la clase Test de la siguiente forma

    1 public class Test {
    2
    3 Reproductor c = new Reproductor();
    4 c.loadFile(«/Tank.mp3»);
    5 }

    y me da un error en la 4ta linea… me dice que «package c doesn’t exist» y no se porque es ese error, mi mas bien estoy implementando el objeto Reproductor no?? no se si la ruta esta mala… el archivo mp3 lo tengo en la carpeta donde esta el codigo. No se como es el formato para colocar la ruta si es eso lo que esta malo.

    Estoy haciendo unas JFrame y cuando le pongo la ruta de las imagnes que tambien las tengo en la misma carpeta del proyeco le coloco «/imagen.JPG» y funciona.

    Saludos

  20. Metalupurazz, estás poniendo instrucciones en una clase, cuando Java únicamente permite instrucciones en métodos.

    Prueba con:
    public class Test{
    public Test(){
    Reproductor c = new Reproductor();
    c.loadFile(«Tank.mp3»);
    }

    public static void Main(String args[]){
    new Test();
    }
    }

    Eso debería funcionar, suerte ;)

  21. Coye es verdad… bueno mira lo que puse porque tu ayuda me dio un warning respecto a la exception que hay

    import javazoom.jlgui.basicplayer.BasicPlayerException;

    public class Test{
    public Test() throws BasicPlayerException{
    Reproductor c = new Reproductor();
    c.loadFile(«C:/Documents and Settings/hmiranda/Mis documentos/NetBeansProjects/musica/src/Tank.mp3»);
    }

    public static void main(String args[]) throws BasicPlayerException{
    new Test();
    }
    }

    El problema es que no suena nada y el mensaje que da al correr el programa es el siguiente:

    20/08/2009 04:58:12 PM javazoom.jlgui.basicplayer.BasicPlayer open
    INFO: open(C:\Documents and Settings\hmiranda\Mis documentos\NetBeansProjects\musica\src\Tank.mp3)
    20/08/2009 04:58:12 PM javazoom.jlgui.basicplayer.BasicPlayer createLine
    INFO: Create Line
    20/08/2009 04:58:12 PM javazoom.jlgui.basicplayer.BasicPlayer createLine
    INFO: Create Line : Source format : MPEG1L3 44100.0 Hz, unknown bits per sample, stereo, unknown frame size, 38.28125 frames/second,
    20/08/2009 04:58:12 PM javazoom.jlgui.basicplayer.BasicPlayer createLine
    INFO: Create Line : Target format: PCM_SIGNED 44100.0 Hz, 16 bit, stereo, 4 bytes/frame, little-endian
    20/08/2009 04:58:12 PM javazoom.jlgui.basicplayer.BasicPlayer createLine
    INFO: Line : com.sun.media.sound.DirectAudioDevice$DirectSDL@253498
    BUILD SUCCESSFUL (total time: 0 seconds)

  22. De todas formas la clase reproductor la hice asi… no se si esta bien

    import java.io.File;
    import javazoom.jlgui.basicplayer.BasicPlayer;
    import javazoom.jlgui.basicplayer.BasicPlayerException;

    public class Reproductor {
    public BasicPlayer basicPlayer;

    public Reproductor() {
    basicPlayer = new BasicPlayer();

    }

    public void play() {
    try {
    basicPlayer.play();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block e.printStackTrace();
    }
    }

    public void stop() {
    try {
    basicPlayer.stop();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block e.printStackTrace();
    }
    }

    public void pause() {
    try {
    basicPlayer.pause();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block e.printStackTrace();
    }
    }

    public void resume() {
    try {
    basicPlayer.resume();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block e.printStackTrace();
    }
    }

    public void loadFile(String ruta) throws BasicPlayerException {
    basicPlayer.open(new File(ruta));
    }
    }

  23. Hey Carballude, ya puedo reproducir musica. Intente otro constructor que publicaste en otra pagina http://pablocarballude.blogspot.com/2007/11/reproducir-msica-mp3-ogg-wav-en-java.html

    public Test() {
    Reproductor rep = new Reproductor();
    try {
    rep.loadFile(«Tank.mp3»);
    rep.play();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }

    Gracias! Ahora quiero implementar la interfaz y tengo problemas tambien. Sabes que tengo las 2 clases, Test y Reproductor. Lo que entendi de la explicacion, es que en el constructor de Reproductor agrego:

    basicPlayer.addBasicPlayerListener(this);

    esa linea me genera un warning para hacer un casteo, y me la coloca asi

    basicPlayer.addBasicPlayerListener((BasicPlayerListener) this);

    Luego en la misma clase Reproductor implemento los procedimientos opened, progress, setController y stateUpdate. Pero no me sale la interfaz ni se escucha audio. El mensaje de salida es el siguiente

    Exception in thread «main» java.lang.ClassCastException: Reproductor cannot be cast to javazoom.jlgui.basicplayer.BasicPlayerListener
    at Reproductor.(Reproductor.java:27)
    at Test.(Test.java:17)
    at Test.main(Test.java:31)
    Java Result: 1
    BUILD SUCCESSFUL (total time: 2 seconds)

    Gracias por tu atencion y ayuda.

  24. Coye me vas a decir que molesto demasiado Carballude, pero ya logre que sonara, pero no me sale la interfaz.

    Veo que el error de antes (que no reproducia nada), era porque falta llamar al procedimiento play(), capaz me falta llamar al procedimiento opened(Object arg0, Map arg1), pero que valores les paso? y tambien hay que llamar a progress??

    Espero tu respuesta

  25. El problema es que no has hecho que Reproductor implemente BasicPlayerListener.

    Tienes que cambiar:
    public class Reproductor {

    Por:
    public class Reproductor implements BasicPlayerListener {

    Los métodos Opened y Progress no se llaman, la librería los lanza automáticamente. Por ejemplo, cuando tú le hagas un «loadFile» automáticamente se ejecutará el método «opened». Cuando se esté reproduciendo un archivo, el método «progress» se ejecutará cada poco (varias veces por segundo) para informar del progreso.

    Suerte ;)

  26. Hey Carballude, si se que me falto el implementrs BasicPlayerListener, pero luego se lo puse, y por eso sono, pero no salio la interfaz. POr eso mi pregunta de si habia que llamar al metodo opened, cosa que me parecia extraño porque deberia de ser automatico, pero no salio la GUI =( no se que pudo haber pasado…

  27. Hey Carballude, si se que me falto el implementrs BasicPlayerListener….

    Pero luego se lo puse, y por eso sono, pero no salio la interfaz. Por eso mi pregunta de si habia que llamar al metodo opened, cosa que me parecia extraño porque deberia de ser automatico, pero no salio la GUI =( no se que pudo haber pasado…

  28. Hey Carballude, aqui estoy devuelta para colocar el codigo, aun no me sale la interfaz. Gracias por tu ayuda

    import java.io.File;
    import java.util.Map;
    import javazoom.jlgui.basicplayer.BasicController;
    import javazoom.jlgui.basicplayer.BasicPlayer;
    import javazoom.jlgui.basicplayer.BasicPlayerEvent;
    import javazoom.jlgui.basicplayer.BasicPlayerException;
    import javazoom.jlgui.basicplayer.BasicPlayerListener;

    public class Reproductor implements BasicPlayerListener {
    private BasicPlayer basicPlayer;
    private double bytesLength;

    public Reproductor() {
    basicPlayer = new BasicPlayer();
    basicPlayer.addBasicPlayerListener(this);
    }

    public void play() {
    try {
    basicPlayer.play();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block e.printStackTrace();
    }
    }

    public void stop() {
    try {
    basicPlayer.stop();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block e.printStackTrace();
    }
    }

    public void pause() {
    try {
    basicPlayer.pause();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block e.printStackTrace();
    }
    }

    public void resume() {
    try {
    basicPlayer.resume();
    } catch (BasicPlayerException e) {
    // TODO Auto-generated catch block e.printStackTrace();
    }
    }

    public void loadFile(String ruta) throws BasicPlayerException {
    basicPlayer.open(new File(ruta));
    }

    public void opened(Object arg0, Map arg1) {
    if (arg1.containsKey(«audio.length.bytes»)) {
    bytesLength = Double.parseDouble(arg1.get(«audio.length.bytes»).toString());
    }
    }

    public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties) {
    float progressUpdate = (float) (bytesread * 1.0f / bytesLength * 1.0f);
    int progressNow = (int) (bytesLength * progressUpdate);
    // Descomentando la siguiente línea se mosrtaría el progreso
    //System.out.println(» -> » + progressNow);
    }

    public void stateUpdated(BasicPlayerEvent arg0) {
    // TODO Auto-generated method stub
    }

    public void setController(BasicController arg0) {
    // TODO Auto-generated method stub
    }
    }

  29. Hola la lectura de las etiquetas id3 de los archivos mp3 en java me han servido mucho, pero quisiera saber como puedo obtener tambien el numero de la pista y el año y ademas que otros datos de las canciones se pueden obtener gracias….

  30. Hola, realmente me han servido tus tutoriales de jlgui, ahora,
    ¿sería posible que tengas algun ejemplo de playlist usando las primitivas de jlgui BasePlaylist y PlaylistItem?
    Hasta el momento he logrado que carguen un archivo m3u y recuperar los tags que allí se encuetran, pero no he logrado reproducir la playlist.

    Muchas gracias

  31. hola, pues todo esta muy bien es solo que en el metodo opened no se como debo crear el mapa que recibe como parametro. porfa si me puedes ayudar te lo agradeceria de todo corazon

  32. bueno ya supe como hacer funcionar ese metodo pero como convierto lo que me retorna en un formato de minutos o segundo grax

  33. Estube leyendo tu respuesta en el comentario que me dejaste y tienes toda la razon ya que no me especifique,por que yo no estoy aconstumbrado a que me hagan las cosas.
    Lo que queria saber era con cual control del BasicPlayer es el que se utiliza, ya hice que me tire el titulo de la cancion, el artista y el album,

  34. karencita :

    hola, pues todo esta muy bien es solo que en el metodo opened no se como debo crear el mapa que recibe como parametro. porfa si me puedes ayudar te lo agradeceria de todo corazon

    Sólo por aclarar, a ese método no tienes que llamarlo en ningún momento. El método será llamado automáticamente por la librería de reproducción.

    karencita :

    bueno ya supe como hacer funcionar ese metodo pero como convierto lo que me retorna en un formato de minutos o segundo grax

    El método opened no retorna nada, es void. Si lo que quieres es obtener la duración del mp3 ANTES de empezar a reproducirlo, deberías usar alguna librería de ID3. Hay un ejemplo en http://www.carballude.es/Blog/?p=156 no muestra como obtener la duración, pero se puede de esa forma ;)

  35. Hola carballude mira soy nuevo en la POO pero lo que solo queria preguntarte es como implemeto el metodo progress en el jslider esque en la interfaz tengo el Jslider y desde la clase formulario llamo el metodo pero los valores con que van no se como inicializarloas a a quien colocarselos agradezco mucho tu ayuda de verdad es que es un tyrabajo que entregar graccias :p…….

  36. Pues… no sé que más decirte la verdad… el método es tal cual está en el post. Simplemente ponerle nombreDelSlider.setValue(progressNow) para que actualizase la posición del slider.

  37. Hola amigo gracias por la respuesta pero mira que lo ago tal y como esta en el post y no me sirve el Slider te voy a explicar como lo tengo yo

    Lo estoy elaborando en netbeans tengo un clase reproductor en la que tengo todo los metodos y la clase player como me indicstaes en el post aparte pero en el mismo paquete tengo un JForm instancio la clase resproductor y los objetos play,pause,stop y resume funcionan correctamente pero instancia la clase playe que esta hay dentro de la clase reproducto y voy a utilizar solo el metodo progress me lo instancia pero lo que pasa es que va con estos valores
    progress( bytesread, microseconds, byte[] pcmdata, Map properties)
    me aparece porsupuesto el error de que estas variables no estan inicializadas o no estan declaradas hay es donde me quedo yo porque quiero utilizar este metodo en el Jslider pero la verdad no se como explicame porfa te lo agradecere toda la vida este favor gracias

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *