⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp3player.c

📁 qt91上实现的mp3播放机,支持sam9260,参考用
💻 C
字号:
/*!
 * Copyright (C) 2006-2007 by egnite Software GmbH. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
 * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * For additional information see http://www.ethernut.de/
 */

/*!
 * \file mp3player.c
 * \brief MP3 player.
 *
 * \verbatim
 *
 * $Log$
 *
 * \endverbatim
 */

#include <cfg/os.h>
#include <cfg/clock.h>
#include <dev/board.h>
#include <sys/heap.h>
#include <sys/timer.h>
#include <sys/event.h>

#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <stdio.h>
#include <io.h>

#include "tlv320dac.h"
#include "webradio.h"
#include "utils.h"
#include "userif.h"
#include "mp3player.h"

#ifndef MP3_THREAD_STACK
#ifdef AT91SAM7X_EK
#define MP3_THREAD_STACK  1024
#else
#define MP3_THREAD_STACK  2048
#endif
#endif

static void *hres;

#if defined (AT91SAM9260_EK)
#define ENABLE_RESAMPLER
#endif

#ifdef ENABLE_RESAMPLERstatic int rs_maxout;static short *rs_pcmbuf;
#endif

/*!
 * \brief Wait until the MP3 data buffer is sufficiently filled.
 *
 * \param pip Pointer to the player info structure.
 */
static void Mp3PlayerBufferFill(PLAYERINFO *pip)
{
    RECEIVERINFO *rip;
    time_t start = time(NULL);

    printf("\nBuffering");
    for (;;) {
        /* Return if 2/3 of the buffer is filled. */
        rip = pip->pi_rcvr;
        if (rip == NULL || rip->ri_avail >= (MP3_BUFSIZ * 2) / 3) {
            break;
        }
        /* Return if we reached our time limit. */
        if (time(NULL) - start >= MAX_WAIT_MP3BUF_FILLED) {
            break;
        }
        /* Return if someone stopped the player. */
        if (pip->pi_status != PSTAT_RUNNING) {
            break;
        }
        /* Wait for an event from the producer. */
        if (NutEventWait(&rip->ri_rdbque, 500) == 0) {
            putchar('.');
        }
        UserIfShowMessage(1, 1, "Buffering %u%%",  (rip->ri_avail * 100) / MP3_BUFSIZ);
    }
    printf(" %u bytes free\n", (u_int)NutHeapAvailable());
}

/*!
 * \brief MP3 player thread.
 *
 * \param arg Pointer to the player info structure.
 */
