Fix and force USB audio driver to work with new OHCI module

* some functionality like recording temporarily disabled;
* set the endpoint speed call added;
* packet size hard-coded for 48kHz case;
* draft support for formats and sampling rate handling;
* implement sampling rate change on the fly;
* optimized using of starting frame;
* fix user_memory in buffer exchaqnge call;
* fix exchanged buffer recoriding processing;
* debug tweaks, fix current buffer switching;
* cleanup, cleanup, cleanup...
This commit is contained in:
Siarzhuk Zharski
2013-08-18 14:48:11 +02:00
parent 291e40c309
commit 2cc4703b91
6 changed files with 447 additions and 201 deletions
@@ -11,6 +11,29 @@
#include "audio.h"
static struct RatePair {
uint32 rate;
uint32 rateId;
} ratesMap[] = {
{ 8000, B_SR_8000 },
{ 11025, B_SR_11025 },
{ 12000, B_SR_12000 },
{ 16000, B_SR_16000 },
{ 22050, B_SR_22050 },
{ 24000, B_SR_24000 },
{ 32000, B_SR_32000 },
{ 44100, B_SR_44100 },
{ 48000, B_SR_48000 },
{ 64000, B_SR_64000 },
{ 88200, B_SR_88200 },
{ 96000, B_SR_96000 },
{ 176400, B_SR_176400 },
{ 192000, B_SR_192000 },
{ 384000, B_SR_384000 },
{ 1536000, B_SR_1536000 }
};
//
// Audio Stream information entities
//
@@ -44,28 +67,31 @@ ASInterfaceDescriptor::~ASInterfaceDescriptor()
ASEndpointDescriptor::ASEndpointDescriptor(usb_endpoint_descriptor* Endpoint,
usb_as_cs_endpoint_descriptor* Descriptor)
:
fAttributes(0),
fCSAttributes(0),
fLockDelayUnits(0),
fLockDelay(0),
fMaxPacketSize(0),
fEndpointAddress(0)
fEndpointAddress(0),
fEndpointAttributes(0)
{
// usb_audiocontrol_header_descriptor *Header
// = (usb_audiocontrol_header_descriptor *)Interface->generic[i];
fAttributes = Descriptor->attributes;
fCSAttributes = Descriptor->attributes;
fLockDelayUnits = Descriptor->lock_delay_units;
fLockDelay = Descriptor->lock_delay;
// usb_endpoint_descriptor* endpoint = Interface->endpoint[0]->descr;
fEndpointAttributes = Endpoint->attributes;
fEndpointAddress = Endpoint->endpoint_address;
fMaxPacketSize = Endpoint->max_packet_size;
TRACE("fAttributes:%d\n", fAttributes);
TRACE("fCSAttributes:%d\n", fCSAttributes);
TRACE("fLockDelayUnits:%d\n", fLockDelayUnits);
TRACE("fLockDelay:%d\n", fLockDelay);
TRACE("fMaxPacketSize:%d\n", fMaxPacketSize);
TRACE("fEndpointAddress:%#02x\n", fEndpointAddress);
TRACE("fEndpointAttributes:%d\n", fEndpointAttributes);
}
@@ -186,8 +212,10 @@ AudioStreamAlternate::AudioStreamAlternate(size_t alternate,
fAlternate(alternate),
fInterface(interface),
fEndpoint(endpoint),
fFormat(format)
fFormat(format),
fSamplingRate(0)
{
// SetSamplingRate(0); // init to default (max) sampling rate
}
@@ -199,6 +227,166 @@ AudioStreamAlternate::~AudioStreamAlternate()
}
status_t
AudioStreamAlternate::SetSamplingRate(uint32 newRate)
{
TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(Format());
if (format == NULL) {
TRACE_ALWAYS("Format not set for active alternate\n");
return B_NO_INIT;
}
Vector<uint32>& frequencies = format->fSampleFrequencies;
bool continuous = format->fSampleFrequencyType == 0;
if (newRate == 0) { // by default select max available
fSamplingRate = 0;
if (continuous)
fSamplingRate = max_c(frequencies[0], frequencies[1]);
else
for (int i = 0; i < frequencies.Count(); i++)
fSamplingRate = max_c(fSamplingRate, frequencies[i]);
} else {
if (continuous) {
uint32 min = min_c(frequencies[0], frequencies[1]);
uint32 max = max_c(frequencies[0], frequencies[1]);
if (newRate < min || newRate > max) {
TRACE_ALWAYS("Rate %d outside of %d - %d ignored.\n",
newRate, min, max);
return B_BAD_INDEX;
}
fSamplingRate = newRate;
} else {
for (int i = 0; i < frequencies.Count(); i++)
if (newRate == frequencies[i]) {
fSamplingRate = newRate;
return B_OK;
}
TRACE_ALWAYS("Rate %d not found - ignore it.\n", newRate);
return B_BAD_INDEX;
}
}
// newRate = fSamplingRate;
return B_OK;
}
uint32
AudioStreamAlternate::GetSamplingRateId(uint32 rate)
{
if (rate == 0)
rate = fSamplingRate;
for (size_t i = 0; i < _countof(ratesMap); i++)
if (ratesMap[i].rate == rate)
return ratesMap[i].rateId;
TRACE_ALWAYS("Ignore unsupported sample rate %d.\n", rate);
return 0;
}
uint32
AudioStreamAlternate::GetSamplingRateIds()
{
TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(Format());
if (format == NULL) {
TRACE_ALWAYS("Format not set for active alternate\n");
return 0;
}
uint32 rates = 0;
Vector<uint32>& frequencies = format->fSampleFrequencies;
if (format->fSampleFrequencyType == 0) { // continuous frequencies
uint32 min = min_c(frequencies[0], frequencies[1]);
uint32 max = max_c(frequencies[0], frequencies[1]);
for (int i = 0; i < frequencies.Count(); i++) {
if (frequencies[i] < min || frequencies[i] > max)
continue;
rates |= GetSamplingRateId(frequencies[i]);
}
} else
for (int i = 0; i < frequencies.Count(); i++)
rates |= GetSamplingRateId(frequencies[i]);
return rates;
}
uint32
AudioStreamAlternate::GetFormatId()
{
TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(Format());
if (format == NULL || Interface() == NULL) {
TRACE_ALWAYS("Ignore alternate due format "
"%#08x or interface %#08x null.\n", format, Interface());
return 0;
}
uint32 formats = 0;
switch (Interface()->fFormatTag) {
case UAF_PCM8: formats = B_FMT_8BIT_U; break;
case UAF_IEEE_FLOAT: formats = B_FMT_FLOAT; break;
case UAF_PCM:
switch(format->fBitResolution) {
case 8: formats = B_FMT_8BIT_S; break;
case 16: formats = B_FMT_16BIT; break;
case 18: formats = B_FMT_18BIT; break;
case 20: formats = B_FMT_20BIT; break;
case 24: formats = B_FMT_24BIT; break;
case 32: formats = B_FMT_32BIT; break;
default:
TRACE_ALWAYS("Ignore unsupported "
"bit resolution %d for alternate.\n",
format->fBitResolution);
break;
}
break;
default:
TRACE_ALWAYS("Ignore unsupported "
"format bit resolution %d for alternate.\n",
Interface()->fFormatTag);
break;
}
return formats;
}
uint32
AudioStreamAlternate::SamplingRateFromId(uint32 id)
{
for (size_t i = 0; i < _countof(ratesMap); i++)
if (ratesMap[i].rateId == id)
return ratesMap[i].rate;
TRACE_ALWAYS("Unknown sample rate id: %d.\n", id);
return 0;
}
status_t
AudioStreamAlternate::SetSamplingRateById(uint32 newId)
{
return SetSamplingRate(SamplingRateFromId(newId));
}
status_t
AudioStreamAlternate::SetFormatId(uint32 /*newFormatId*/)
{
return B_OK; // TODO
}
AudioStreamingInterface::AudioStreamingInterface(
AudioControlInterface* controlInterface,
size_t interface, usb_interface_list *List)
@@ -329,9 +517,8 @@ AudioStreamingInterface::GetFormatsAndRates(multi_description *Description)
Description->interface_flags
|= fIsInput ? B_MULTI_INTERFACE_RECORD : B_MULTI_INTERFACE_PLAYBACK;
uint32 rates = 0;
uint32 formats = 0;
// uint32 rates = 0;
/*
TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(
fAlternates[fActiveAlternate]->Format());
@@ -373,27 +560,9 @@ AudioStreamingInterface::GetFormatsAndRates(multi_description *Description)
}
}
}
switch (fAlternates[fActiveAlternate]->Interface()->fFormatTag) {
case UAF_PCM8: formats = B_FMT_8BIT_U; break;
case UAF_IEEE_FLOAT: formats = B_FMT_FLOAT; break;
case UAF_PCM:
switch(format->fBitResolution) {
case 8: formats = B_FMT_8BIT_S; break;
case 16: formats = B_FMT_16BIT; break;
case 18: formats = B_FMT_18BIT; break;
case 20: formats = B_FMT_20BIT; break;
case 24: formats = B_FMT_24BIT; break;
case 32: formats = B_FMT_32BIT; break;
break;
default:
TRACE_ALWAYS("Ignore unsupported "
"bit resolution %d for alternate %d.\n",
format->fBitResolution, fActiveAlternate);
break;
}
break;
}
*/
uint32 rates = fAlternates[fActiveAlternate]->GetSamplingRateIds();
uint32 formats = fAlternates[fActiveAlternate]->GetFormatId();
if (fIsInput) {
Description->input_rates = rates;
@@ -40,11 +40,12 @@ public:
~ASEndpointDescriptor();
// protected:
uint8 fAttributes;
uint8 fCSAttributes;
uint8 fLockDelayUnits;
uint16 fLockDelay;
uint16 fMaxPacketSize;
uint8 fEndpointAddress;
uint8 fEndpointAttributes;
};
@@ -113,11 +114,22 @@ public:
ASEndpointDescriptor* Endpoint() { return fEndpoint; }
_ASFormatDescriptor* Format() { return fFormat; }
status_t SetSamplingRate(uint32 newRate);
status_t SetSamplingRateById(uint32 newId);
uint32 GetSamplingRate() { return fSamplingRate; }
uint32 GetSamplingRateId(uint32 rate);
uint32 GetSamplingRateIds();
uint32 GetFormatId();
status_t SetFormatId(uint32 newFormatId);
uint32 SamplingRateFromId(uint32 id);
protected:
size_t fAlternate;
ASInterfaceDescriptor* fInterface;
ASEndpointDescriptor* fEndpoint;
_ASFormatDescriptor* fFormat;
uint32 fSamplingRate;
};
@@ -23,9 +23,9 @@ Device::Device(usb_device device)
fDevice(device),
fNonBlocking(false),
fAudioControl(this),
fControlEndpoint(0),
fInStreamEndpoint(0),
fOutStreamEndpoint(0),
// fControlEndpoint(0),
// fInStreamEndpoint(0),
// fOutStreamEndpoint(0),
fNotifyReadSem(-1),
fNotifyWriteSem(-1),
fNotifyBuffer(NULL),
@@ -42,6 +42,7 @@ Device::Device(usb_device device)
fVendorID = deviceDescriptor->vendor_id;
fProductID = deviceDescriptor->product_id;
fUSBVersion = deviceDescriptor->usb_version;
fNotifyReadSem = create_sem(0, DRIVER_NAME"_notify_read");
if (fNotifyReadSem < B_OK) {
@@ -155,9 +156,9 @@ Device::Close()
// wait until possible notification handling finished...
while (atomic_add(&fInsideNotify, 0) != 0)
snooze(100);
gUSBModule->cancel_queued_transfers(fControlEndpoint);
gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
// gUSBModule->cancel_queued_transfers(fControlEndpoint);
// gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
// gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
fOpen = false;
@@ -289,9 +290,9 @@ Device::Removed()
while (atomic_add(&fInsideNotify, 0) != 0)
snooze(100);
gUSBModule->cancel_queued_transfers(fControlEndpoint);
gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
// gUSBModule->cancel_queued_transfers(fControlEndpoint);
// gUSBModule->cancel_queued_transfers(fInStreamEndpoint);
// gUSBModule->cancel_queued_transfers(fOutStreamEndpoint);
/*
if (fLinkStateChangeSem >= B_OK)
release_sem_etc(fLinkStateChangeSem, 1, B_DO_NOT_RESCHEDULE);
@@ -415,7 +416,7 @@ Device::_MultiGetDescription(multi_description *multiDescription)
TraceMultiDescription(&Description, Channels);
if (user_memcpy(multiDescription, &Description,
sizeof(multi_description)) != B_OK) {
sizeof(multi_description)) != B_OK) {
return B_BAD_ADDRESS;
}
@@ -555,6 +556,10 @@ Device::_MultiGetBuffers(multi_buffer_list* List)
List->request_record_channels,
List->request_record_buffer_size);
List->flags = 0;
List->return_playback_channels = 0;
List->return_record_channels = 0;
for (int i = 0; i < fStreams.Count() && status == B_OK; i++) {
status = fStreams[i]->GetBuffers(List);
}
@@ -564,18 +569,23 @@ Device::_MultiGetBuffers(multi_buffer_list* List)
status_t
Device::_MultiBufferExchange(multi_buffer_info* Info)
Device::_MultiBufferExchange(multi_buffer_info* multiInfo)
{
multi_buffer_info Info;
if (user_memcpy(&Info, multiInfo, sizeof(multi_buffer_info)) != B_OK)
return B_BAD_ADDRESS;
for (int i = 0; i < fStreams.Count(); i++) {
if (!fStreams[i]->IsRunning()) {
fStreams[i]->Start();
}
}
TRACE_ALWAYS("Exchange!\n");
// TRACE_ALWAYS("Exchange!\n");
/*
snooze(1000000);
return B_OK;
*/
status_t status = B_ERROR;
bool anyBufferProcessed = false;
for (int i = 0; i < fStreams.Count() && !anyBufferProcessed; i++) {
@@ -586,10 +596,13 @@ Device::_MultiBufferExchange(multi_buffer_info* Info)
break;
}
anyBufferProcessed = fStreams[i]->ExchangeBuffer(Info);
anyBufferProcessed = fStreams[i]->ExchangeBuffer(&Info);
status = anyBufferProcessed ? B_OK : B_ERROR;
}
if (user_memcpy(multiInfo, &Info, sizeof(multi_buffer_info)) != B_OK)
return B_BAD_ADDRESS;
return status;
}
@@ -713,7 +726,7 @@ Device::_SetupEndpoints()
status_t
Device::StopDevice()
{
status_t result = B_OK; // WriteRXControlRegister(0);
status_t result = B_OK;
if (result != B_OK) {
TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result);
@@ -81,6 +81,7 @@ virtual status_t StopDevice();
bool fRemoved;
vint32 fInsideNotify;
usb_device fDevice;
uint16 fUSBVersion;
uint16 fVendorID;
uint16 fProductID;
const char * fDescription;
@@ -116,9 +117,9 @@ protected:
// uint16 fFrameSize;
// pipes for notifications and data io
usb_pipe fControlEndpoint;
usb_pipe fInStreamEndpoint;
usb_pipe fOutStreamEndpoint;
// usb_pipe fControlEndpoint;
// usb_pipe fInStreamEndpoint;
// usb_pipe fOutStreamEndpoint;
// data stores for async usb transfers
uint32 fActualLengthRead;
@@ -21,18 +21,16 @@ Stream::Stream(Device *device, size_t interface, usb_interface_list *List
fStreamEndpoint(0),
fIsRunning(false),
fArea(-1),
fDescriptors(0),
fAreaSize(0),
fDescriptors(NULL),
fDescriptorsCount(0),
fCurrentBuffer(0),
fStartingFrame(0),
fSamplesCount(0),
fProcessedBuffers(0)/*,
fBuffersPhysAddress(0)/ *,
fRealTime(0),
fFramesCount(0),
fBufferCycle(0)*/
fPacketSize(0),
fProcessedBuffers(0)
{
memset(&fFormat, 0, sizeof(_multi_format));
}
@@ -43,7 +41,7 @@ Stream::~Stream()
status_t
Stream::Init()
Stream::_ChooseAlternate()
{
// lookup alternate with maximal (ch * 100 + resolution)
uint16 maxChxRes = 0;
@@ -80,6 +78,12 @@ Stream::Init()
TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(fAlternates[i]->Format());
if (format->fNumChannels > 2) {
TRACE("Ignore alternate %d - channel count %d "
"is not supported.\n", i, format->fNumChannels);
continue;
}
if (fAlternates[i]->Interface()->fFormatTag == UAF_PCM) {
switch(format->fBitResolution) {
default:
@@ -100,80 +104,94 @@ Stream::Init()
if (maxChxRes <= 0) {
TRACE("No compatible alternate found. Stream initialization failed.\n");
return fStatus;
return B_NO_INIT;
}
const ASEndpointDescriptor* endpoint = fAlternates[
fActiveAlternate]->Endpoint();
fIsInput = (endpoint->fEndpointAddress & USB_ENDPOINT_ADDR_DIR_IN)
== USB_ENDPOINT_ADDR_DIR_IN;
TRACE("Alternate %d selected!\n", fActiveAlternate);
TRACE("Alternate %d EP:%x selected for %s!\n",
fActiveAlternate, endpoint->fEndpointAddress,
fIsInput ? "recording" : "playback");
TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(fAlternates[
fActiveAlternate]->Format());
return B_OK;
}
size_t bufferSize = format->fNumChannels * format->fSubframeSize;
TRACE("bufferSize:%d\n", bufferSize);
bufferSize *= kSamplesBufferSize;
TRACE("bufferSize:%d\n", bufferSize);
status_t
Stream::Init()
{
fStatus = _ChooseAlternate();
//if (fStatus != B_OK)
return fStatus;
}
bufferSize *= (sizeof(usb_iso_packet_descriptor) + endpoint->fMaxPacketSize);
TRACE("bufferSize:%d\n", bufferSize);
bufferSize /= endpoint->fMaxPacketSize;
TRACE("bufferSize:%d\n", bufferSize);
status_t
Stream::_SetupBuffers()
{
// allocate buffer for worst (maximal size) case
TypeIFormatDescriptor* format = static_cast<TypeIFormatDescriptor*>(
fAlternates[fActiveAlternate]->Format());
uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate();
uint32 sampleSize = format->fNumChannels * format->fSubframeSize;
// data size pro 1 ms USB 1 frame or 1/8 ms USB 2 microframe
fPacketSize = samplingRate * sampleSize
/ (fDevice->fUSBVersion < 0x0200 ? 1000 : 8000);
TRACE("packetSize:%ld\n", fPacketSize);
bufferSize = (bufferSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1);
TRACE("bufferSize:%d\n", bufferSize);
if (fArea == -1) {
fAreaSize = (sizeof(usb_iso_packet_descriptor) + fPacketSize)
* sampleSize * 1024 / fPacketSize;
TRACE("estimate fAreaSize:%d\n", fAreaSize);
fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area" :
DRIVER_NAME "_playback_area",
(void**)&fDescriptors, B_ANY_KERNEL_ADDRESS,
bufferSize, B_CONTIGUOUS,
B_READ_AREA | B_WRITE_AREA);
if (fArea < 0) {
TRACE_ALWAYS("Error of creating %#x - bytes size buffer area:%#010x\n",
bufferSize, fArea);
fStatus = fArea;
return fStatus;
// round up to B_PAGE_SIZE and create area
fAreaSize = (fAreaSize + (B_PAGE_SIZE - 1)) &~ (B_PAGE_SIZE - 1);
TRACE("rounded up fAreaSize:%d\n", fAreaSize);
fArea = create_area( (fIsInput) ? DRIVER_NAME "_record_area"
: DRIVER_NAME "_playback_area", (void**)&fDescriptors,
B_ANY_KERNEL_ADDRESS, fAreaSize, B_CONTIGUOUS,
B_READ_AREA | B_WRITE_AREA);
if (fArea < 0) {
TRACE_ALWAYS("Error of creating %#x - bytes size buffer area:%#010x\n",
fAreaSize, fArea);
fStatus = fArea;
return fStatus;
}
// physical_entry PhysEntry;
// get_memory_map(fDescriptors, fAreaSize, &PhysEntry, 1);
TRACE_ALWAYS("Created area id:%d at addr:%#010x size:%#010lx\n",
fArea, fDescriptors, fAreaSize);
}
physical_entry PhysEntry;
get_memory_map(fDescriptors, bufferSize, &PhysEntry, 1);
TRACE_ALWAYS("Created area id: "
"%d\naddress:%#010x[phys:%#010x]\nsize:%#010x\n",
fArea, fDescriptors, PhysEntry.address, bufferSize);
fDescriptorsCount = bufferSize;
fDescriptorsCount /= (sizeof(usb_iso_packet_descriptor)
+ endpoint->fMaxPacketSize);
// descriptors count
fDescriptorsCount = fAreaSize
/ (sizeof(usb_iso_packet_descriptor) + fPacketSize);
// we need same size sub-buffers. round it
fDescriptorsCount /= kSamplesBufferCount;
// we need same size buffers. round it!
fDescriptorsCount *= kSamplesBufferCount;
TRACE("descriptorsCount:%d\n", fDescriptorsCount);
fSamplesCount = fDescriptorsCount * endpoint->fMaxPacketSize;
TRACE("samplesCount:%d\n", fSamplesCount);
fSamplesCount /= format->fNumChannels * format->fSubframeSize;
// samples count
fSamplesCount = fDescriptorsCount * fPacketSize / sampleSize;
TRACE("samplesCount:%d\n", fSamplesCount);
// initialize descriptors array
for (size_t i = 0; i < fDescriptorsCount; i++) {
fDescriptors[i].request_length = endpoint->fMaxPacketSize;
fDescriptors[i].request_length = fPacketSize;
fDescriptors[i].actual_length = 0;
fDescriptors[i].status = B_OK;
}
/* uint32* b = (uint32*)(fDescriptors + fDescriptorsCount);
for (size_t i = 0; i < fSamplesCount; i++) {
b[i] = i * 10;
}*/
TRACE_ALWAYS("Descriptors count:%d\nsample size:%d\nchannels:%d:%d\n",
fDescriptorsCount, format->fSubframeSize, format->fNumChannels,
sizeof(usb_iso_packet_descriptor));
return fStatus = B_OK;
return fStatus;
}
@@ -193,14 +211,32 @@ Stream::OnSetConfiguration(usb_device device,
return B_ERROR;
}
/*status_t status =*/ gUSBModule->set_alt_interface(device, interface);
status_t status = gUSBModule->set_alt_interface(device, interface);
uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
TRACE_ALWAYS("set_alt_interface %x\n", status);
for (size_t i = 0; i < interface->endpoint_count; i++) {
if (address == interface->endpoint[i].descr->endpoint_address) {
fStreamEndpoint = interface->endpoint[i].handle;
TRACE("%s Stream Endpoint [address %#04x] handle is: %#010x.\n",
fIsInput ? "Input" : "Output", address, fStreamEndpoint);
/*
size_t actualLength = 0;
uint32 speed = 48000;
uint8 data[3];
data[0] = 0xFF & speed;
data[1] = (uint8) 0xFF & speed >> 8;
data[2] = (uint8) 0xFF & speed >> 16;
status_t status = gUSBModule->send_request(device,
USB_REQTYPE_CLASS | USB_REQTYPE_ENDPOINT_OUT,
UAS_SET_CUR, UAS_SAMPLING_FREQ_CONTROL << 8,
address, 3, data, &actualLength);
TRACE_ALWAYS("set_speed for ep %#x %d: %x\n",
address, actualLength, status);
*/
return B_OK;
}
}
@@ -216,12 +252,9 @@ Stream::Start()
{
status_t result = B_BUSY;
if (!fIsRunning) {
if (!fIsInput) {
// for (size_t i = 0; i < kSamplesBufferCount; i++)
// result = _QueueNextTransfer(i);
// TODO
// result = _QueueNextTransfer(0);
result = B_OK;
if (!fIsInput) { // TODO: recording
for (size_t i = 0; i < kSamplesBufferCount; i++)
result = _QueueNextTransfer(i, true);
} else
result = B_OK;
fIsRunning = result == B_OK;
@@ -243,7 +276,7 @@ Stream::Stop()
status_t
Stream::_QueueNextTransfer(size_t queuedBuffer)
Stream::_QueueNextTransfer(size_t queuedBuffer, bool start)
{
TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(fAlternates[
@@ -259,14 +292,35 @@ Stream::_QueueNextTransfer(size_t queuedBuffer)
TRACE("buffers:%#010x[%#x]\ndescrs:%#010x[%#x]\n",
buffers + bufferSize * queuedBuffer, bufferSize,
fDescriptors + queuedBuffer * packetsCount, packetsCount);
#if 0
{
static int16 sin[24] = { 0, 4277, 8481, 12540, 16384, 19948, 23170, 25996,
28378, 30273, 31651, 32487, 32767, 32487, 31651, 30273, 28378, 25996,
23170, 19948, 16384, 12540, 8481, 4277 };
static uint16 sample = 0;
static bool sign = true;
uint16* b = (uint16*)(buffers + bufferSize * queuedBuffer);
size_t length = bufferSize;
for (size_t u = 0; u < length / 2; u += 2) {
b[u] = b[u + 1] = sign ? sin[sample] : -sin[sample];
sample ++;
if (sample == 24) {
sample = 0;
sign = !sign;
}
}
}
#endif
return gUSBModule->queue_isochronous(fStreamEndpoint,
status_t status = gUSBModule->queue_isochronous(fStreamEndpoint,
buffers + bufferSize * queuedBuffer, bufferSize,
fDescriptors + queuedBuffer * packetsCount, packetsCount,
NULL/*&fStartingFrame*/, USB_ISO_ASAP,
&fStartingFrame, start ? USB_ISO_ASAP : 0,
Stream::_TransferCallback, this);
return B_OK;
TRACE("frame:%#010x\n", fStartingFrame);
return status; // B_OK;
}
@@ -274,48 +328,39 @@ void
Stream::_TransferCallback(void *cookie, int32 status, void *data,
uint32 actualLength)
{
Stream *stream = (Stream *)cookie;
stream->fCurrentBuffer++;
if (stream->fCurrentBuffer >= kSamplesBufferCount) {
stream->fCurrentBuffer = 0;
if (status == B_CANCELED) {
TRACE_ALWAYS("Cancelled: c:%p st:%#010x, data:%#010x, len:%d\n",
cookie, status, data, actualLength);
return;
}
stream->_DumpDescriptors();
Stream *stream = (Stream *)cookie;
stream->fCurrentBuffer = (stream->fCurrentBuffer + 1) % kSamplesBufferCount;
stream->_DumpDescriptors();
/*
status_t result = stream->_QueueNextTransfer(stream->fCurrentBuffer);
/*status_t result =*/ stream->_QueueNextTransfer(stream->fCurrentBuffer, false);
if (atomic_add(&stream->fProcessedBuffers, 1) > (int32)kSamplesBufferCount) {
TRACE_ALWAYS("Processed buffers overflow:%d\n", stream->fProcessedBuffers);
}
*/
release_sem_etc(stream->fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
// TRACE_ALWAYS("st:%#010x, len:%d -> %#010x\n", status, actualLength, result);
TRACE_ALWAYS("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength);
/* if (status != B_OK) {
TRACE_ALWAYS("Device status error:%#010x\n", status);
status_t result = gUSBModule->clear_feature(device->fControLeNDPOint,
USB_FEATURE_ENDPOINT_HALT);
if (result != B_OK)
TRACE_ALWAYS("Error during clearing of HALT state:%#010x.\n", result);
}
*/
TRACE("st:%#010x, data:%#010x, len:%d\n", status, data, actualLength);
}
void
Stream::_DumpDescriptors()
{
size_t packetsCount = fDescriptorsCount / kSamplesBufferCount;
//size_t packetsCount = fDescriptorsCount / kSamplesBufferCount;
size_t from = /*fCurrentBuffer > 0 ? packetsCount :*/ 0 ;
size_t to = /*fCurrentBuffer > 0 ?*/ fDescriptorsCount /*: packetsCount*/ ;
for (size_t i = from; i < to; i++) {
TRACE_ALWAYS("%d:req_len:%d; act_len:%d; stat:%#010x\n", i,
TRACE("%d:req_len:%d; act_len:%d; stat:%#010x\n", i,
fDescriptors[i].request_length, fDescriptors[i].actual_length,
fDescriptors[i].status);
}
@@ -359,18 +404,13 @@ Stream::SetEnabledChannels(uint32& offset, multi_channel_enable *Enable)
status_t
Stream::GetGlobalFormat(multi_format_info *Format)
{
if (IsInput()) {
// TODO
Format->input.rate = B_SR_48000;
Format->input.cvsr = 48000;
Format->input.format = B_FMT_16BIT;
} else {
// TODO
Format->output.rate = B_SR_48000;
Format->output.cvsr = 48000;
Format->output.format = B_FMT_16BIT;
}
_multi_format* format = fIsInput ? &Format->input : &Format->output;
format->cvsr = fAlternates[fActiveAlternate]->GetSamplingRate();
format->rate = fAlternates[fActiveAlternate]->GetSamplingRateId(0);
format->format = fAlternates[fActiveAlternate]->GetFormatId();
TRACE("%s.rate:%d cvsr:%f format:%#08x\n",
fIsInput ? "input" : "ouput",
format->rate, format->cvsr, format->format);
return B_OK;
}
@@ -378,19 +418,49 @@ Stream::GetGlobalFormat(multi_format_info *Format)
status_t
Stream::SetGlobalFormat(multi_format_info *Format)
{
if (IsInput()) {
// TODO
TRACE("input.rate:%d\n", Format->input.rate);
TRACE("input.cvsr:%f\n", Format->input.cvsr);
TRACE("input.format:%#08x\n", Format->input.format);
} else {
// TODO
TRACE("output.rate:%d\n", Format->output.rate);
TRACE("output.cvsr:%f\n", Format->output.cvsr);
TRACE("output.format:%#08x\n", Format->output.format);
_multi_format* format = fIsInput ? &Format->input : &Format->output;
AudioStreamAlternate* alternate = fAlternates[fActiveAlternate];
if (format->rate == alternate->GetSamplingRateId(0)
&& format->format == alternate->GetFormatId()) {
TRACE("No changes required\n");
return B_OK;
}
return B_OK;
alternate->SetSamplingRateById(format->rate);
alternate->SetFormatId(format->format);
TRACE("%s.rate:%d cvsr:%f format:%#08x\n",
fIsInput ? "input" : "ouput",
format->rate, format->cvsr, format->format);
// cancel data flow - it will be rewaked at next buffer exchange call
Stop();
// TODO: wait for cancelling?
// layout of buffers should be adjusted after changing sampling rate/format
status_t status = _SetupBuffers();
if (status != B_OK)
return status;
// set endpoint speed
uint32 samplingRate = fAlternates[fActiveAlternate]->GetSamplingRate();
size_t actualLength = 0;
uint8 data[3];
data[0] = 0xFF & samplingRate;
data[1] = 0xFF & samplingRate >> 8;
data[2] = 0xFF & samplingRate >> 16;
uint8 address = fAlternates[fActiveAlternate]->Endpoint()->fEndpointAddress;
status = gUSBModule->send_request(fDevice->fDevice,
USB_REQTYPE_CLASS | USB_REQTYPE_ENDPOINT_OUT,
UAS_SET_CUR, UAS_SAMPLING_FREQ_CONTROL << 8,
address, 3, data, &actualLength);
TRACE_ALWAYS("set_speed %02x%02x%02x for ep %#x %d: %x\n",
data[0], data[1], data[2],
address, actualLength, status);
return status;
}
@@ -398,6 +468,8 @@ status_t
Stream::GetBuffers(multi_buffer_list* List)
{
// TODO: check the available buffers count!
if (fAreaSize == 0)
return B_NO_INIT;
int32 startChannel = List->return_playback_channels;
buffer_desc** Buffers = List->playback_buffers;
@@ -425,8 +497,8 @@ Stream::GetBuffers(multi_buffer_list* List)
TypeIFormatDescriptor* format
= static_cast<TypeIFormatDescriptor*>(
fAlternates[fActiveAlternate]->Format());
const ASEndpointDescriptor* endpoint
= fAlternates[fActiveAlternate]->Endpoint();
// const ASEndpointDescriptor* endpoint
// = fAlternates[fActiveAlternate]->Endpoint();
// [buffer][channel] init buffers
for (size_t buffer = 0; buffer < kSamplesBufferCount; buffer++) {
@@ -443,7 +515,7 @@ Stream::GetBuffers(multi_buffer_list* List)
Buffers[buffer][channel].base
= (char*)(fDescriptors + fDescriptorsCount);
// shift for whole buffer if required
size_t bufferSize = endpoint->fMaxPacketSize
size_t bufferSize = fPacketSize/*endpoint->fMaxPacketSize*/
* (fDescriptorsCount / kSamplesBufferCount);
Buffers[buffer][channel].base += buffer * bufferSize;
// shift for channel if required
@@ -467,29 +539,6 @@ Stream::GetBuffers(multi_buffer_list* List)
}
/*
int32
Stream::InterruptHandler(uint32 SignaledChannelsMask)
{
uint32 ChannelMask = 1 << fHWChannel;
if ((SignaledChannelsMask & ChannelMask) == 0) {
return B_UNHANDLED_INTERRUPT;
}
uint32 CurrentSamplePositionFlag = fDevice->ReadPCI32(TrCurSPFBReg);
fRealTime = system_time();
fFramesCount += fBufferSize;
fBufferCycle = ((CurrentSamplePositionFlag & ChannelMask) == ChannelMask) ? 1 : 0;
fCSP = CurrentSamplePositionFlag;
release_sem_etc(fDevice->fBuffersReadySem, 1, B_DO_NOT_RESCHEDULE);
return B_HANDLED_INTERRUPT;
}*/
bool
Stream::ExchangeBuffer(multi_buffer_info* Info)
{
@@ -499,12 +548,15 @@ Stream::ExchangeBuffer(multi_buffer_info* Info)
return false;
}
Info->played_real_time = system_time();// TODO fRealTime;
Info->played_frames_count += fSamplesCount / kSamplesBufferCount;
Info->playback_buffer_cycle = fCurrentBuffer;
fCurrentBuffer++;
fCurrentBuffer %= kSamplesBufferCount;
if (fIsInput) {
Info->recorded_real_time = system_time();// TODO fRealTime;
Info->recorded_frames_count += fSamplesCount / kSamplesBufferCount;
Info->record_buffer_cycle = fCurrentBuffer;
} else {
Info->played_real_time = system_time();// TODO fRealTime;
Info->played_frames_count += fSamplesCount / kSamplesBufferCount;
Info->playback_buffer_cycle = fCurrentBuffer;
}
atomic_add(&fProcessedBuffers, -1);
@@ -62,22 +62,21 @@ protected:
uint8 fTerminalID;
usb_pipe fStreamEndpoint;
bool fIsRunning;
/* uint32 fHWChannel;*/
area_id fArea;
size_t fAreaSize;
usb_iso_packet_descriptor* fDescriptors;
size_t fDescriptorsCount;
size_t fCurrentBuffer;
uint32 fStartingFrame;
size_t fSamplesCount;
size_t fPacketSize;
int32 fProcessedBuffers;
// void* fBuffersPhysAddress;
/* bigtime_t fRealTime;
bigtime_t fFramesCount;
int32 fBufferCycle;
public:
uint32 fCSP; */
_multi_format fFormat;
private:
status_t _QueueNextTransfer(size_t buffer);
status_t _ChooseAlternate();
status_t _SetupBuffers();
status_t _QueueNextTransfer(size_t buffer, bool start);
static void _TransferCallback(void *cookie, int32 status,
void *data, uint32 actualLength);
void _DumpDescriptors();