| /* $Id$ */ |
| /* |
| * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com) |
| * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| #include <pjmedia-audiodev/audiodev_imp.h> |
| #include <pj/errno.h> |
| |
| /* |
| * The Device ID seen by application and driver is different. |
| * |
| * At application level, device ID is a 32bit value. The high 16bit contains |
| * the factory ID, and the low 16bit contains the device index in the |
| * specified factory. The device ID may also be -1 to denote default device. |
| * |
| * At driver level, device ID is a 16bit unsigned integer index. |
| */ |
| #define MAKE_DEV_ID(f_id, index) (((f_id & 0xFFFF) << 16) & (index & 0xFFFF)) |
| #define GET_INDEX(dev_id) ((dev_id) & 0xFFFF) |
| #define GET_FID(dev_id) ((dev_id) >> 16) |
| #define DEFAULT_DEV_ID 0 |
| |
| |
| /* extern functions to create factories */ |
| pjmedia_aud_dev_factory* pjmedia_pa_factory(pj_pool_factory *pf); |
| pjmedia_aud_dev_factory* pjmedia_wmme_factory(pj_pool_factory *pf); |
| |
| |
| /* Array of factories */ |
| static struct factory |
| { |
| pjmedia_aud_dev_factory* (*create)(pj_pool_factory*); |
| pjmedia_aud_dev_factory *f; |
| |
| } factories[] = |
| { |
| /* WMME */ |
| { |
| &pjmedia_wmme_factory |
| }, |
| /* PortAudio: */ |
| { |
| &pjmedia_pa_factory |
| }, |
| }; |
| static unsigned factory_cnt; |
| |
| |
| /* API: Initialize the audio subsystem. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_subsys_init(pj_pool_factory *pf) |
| { |
| unsigned i; |
| pj_status_t status = PJ_ENOMEM; |
| |
| factory_cnt = 0; |
| |
| for (i=0; i<PJ_ARRAY_SIZE(factories); ++i) { |
| factories[i].f = (*factories[i].create)(pf); |
| if (!factories[i].f) |
| continue; |
| |
| status = factories[i].f->op->init(factories[i].f); |
| if (status != PJ_SUCCESS) { |
| factories[i].f->op->destroy(factories[i].f); |
| factories[i].f = NULL; |
| } |
| |
| factories[i].f->internal.id = i; |
| ++factory_cnt; |
| } |
| |
| return factory_cnt ? PJ_SUCCESS : status; |
| } |
| |
| /* API: Shutdown the audio subsystem. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_subsys_shutdown(void) |
| { |
| unsigned i; |
| |
| for (i=0; i<PJ_ARRAY_SIZE(factories); ++i) { |
| if (!factories[i].f) |
| continue; |
| |
| factories[i].f->op->destroy(factories[i].f); |
| factories[i].f = NULL; |
| } |
| |
| return PJ_SUCCESS; |
| } |
| |
| /* API: Get the number of sound devices installed in the system. */ |
| PJ_DEF(unsigned) pjmedia_aud_dev_count(void) |
| { |
| unsigned i, count = 0; |
| |
| for (i=0; i<PJ_ARRAY_SIZE(factories); ++i) { |
| if (!factories[i].f) |
| continue; |
| |
| count += factories[i].f->op->get_dev_count(factories[i].f); |
| } |
| |
| return count; |
| } |
| |
| /* API: Enumerate device ID's. */ |
| PJ_DEF(unsigned) pjmedia_aud_dev_enum(unsigned max_count, |
| pjmedia_aud_dev_id ids[]) |
| { |
| unsigned i, count = 0; |
| |
| for (i=0; i<PJ_ARRAY_SIZE(factories) && count < max_count; ++i) { |
| unsigned j, fcount; |
| |
| if (!factories[i].f) |
| continue; |
| |
| fcount = factories[i].f->op->get_dev_count(factories[i].f); |
| for (j=0; j<fcount && count<max_count; ++j) { |
| ids[count++] = MAKE_DEV_ID(i, j); |
| } |
| } |
| |
| return count; |
| } |
| |
| |
| /* API: Get device information. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_dev_get_info(pjmedia_aud_dev_id id, |
| pjmedia_aud_dev_info *info) |
| { |
| int f_id, index; |
| |
| if (id == PJMEDIA_AUD_DEV_DEFAULT_ID) |
| id = DEFAULT_DEV_ID; |
| |
| f_id = GET_FID(id); |
| index = GET_INDEX(id); |
| |
| if (f_id < 0 || f_id >= PJ_ARRAY_SIZE(factories)) |
| return PJMEDIA_EAUD_INVDEV; |
| |
| if (factories[f_id].f == NULL) |
| return PJMEDIA_EAUD_INVDEV; |
| |
| return factories[f_id].f->op->get_dev_info(factories[f_id].f, |
| index, info); |
| } |
| |
| /* API: Initialize the audio device parameters with default values for the |
| * specified device. |
| */ |
| PJ_DEF(pj_status_t) pjmedia_aud_dev_default_param(pjmedia_aud_dev_id id, |
| pjmedia_aud_dev_param *param) |
| { |
| int f_id, index; |
| pj_status_t status; |
| |
| if (id == PJMEDIA_AUD_DEV_DEFAULT_ID) |
| id = DEFAULT_DEV_ID; |
| |
| f_id = GET_FID(id); |
| index = GET_INDEX(id); |
| |
| if (f_id < 0 || f_id >= PJ_ARRAY_SIZE(factories)) |
| return PJMEDIA_EAUD_INVDEV; |
| |
| if (factories[f_id].f == NULL) |
| return PJMEDIA_EAUD_INVDEV; |
| |
| status = factories[f_id].f->op->default_param(factories[f_id].f, |
| index, param); |
| if (status != PJ_SUCCESS) |
| return status; |
| |
| /* Normalize device IDs */ |
| if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID) |
| param->rec_id = MAKE_DEV_ID(f_id, param->rec_id); |
| if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID) |
| param->play_id = MAKE_DEV_ID(f_id, param->play_id); |
| |
| return PJ_SUCCESS; |
| } |
| |
| /* API: Open audio stream object using the specified parameters. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_stream_create(const pjmedia_aud_dev_param *p, |
| pjmedia_aud_rec_cb rec_cb, |
| pjmedia_aud_play_cb play_cb, |
| void *user_data, |
| pjmedia_aud_stream **p_aud_strm) |
| { |
| pjmedia_aud_dev_param param; |
| int f_id; |
| pj_status_t status; |
| |
| /* Must make copy of param because we're changing device ID */ |
| pj_memcpy(¶m, p, sizeof(param)); |
| |
| /* Set default device */ |
| if (param.rec_id == PJMEDIA_AUD_DEV_DEFAULT_ID) |
| param.rec_id = DEFAULT_DEV_ID; |
| if (param.play_id == PJMEDIA_AUD_DEV_DEFAULT_ID) |
| param.play_id = DEFAULT_DEV_ID; |
| |
| if (param.dir & PJMEDIA_DIR_CAPTURE) |
| f_id = GET_FID(param.rec_id); |
| else |
| f_id = GET_FID(param.play_id); |
| |
| if (f_id < 0 || f_id >= PJ_ARRAY_SIZE(factories)) |
| return PJMEDIA_EAUD_INVDEV; |
| |
| /* Normalize device id's */ |
| param.rec_id = GET_INDEX(param.rec_id); |
| param.play_id = GET_INDEX(param.play_id); |
| |
| if (factories[f_id].f == NULL) |
| return PJMEDIA_EAUD_INVDEV; |
| |
| status = factories[f_id].f->op->create_stream(factories[f_id].f, |
| ¶m, rec_cb, play_cb, |
| user_data, p_aud_strm); |
| if (status != PJ_SUCCESS) |
| return status; |
| |
| (*p_aud_strm)->factory = factories[f_id].f; |
| return PJ_SUCCESS; |
| } |
| |
| /* API: Get the running parameters for the specified audio stream. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_stream_get_param(pjmedia_aud_stream *strm, |
| pjmedia_aud_dev_param *param) |
| { |
| pj_status_t status; |
| |
| status = strm->op->get_param(strm, param); |
| if (status != PJ_SUCCESS) |
| return status; |
| |
| /* Normalize device id's */ |
| if (param->rec_id != PJMEDIA_AUD_DEV_DEFAULT_ID) |
| param->rec_id = MAKE_DEV_ID(strm->factory->internal.id, param->rec_id); |
| if (param->play_id != PJMEDIA_AUD_DEV_DEFAULT_ID) |
| param->play_id = MAKE_DEV_ID(strm->factory->internal.id, param->play_id); |
| |
| return PJ_SUCCESS; |
| } |
| |
| /* API: Get the value of a specific capability of the audio stream. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_stream_get_cap(pjmedia_aud_stream *strm, |
| pjmedia_aud_dev_cap cap, |
| void *value) |
| { |
| return strm->op->get_cap(strm, cap, value); |
| } |
| |
| /* API: Set the value of a specific capability of the audio stream. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_stream_set_cap(pjmedia_aud_stream *strm, |
| pjmedia_aud_dev_cap cap, |
| const void *value) |
| { |
| return strm->op->set_cap(strm, cap, value); |
| } |
| |
| /* API: Start the stream. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_stream_start(pjmedia_aud_stream *strm) |
| { |
| return strm->op->start(strm); |
| } |
| |
| /* API: Stop the stream. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_stream_stop(pjmedia_aud_stream *strm) |
| { |
| return strm->op->stop(strm); |
| } |
| |
| /* API: Destroy the stream. */ |
| PJ_DEF(pj_status_t) pjmedia_aud_stream_destroy(pjmedia_aud_stream *strm) |
| { |
| return strm->op->destroy(strm); |
| } |
| |
| |