📄 audio.c
字号:
*outptr++ = \ (sample_type) \ ((inptr[((x1 >> 12) << 1) + 1] * \ ((1<<12) - frac) + \ inptr[(((x1 >> 12) + 1) << 1) + 1] * \ frac) >> 12); \ x += delta; \ } \ if (NOT_NATIVE_ENDIAN) \ swap_endian(nbuffer, nlen); \ w = write_all(fd, nbuffer, nlen); \} while (0)#define RESAMPLE_MONO(sample_type) \do { \ const gint shift = sizeof (sample_type) - 1; \ gint i, x, delta, in_samples, out_samples; \ sample_type *inptr = (sample_type *)ob, *outptr; \ guint nlen = (((length >> shift) * espeed) / speed); \ if (nlen == 0) \ break; \ nlen <<= shift; \ if (NOT_NATIVE_ENDIAN) \ swap_endian(ob, length); \ if(nlen > nbuffer_size) \ { \ nbuffer = g_realloc(nbuffer, nlen); \ nbuffer_size = nlen; \ } \ outptr = (sample_type *)nbuffer; \ in_samples = length >> shift; \ out_samples = nlen >> shift; \ delta = ((length >> shift) << 12) / out_samples; \ for (x = 0, i = 0; i < out_samples; i++) \ { \ gint x1, frac; \ x1 = (x >> 12) << 12; \ frac = x - x1; \ *outptr++ = \ (sample_type) \ ((inptr[x1 >> 12] * ((1<<12) - frac) + \ inptr[(x1 >> 12) + 1] * frac) >> 12); \ x += delta; \ } \ if (NOT_NATIVE_ENDIAN) \ swap_endian(nbuffer, nlen); \ w = write_all(fd, nbuffer, nlen); \} while (0)static gint oss_downsample(gpointer ob, guint length, guint speed, guint espeed){ guint w = 0; static gpointer nbuffer = NULL; static gint nbuffer_size = 0; switch (output.format.oss) { case AFMT_S16_BE: case AFMT_S16_LE: if (output.channels == 2) RESAMPLE_STEREO(gint16); else RESAMPLE_MONO(gint16); break; case AFMT_U16_BE: case AFMT_U16_LE: if (output.channels == 2) RESAMPLE_STEREO(guint16); else RESAMPLE_MONO(guint16); break; case AFMT_S8: if (output.channels == 2) RESAMPLE_STEREO(gint8); else RESAMPLE_MONO(gint8); break; case AFMT_U8: if (output.channels == 2) RESAMPLE_STEREO(guint8); else RESAMPLE_MONO(guint8); break; } return w;}void oss_write(gpointer ptr, int length){ int cnt, off = 0; if (!realtime) { remove_prebuffer = FALSE; written += length; while (length > 0) { cnt = MIN(length, buffer_size - wr_index); memcpy(buffer + wr_index, (char *)ptr + off, cnt); wr_index = (wr_index + cnt) % buffer_size; length -= cnt; off += cnt; } } else { if (paused) return; oss_write_audio(ptr, length); written += length; }}void oss_close(void){ if (!going) return; going = 0; if (!realtime) pthread_join(buffer_thread, NULL); else { ioctl(fd, SNDCTL_DSP_RESET, 0); close(fd); } g_free(device_name); oss_free_convert_buffer(); wr_index = 0; rd_index = 0;}void oss_flush(gint time){ if (!realtime) { flush = time; while (flush != -1) xmms_usleep(10000); } else { ioctl(fd, SNDCTL_DSP_RESET, 0); close(fd); fd = open(device_name, O_WRONLY); oss_set_audio_params(); output_time_offset = time; written = ((guint64)time * input.bps) / 1000; output_bytes = 0; }}void oss_pause(short p){ if (!realtime) { if (p == TRUE) do_pause = TRUE; else unpause = TRUE; } else paused = p;}void *oss_loop(void *arg){ gint length, cnt; fd_set set; struct timeval tv; while (going) { if (oss_used() > prebuffer_size) prebuffer = FALSE; if (oss_used() > 0 && !paused && !prebuffer) { tv.tv_sec = 0; tv.tv_usec = 10000; FD_ZERO(&set); FD_SET(fd, &set); if(!select_works || (select(fd + 1, NULL, &set, NULL, &tv) > 0)) { length = MIN(blk_size, oss_used()); while (length > 0) { cnt = MIN(length,buffer_size-rd_index); oss_write_audio(buffer + rd_index, cnt); rd_index=(rd_index+cnt)%buffer_size; length-=cnt; } if (!oss_used()) ioctl(fd, SNDCTL_DSP_POST, 0); } } else xmms_usleep(10000); oss_calc_device_buffer_used(); if (do_pause && !paused) { do_pause = FALSE; paused = TRUE; /* * We lose some data here that is sent to the * soundcard, but not yet played. I don't * think this is worth fixing. */ ioctl(fd, SNDCTL_DSP_RESET, 0); } else if (unpause && paused) { unpause = FALSE; close(fd); fd = open(device_name, O_WRONLY); oss_set_audio_params(); paused = FALSE; } if (flush != -1) { /* * This close and open is a work around of a * bug that exists in some drivers which cause * the driver to get fucked up by a reset */ ioctl(fd, SNDCTL_DSP_RESET, 0); close(fd); fd = open(device_name, O_WRONLY); oss_set_audio_params(); output_time_offset = flush; written = ((guint64)flush * input.bps) / 1000; rd_index = wr_index = output_bytes = 0; flush = -1; prebuffer = TRUE; } } ioctl(fd, SNDCTL_DSP_RESET, 0); close(fd); g_free(buffer); pthread_exit(NULL);}void oss_set_audio_params(void){ int frag, stereo, ret; struct timeval tv; fd_set set; ioctl(fd, SNDCTL_DSP_RESET, 0); frag = (NFRAGS << 16) | fragsize; ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag); /* * Set the stream format. This ioctl() might fail, but should * return a format that works if it does. */ ioctl(fd, SNDCTL_DSP_SETFMT, &output.format.oss); if (ioctl(fd, SNDCTL_DSP_SETFMT, &output.format.oss) == -1) g_warning("SNDCTL_DSP_SETFMT ioctl failed: %s", strerror(errno)); stereo = output.channels - 1; ioctl(fd, SNDCTL_DSP_STEREO, &stereo); output.channels = stereo + 1; oss_stereo_convert_func = oss_get_stereo_convert_func(output.channels, effect.channels); if (ioctl(fd, SNDCTL_DSP_SPEED, &output.frequency) == -1) g_warning("SNDCTL_DSP_SPEED ioctl failed: %s", strerror(errno)); if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blk_size) == -1) blk_size = 1L << fragsize; oss_convert_func = oss_get_convert_func(output.format.oss, oss_get_format(effect.format.xmms)); /* * Stupid hack to find out if the driver support selects, some * drivers won't work properly without a select and some won't * work with a select :/ */ tv.tv_sec = 0; tv.tv_usec = 50000; FD_ZERO(&set); FD_SET(fd, &set); ret = select(fd + 1, NULL, &set, NULL, &tv); if (ret > 0) select_works = TRUE; else select_works = FALSE;}gint oss_open(AFormat fmt, gint rate, gint nch){ if (oss_cfg.use_alt_audio_device && oss_cfg.alt_audio_device) device_name = g_strdup(oss_cfg.alt_audio_device); else { if (oss_cfg.audio_device > 0) device_name = g_strdup_printf("%s%d", DEV_DSP, oss_cfg.audio_device); else device_name = g_strdup(DEV_DSP); } fd = open(device_name, O_WRONLY); if (fd == -1) { g_warning("oss_open(): Failed to open audio device (%s): %s", device_name, strerror(errno)); g_free(device_name); return 0; } input.format.xmms = fmt; input.frequency = rate; input.channels = nch; input.bps = oss_calc_bitrate(oss_get_format(fmt), rate, nch); oss_setup_format(fmt, rate, nch); realtime = xmms_check_realtime_priority(); if(!realtime) { buffer_size = (oss_cfg.buffer_size * input.bps) / 1000; if (buffer_size < 8192) buffer_size = 8192; prebuffer_size = (buffer_size * oss_cfg.prebuffer) / 100; if (buffer_size - prebuffer_size < 4096) prebuffer_size = buffer_size - 4096; buffer_size += device_buffer_size; buffer = g_malloc0(buffer_size); } flush = -1; prebuffer = TRUE; wr_index = rd_index = output_time_offset = written = output_bytes = 0; paused = FALSE; do_pause = FALSE; unpause = FALSE; remove_prebuffer = FALSE; going = 1; if (!realtime) pthread_create(&buffer_thread, NULL, oss_loop, NULL); return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -