/* * OpenSound media addon for BeOS and Haiku * * Copyright (c) 2007, François Revol (revol@free.fr) * Distributed under the terms of the MIT License. */ #include "OpenSoundDeviceEngine.h" #include "debug.h" #include "driver_io.h" #include #include #include #include #include "SupportFunctions.h" OpenSoundDeviceEngine::~OpenSoundDeviceEngine() { CALLED(); if (fFD != 0) { close(fFD); } } OpenSoundDeviceEngine::OpenSoundDeviceEngine(oss_audioinfo *info) : fNextPlay(NULL) , fNextRec(NULL) , fOpenMode(0) , fFD(-1) , fMediaFormat() , fDriverBufferSize(0) { CALLED(); fInitCheckStatus = B_NO_INIT; memcpy(&fAudioInfo, info, sizeof(oss_audioinfo)); // XXX:REMOVEME // set default format /* SetFormat(OpenSoundDevice::select_oss_format(info->oformats)); SetChannels(info->max_channels); SetSpeed(info->max_rate); */ fInitCheckStatus = B_OK; } status_t OpenSoundDeviceEngine::InitCheck(void) const { CALLED(); return fInitCheckStatus; } status_t OpenSoundDeviceEngine::Open(int mode) { int omode, v; CALLED(); switch (mode) { case OPEN_READ: if (!(Caps() & DSP_CAP_INPUT)) return EINVAL; omode = O_RDONLY; break; case OPEN_WRITE: if (!(Caps() & DSP_CAP_OUTPUT)) return EINVAL; omode = O_WRONLY; break; case OPEN_READWRITE: if (!(Caps() & DSP_CAP_OUTPUT) || !(Caps() & DSP_CAP_INPUT)) return EINVAL; omode = O_RDWR; break; default: return EINVAL; } // O_EXCL = bypass soft mixer = direct access omode |= O_EXCL; Close(); fOpenMode = mode; fFD = open(fAudioInfo.devnode, omode); if (fFD < 0) { fInitCheckStatus = errno; return EIO; } // disable format convertions v = 0; if (ioctl(fFD, SNDCTL_DSP_COOKEDMODE, &v, sizeof(int)) < 0) { fInitCheckStatus = errno; Close(); return EIO; } // set driver buffer size by using the "fragments" API // TODO: export this setting as a BParameter? uint32 bufferCount = 4; uint32 bufferSize = 0x000b; // 1024 bytes v = (bufferCount << 16) | bufferSize; if (ioctl(fFD, SNDCTL_DSP_SETFRAGMENT, &v, sizeof(int)) < 0) { fInitCheckStatus = errno; Close(); return EIO; } fDriverBufferSize = 2048; // preliminary, adjusted in AcceptFormat() return B_OK; } status_t OpenSoundDeviceEngine::Close(void) { CALLED(); if (fFD > -1) close(fFD); fFD = -1; fOpenMode = 0; fMediaFormat = media_format(); return B_OK; } ssize_t OpenSoundDeviceEngine::Read(void *buffer, size_t size) { ssize_t done; CALLED(); done = read(fFD, buffer, size); if (done < 0) return errno; return done; } ssize_t OpenSoundDeviceEngine::Write(const void *buffer, size_t size) { CALLED(); ASSERT(size > 0); ssize_t done = write(fFD, buffer, size); if (done < 0) return errno; return done; } status_t OpenSoundDeviceEngine::UpdateInfo() { CALLED(); if (fFD < 0) return ENODEV; if (ioctl(fFD, SNDCTL_ENGINEINFO, &fAudioInfo, sizeof(oss_audioinfo)) < 0) return errno; return B_OK; } bigtime_t OpenSoundDeviceEngine::PlaybackLatency() { bigtime_t latency = time_for_buffer(fDriverBufferSize, fMediaFormat); bigtime_t cardLatency = CardLatency(); if (cardLatency == 0) { // that's unrealistic, take matters into own hands cardLatency = latency / 3; } latency += cardLatency; // PRINT(("PlaybackLatency: odelay %d latency %lld card %lld\n", // fDriverBufferSize, latency, CardLatency())); return latency; } bigtime_t OpenSoundDeviceEngine::RecordingLatency() { return 0LL; //XXX } int OpenSoundDeviceEngine::GetChannels(void) { int chans = -1; CALLED(); if (ioctl(fFD, SNDCTL_DSP_CHANNELS, &chans, sizeof(int)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_CHANNELS", strerror(errno))); return -1; } return chans; } status_t OpenSoundDeviceEngine::SetChannels(int chans) { CALLED(); if (ioctl(fFD, SNDCTL_DSP_CHANNELS, &chans, sizeof(int)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_CHANNELS", strerror(errno))); return EIO; } PRINT(("OpenSoundDeviceEngine::%s: %d\n", __FUNCTION__, chans)); return B_OK; } //XXX: either GetFormat*s*() or cache SetFormat()! int OpenSoundDeviceEngine::GetFormat(void) { int fmt = -1; CALLED(); if (ioctl(fFD, SNDCTL_DSP_GETFMTS, &fmt, sizeof(int)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_GETFMTS", strerror(errno))); return -1; } return fmt; } status_t OpenSoundDeviceEngine::SetFormat(int fmt) { CALLED(); if (ioctl(fFD, SNDCTL_DSP_SETFMT, &fmt, sizeof(int)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_SETFMT", strerror(errno))); return EIO; } PRINT(("OpenSoundDeviceEngine::%s: 0x%08x\n", __FUNCTION__, fmt)); return B_OK; } int OpenSoundDeviceEngine::GetSpeed(void) { int speed = -1; CALLED(); if (ioctl(fFD, SNDCTL_DSP_SPEED, &speed, sizeof(int)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_SPEED", strerror(errno))); return -1; } return speed; } status_t OpenSoundDeviceEngine::SetSpeed(int speed) { CALLED(); if (ioctl(fFD, SNDCTL_DSP_SPEED, &speed, sizeof(int)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_SPEED", strerror(errno))); return EIO; } PRINT(("OpenSoundDeviceEngine::%s: %d\n", __FUNCTION__, speed)); return B_OK; } size_t OpenSoundDeviceEngine::GetISpace(audio_buf_info *info) { audio_buf_info abinfo; CALLED(); if (!info) info = &abinfo; memset(info, 0, sizeof(audio_buf_info)); if (!(fOpenMode & OPEN_READ)) return 0; if (ioctl(fFD, SNDCTL_DSP_GETISPACE, info, sizeof(audio_buf_info)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_GETISPACE", strerror(errno))); return EIO; } //PRINT(("OpenSoundDeviceEngine::%s: ISPACE: { bytes=%d, fragments=%d, fragsize=%d, fragstotal=%d }\n", __FUNCTION__, info->bytes, info->fragments, info->fragsize, info->fragstotal)); return info->bytes; } size_t OpenSoundDeviceEngine::GetOSpace(audio_buf_info *info) { audio_buf_info abinfo; //CALLED(); if (!info) info = &abinfo; memset(info, 0, sizeof(audio_buf_info)); if (!(fOpenMode & OPEN_WRITE)) return 0; if (ioctl(fFD, SNDCTL_DSP_GETOSPACE, info, sizeof(audio_buf_info)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_GETOSPACE", strerror(errno))); return EIO; } //PRINT(("OpenSoundDeviceEngine::%s: OSPACE: { bytes=%d, fragments=%d, fragsize=%d, fragstotal=%d }\n", __FUNCTION__, info->bytes, info->fragments, info->fragsize, info->fragstotal)); return info->bytes; } int64 OpenSoundDeviceEngine::GetCurrentIPtr(int32 *fifoed, oss_count_t *info) { oss_count_t ocount; count_info cinfo; CALLED(); if (!info) info = &ocount; memset(info, 0, sizeof(oss_count_t)); if (!(fOpenMode & OPEN_READ)) return 0; if (ioctl(fFD, SNDCTL_DSP_CURRENT_IPTR, info, sizeof(oss_count_t)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_CURRENT_IPTR", strerror(errno))); //return EIO; // fallback: try GET*PTR if (ioctl(fFD, SNDCTL_DSP_GETIPTR, &cinfo, sizeof(count_info)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_GETIPTR", strerror(errno))); return 0; } // it's probably wrong... info->samples = cinfo.bytes / (fMediaFormat.u.raw_audio.channel_count * (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK)); info->fifo_samples = 0; } PRINT(("OpenSoundDeviceEngine::%s: IPTR: { samples=%lld, fifo_samples=%d }\n", __FUNCTION__, info->samples, info->fifo_samples)); if (fifoed) *fifoed = info->fifo_samples; return info->samples; } int64 OpenSoundDeviceEngine::GetCurrentOPtr(int32* fifoed, size_t* fragmentPos) { CALLED(); if (!(fOpenMode & OPEN_WRITE)) { if (fifoed != NULL) *fifoed = 0; return 0; } oss_count_t info; memset(&info, 0, sizeof(oss_count_t)); if (ioctl(fFD, SNDCTL_DSP_CURRENT_OPTR, &info, sizeof(oss_count_t)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_CURRENT_OPTR", strerror(errno))); return 0; } if (fragmentPos != NULL) { count_info cinfo; if (ioctl(fFD, SNDCTL_DSP_GETOPTR, &cinfo, sizeof(count_info)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_GETOPTR", strerror(errno))); return 0; } *fragmentPos = cinfo.ptr; } // PRINT(("OpenSoundDeviceEngine::%s: OPTR: { samples=%lld, " // "fifo_samples=%d }\n", __FUNCTION__, info->samples, // info->fifo_samples)); if (fifoed != NULL) *fifoed = info.fifo_samples; return info.samples; } int32 OpenSoundDeviceEngine::GetIOverruns() { audio_errinfo info; CALLED(); memset(&info, 0, sizeof(info)); if (!(fOpenMode & OPEN_WRITE)) return 0; if (ioctl(fFD, SNDCTL_DSP_GETERROR, &info, sizeof(info)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_GETERROR", strerror(errno))); return 0; } PRINT(("OpenSoundDeviceEngine::%s: IOVERRUNS: { overruns=%d }\n", __FUNCTION__, info.rec_overruns)); return info.rec_overruns; } int32 OpenSoundDeviceEngine::GetOUnderruns() { audio_errinfo info; CALLED(); memset(&info, 0, sizeof(info)); if (!(fOpenMode & OPEN_WRITE)) return 0; if (ioctl(fFD, SNDCTL_DSP_GETERROR, &info, sizeof(info)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_GETERROR", strerror(errno))); return 0; } //PRINT(("OpenSoundDeviceEngine::%s: OUNDERRUNS: { underruns=%d }\n", __FUNCTION__, info.play_underruns)); return info.play_underruns; } size_t OpenSoundDeviceEngine::DriverBufferSize() const { return fDriverBufferSize; } status_t OpenSoundDeviceEngine::StartRecording(void) { CALLED(); oss_syncgroup group; group.id = 0; group.mode = PCM_ENABLE_INPUT; if (ioctl(fFD, SNDCTL_DSP_SYNCGROUP, &group, sizeof(group)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_SYNCGROUP", strerror(errno))); return EIO; } if (ioctl(fFD, SNDCTL_DSP_SYNCSTART, &group.id, sizeof(group.id)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_SYNCSTART", strerror(errno))); return EIO; } return B_OK; } status_t OpenSoundDeviceEngine::WildcardFormatFor(int fmt, media_format &format, bool rec) { status_t err; CALLED(); fmt &= rec ? Info()->iformats : Info()->oformats; if (fmt == 0) return B_MEDIA_BAD_FORMAT; err = OpenSoundDevice::get_media_format_for(fmt, format); if (err < B_OK) return err; char buf[1024]; string_for_format(format, buf, 1024); if (format.type == B_MEDIA_RAW_AUDIO) { format.u.raw_audio = media_multi_audio_format::wildcard; format.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; // single rate supported if (Info()->min_rate == Info()->max_rate) format.u.raw_audio.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz } else if (format.type == B_MEDIA_ENCODED_AUDIO) { format.u.encoded_audio.output = media_multi_audio_format::wildcard; //format.u.encoded_audio.output.byte_order = B_MEDIA_HOST_ENDIAN; // single rate supported //if (Info()->min_rate == Info()->max_rate) // format.u.encoded_audio.output.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz } else return EINVAL; PRINT(("%s: %s\n", __FUNCTION__, buf)); return B_OK; } status_t OpenSoundDeviceEngine::PreferredFormatFor(int fmt, media_format &format, bool rec) { status_t err; CALLED(); fmt &= rec ? Info()->iformats : Info()->oformats; if (fmt == 0) return B_MEDIA_BAD_FORMAT; err = WildcardFormatFor(fmt, format); if (err < B_OK) return err; if (format.type == B_MEDIA_RAW_AUDIO) { media_multi_audio_format &raw = format.u.raw_audio; //format.u.raw_audio.channel_count = Info()->max_channels; raw.byte_order = B_MEDIA_HOST_ENDIAN; raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz raw.buffer_size = DEFAULT_BUFFER_SIZE; /*if (rec) raw.buffer_size = 2048;*/ /* format.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; format.u.raw_audio.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz format.u.raw_audio.buffer_size = DEFAULT_BUFFER_SIZE; */ } else if (format.type == B_MEDIA_ENCODED_AUDIO) { media_raw_audio_format &raw = format.u.encoded_audio.output; //format.u.encoded_audio.output.channel_count = Info()->max_channels; raw.byte_order = B_MEDIA_HOST_ENDIAN; // single rate supported if (Info()->min_rate == Info()->max_rate) raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz raw.buffer_size = DEFAULT_BUFFER_SIZE; } else return EINVAL; char buf[1024]; string_for_format(format, buf, 1024); PRINT(("%s: %s\n", __FUNCTION__, buf)); return B_OK; } status_t OpenSoundDeviceEngine::AcceptFormatFor(int fmt, media_format &format, bool rec) { status_t err; int afmt = 0; char buf[1024]; CALLED(); fmt &= rec ? Info()->iformats : Info()->oformats; if (fmt == 0) return B_MEDIA_BAD_FORMAT; media_format wc; err = WildcardFormatFor(fmt, wc); if (err < B_OK) return err; err = Open(rec ? OPEN_READ : OPEN_WRITE); if (err < B_OK) return err; if (format.type == B_MEDIA_RAW_AUDIO) { media_multi_audio_format &raw = format.u.raw_audio; // channel count raw.channel_count = MAX((unsigned)(Info()->min_channels), MIN((unsigned)(Info()->max_channels), raw.channel_count)); err = SetChannels(raw.channel_count); if (err < B_OK) { Close(); return err; } PRINT(("%s:step1 fmt=0x%08x, raw.format=0x%08" B_PRIx32 "\n", __FUNCTION__, fmt, raw.format)); // if specified, try it if (raw.format) afmt = OpenSoundDevice::convert_media_format_to_oss_format(raw.format); afmt &= fmt; PRINT(("%s:step2 afmt=0x%08x\n", __FUNCTION__, afmt)); // select the best as default if (afmt == 0) { afmt = OpenSoundDevice::select_oss_format(fmt); raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt); //Close(); //return B_MEDIA_BAD_FORMAT; } PRINT(("%s:step3 afmt=0x%08x\n", __FUNCTION__, afmt)); // convert back raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt); PRINT(("%s:step4 afmt=0x%08x, raw.format=0x%08" B_PRIx32 "\n", __FUNCTION__, afmt, raw.format)); raw.valid_bits = OpenSoundDevice::convert_oss_format_to_valid_bits(afmt); err = SetFormat(afmt); if (err < B_OK) { Close(); return err; } // endianness raw.byte_order = OpenSoundDevice::convert_oss_format_to_endian(afmt); // sample rate raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz err = SetSpeed(OpenSoundDevice::convert_media_rate_to_oss_rate(raw.frame_rate)); if (err < B_OK) { Close(); return err; } // retrieve the driver buffer size (it's important to do this // after all the other setup, since OSS may have adjusted it, and // also weird things happen if this ioctl() is done before other // setup itctl()s) audio_buf_info abinfo; memset(&abinfo, 0, sizeof(audio_buf_info)); if (ioctl(fFD, SNDCTL_DSP_GETOSPACE, &abinfo, sizeof(audio_buf_info)) < 0) { fprintf(stderr, "failed to retrieve driver buffer size!\n"); abinfo.bytes = 0; } fDriverBufferSize = abinfo.bytes; raw.buffer_size = fDriverBufferSize; } else if (format.type == B_MEDIA_ENCODED_AUDIO) { media_raw_audio_format &raw = format.u.encoded_audio.output; // XXX: do we really have to do this ? raw.channel_count = MAX((unsigned)(Info()->min_channels), MIN((unsigned)(Info()->max_channels), raw.channel_count)); raw.byte_order = B_MEDIA_HOST_ENDIAN; raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz raw.buffer_size = DEFAULT_BUFFER_SIZE; } else { PRINT(("%s: unknown media type\n", __FUNCTION__)); Close(); return EINVAL; } // cache it fMediaFormat = format; string_for_format(format, buf, 1024); PRINT(("%s: %s\n", __FUNCTION__, buf)); return B_OK; } status_t OpenSoundDeviceEngine::SpecializeFormatFor(int fmt, media_format &format, bool rec) { status_t err; int afmt = 0; CALLED(); fmt &= rec ? Info()->iformats : Info()->oformats; if (fmt == 0) return B_MEDIA_BAD_FORMAT; media_format wc; err = WildcardFormatFor(fmt, wc); if (err < B_OK) return err; err = Open(rec ? OPEN_READ : OPEN_WRITE); if (err < B_OK) return err; if (format.type == B_MEDIA_RAW_AUDIO) { media_multi_audio_format &raw = format.u.raw_audio; PRINT(("%s:step1 fmt=0x%08x, raw.format=0x%08" B_PRIx32 "\n", __FUNCTION__, fmt, raw.format)); // select the best as default if (!raw.format) { afmt = OpenSoundDevice::select_oss_format(fmt); raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt); } // if specified, try it if (raw.format) afmt = OpenSoundDevice::convert_media_format_to_oss_format(raw.format); afmt &= fmt; PRINT(("%s:step2 afmt=0x%08x\n", __FUNCTION__, afmt)); if (afmt == 0) { Close(); return B_MEDIA_BAD_FORMAT; } // convert back raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt); PRINT(("%s:step4 afmt=0x%08x, raw.format=0x%08" B_PRIx32 "\n", __FUNCTION__, afmt, raw.format)); if (!raw.valid_bits) raw.valid_bits = OpenSoundDevice::convert_oss_format_to_valid_bits(afmt); if (raw.valid_bits != OpenSoundDevice::convert_oss_format_to_valid_bits(afmt)) { Close(); return B_MEDIA_BAD_FORMAT; } err = SetFormat(afmt); if (err < B_OK) { Close(); return err; } // endianness if (!raw.byte_order) raw.byte_order = OpenSoundDevice::convert_oss_format_to_endian(afmt); if ((int)raw.byte_order != OpenSoundDevice::convert_oss_format_to_endian(afmt)) { Close(); return B_MEDIA_BAD_FORMAT; } // channel count if (raw.channel_count == 0) raw.channel_count = (unsigned)Info()->min_channels; if ((int)raw.channel_count < Info()->min_channels || (int)raw.channel_count > Info()->max_channels) return B_MEDIA_BAD_FORMAT; err = SetChannels(raw.channel_count); if (err < B_OK) { Close(); return err; } // sample rate if (!raw.frame_rate) raw.frame_rate = Info()->max_rate; //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz err = SetSpeed(OpenSoundDevice::convert_media_rate_to_oss_rate(raw.frame_rate)); if (err < B_OK) { Close(); return err; } #if 0 raw.buffer_size = DEFAULT_BUFFER_SIZE * (raw.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) * raw.channel_count; #endif audio_buf_info abinfo; if (ioctl(fFD, rec?SNDCTL_DSP_GETISPACE:SNDCTL_DSP_GETOSPACE, &abinfo, sizeof(abinfo)) < 0) { PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", __FUNCTION__, "SNDCTL_DSP_GET?SPACE", strerror(errno))); return -1; } PRINT(("OSS: %cSPACE: { bytes=%d, fragments=%d, fragsize=%d, fragstotal=%d }\n", rec?'I':'O', abinfo.bytes, abinfo.fragments, abinfo.fragsize, abinfo.fragstotal)); // cache the first one in the Device // so StartThread() knows the number of frags //if (!fFragments.fragstotal) // memcpy(&fFragments, &abinfo, sizeof(abinfo)); // make sure buffer size is less than the driver's own buffer ( /2 to keep some margin ) if (/*rec && raw.buffer_size &&*/ (int)raw.buffer_size > abinfo.fragsize * abinfo.fragstotal / 4) return B_MEDIA_BAD_FORMAT; if (!raw.buffer_size) raw.buffer_size = abinfo.fragsize;//XXX /* * (raw.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) * raw.channel_count;*/ } else if (format.type == B_MEDIA_ENCODED_AUDIO) { media_raw_audio_format &raw = format.u.encoded_audio.output; // XXX: do we really have to do this ? raw.channel_count = MAX((unsigned)(Info()->min_channels), MIN((unsigned)(Info()->max_channels), raw.channel_count)); raw.byte_order = B_MEDIA_HOST_ENDIAN; raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz raw.buffer_size = DEFAULT_BUFFER_SIZE; } else { Close(); return EINVAL; } // cache it fMediaFormat = format; char buf[1024]; string_for_format(format, buf, 1024); PRINT(("%s: %s\n", __FUNCTION__, buf)); return B_OK; }