root/src/add-ons/kernel/drivers/audio/usb/AudioStreamingInterface.cpp
/*
 *      Driver for USB Audio Device Class devices.
 *      Copyright (c) 2009-13 S.Zharski <imker@gmx.li>
 *      Distributed under the tems of the MIT license.
 *
 */


#include "AudioStreamingInterface.h"

#include <usb/USB_audio.h>

#include "Driver.h"
#include "Settings.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
//
//
ASInterfaceDescriptor::ASInterfaceDescriptor(
                usb_audio_streaming_interface_descriptor* Descriptor)
        :
        fTerminalLink(0),
        fDelay(0),
        fFormatTag(0)
{
// TODO: what aboput rev 2???????
        fTerminalLink = Descriptor->terminal_link;
        fDelay = Descriptor->r1.delay;
        fFormatTag = Descriptor->r1.format_tag;

        TRACE(UAC, "fTerminalLink:%d\n", fTerminalLink);
        TRACE(UAC, "fDelay:%d\n", fDelay);
        TRACE(UAC, "fFormatTag:%#06x\n", fFormatTag);

        // fStatus = B_OK;
}


ASInterfaceDescriptor::~ASInterfaceDescriptor()
{
}


ASEndpointDescriptor::ASEndpointDescriptor(usb_endpoint_descriptor* Endpoint,
                usb_audio_streaming_endpoint_descriptor* Descriptor)
        :
        fCSAttributes(0),
        fLockDelayUnits(0),
        fLockDelay(0),
        fMaxPacketSize(0),
        fEndpointAddress(0),
        fEndpointAttributes(0)
{
        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(UAC, "fCSAttributes:%d\n", fCSAttributes);
        TRACE(UAC, "fLockDelayUnits:%d\n", fLockDelayUnits);
        TRACE(UAC, "fLockDelay:%d\n", fLockDelay);
        TRACE(UAC, "fMaxPacketSize:%d\n", fMaxPacketSize);
        TRACE(UAC, "fEndpointAddress:%#02x\n", fEndpointAddress);
        TRACE(UAC, "fEndpointAttributes:%d\n", fEndpointAttributes);
}


ASEndpointDescriptor::~ASEndpointDescriptor()
{
}


_ASFormatDescriptor::_ASFormatDescriptor(
                usb_audio_format_descriptor* Descriptor)
        :
        fFormatType(USB_AUDIO_FORMAT_TYPE_UNDEFINED)
{
        fFormatType = Descriptor->format_type;
}


_ASFormatDescriptor::~_ASFormatDescriptor()
{
}


uint32
_ASFormatDescriptor::GetSamFreq(const usb_audio_sampling_freq& freq)
{
        return freq.bytes[0] | freq.bytes[1] << 8 | freq.bytes[2] << 16;
}


usb_audio_sampling_freq
_ASFormatDescriptor::GetSamFreq(uint32 samplingRate)
{
        usb_audio_sampling_freq freq;
        for (size_t i = 0; i < 3; i++)
                freq.bytes[i] = 0xFF & samplingRate >> 8 * i;
        return freq;
}


TypeIFormatDescriptor::TypeIFormatDescriptor(
                usb_audio_format_descriptor* Descriptor)
        :
        _ASFormatDescriptor(Descriptor),
        fNumChannels(0),
        fSubframeSize(0),
        fBitResolution(0),
        fSampleFrequencyType(0)
{
        /*fStatus =*/ Init(Descriptor);
}


TypeIFormatDescriptor::~TypeIFormatDescriptor()
{
}


status_t
TypeIFormatDescriptor::Init(usb_audio_format_descriptor* Descriptor)
{
        fNumChannels = Descriptor->typeI.nr_channels;
        fSubframeSize = Descriptor->typeI.subframe_size;
        fBitResolution = Descriptor->typeI.bit_resolution;
        fSampleFrequencyType = Descriptor->typeI.sam_freq_type;

        if (fSampleFrequencyType == 0) {
                fSampleFrequencies.PushBack(
                        GetSamFreq(Descriptor->typeI.sam_freqs[0]));
                fSampleFrequencies.PushBack(
                        GetSamFreq(Descriptor->typeI.sam_freqs[1]));
        } else
                for (size_t i = 0; i < fSampleFrequencyType; i++)
                        fSampleFrequencies.PushBack(
                                GetSamFreq(Descriptor->typeI.sam_freqs[i]));

        TRACE(UAC, "fNumChannels:%d\n", fNumChannels);
        TRACE(UAC, "fSubframeSize:%d\n", fSubframeSize);
        TRACE(UAC, "fBitResolution:%d\n", fBitResolution);
        TRACE(UAC, "fSampleFrequencyType:%d\n", fSampleFrequencyType);

        for (int32 i = 0; i < fSampleFrequencies.Count(); i++)
                TRACE(UAC, "Frequency #%d: %d\n", i, fSampleFrequencies[i]);

        return B_OK;
}


TypeIIFormatDescriptor::TypeIIFormatDescriptor(
                usb_audio_format_descriptor* Descriptor)
        :
        _ASFormatDescriptor(Descriptor),
        fMaxBitRate(0),
        fSamplesPerFrame(0),
        fSampleFrequencyType(0),
        fSampleFrequencies(0)
{
}


TypeIIFormatDescriptor::~TypeIIFormatDescriptor()
{
}


TypeIIIFormatDescriptor::TypeIIIFormatDescriptor(
                usb_audio_format_descriptor* Descriptor)
        :
        TypeIFormatDescriptor(Descriptor)
{
}


TypeIIIFormatDescriptor::~TypeIIIFormatDescriptor()
{
}


AudioStreamAlternate::AudioStreamAlternate(size_t alternate,
                ASInterfaceDescriptor* interface, ASEndpointDescriptor* endpoint,
                _ASFormatDescriptor* format)
        :
        fAlternate(alternate),
        fInterface(interface),
        fEndpoint(endpoint),
        fFormat(format),
        fSamplingRate(0)
{
}


AudioStreamAlternate::~AudioStreamAlternate()
{
        delete fInterface;
        delete fEndpoint;
        delete fFormat;
}


status_t
AudioStreamAlternate::SetSamplingRate(uint32 newRate)
{
        TypeIFormatDescriptor* format
                = static_cast<TypeIFormatDescriptor*>(Format());

        if (format == NULL) {
                TRACE(ERR, "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(ERR, "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(ERR, "Rate %d not found - ignore it.\n", newRate);
                        return B_BAD_INDEX;
                }
        }

        return B_OK;
}


uint32
AudioStreamAlternate::GetSamplingRateId(uint32 rate)
{
        if (rate == 0)
                rate = fSamplingRate;

        for (size_t i = 0; i < B_COUNT_OF(ratesMap); i++)
                if (ratesMap[i].rate == rate)
                        return ratesMap[i].rateId;

        TRACE(ERR, "Ignore unsupported sample rate %d.\n", rate);
        return 0;
}


uint32
AudioStreamAlternate::GetSamplingRateIds()
{
        TypeIFormatDescriptor* format
                = static_cast<TypeIFormatDescriptor*>(Format());

        if (format == NULL) {
                TRACE(ERR, "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(ERR, "Ignore alternate due format "
                        "%#08x or interface %#08x null.\n", format, Interface());
                return 0;
        }

        uint32 formats = 0;
        switch (Interface()->fFormatTag) {
                case USB_AUDIO_FORMAT_PCM8:
                        formats = B_FMT_8BIT_U;
                        break;
                case USB_AUDIO_FORMAT_IEEE_FLOAT:
                        formats = B_FMT_FLOAT;
                        break;
                case USB_AUDIO_FORMAT_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(ERR, "Ignore unsupported "
                                                "bit resolution %d for alternate.\n",
                                                format->fBitResolution);
                                        break;
                        }
                        break;
                default:
                        TRACE(ERR, "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 < B_COUNT_OF(ratesMap); i++)
                if (ratesMap[i].rateId == id)
                        return ratesMap[i].rate;

        TRACE(ERR, "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)
        :
        fInterface(interface),
        fControlInterface(controlInterface),
        fIsInput(false),
        fActiveAlternate(0)
{
        TRACE(ERR, "if[%d]:alt_count:%d\n", interface, List->alt_count);

        for (size_t alt = 0; alt < List->alt_count; alt++) {
                ASInterfaceDescriptor*  ASInterface     = NULL;
                ASEndpointDescriptor*   ASEndpoint      = NULL;
                _ASFormatDescriptor*    ASFormat        = NULL;

                usb_interface_info* Interface = &List->alt[alt];

                TRACE(ERR, "if[%d]:alt[%d]:descrs_count:%d\n",
                        interface, alt, Interface->generic_count);
                for (size_t i = 0; i < Interface->generic_count; i++) {
                        usb_audiocontrol_header_descriptor* Header
                                = (usb_audiocontrol_header_descriptor*)Interface->generic[i];

                        if (Header->descriptor_type == USB_AUDIO_CS_INTERFACE) {
                                switch(Header->descriptor_subtype) {
                                        case USB_AUDIO_AS_GENERAL:
                                                if (ASInterface == 0)
                                                        ASInterface = new(std::nothrow)
                                                                ASInterfaceDescriptor(
                                                                (usb_audio_streaming_interface_descriptor*)Header);
                                                else
                                                        TRACE(ERR, "Duplicate AStream interface ignored.\n");
                                                break;
                                        case USB_AUDIO_AS_FORMAT_TYPE:
                                                if (ASFormat == 0)
                                                        ASFormat = new(std::nothrow) TypeIFormatDescriptor(
                                                                (usb_audio_format_descriptor*) Header);
                                                else
                                                        TRACE(ERR, "Duplicate AStream format ignored.\n");
                                                break;
                                        default:
                                                TRACE(ERR, "Ignore AStream descr subtype %#04x\n",
                                                        Header->descriptor_subtype);
                                                break;
                                }
                                continue;
                        }

                        if (Header->descriptor_type == USB_AUDIO_CS_ENDPOINT) {
                                if (ASEndpoint == 0) {
                                        usb_endpoint_descriptor* Endpoint
                                                = Interface->endpoint[0].descr;
                                        ASEndpoint = new(std::nothrow) ASEndpointDescriptor(Endpoint,
                                                (usb_audio_streaming_endpoint_descriptor*)Header);
                                } else
                                        TRACE(ERR, "Duplicate AStream endpoint ignored.\n");
                                continue;
                        }

                        TRACE(ERR, "Ignore Audio Stream of "
                                "unknown descriptor type %#04x.\n",     Header->descriptor_type);
                }

                fAlternates.Add(new(std::nothrow) AudioStreamAlternate(alt, ASInterface,
                        ASEndpoint, ASFormat));
        }
}


AudioStreamingInterface::~AudioStreamingInterface()
{
        // we own stream header objects too, so free them
        for (Vector<AudioStreamAlternate*>::Iterator I = fAlternates.Begin();
                        I != fAlternates.End(); I++)
                delete *I;

        fAlternates.MakeEmpty();
}


uint8
AudioStreamingInterface::TerminalLink()
{
        if (fAlternates[fActiveAlternate]->Interface() != NULL)
                return fAlternates[fActiveAlternate]->Interface()->fTerminalLink;
        return 0;
}


AudioChannelCluster*
AudioStreamingInterface::ChannelCluster()
{
        _AudioControl* control = fControlInterface->Find(TerminalLink());
        if (control == 0) {
                TRACE(ERR, "Control was not found for terminal id:%d.\n",
                        TerminalLink());
                return NULL;
        }

        return control->OutCluster();
}


void
AudioStreamingInterface::GetFormatsAndRates(multi_description* Description)
{
        Description->interface_flags
                |= fIsInput ? B_MULTI_INTERFACE_RECORD : B_MULTI_INTERFACE_PLAYBACK;

        uint32 rates = fAlternates[fActiveAlternate]->GetSamplingRateIds();
        uint32 formats = fAlternates[fActiveAlternate]->GetFormatId();

        if (fIsInput) {
                Description->input_rates = rates;
                Description->input_formats = formats;
        } else {
                Description->output_rates = rates;
                Description->output_formats = formats;
        }
}