#include #include #include #include #include #include #include "mpg123.h" #include static void audio_set_format_helper(int fmt, audio_info_t *ainfo); static int audio_fd = -1; static int uptodate = 1; static int possible = 0; static audio_info_t ainfo; static void really_close_audio() { if (audio_fd != -1) close(audio_fd); } static void really_open_audio(struct audio_info_struct *ai) { if (audio_fd == -1) { audio_encoding_t cap; if(!ai->device) { if(getenv("AUDIODEV")) { if(param.verbose > 1) fprintf(stderr,"Using audio-device value from AUDIODEV environment variable!\n"); ai->device = getenv("AUDIODEV"); } else ai->device = "/dev/audio"; } audio_fd = open(ai->device, O_WRONLY); for (cap.index = 0; ioctl(audio_fd, AUDIO_GETENC, &cap) == 0; cap.index++) { if (cap.flags & AUDIO_ENCODINGFLAG_EMULATED) continue; switch(cap.encoding) { case AUDIO_ENCODING_ULAW: possible |= AUDIO_FORMAT_ULAW_8; break; case AUDIO_ENCODING_ALAW: possible |= AUDIO_FORMAT_ALAW_8; break; case AUDIO_ENCODING_SLINEAR: case AUDIO_ENCODING_SLINEAR_BE: case AUDIO_ENCODING_SLINEAR_LE: if (cap.precision == 8) possible |= AUDIO_FORMAT_SIGNED_8; else possible |= AUDIO_FORMAT_SIGNED_16; break; case AUDIO_ENCODING_ULINEAR: case AUDIO_ENCODING_ULINEAR_BE: case AUDIO_ENCODING_ULINEAR_LE: if (cap.precision == 8) possible |= AUDIO_FORMAT_UNSIGNED_8; else possible |= AUDIO_FORMAT_UNSIGNED_16; break; } } atexit(really_close_audio); } } int audio_open(struct audio_info_struct *ai) { really_open_audio(ai); ai->fn = audio_fd; if(ai->fn < 0) return ai->fn; AUDIO_INITINFO(&ainfo); uptodate = 0; { audio_device_t ad; if(ioctl(ai->fn, AUDIO_GETDEV, &ad) == -1) return -1; if(param.verbose > 1) fprintf(stderr,"Audio device type: %s\n",ad.name); } if(audio_reset_parameters(ai) < 0) { return -1; } if(ai->output > 0) ainfo.play.port = 0; if(ai->output & AUDIO_OUT_INTERNAL_SPEAKER) ainfo.play.port |= AUDIO_SPEAKER; if(ai->output & AUDIO_OUT_HEADPHONES) ainfo.play.port |= AUDIO_HEADPHONE; if(ai->output & AUDIO_OUT_LINE_OUT) ainfo.play.port |= AUDIO_LINE_OUT; return ai->fn; } int audio_reset_parameters(struct audio_info_struct *ai) { if(ai->rate != -1) ainfo.play.sample_rate = ai->rate; if(ai->channels >= 0) ainfo.play.channels = ai->channels; audio_set_format_helper(ai->format,&ainfo); uptodate = 0; return 0; } int audio_rate_best_match(struct audio_info_struct *ai) { audio_info_t ainfo; ainfo.play.sample_rate = ai->rate; if(ioctl(ai->fn, AUDIO_SETINFO, &ainfo) < 0) { ai->rate = 0; return 0; } if(ioctl(ai->fn, AUDIO_GETINFO, &ainfo) < 0) { return -1; } ai->rate = ainfo.play.sample_rate; uptodate = 1; return 0; } int audio_set_rate(struct audio_info_struct *ai) { audio_info_t ainfo; if(ai->rate != -1) { ainfo.play.sample_rate = ai->rate; uptodate = 0; return 0; } return -1; } int audio_set_channels(struct audio_info_struct *ai) { audio_info_t ainfo; ainfo.play.channels = ai->channels; uptodate = 0; return 0; } static void audio_set_format_helper(int fmt, audio_info_t *ainfo) { switch(fmt) { case -1: case AUDIO_FORMAT_SIGNED_16: default: ainfo->play.encoding = AUDIO_ENCODING_SLINEAR; ainfo->play.precision = 16; break; case AUDIO_FORMAT_UNSIGNED_16: ainfo->play.encoding = AUDIO_ENCODING_ULINEAR; ainfo->play.precision = 16; break; case AUDIO_FORMAT_UNSIGNED_8: ainfo->play.encoding = AUDIO_ENCODING_ULINEAR; ainfo->play.precision = 8; break; case AUDIO_FORMAT_SIGNED_8: ainfo->play.encoding = AUDIO_ENCODING_SLINEAR; ainfo->play.precision = 8; break; case AUDIO_FORMAT_ULAW_8: ainfo->play.encoding = AUDIO_ENCODING_ULAW; ainfo->play.precision = 8; break; case AUDIO_FORMAT_ALAW_8: ainfo->play.encoding = AUDIO_ENCODING_ALAW; ainfo->play.precision = 8; break; } } int audio_set_format(struct audio_info_struct *ai) { audio_set_format_helper(ai->format,&ainfo); uptodate = 0; return 0; } static int try_format(int fmt, struct audio_info_struct *ai) { audio_info_t ainfo; AUDIO_INITINFO(&ainfo); audio_set_format_helper(fmt, &ainfo); ainfo.play.sample_rate = ai->rate; ainfo.play.channels = ai->channels; if(ioctl(audio_fd, AUDIO_SETINFO, &ainfo) >= 0) return fmt; else return 0; } int audio_get_formats(struct audio_info_struct *ai) { int fmts = 0; really_open_audio(ai); if ((possible & AUDIO_FORMAT_SIGNED_16) == AUDIO_FORMAT_SIGNED_16) fmts |= try_format(AUDIO_FORMAT_SIGNED_16, ai); else if ((possible & AUDIO_FORMAT_UNSIGNED_16) == AUDIO_FORMAT_UNSIGNED_16) fmts |= try_format(AUDIO_FORMAT_UNSIGNED_16, ai); if ((possible & AUDIO_FORMAT_SIGNED_8) == AUDIO_FORMAT_SIGNED_8) fmts |= try_format(AUDIO_FORMAT_SIGNED_8, ai); else if ((possible & AUDIO_FORMAT_UNSIGNED_8) == AUDIO_FORMAT_UNSIGNED_8) fmts |= try_format(AUDIO_FORMAT_UNSIGNED_8, ai); if (!fmts && ((possible & AUDIO_FORMAT_ULAW_8) == AUDIO_FORMAT_ULAW_8)) fmts |= try_format(AUDIO_FORMAT_ULAW_8, ai); if (!fmts && ((possible & AUDIO_FORMAT_ALAW_8) == AUDIO_FORMAT_ALAW_8)) fmts |= try_format(AUDIO_FORMAT_ALAW_8, ai); return fmts; } int audio_play_samples(struct audio_info_struct *ai,unsigned char *buf,int len) { if (!uptodate) { uptodate = 1; ioctl(ai->fn, AUDIO_SETINFO, &ainfo); } return write(ai->fn,buf,len); } int audio_close(struct audio_info_struct *ai) { return 0; } void audio_queueflush (struct audio_info_struct *ai) { ioctl (ai->fn, AUDIO_FLUSH, 0); }