Reproducir el audio

Tenemos que hacer clic en la tarjeta para reproducir el audio.

Primero coloca los archivos de audio mp3 dentro del directorio www/audio

Como este es un proyecto de demostración, basta con colocar el archivo b.mp3 en esa carpeta.

Método 1‑Reproducción con HTML5

Reproduce el audio mediante HTML5 Audio compatible con WebView, no requiere plugins

Modifica el contenido de main.js de la siguiente forma

// Datos de consonantes del vietnamita
const consonants = [
    {char: "b", pronounce: "/ɓ/", desc: "Consonante oclusiva bilabial implosiva"},
    {char: "c", pronounce: "/k/", desc: "Consonante oclusiva velar"},
    {char: "ch", pronounce: "/tɕ/", desc: "Consonante africada palatal"},
    {char: "d", pronounce: "/ɗ/", desc: "Consonante oclusiva alveolar implosiva"},
    {char: "đ", pronounce: "/ɗ/", desc: "Consonante implosiva alveolar"},
    {char: "g", pronounce: "/ɣ/", desc: "Consonante fricativa velar"},
    {char: "gh", pronounce: "/ɣ/", desc: "Se usa antes de e, i"},
    {char: "h", pronounce: "/h/", desc: "Consonante fricativa glotal"},
    {char: "k", pronounce: "/k/", desc: "Consonante oclusiva velar sorda"},
    {char: "kh", pronounce: "/x/", desc: "Consonante fricativa velar sorda"},
    {char: "l", pronounce: "/l/", desc: "Consonante lateral alveolar"},
    {char: "m", pronounce: "/m/", desc: "Consonante nasal bilabial"},
    {char: "n", pronounce: "/n/", desc: "Consonante nasal alveolar"},
    {char: "ng", pronounce: "/ŋ/", desc: "Consonante nasal velar"},
    {char: "ngh", pronounce: "/ŋ/", desc: "Se usa antes de e,i"},
    {char: "nh", pronounce: "/ɲ/", desc: "Consonante nasal palatal"},
    {char: "p", pronounce: "/p/", desc: "Consonante oclusiva bilabial no aspirada"},
    {char: "ph", pronounce: "/f/", desc: "Consonante fricativa labiodental"},
    {char: "q", pronounce: "/kw/", desc: "Siempre va acompañada de u"},
    {char: "r", pronounce: "/r/", desc: "Consonante vibrante alveolar"},
    {char: "s", pronounce: "/s/", desc: "Consonante fricativa alveolar sorda"},
    {char: "t", pronounce: "/t/", desc: "Consonante oclusiva alveolar sorda"},
    {char: "th", pronounce: "/θ/", desc: "Consonante fricativa dental"},
    {char: "v", pronounce: "/v/", desc: "Consonante fricativa labiodental sonora"},
    {char: "x", pronounce: "/s/", desc: "Consonante fricativa alveolar sorda"}
];

let favList = JSON.parse(localStorage.getItem("vn_consonant_fav")) || [];
let currentAudio = null; // Objeto de audio global, para detener la reproducción anterior

const gridEl = document.getElementById("consonant-grid");
const favGridEl = document.getElementById("favorite-grid");
const modal = document.getElementById("modal");
const modalChar = document.getElementById("modal-char");
const modalPro = document.getElementById("modal-pronounce");
const modalDesc = document.getElementById("modal-desc");
const btnFav = document.getElementById("btn-fav");
const closeModal = document.getElementById("close-modal");

let currentItem = null;

// ====================== FUNCIÓN PARA REPRODUCIR MP3 ======================
function playAudio(charName) {
    // Detener el audio que se esté reproduciendo
    if(currentAudio){
        currentAudio.pause();
        currentAudio.currentTime = 0;
    }
    // Crear objeto de audio
    currentAudio = new Audio(`audio/${charName}.mp3`);
    currentAudio.volume = 1;
    currentAudio.play().catch(err=>{
        console.log("No se pudo reproducir el archivo: ", charName, err);
        alert(`No se encuentra el archivo de audio: ${charName}.mp3`);
    });
}

