if (mixer_fd != -1)
close(mixer_fd); return CUBEB_OK;
fail:
if (mixer_fd != -1)
close(mixer_fd);
free(devinfop); return CUBEB_ERROR;
}
#endif
static int
oss_device_collection_destroy(cubeb * context,
cubeb_device_collection * collection)
{
size_t i;
for (i = 0; i < collection->count; i++) {
oss_free_cubeb_device_info_strings(&collection->device[i]);
}
free(collection->device);
collection->device = NULL;
collection->count = 0; return0;
}
staticunsigned int
oss_chn_from_cubeb(cubeb_channel chn)
{ switch (chn) { case CHANNEL_FRONT_LEFT: return CHID_L; case CHANNEL_FRONT_RIGHT: return CHID_R; case CHANNEL_FRONT_CENTER: return CHID_C; case CHANNEL_LOW_FREQUENCY: return CHID_LFE; case CHANNEL_BACK_LEFT: return CHID_LR; case CHANNEL_BACK_RIGHT: return CHID_RR; case CHANNEL_SIDE_LEFT: return CHID_LS; case CHANNEL_SIDE_RIGHT: return CHID_RS; default: return CHID_UNDEF;
}
}
staticunsigned long long
oss_cubeb_layout_to_chnorder(cubeb_channel_layout layout)
{ unsigned int i, nchns = 0; unsigned long long chnorder = 0;
for (i = 0; layout; i++, layout >>= 1) { unsigned long long chid = oss_chn_from_cubeb((layout & 1) << i);
if (chid == CHID_UNDEF) continue;
chnorder |= (chid & 0xf) << nchns * 4;
nchns++;
}
return chnorder;
}
static int
oss_copy_params(int fd, cubeb_stream * stream, cubeb_stream_params * params, struct stream_info * sinfo)
{ unsigned long long chnorder;
sinfo->channels = params->channels;
sinfo->sample_rate = params->rate; switch (params->format) { case CUBEB_SAMPLE_S16LE:
sinfo->fmt = AFMT_S16_LE;
sinfo->precision = 16; break; case CUBEB_SAMPLE_S16BE:
sinfo->fmt = AFMT_S16_BE;
sinfo->precision = 16; break; case CUBEB_SAMPLE_FLOAT32NE:
sinfo->fmt = AFMT_S32_NE;
sinfo->precision = 32; break; default:
LOG("Unsupported format"); return CUBEB_ERROR_INVALID_FORMAT;
}
if (ioctl(fd, SNDCTL_DSP_CHANNELS, &sinfo->channels) == -1) { return CUBEB_ERROR;
}
if (ioctl(fd, SNDCTL_DSP_SETFMT, &sinfo->fmt) == -1) { return CUBEB_ERROR;
}
if (ioctl(fd, SNDCTL_DSP_SPEED, &sinfo->sample_rate) == -1) { return CUBEB_ERROR;
} /* Mono layout is an exception */
if (params->layout != CUBEB_LAYOUT_UNDEFINED &&
params->layout != CUBEB_LAYOUT_MONO) {
chnorder = oss_cubeb_layout_to_chnorder(params->layout);
if (ioctl(fd, SNDCTL_DSP_SET_CHNORDER, &chnorder) == -1)
LOG("Non-fatal error %d occured when setting channel order.", errno);
} return CUBEB_OK;
}
if (poll(pfds, 2, 1000) == -1) { return CUBEB_ERROR;
}
for (i = 0; i < 2; i++) {
if (pfds[i].revents & POLLHUP) { return CUBEB_ERROR;
}
}
if (s->play.fd != -1) {
if (ioctl(s->play.fd, SNDCTL_DSP_GETOSPACE, &bi) == -1) { return CUBEB_STATE_ERROR;
}
tnfr = bi.bytes / s->play.frame_size;
if (tnfr <= 0) { /* too little space - stop polling record, if any */
pfds[0].fd = s->play.fd;
pfds[1].fd = -1;
goto retry;
} else if (tnfr > (long)s->play.maxframes) { /* too many frames available - limit */
tnfr = (long)s->play.maxframes;
}
if (nfr > tnfr) {
nfr = tnfr;
}
}
if (s->record.fd != -1) {
if (ioctl(s->record.fd, SNDCTL_DSP_GETISPACE, &bi) == -1) { return CUBEB_STATE_ERROR;
}
tnfr = bi.bytes / s->record.frame_size;
if (tnfr <= 0) { /* too little space - stop polling playback, if any */
pfds[0].fd = -1;
pfds[1].fd = s->record.fd;
goto retry;
} else if (tnfr > (long)s->record.maxframes) { /* too many frames available - limit */
tnfr = (long)s->record.maxframes;
}
if (nfr > tnfr) {
nfr = tnfr;
}
}
*nfrp = nfr; return0;
}
/* 1 - Stopped by cubeb_stream_stop, otherwise 0 */ static int
oss_audio_loop(cubeb_stream * s, cubeb_state * new_state)
{
cubeb_state state = CUBEB_STATE_STOPPED;
int trig = 0, drain = 0; constbool play_on = s->play.fd != -1, record_on = s->record.fd != -1;
long nfr = 0;
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) { /* *Stophereifthestreamisnotplay&recordstream, *play-onlystreamorrecord-onlystream
*/
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 { /* *Thisisarecord-onlystreamandnumberofframes *returnedfromdata_cb()issmallerthannumber *offramesrequiredtoread.Stophere.
*/
state = CUBEB_STATE_STOPPED;
goto breakdown;
}
}
static inline int
oss_calc_frag_shift(unsigned int frames, unsigned int frame_size)
{
int n = 4;
int blksize = frames * frame_size; while ((1 << n) < blksize) {
n++;
} return n;
}
static inline int
oss_get_frag_params(unsigned int shift)
{ return (OSS_NFRAGS << 16) | shift;
}
static int
oss_stream_init(cubeb * context, cubeb_stream ** stream,
char const * stream_name, cubeb_devid input_device,
cubeb_stream_params * input_stream_params,
cubeb_devid output_device,
cubeb_stream_params * output_stream_params, unsigned int latency_frames, cubeb_data_callback data_callback,
cubeb_state_callback state_callback, void * user_ptr)
{
int ret = CUBEB_OK;
cubeb_stream * s = NULL; const char * defdsp;
if (input_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(input_stream_params->layout);
if (input_stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
nb_channels != input_stream_params->channels) {
LOG("input_stream_params->layout does not match " "input_stream_params->channels");
ret = CUBEB_ERROR_INVALID_PARAMETER;
goto error;
}
if ((s->record.fd = open(s->record.name, O_RDONLY)) == -1) {
LOG("Audio device \"%s\" could not be opened as read-only",
s->record.name);
ret = CUBEB_ERROR_DEVICE_UNAVAILABLE;
goto error;
}
if ((ret = oss_copy_params(s->record.fd, s, input_stream_params,
&s->record.info)) != CUBEB_OK) {
LOG("Setting record params failed");
goto error;
}
s->record.floating =
(input_stream_params->format == CUBEB_SAMPLE_FLOAT32NE);
s->record.frame_size =
s->record.info.channels * (s->record.info.precision / 8);
s->record.bufframes = latency_frames;
oss_get_min_latency(context, *input_stream_params, &minframes);
if (s->record.bufframes < minframes) {
s->record.bufframes = minframes;
}
}
if (output_stream_params != NULL) { unsigned int nb_channels;
uint32_t minframes;
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;
/* *Force32msserviceintervalsatmost,orwhenrecordingis *active,usetherecordingserviceintervalsasareference.
*/
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;
}
static int
oss_stream_thr_create(cubeb_stream * s)
{
if (s->thread_created) {
s->doorbell = true;
pthread_cond_signal(&s->doorbell_cv); return CUBEB_OK;
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.22Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-27)
¤
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.