#ifndef OSS_MAX_CHANNELS #ifdefined(__FreeBSD__) || defined(__DragonFly__) /* * The current maximum number of channels supported * on FreeBSD is 8. * * Reference: FreeBSD 12.1-RELEASE
*/ #define OSS_MAX_CHANNELS (8) #elifdefined(__sun__) /* * The current maximum number of channels supported * on Illumos is 16. * * Reference: PSARC 2008/318
*/ #define OSS_MAX_CHANNELS (16) #else #define OSS_MAX_CHANNELS (2) #endif #endif
#ifdefined(__FreeBSD__) || defined(__DragonFly__) /* * Check if the specified DSP is okay for the purpose specified * in type. Here type can only specify one operation each time * this helper is called. * * Return 0 if OK, otherwise 1.
*/ staticint
oss_probe_open(constchar * dsppath, cubeb_device_type type, int * fdp,
oss_audioinfo * resai)
{
oss_audioinfo ai; int error; int oflags = (type == CUBEB_DEVICE_TYPE_INPUT) ? O_RDONLY : O_WRONLY; int dspfd = open(dsppath, oflags); if (dspfd == -1) return 1;
strlcpy(res.devname, "/dev/", sizeof(res.devname));
strncat(res.devname, matchptr, n - matchptr);
}
matchptr = n + 1;
n = strchr(matchptr, '<'); if (n == NULL) goto fail;
matchptr = n + 1;
n = strrchr(matchptr, '>'); if (n == NULL) goto fail;
*n = 0;
res.desc = matchptr;
matchptr = n + 1;
n = strchr(matchptr, '('); if (n == NULL) goto fail;
matchptr = n + 1;
n = strrchr(matchptr, ')'); if (n == NULL) goto fail;
*n = 0; if (!isdigit(matchptr[0])) { if (strstr(matchptr, "play") != NULL)
res.type |= CUBEB_DEVICE_TYPE_OUTPUT; if (strstr(matchptr, "rec") != NULL)
res.type |= CUBEB_DEVICE_TYPE_INPUT;
} else { int p, r; if (sscanf(matchptr, "%dp:%*dv/%dr:%*dv", &p, &r) != 2) goto fail; if (p > 0)
res.type |= CUBEB_DEVICE_TYPE_OUTPUT; if (r > 0)
res.type |= CUBEB_DEVICE_TYPE_INPUT;
}
matchptr = n + 1; if (strstr(matchptr, "default") != NULL)
res.preferred = 1;
*sinfo = res; return 0;
fail: return 1;
}
/* * XXX: On FreeBSD we have to rely on SNDCTL_CARDINFO to get all * the usable audio devices currently, as SNDCTL_AUDIOINFO will * never return directly usable audio device nodes.
*/ staticint
oss_enumerate_devices(cubeb * context, cubeb_device_type type,
cubeb_device_collection * collection)
{
cubeb_device_info * devinfop = NULL; char * line = NULL;
size_t linecap = 0;
FILE * sndstatfp = NULL; int collection_cnt = 0; int is_ud = 0; int skipall = 0;
devinfop = calloc(1, sizeof(cubeb_device_info)); if (devinfop == NULL) goto fail;
if (record_on) { if (ioctl(s->record.fd, SNDCTL_DSP_SETTRIGGER, &trig)) {
LOG("Error %d occured when setting trigger on record fd", errno);
state = CUBEB_STATE_ERROR; goto breakdown;
}
if (ioctl(s->record.fd, SNDCTL_DSP_SETTRIGGER, &trig) == -1) {
LOG("Error %d occured when setting trigger on record fd", errno);
state = CUBEB_STATE_ERROR; goto breakdown;
}
}
if (!play_on && !record_on) { /* * Stop here if the stream is not play & record stream, * play-only stream or record-only stream
*/
goto breakdown;
}
while (1) {
pthread_mutex_lock(&s->mtx); if (!s->running || s->destroying) {
pthread_mutex_unlock(&s->mtx); break;
}
pthread_mutex_unlock(&s->mtx);
long got = 0; if (nfr > 0) { if (record_on) { if (oss_get_rec_frames(s, nfr) == CUBEB_ERROR) {
state = CUBEB_STATE_ERROR; goto breakdown;
} if (s->record.floating) {
oss_linear32_to_float(s->record.buf, s->record.info.channels * nfr);
}
}
got = s->data_cb(s, s->user_ptr, s->record.buf, s->play.buf, nfr); if (got == CUBEB_ERROR) {
state = CUBEB_STATE_ERROR; goto breakdown;
} if (got < nfr) { if (s->play.fd != -1) {
drain = 1;
} else { /* * This is a record-only stream and number of frames * returned from data_cb() is smaller than number * of frames required to read. Stop here.
*/
state = CUBEB_STATE_STOPPED; goto breakdown;
}
}
if (output_stream_params->prefs & CUBEB_STREAM_PREF_LOOPBACK) {
LOG("Loopback not supported");
ret = CUBEB_ERROR_NOT_SUPPORTED; goto error;
}
nb_channels =
cubeb_channel_layout_nb_channels(output_stream_params->layout); if (output_stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
nb_channels != output_stream_params->channels) {
LOG("output_stream_params->layout does not match " "output_stream_params->channels");
ret = CUBEB_ERROR_INVALID_PARAMETER; goto error;
} if ((s->play.fd = open(s->play.name, O_WRONLY)) == -1) {
LOG("Audio device \"%s\" could not be opened as write-only",
s->play.name);
ret = CUBEB_ERROR_DEVICE_UNAVAILABLE; goto error;
} if ((ret = oss_copy_params(s->play.fd, s, output_stream_params,
&s->play.info)) != CUBEB_OK) {
LOG("Setting play params failed"); goto error;
}
s->play.floating = (output_stream_params->format == CUBEB_SAMPLE_FLOAT32NE);
s->play.frame_size = s->play.info.channels * (s->play.info.precision / 8);
s->play.bufframes = latency_frames;
oss_get_min_latency(context, *output_stream_params, &minframes); if (s->play.bufframes < minframes) {
s->play.bufframes = minframes;
}
} if (s->play.fd != -1) { int frag = oss_get_frag_params(
oss_calc_frag_shift(s->play.bufframes, s->play.frame_size)); if (ioctl(s->play.fd, SNDCTL_DSP_SETFRAGMENT, &frag))
LOG("Failed to set play fd with SNDCTL_DSP_SETFRAGMENT. frag: 0x%x",
frag);
audio_buf_info bi; if (ioctl(s->play.fd, SNDCTL_DSP_GETOSPACE, &bi))
LOG("Failed to get play fd's buffer info."); else {
s->play.bufframes = (bi.fragsize * bi.fragstotal) / s->play.frame_size;
} int lw;
/* * Force 32 ms service intervals at most, or when recording is * active, use the recording service intervals as a reference.
*/
s->play.maxframes = (32 * output_stream_params->rate) / 1000; if (s->record.fd != -1 || s->play.maxframes >= s->play.bufframes) {
lw = s->play.frame_size; /* Feed data when possible. */
s->play.maxframes = s->play.bufframes;
} else {
lw = (s->play.bufframes - s->play.maxframes) * s->play.frame_size;
} if (ioctl(s->play.fd, SNDCTL_DSP_LOW_WATER, &lw))
LOG("Audio device \"%s\" (play) could not set trigger threshold",
s->play.name);
} if (s->record.fd != -1) { int frag = oss_get_frag_params(
oss_calc_frag_shift(s->record.bufframes, s->record.frame_size)); if (ioctl(s->record.fd, SNDCTL_DSP_SETFRAGMENT, &frag))
LOG("Failed to set record fd with SNDCTL_DSP_SETFRAGMENT. frag: 0x%x",
frag);
audio_buf_info bi; if (ioctl(s->record.fd, SNDCTL_DSP_GETISPACE, &bi))
LOG("Failed to get record fd's buffer info."); else {
s->record.bufframes =
(bi.fragsize * bi.fragstotal) / s->record.frame_size;
}
s->record.maxframes = s->record.bufframes; int lw = s->record.frame_size; if (ioctl(s->record.fd, SNDCTL_DSP_LOW_WATER, &lw))
LOG("Audio device \"%s\" (record) could not set trigger threshold",
s->record.name);
}
s->context = context;
s->volume = 1.0;
s->state_cb = state_callback;
s->data_cb = data_callback;
s->user_ptr = user_ptr;
if (pthread_mutex_init(&s->mtx, NULL) != 0) {
LOG("Failed to create mutex"); goto error;
} if (pthread_cond_init(&s->doorbell_cv, NULL) != 0) {
LOG("Failed to create cv"); goto error;
} if (pthread_cond_init(&s->stopped_cv, NULL) != 0) {
LOG("Failed to create cv"); goto error;
}
s->doorbell = false;
if (s->play.fd != -1) { if ((s->play.buf = calloc(s->play.bufframes, s->play.frame_size)) == NULL) {
ret = CUBEB_ERROR; goto error;
}
} if (s->record.fd != -1) { if ((s->record.buf = calloc(s->record.bufframes, s->record.frame_size)) ==
NULL) {
ret = CUBEB_ERROR; goto error;
}
}
*stream = s; return CUBEB_OK;
error: if (s != NULL) {
oss_stream_destroy(s);
} return ret;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.17Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.