Ignore:
Timestamp:
Feb 22, 2009 5:15:34 PM (15 years ago)
Author:
bennylp
Message:
  • Added pjmedia-audiodev/config.h
  • Added a bit of doxygen documentation
  • Added support for PCMA/PCMU codecs in wmme_dev.c
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/branches/projects/aps-direct/pjmedia/src/pjmedia-audiodev/wmme_dev.c

    r2469 r2470  
    3131#include <windows.h> 
    3232#include <mmsystem.h> 
     33#include <mmreg.h> 
    3334 
    3435#ifdef _MSC_VER 
     
    103104    void                *buffer;            /**< Temp. frame buffer.   */ 
    104105    unsigned             clock_rate;        /**< Clock rate.           */ 
     106    unsigned             bytes_per_frame;   /**< Bytes per frame       */ 
    105107    unsigned             samples_per_frame; /**< Samples per frame.    */ 
    106108    unsigned             bits_per_sample;   /**< Bits per sample.      */ 
    107109    unsigned             channel_count;     /**< Channel count.        */ 
     110 
     111    pjmedia_frame_ext   *xfrm;              /**< Extended frame buffer */ 
     112    unsigned             xfrm_size;         /**< Total ext frm size    */ 
    108113 
    109114    pj_thread_t         *thread;            /**< Thread handle.        */ 
     
    193198/* Internal: build device info from WAVEINCAPS/WAVEOUTCAPS */ 
    194199static void build_dev_info(UINT deviceId, struct wmme_dev_info *wdi,  
    195                            WAVEINCAPS *wic, WAVEOUTCAPS *woc) 
     200                           const WAVEINCAPS *wic, const WAVEOUTCAPS *woc) 
    196201{ 
    197202#define WIC_WOC(wic,woc,field)  (wic? wic->field : woc->field) 
     
    205210        wdi->info.name[sizeof(wdi->info.name)-1] = '\0'; 
    206211    } else { 
    207         pj_char_t *szPname = WIC_WOC(wic, woc, szPname); 
     212        const pj_char_t *szPname = WIC_WOC(wic, woc, szPname); 
    208213        PJ_DECL_ANSI_TEMP_BUF(wTmp, sizeof(wdi->info.name)); 
    209214         
     
    246251        } 
    247252    } 
     253 
     254    /* Extended formats */ 
     255    wdi->info.caps |= PJMEDIA_AUD_DEV_CAP_EXT_FORMAT; 
     256    wdi->info.ext_fmt_cnt = 2; 
     257    wdi->info.ext_fmt[0].id = PJMEDIA_FORMAT_PCMU; 
     258    wdi->info.ext_fmt[0].bitrate = 64000; 
     259    wdi->info.ext_fmt[0].vad = 0; 
     260    wdi->info.ext_fmt[1].id = PJMEDIA_FORMAT_PCMA; 
     261    wdi->info.ext_fmt[1].bitrate = 64000; 
     262    wdi->info.ext_fmt[1].vad = 0; 
    248263} 
    249264 
     
    280295                                  sizeof(struct wmme_dev_info)); 
    281296 
    282     if (devCount) { 
     297    if (inputDeviceCount && outputDeviceCount) { 
    283298        /* Attempt to add WAVE_MAPPER as input and output device */ 
    284299        WAVEINCAPS wic; 
     
    435450 
    436451/* Internal: init WAVEFORMATEX */ 
    437 static void init_waveformatex (LPWAVEFORMATEX pcmwf,  
    438                                unsigned clock_rate, 
    439                                unsigned channel_count) 
    440 { 
    441     pj_bzero(pcmwf, sizeof(PCMWAVEFORMAT));  
    442     pcmwf->wFormatTag = WAVE_FORMAT_PCM;  
    443     pcmwf->nChannels = (pj_uint16_t)channel_count; 
    444     pcmwf->nSamplesPerSec = clock_rate; 
    445     pcmwf->nBlockAlign = (pj_uint16_t)(channel_count * BYTES_PER_SAMPLE); 
    446     pcmwf->nAvgBytesPerSec = clock_rate * channel_count * BYTES_PER_SAMPLE; 
    447     pcmwf->wBitsPerSample = BITS_PER_SAMPLE; 
     452static pj_status_t init_waveformatex(LPWAVEFORMATEX wfx,  
     453                                     const pjmedia_aud_param *prm) 
     454{ 
     455 
     456    pj_bzero(wfx, sizeof(PCMWAVEFORMAT));  
     457    if (prm->ext_fmt.id == PJMEDIA_FORMAT_L16) { 
     458        wfx->wFormatTag = WAVE_FORMAT_PCM;  
     459        wfx->nChannels = (pj_uint16_t)prm->channel_count; 
     460        wfx->nSamplesPerSec = prm->clock_rate; 
     461        wfx->nBlockAlign = (pj_uint16_t)(prm->channel_count *  
     462                                         BYTES_PER_SAMPLE); 
     463        wfx->nAvgBytesPerSec = prm->clock_rate * prm->channel_count *  
     464                               BYTES_PER_SAMPLE; 
     465        wfx->wBitsPerSample = BITS_PER_SAMPLE; 
     466 
     467        return PJ_SUCCESS; 
     468 
     469    } else if ((prm->flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) && 
     470               (prm->ext_fmt.id == PJMEDIA_FORMAT_PCMA || 
     471                prm->ext_fmt.id == PJMEDIA_FORMAT_PCMU)) 
     472    { 
     473        unsigned ptime; 
     474 
     475        ptime = prm->samples_per_frame * 1000 /  
     476                (prm->clock_rate * prm->channel_count); 
     477        wfx->wFormatTag = (pj_uint16_t) 
     478                          ((prm->ext_fmt.id==PJMEDIA_FORMAT_PCMA) ? 
     479                            WAVE_FORMAT_ALAW : WAVE_FORMAT_MULAW);   
     480        wfx->nChannels = (pj_uint16_t)prm->channel_count; 
     481        wfx->nSamplesPerSec = prm->clock_rate; 
     482        wfx->nAvgBytesPerSec = prm->clock_rate * prm->channel_count; 
     483        wfx->nBlockAlign = (pj_uint16_t)(wfx->nAvgBytesPerSec * ptime / 
     484                                         1000); 
     485        wfx->wBitsPerSample = 8; 
     486        wfx->cbSize = 0; 
     487 
     488        return PJ_SUCCESS; 
     489 
     490    } else { 
     491 
     492        return PJMEDIA_EAUD_BADFORMAT; 
     493 
     494    } 
    448495} 
    449496 
     
    452499static pj_status_t init_player_stream(  struct wmme_factory *wf, 
    453500                                        pj_pool_t *pool, 
     501                                        struct wmme_stream *parent, 
    454502                                        struct wmme_channel *wmme_strm, 
    455                                         unsigned dev_id, 
    456                                         unsigned clock_rate, 
    457                                         unsigned channel_count, 
    458                                         unsigned samples_per_frame, 
     503                                        const pjmedia_aud_param *prm, 
    459504                                        unsigned buffer_count) 
    460505{ 
    461506    MMRESULT mr; 
    462     WAVEFORMATEX pcmwf;  
    463     unsigned bytes_per_frame; 
    464     unsigned i; 
    465  
    466     PJ_ASSERT_RETURN(dev_id < wf->dev_count, PJ_EINVAL); 
     507    WAVEFORMATEX wfx;  
     508    unsigned i, ptime; 
     509    pj_status_t status; 
     510 
     511    PJ_ASSERT_RETURN(prm->play_id < (int)wf->dev_count, PJ_EINVAL); 
    467512 
    468513    /* 
     
    476521     * Set up wave format structure for opening the device. 
    477522     */ 
    478     init_waveformatex(&pcmwf, clock_rate, channel_count); 
    479     bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE; 
     523    status = init_waveformatex(&wfx, prm); 
     524    if (status != PJ_SUCCESS) 
     525        return status; 
     526 
     527    ptime = prm->samples_per_frame * 1000 /  
     528            (prm->clock_rate * prm->channel_count); 
     529    ptime = prm->samples_per_frame * 1000 /  
     530            (prm->clock_rate * prm->channel_count); 
     531    parent->bytes_per_frame = wfx.nAvgBytesPerSec / ptime; 
    480532 
    481533    /* 
    482534     * Open wave device. 
    483535     */ 
    484     mr = waveOutOpen(&wmme_strm->hWave.Out, wf->dev_info[dev_id].deviceId,  
    485                      &pcmwf, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT); 
     536    mr = waveOutOpen(&wmme_strm->hWave.Out,  
     537                     wf->dev_info[prm->play_id].deviceId, 
     538                     &wfx, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT); 
    486539    if (mr != MMSYSERR_NOERROR) { 
    487540        return CONVERT_MM_ERROR(mr); 
     
    500553                         pj_pool_zalloc(pool, sizeof(WAVEHDR) * buffer_count); 
    501554    for (i = 0; i < buffer_count; ++i) { 
    502         wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, bytes_per_frame); 
    503         wmme_strm->WaveHdr[i].dwBufferLength = bytes_per_frame; 
     555        wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool,  
     556                                                      parent->bytes_per_frame); 
     557        wmme_strm->WaveHdr[i].dwBufferLength = parent->bytes_per_frame; 
    504558        mr = waveOutPrepareHeader(wmme_strm->hWave.Out,  
    505559                                  &(wmme_strm->WaveHdr[i]), 
     
    523577               " WaveAPI Sound player \"%s\" initialized (clock_rate=%d, " 
    524578               "channel_count=%d, samples_per_frame=%d (%dms))", 
    525                wf->dev_info[dev_id].info.name, 
    526                clock_rate, channel_count, samples_per_frame, 
    527                samples_per_frame * 1000 / clock_rate)); 
     579               wf->dev_info[prm->play_id].info.name, 
     580               prm->clock_rate, prm->channel_count, prm->samples_per_frame, 
     581               prm->samples_per_frame * 1000 / prm->clock_rate)); 
    528582 
    529583    return PJ_SUCCESS; 
     
    534588static pj_status_t init_capture_stream( struct wmme_factory *wf, 
    535589                                        pj_pool_t *pool, 
     590                                        struct wmme_stream *parent, 
    536591                                        struct wmme_channel *wmme_strm, 
    537                                         unsigned dev_id, 
    538                                         unsigned clock_rate, 
    539                                         unsigned channel_count, 
    540                                         unsigned samples_per_frame, 
     592                                        const pjmedia_aud_param *prm, 
    541593                                        unsigned buffer_count) 
    542594{ 
    543595    MMRESULT mr; 
    544     WAVEFORMATEX pcmwf;  
    545     unsigned bytes_per_frame; 
    546     unsigned i; 
    547  
    548     PJ_ASSERT_RETURN(dev_id < wf->dev_count, PJ_EINVAL); 
     596    WAVEFORMATEX wfx;  
     597    unsigned i, ptime; 
     598 
     599    PJ_ASSERT_RETURN(prm->rec_id < (int)wf->dev_count, PJ_EINVAL); 
    549600 
    550601    /* 
     
    559610     * Set up wave format structure for opening the device. 
    560611     */ 
    561     init_waveformatex(&pcmwf, clock_rate, channel_count); 
    562     bytes_per_frame = samples_per_frame * BYTES_PER_SAMPLE; 
     612    init_waveformatex(&wfx, prm); 
     613    ptime = prm->samples_per_frame * 1000 /  
     614            (prm->clock_rate * prm->channel_count); 
     615    parent->bytes_per_frame = wfx.nAvgBytesPerSec / ptime; 
    563616 
    564617    /* 
    565618     * Open wave device. 
    566619     */ 
    567     mr = waveInOpen(&wmme_strm->hWave.In, wf->dev_info[dev_id].deviceId,  
    568                     &pcmwf, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT); 
     620    mr = waveInOpen(&wmme_strm->hWave.In,  
     621                    wf->dev_info[prm->rec_id].deviceId,  
     622                    &wfx, (DWORD)wmme_strm->hEvent, 0, CALLBACK_EVENT); 
    569623    if (mr != MMSYSERR_NOERROR) { 
    570624        return CONVERT_MM_ERROR(mr); 
     
    577631                         pj_pool_zalloc(pool, sizeof(WAVEHDR) * buffer_count); 
    578632    for (i = 0; i < buffer_count; ++i) { 
    579         wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool, bytes_per_frame); 
    580         wmme_strm->WaveHdr[i].dwBufferLength = bytes_per_frame; 
     633        wmme_strm->WaveHdr[i].lpData = pj_pool_zalloc(pool,  
     634                                                      parent->bytes_per_frame); 
     635        wmme_strm->WaveHdr[i].dwBufferLength = parent->bytes_per_frame; 
    581636        mr = waveInPrepareHeader(wmme_strm->hWave.In,  
    582637                                 &(wmme_strm->WaveHdr[i]), 
     
    600655        " WaveAPI Sound recorder \"%s\" initialized (clock_rate=%d, " 
    601656        "channel_count=%d, samples_per_frame=%d (%dms))", 
    602         wf->dev_info[dev_id].info.name, 
    603         clock_rate, channel_count, samples_per_frame, 
    604         samples_per_frame * 1000 / clock_rate)); 
     657        wf->dev_info[prm->rec_id].info.name, 
     658        prm->clock_rate, prm->channel_count, prm->samples_per_frame, 
     659        prm->samples_per_frame * 1000 / prm->clock_rate)); 
    605660 
    606661    return PJ_SUCCESS; 
     
    614669    HANDLE events[3]; 
    615670    unsigned eventCount; 
    616     unsigned bytes_per_frame; 
    617671    pj_status_t status = PJ_SUCCESS; 
    618  
    619672 
    620673    eventCount = 0; 
     
    638691#endif 
    639692 
    640     /* Calculate bytes per frame */ 
    641     bytes_per_frame = strm->samples_per_frame * BYTES_PER_SAMPLE; 
    642  
    643693    /* 
    644694     * Loop while not signalled to quit, wait for event objects to be  
     
    677727        { 
    678728            struct wmme_channel *wmme_strm = &strm->play_strm; 
    679             MMRESULT mr = MMSYSERR_NOERROR; 
     729 
    680730            status = PJ_SUCCESS; 
    681731 
     
    688738            { 
    689739                void *buffer = wmme_strm->WaveHdr[wmme_strm->dwBufIdx].lpData; 
    690                 pjmedia_frame frame; 
     740                pjmedia_frame pcm_frame, *frame; 
     741                pj_bool_t has_frame = PJ_FALSE; 
    691742 
    692743                //PJ_LOG(5,(THIS_FILE, "Finished writing buffer %d",  
    693744                //        wmme_strm->dwBufIdx)); 
    694745 
    695                 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    696                 frame.size = bytes_per_frame; 
    697                 frame.buf = buffer; 
    698                 frame.timestamp.u64 = wmme_strm->timestamp.u64; 
    699                 frame.bit_info = 0; 
     746                if (strm->xfrm == NULL) { 
     747                    /* PCM mode */ 
     748                    frame = &pcm_frame; 
     749 
     750                    frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 
     751                    frame->size = strm->bytes_per_frame; 
     752                    frame->buf = buffer; 
     753                    frame->timestamp.u64 = wmme_strm->timestamp.u64; 
     754                    frame->bit_info = 0; 
     755                } else { 
     756                    /* Codec mode */ 
     757                    frame = &strm->xfrm->base; 
     758 
     759                    strm->xfrm->base.type = PJMEDIA_FRAME_TYPE_EXTENDED; 
     760                    strm->xfrm->base.size = strm->bytes_per_frame; 
     761                    strm->xfrm->base.buf = NULL; 
     762                    strm->xfrm->base.timestamp.u64 = wmme_strm->timestamp.u64; 
     763                    strm->xfrm->base.bit_info = 0; 
     764                } 
    700765 
    701766                /* Get frame from application. */ 
    702                 status = (*strm->play_cb)(strm->user_data, &frame); 
     767                status = (*strm->play_cb)(strm->user_data, frame); 
    703768 
    704769                if (status != PJ_SUCCESS) 
    705770                    break; 
    706771 
    707                 if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) { 
    708                     pj_bzero(buffer, bytes_per_frame); 
     772                if (strm->xfrm == NULL) { 
     773                    /* PCM mode */ 
     774                    if (frame->type == PJMEDIA_FRAME_TYPE_NONE) { 
     775                        pj_bzero(buffer, strm->bytes_per_frame); 
     776                        has_frame = PJ_TRUE; 
     777                    } else if (frame->type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
     778                        pj_assert(!"Frame type not supported"); 
     779                    } else if (frame->type == PJMEDIA_FRAME_TYPE_AUDIO) { 
     780                        has_frame = PJ_TRUE; 
     781                    } else { 
     782                        pj_assert(!"Frame type not supported"); 
     783                    } 
     784                } else { 
     785                    /* Codec mode */ 
     786                    if (frame->type == PJMEDIA_FRAME_TYPE_NONE) { 
     787                        /* Not supported */ 
     788                    } else if (frame->type == PJMEDIA_FRAME_TYPE_EXTENDED) { 
     789                        unsigned sz; 
     790                        sz = pjmedia_frame_ext_copy_payload(strm->xfrm, 
     791                                                            buffer, 
     792                                                            strm->bytes_per_frame); 
     793                        pj_assert(sz == strm->bytes_per_frame); 
     794                    } else { 
     795                        pj_assert(!"Frame type not supported"); 
     796                    } 
    709797                } 
    710798 
    711799                /* Write to the device. */ 
    712                 mr = waveOutWrite(wmme_strm->hWave.Out,  
    713                                   &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]),  
    714                                   sizeof(WAVEHDR)); 
    715                 if (mr != MMSYSERR_NOERROR) 
    716                 { 
    717                     status = CONVERT_MM_ERROR(mr); 
    718                     break; 
     800                if (has_frame) { 
     801                    MMRESULT mr = MMSYSERR_NOERROR; 
     802 
     803                    mr = waveOutWrite(wmme_strm->hWave.Out,  
     804                                      &(wmme_strm->WaveHdr[wmme_strm->dwBufIdx]), 
     805                                      sizeof(WAVEHDR)); 
     806                    if (mr != MMSYSERR_NOERROR) { 
     807                        status = CONVERT_MM_ERROR(mr); 
     808                        break; 
     809                    } 
    719810                } 
    720811 
     
    766857                unsigned cap_len =  
    767858                        wmme_strm->WaveHdr[wmme_strm->dwBufIdx].dwBytesRecorded; 
    768                 pjmedia_frame frame; 
     859                pjmedia_frame pcm_frame, *frame; 
    769860 
    770861                /* 
     
    772863                          wmme_strm->dwBufIdx)); 
    773864                */ 
    774  
    775                 if (cap_len < bytes_per_frame) 
    776                     pj_bzero(buffer + cap_len, bytes_per_frame - cap_len); 
    777  
    778                 /* Copy the audio data out of the wave buffer. */ 
    779                 pj_memcpy(strm->buffer, buffer, bytes_per_frame); 
     865             
     866                if (strm->xfrm == NULL) { 
     867                    /* PCM mode */ 
     868                    if (cap_len < strm->bytes_per_frame) 
     869                        pj_bzero(buffer + cap_len,  
     870                                 strm->bytes_per_frame - cap_len); 
     871 
     872                    /* Copy the audio data out of the wave buffer. */ 
     873                    pj_memcpy(strm->buffer, buffer, strm->bytes_per_frame); 
     874 
     875                    /* Prepare frame */ 
     876                    frame = &pcm_frame; 
     877                    frame->type = PJMEDIA_FRAME_TYPE_AUDIO; 
     878                    frame->buf = strm->buffer; 
     879                    frame->size = strm->bytes_per_frame; 
     880                    frame->timestamp.u64 = wmme_strm->timestamp.u64; 
     881                    frame->bit_info = 0; 
     882 
     883                } else { 
     884                    /* Codec mode */ 
     885                    frame = &strm->xfrm->base; 
     886 
     887                    frame->type = PJMEDIA_FRAME_TYPE_EXTENDED; 
     888                    frame->buf = NULL; 
     889                    frame->size = strm->bytes_per_frame; 
     890                    frame->timestamp.u64 = wmme_strm->timestamp.u64; 
     891                    frame->bit_info = 0; 
     892 
     893                    strm->xfrm->samples_cnt = 0; 
     894                    strm->xfrm->subframe_cnt = 0; 
     895                    pjmedia_frame_ext_append_subframe(strm->xfrm, buffer, 
     896                                                      strm->bytes_per_frame *8, 
     897                                                      strm->samples_per_frame); 
     898                } 
    780899 
    781900                /* Re-add the buffer to the device. */ 
     
    788907                } 
    789908 
    790                 /* Prepare frame */ 
    791                 frame.type = PJMEDIA_FRAME_TYPE_AUDIO; 
    792                 frame.buf = strm->buffer; 
    793                 frame.size = bytes_per_frame; 
    794                 frame.timestamp.u64 = wmme_strm->timestamp.u64; 
    795                 frame.bit_info = 0; 
    796909 
    797910                /* Call callback */ 
    798                 status = (*strm->rec_cb)(strm->user_data, &frame); 
     911                status = (*strm->rec_cb)(strm->user_data, frame); 
    799912                if (status != PJ_SUCCESS) 
    800913                    break; 
     
    866979 
    867980        status = init_player_stream(wf, strm->pool, 
     981                                    strm, 
    868982                                    &strm->play_strm, 
    869                                     param->play_id, 
    870                                     param->clock_rate, 
    871                                     param->channel_count, 
    872                                     param->samples_per_frame, 
     983                                    param, 
    873984                                    buf_count); 
    874985 
     
    8921003 
    8931004        status = init_capture_stream(wf, strm->pool, 
     1005                                     strm, 
    8941006                                     &strm->rec_strm, 
    895                                      param->rec_id, 
    896                                      param->clock_rate, 
    897                                      param->channel_count, 
    898                                      param->samples_per_frame, 
     1007                                     param, 
    8991008                                     buf_count); 
    9001009 
     
    9031012            return status; 
    9041013        } 
     1014    } 
     1015 
     1016    /* If format is extended, must create buffer for the extended frame. */ 
     1017    if (param->ext_fmt.id != PJMEDIA_FORMAT_L16) { 
     1018        unsigned ptime = param->samples_per_frame * 1000 / 
     1019                         (param->clock_rate * param->channel_count); 
     1020        strm->xfrm_size = sizeof(pjmedia_frame_ext) +  
     1021                          32 * sizeof(pjmedia_frame_ext_subframe) + 
     1022                          (8000 * ptime / 1000) + 4; 
     1023        strm->xfrm = (pjmedia_frame_ext*) 
     1024                     pj_pool_alloc(pool, strm->xfrm_size); 
    9051025    } 
    9061026 
Note: See TracChangeset for help on using the changeset viewer.