// Renderizar tarjetas de consonantes
function renderCards(){
    gridEl.innerHTML = "";
    consonants.forEach(item=>{
        const div = document.createElement("div");
        div.className = "bg-cardBg rounded-lg py-5 text-center card-shadow active:scale-95 transition-transform cursor-pointer";
        div.innerHTML = `<span class="text-2xl font-bold text-gray-800">${item.char}</span>`;
        div.onclick = ()=> {
            playAudio(item.char); // Al pulsar la tarjeta reproduce el mp3
            openModal(item);
        };
        gridEl.appendChild(div);
    })
}

// Renderizar página de favoritos
function renderFav(){
    favGridEl.innerHTML = "";
    if(favList.length === 0){
        favGridEl.innerHTML = `<p class="col-span-3 text-center text-gray-400 py-10">Todavía no hay elementos favoritos</p>`;
        return;
    }
    favList.forEach(item=>{
        const div = document.createElement("div");
        div.className = "bg-cardBg rounded-lg py-5 text-center card-shadow active:scale-95 transition-transform cursor-pointer";
        div.innerHTML = `<span class="text-2xl font-bold text-gray-800">${item.char}</span>`;
        div.onclick = ()=> {
            playAudio(item.char);
            openModal(item);
        };
        favGridEl.appendChild(div);
    })
}

// Abrir ventana emergente con detalles
function openModal(item){
    currentItem = item;
    modalChar.innerText = item.char;
    modalPro.innerText = item.pronounce;
    modalDesc.innerText = item.desc;
    updateFavButton();
    modal.classList.remove("hidden");
}

// Cerrar ventana emergente
closeModal.onclick = ()=>{
    modal.classList.add("hidden");
}
modal.onclick = (e)=>{
    if(e.target === modal) modal.classList.add("hidden");
}

// Botón para agregar / quitar de favoritos
function updateFavButton(){
    const exist = favList.find(x=>x.char === currentItem.char);
    btnFav.innerText = exist ? "Quitar de favoritos" : "Agregar a favoritos";
}
btnFav.onclick = ()=>{
    const idx = favList.findIndex(x=>x.char === currentItem.char);
    if(idx >=0) favList.splice(idx,1);
    else favList.push(currentItem);
    localStorage.setItem("vn_consonant_fav", JSON.stringify(favList));
    updateFavButton();
    renderFav();
}

// Pestañas para cambiar de página
const tabBtns = document.querySelectorAll(".tab-btn");
const pages = document.querySelectorAll(".page");
tabBtns.forEach(btn=>{
    btn.onclick = ()=>{
        const targetId = btn.dataset.target;
        tabBtns.forEach(b=>{
            b.classList.remove("tab-active");
            b.querySelector("svg").classList.add("text-gray-500");
        })
        btn.classList.add("tab-active");
        btn.querySelector("svg").classList.remove("text-gray-500");
        pages.forEach(p=>p.classList.add("hidden"));
        document.getElementById(targetId).classList.remove("hidden");
    }
})

document.addEventListener("DOMContentLoaded", ()=>{
    renderCards();
    renderFav();
})

document.addEventListener("deviceready", ()=>{
    console.log("Cordova listo");
}, false);Lenguaje del código: JavaScript (javascript)

Método 2‑Reproducción mediante plugin

Reproducir audio usando el plugin de cordova cordova-plugin-media

Instalar el plugin

cordova plugin add cordova-plugin-media

Salida de ejecución

D:\cordovademo\hello>cordova plugin add cordova-plugin-media
Installing "cordova-plugin-media" for android
Installing "cordova-plugin-file" for android
Subproject Path: CordovaLib
Subproject Path: app

The Android Persistent storage location now defaults to "Internal". Please check this plugin's README to see if your application needs any changes in its config.xml.

If this is a new application no changes are required.

If this is an update to an existing application that did not specify an "AndroidPersistentFileLocation" you may need to add:

      "<preference name="AndroidPersistentFileLocation" value="Compatibility" />"

to config.xml in order for the application to find previously stored files.

Adding cordova-plugin-media to package.jsonLenguaje del código: HTML, XML (xml)

Reemplazar la función de reproducción de audio

let mediaPlayer = null;

function playAudio(charName) {
    // Detener archivo anterior
    if(mediaPlayer){
        mediaPlayer.stop();
        mediaPlayer.release();
        mediaPlayer = null;
    }
    // Importante: Ruta www/audio/ para Cordova Android
    const src = `audio/${charName}.mp3`;
    mediaPlayer = new Media(src,
        ()=>{
            // Liberar recursos tras finalizar reproducción
            mediaPlayer.release();
            mediaPlayer = null;
        },
        (err)=>{
            console.error("Error al reproducir audio", err);
        }
    );
    mediaPlayer.play();
}Lenguaje del código: JavaScript (javascript)

Sustituye este código por la función correspondiente dentro del archivo main.js original

// Datos de consonantes del vietnamita
const consonants = [
    {char: "b", pronounce: "/ɓ/", desc: "Consonante oclusiva bilabial implosiva"},
    {char: "c", pronounce: "/k/", desc: "Consonante oclusiva velar"},
    {char: "ch", pronounce: "/tɕ/", desc: "Consonante africada palatal"},
    {char: "d", pronounce: "/ɗ/", desc: "Consonante oclusiva alveolar implosiva"},
    {char: "đ", pronounce: "/ɗ/", desc: "Consonante implosiva alveolar"},
    {char: "g", pronounce: "/ɣ/", desc: "Consonante fricativa velar"},
    {char: "gh", pronounce: "/ɣ/", desc: "Se usa antes de e, i"},
    {char: "h", pronounce: "/h/", desc: "Consonante fricativa glotal"},
    {char: "k", pronounce: "/k/", desc: "Consonante oclusiva velar sorda"},
    {char: "kh", pronounce: "/x/", desc: "Consonante fricativa velar sorda"},
    {char: "l", pronounce: "/l/", desc: "Consonante lateral alveolar"},
    {char: "m", pronounce: "/m/", desc: "Consonante nasal bilabial"},
    {char: "n", pronounce: "/n/", desc: "Consonante nasal alveolar"},
    {char: "ng", pronounce: "/ŋ/", desc: "Consonante nasal velar"},
    {char: "ngh", pronounce: "/ŋ/", desc: "Se usa antes de e,i"},
    {char: "nh", pronounce: "/ɲ/", desc: "Consonante nasal palatal"},
    {char: "p", pronounce: "/p/", desc: "Consonante oclusiva bilabial no aspirada"},
    {char: "ph", pronounce: "/f/", desc: "Consonante fricativa labiodental"},
    {char: "q", pronounce: "/kw/", desc: "Siempre va acompañada de u"},
    {char: "r", pronounce: "/r/", desc: "Consonante vibrante alveolar"},
    {char: "s", pronounce: "/s/", desc: "Consonante fricativa alveolar sorda"},
    {char: "t", pronounce: "/t/", desc: "Consonante oclusiva alveolar sorda"},
    {char: "th", pronounce: "/θ/", desc: "Consonante fricativa dental"},
    {char: "v", pronounce: "/v/", desc: "Consonante fricativa labiodental sonora"},
    {char: "x", pronounce: "/s/", desc: "Consonante fricativa alveolar sorda"}
];

let favList = JSON.parse(localStorage.getItem("vn_consonant_fav")) || [];
let currentAudio = null; // Objeto de audio global, para detener la reproducción anterior

const gridEl = document.getElementById("consonant-grid");
const favGridEl = document.getElementById("favorite-grid");
const modal = document.getElementById("modal");
const modalChar = document.getElementById("modal-char");
const modalPro = document.getElementById("modal-pronounce");
const modalDesc = document.getElementById("modal-desc");
const btnFav = document.getElementById("btn-fav");
const closeModal = document.getElementById("close-modal");

let currentItem = null;

// ====================== FUNCIÓN PARA REPRODUCIR MP3 ======================
let mediaPlayer = null;

function playAudio(charName) {
    // Detener archivo anterior
    if(mediaPlayer){
        mediaPlayer.stop();
        mediaPlayer.release();
        mediaPlayer = null;
    }
    // Importante: Ruta www/audio/ para Cordova Android
    const src = `audio/${charName}.mp3`;
    mediaPlayer = new Media(src,
        ()=>{
            // Liberar recursos tras finalizar reproducción
            mediaPlayer.release();
            mediaPlayer = null;
        },
        (err)=>{
            console.error("Error al reproducir audio", err);
        }
    );
    mediaPlayer.play();
}

// Renderizar tarjetas de consonantes
function renderCards(){
    gridEl.innerHTML = "";
    consonants.forEach(item=>{
        const div = document.createElement("div");
        div.className = "bg-cardBg rounded-lg py-5 text-center card-shadow active:scale-95 transition-transform cursor-pointer";
        div.innerHTML = `<span class="text-2xl font-bold text-gray-800">${item.char}</span>`;
        div.onclick = ()=> {
            playAudio(item.char); // Al pulsar la tarjeta reproduce el mp3
            openModal(item);
        };
        gridEl.appendChild(div);
    })
}

// Renderizar página de favoritos
function renderFav(){
    favGridEl.innerHTML = "";
    if(favList.length === 0){
        favGridEl.innerHTML = `<p class="col-span-3 text-center text-gray-400 py-10">Todavía no hay elementos favoritos</p>`;
        return;
    }
    favList.forEach(item=>{
        const div = document.createElement("div");
        div.className = "bg-cardBg rounded-lg py-5 text-center card-shadow active:scale-95 transition-transform cursor-pointer";
        div.innerHTML = `<span class="text-2xl font-bold text-gray-800">${item.char}</span>`;
        div.onclick = ()=> {
            playAudio(item.char);
            openModal(item);
        };
        favGridEl.appendChild(div);
    })
}

// Abrir ventana emergente con detalles
function openModal(item){
    currentItem = item;
    modalChar.innerText = item.char;
    modalPro.innerText = item.pronounce;
    modalDesc.innerText = item.desc;
    updateFavButton();
    modal.classList.remove("hidden");
}

// Cerrar ventana emergente
closeModal.onclick = ()=>{
    modal.classList.add("hidden");
}
modal.onclick = (e)=>{
    if(e.target === modal) modal.classList.add("hidden");
}

// Botón para agregar / quitar de favoritos
function updateFavButton(){
    const exist = favList.find(x=>x.char === currentItem.char);
    btnFav.innerText = exist ? "Quitar de favoritos" : "Agregar a favoritos";
}
btnFav.onclick = ()=>{
    const idx = favList.findIndex(x=>x.char === currentItem.char);
    if(idx >=0) favList.splice(idx,1);
    else favList.push(currentItem);
    localStorage.setItem("vn_consonant_fav", JSON.stringify(favList));
    updateFavButton();
    renderFav();
}

// Pestañas para cambiar de página
const tabBtns = document.querySelectorAll(".tab-btn");
const pages = document.querySelectorAll(".page");
tabBtns.forEach(btn=>{
    btn.onclick = ()=>{
        const targetId = btn.dataset.target;
        tabBtns.forEach(b=>{
            b.classList.remove("tab-active");
            b.querySelector("svg").classList.add("text-gray-500");
        })
        btn.classList.add("tab-active");
        btn.querySelector("svg").classList.remove("text-gray-500");
        pages.forEach(p=>p.classList.add("hidden"));
        document.getElementById(targetId).classList.remove("hidden");
    }
})

document.addEventListener("DOMContentLoaded", ()=>{
    renderCards();
    renderFav();
})

document.addEventListener("deviceready", ()=>{
    console.log("Cordova listo");
}, false);Lenguaje del código: JavaScript (javascript)

Reproducir el audio

Deja una respuesta

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