THREAD(Mp3PlayerThread, arg)
{
    PLAYERINFO *pip = (PLAYERINFO *)arg;
    MP3PLAYERINFO *mpi = (MP3PLAYERINFO *) pip->pi_bcast;
    RECEIVERINFO *rip;
    int rbytes;
    u_char *bufptr;
    int ec;
    int errcnt;
    int tmocnt;
    int first_frame;
    int samprate;

    Tlv320DacInit(DAC_OUTPUT_RATE);
    Tlv320DacSetVolume(radio.rc_rvolume, radio.rc_rvolume);    radio.rc_cvolume = radio.rc_rvolume;
    for (;;) {
        /* Idle loop. */
        for (;;) {
            printf("[PIDLE]");
            pip->pi_status = PSTAT_IDLE;
            NutEventBroadcast(&pip->pi_stsevt);

            if (mpi->mpi_mp3dec) {
                MP3FreeDecoder(mpi->mpi_mp3dec);
                mpi->mpi_mp3dec = NULL;
            }

            /* Wait for start event. */
            NutEventWait(&pip->pi_cmdevt, 0);
            printf("[PEVT%u]", pip->pi_status);
            if (pip->pi_status == PSTAT_START) {
                if (mpi->mpi_mp3dec == NULL) {
                    if ((mpi->mpi_mp3dec = MP3InitDecoder()) == NULL) {
                        printf("\n[ERR-MP3INI]");
                    }
                }
                if (mpi->mpi_mp3dec && pip->pi_rcvr) {
                    break;
                }
            }
        }

        /* Broadcast running event. */
        printf("[PRUN]");
        pip->pi_status = PSTAT_RUNNING;
        NutEventBroadcast(&pip->pi_stsevt);
        rip = pip->pi_rcvr;

        /* Wait for enough data to start playing. */
        NutSleep(500);
        Mp3PlayerBufferFill(pip);

        /* Running loop. */
        errcnt = 0;
        tmocnt = 0;
        first_frame = 1;
        while (pip->pi_status == PSTAT_RUNNING) {
            /* Wait for new data. */
            if (rip->ri_avail < 2 * MAINBUF_SIZE) {
                if (++tmocnt > 4) {
                    break;
                }
                Mp3PlayerBufferFill(pip);
                continue;
            }
            if (tmocnt) {
                tmocnt--;
            }

            if (rip->ri_rpos > rip->ri_wpos && MP3_BUFSIZ - rip->ri_rpos < 2 * MAINBUF_SIZE) {
                /* The read pointer is in front of the write pointer, but
                   there is not enough MP3 data at the end of the buffer.
                   Wrap data from the front to the back, because the decoder
                   requires a continous buffer. Note, that we allocated the
                   additional bytes at the end of the MP3 data buffer for
                   this purpose. */
                memcpy(&rip->ri_buff[MP3_BUFSIZ], rip->ri_buff, 2 * MAINBUF_SIZE - (MP3_BUFSIZ - rip->ri_rpos));
            }

            /* Test for sync error. Discard data up to the next sync word. */
            ec = 0;
            if ((rbytes = MP3FindSyncWord(&rip->ri_buff[rip->ri_rpos], 2 * MAINBUF_SIZE)) < 0) {                puts("\n[ERR-SYN]");			    break;		    }            else if (rbytes == 0) {                /* We are in sync. Decode the next MP3 frame. */                if (ec == 0) {                    rbytes = 2 * MAINBUF_SIZE;                    bufptr = &rip->ri_buff[rip->ri_rpos];                    Led0(1); 		            ec = MP3Decode(mpi->mpi_mp3dec, &bufptr, &rbytes, pip->pi_pcmbuf, 0);                    Led0(0);                    if (ec) {                        rbytes = 0;                    }                    else {                        rbytes = 2 * MAINBUF_SIZE - rbytes;                    }                }                if (ec == 0) {                    if (first_frame) {                        /*                         * This is the first frame. Retrieve the frame data, print it                         * to the debug port and optionally initialize the resampler.                         */                        MP3GetLastFrameInfo(mpi->mpi_mp3dec, &mpi->mpi_frameinfo);                        printf("\nBitrate\t\t: %d", mpi->mpi_frameinfo.bitrate);                        printf("\nChannels\t: ");                        if (mpi->mpi_frameinfo.nChans == 1) {
                            printf("Mono");
                            samprate = mpi->mpi_frameinfo.samprate / 2;
                        }
                        else if (mpi->mpi_frameinfo.nChans == 2) {
                            printf("Stereo");
                            samprate = mpi->mpi_frameinfo.samprate;
                        }
                        else {
                            samprate = 0;
                            putchar('?');
                            ec = -1;
                        }
                        printf("\nSample rate\t: %d", mpi->mpi_frameinfo.samprate);                        if (mpi->mpi_frameinfo.samprate < 8000 || samprate > DAC_OUTPUT_RATE) {                            printf(" not supported");                            ec = -1;                        }                        printf("\nBits/sample\t: %d", mpi->mpi_frameinfo.bitsPerSample);                        if (mpi->mpi_frameinfo.bitsPerSample != 16) {                            printf(" not supported");                            ec = -1;                        }                        printf("\nSamples\t\t: %d", mpi->mpi_frameinfo.outputSamps);#ifdef ENABLE_RESAMPLER                        /* If needed, initialize resampler. */                        if (ec == 0 && samprate != DAC_OUTPUT_RATE) {                            if ((hres = RAInitResamplerHermite(samprate, DAC_OUTPUT_RATE, mpi->mpi_frameinfo.nChans)) == NULL) {                                printf(" failed");                                ec = -1;                            }                            rs_maxout = RAGetMaxOutputHermite(mpi->mpi_frameinfo.outputSamps, hres);                            printf(" -> %d", rs_maxout);                            if ((rs_pcmbuf = malloc(rs_maxout * 2)) == NULL) {                                printf(" no mem");                                ec = -1;                            }                        }#endif                        printf("\nLayer\t\t: %d", mpi->mpi_frameinfo.layer);                        printf("\nVersion\t\t: %d\n", mpi->mpi_frameinfo.version);                        if (ec) {                            break;                        }                        first_frame = 0;                    }                    if (hres == NULL) {                        /* Same rate as our DAC. */                        if (Tlv320DacWrite(pip->pi_pcmbuf, mpi->mpi_frameinfo.outputSamps)) {                            puts("\n[**ERR-ADC**]");                            break;                        }                    }#ifdef ENABLE_RESAMPLER                    else {
                        int os;

                        if (mpi->mpi_frameinfo.nChans == 1) {
                            os = RAResampleMonoHermite(pip->pi_pcmbuf, mpi->mpi_frameinfo.outputSamps, rs_pcmbuf, hres);
                        }
                        else {
                            os = RAResampleStereoHermite(pip->pi_pcmbuf, mpi->mpi_frameinfo.outputSamps, rs_pcmbuf, hres);
                        }
                        if (os <= 0) {
                            puts("\n[**ERR-RSMPLR**]");                            break;                        }
                        if (Tlv320DacWrite(rs_pcmbuf, os)) {                            puts("\n[**ERR-ADC**]");                            break;                        }                    }#endif                    if (radio.rc_rvolume != radio.rc_cvolume) {                        Tlv320DacSetVolume(radio.rc_rvolume, radio.rc_rvolume);                        radio.rc_cvolume = radio.rc_rvolume;                    }                    /* Slowly recover from previous errors. */                    if (errcnt) {                        errcnt--;                    }                }                else {                    printf("\n[ERR%d] %u bytes free\n", ec, (u_int)NutHeapAvailable());                    /* Move to idle state in case of fatal errors. */                    if (ec == ERR_MP3_OUT_OF_MEMORY) {                        break;                    }                    /* In case of too many errors move to idle state. */                    if (++errcnt > MAX_PLAYERRORS) {                        break;                    }                    /* Avoid to get stuck on the same error. */                    if (rbytes == 0) {                        rbytes = 1;
                    }
                }            }            else {                /* In case of too many sync errors move to idle state. */                printf("[SKIP %d]", rbytes);                if (++errcnt > MAX_PLAYERRORS) {                    break;                }            }            /* Adjust the read pointer and the number of bytes available. */            rip->ri_avail -= rbytes;            rip->ri_rpos += rbytes;            if (rip->ri_rpos >= MP3_BUFSIZ) {
                rip->ri_rpos -= MP3_BUFSIZ;
            }
            /* Inform the receiver, that we removed data from the buffer. */
            NutEventPost(&rip->ri_wrbque);
        }
#ifdef ENABLE_RESAMPLER        if (hres) {
            printf("[RSREL]");
            RAFreeResamplerHermite(hres);
            hres = NULL;
            if (rs_pcmbuf) {
                free(rs_pcmbuf);
                rs_pcmbuf = NULL;
            }
        }
#endif
        if (Tlv320DacFlush()) {
            printf("\n[ERR DACFlush]");
        }
    }
}

/*!
 * \brief Create MP3 player instance.
 *
 * Called when creating a player instance.
 *
 * \param pip Pointer to the \ref PLAYERINFO structure.
 *
 * \return 0 on success, otherwise -1.
 */
int Mp3PlayerCreate(PLAYERINFO *pip)
{
    /* Allocate local info structure. */
    if ((pip->pi_bcast = malloc(sizeof(MP3PLAYERINFO))) != NULL) {
        memset(pip->pi_bcast, 0, sizeof(MP3PLAYERINFO));

        /* Start the player thread. */
        if (NutThreadCreate("mp3play", Mp3PlayerThread, pip, MP3_THREAD_STACK)) {
            /* Success! */
            return 0;
        }
        free(pip->pi_bcast);
    }
    /* Not enough memory. */
    return -1;
}/*!
 * \brief Setup MP3 player.
 *
 * Doesn't do anything right now.
 *
 * \return Always 0.
 */
int Mp3PlayerSetup(PLAYERINFO *pip)
{    return 0;}/*!
 * \brief MP3 player plug-in reference structure.
 *
 * Used by the application to link an MP3 player instance.
 */
PLAYERPLUGIN ppiMp3 = {    Mp3PlayerCreate,    /*!< Plugin method pp_create. */    Mp3PlayerSetup      /*!< Plugin method pp_setup. */};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -