root/src/apps/cortex/support/MediaIcon.cpp
/*
 * Copyright (c) 1999-2000, Eric Moon.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions, and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


// MediaIcon.cpp

#include "MediaIcon.h"
#include "MediaIconBits.h"
#include "AddOnHostProtocol.h"

// Application Kit
#include <Application.h>
#include <Roster.h>
// Media Kit
#include <MediaDefs.h>
#include <MediaNode.h>
#include <MediaRoster.h>
#include <MediaAddOn.h>
// Storage Kit
#include <NodeInfo.h>
// Support Kit
#include <String.h>
// Interface Kit
#include <IconUtils.h>


__USE_CORTEX_NAMESPACE

#include <Debug.h>
#define D_ALLOC(x) //PRINT (x)
#define D_INTERNAL(x) //PRINT (x)

// -------------------------------------------------------- //
// *** ctor/dtor
// -------------------------------------------------------- //

MediaIcon::MediaIcon(
        const live_node_info &nodeInfo,
        icon_size size)
        : BBitmap(BRect(0.0, 0.0, size - 1.0, size - 1.0), B_RGBA32),
          m_size(size),
          m_nodeKind(nodeInfo.node.kind) {
        D_ALLOC(("MediaIcon::MediaIcon(live_node_info '%s')\n", nodeInfo.name));

        _findIconFor(nodeInfo);
}

MediaIcon::MediaIcon(
        const dormant_node_info &nodeInfo,
        icon_size size)
        : BBitmap(BRect(0.0, 0.0, size - 1.0, size - 1.0), B_RGBA32),
          m_size(size),
          m_nodeKind(0) {
        D_ALLOC(("MediaIcon::MediaIcon(dormant_node_info '%s')\n", nodeInfo.name));

        _findIconFor(nodeInfo);
}

MediaIcon::~MediaIcon() {
        D_ALLOC(("MediaIcon::~MediaIcon()\n"));

}

// -------------------------------------------------------- //
// *** internal accessors (private)
// -------------------------------------------------------- //

bool MediaIcon::_isPhysicalInput() const {
        D_INTERNAL(("MediaIcon::_isPhysicalInput()\n"));

        return ((m_nodeKind & B_PHYSICAL_INPUT)
             && (m_nodeKind & B_BUFFER_PRODUCER));
}

bool MediaIcon::_isPhysicalOutput() const {
        D_INTERNAL(("MediaIcon::_isPhysicalOutput()\n"));

        return ((m_nodeKind & B_PHYSICAL_OUTPUT)
             && (m_nodeKind & B_BUFFER_CONSUMER));;
}

bool MediaIcon::_isProducer() const {
        D_INTERNAL(("MediaIcon::_isProducer()\n"));

        return (!(m_nodeKind & B_BUFFER_CONSUMER) && 
                         (m_nodeKind & B_BUFFER_PRODUCER) && 
                        !(m_nodeKind & B_PHYSICAL_INPUT)  &&
                        !(m_nodeKind & B_PHYSICAL_OUTPUT));
}

bool MediaIcon::_isFilter() const {
        D_INTERNAL(("MediaIcon::_isFilter()\n"));

        return ( (m_nodeKind & B_BUFFER_CONSUMER) && 
                         (m_nodeKind & B_BUFFER_PRODUCER) && 
                    !(m_nodeKind & B_PHYSICAL_INPUT)  &&
                    !(m_nodeKind & B_PHYSICAL_OUTPUT));
}

bool MediaIcon::_isConsumer() const {
        D_INTERNAL(("MediaIcon::_isConsumer()\n"));

        return ( (m_nodeKind & B_BUFFER_CONSUMER) && 
                    !(m_nodeKind & B_BUFFER_PRODUCER) && 
                    !(m_nodeKind & B_PHYSICAL_INPUT)  &&
                    !(m_nodeKind & B_PHYSICAL_OUTPUT));
}

bool MediaIcon::_isSystemMixer() const {
        D_INTERNAL(("MediaIcon::_isSystemMixer()\n"));

        return (m_nodeKind & B_SYSTEM_MIXER);
}

bool MediaIcon::_isTimeSource() const {
        D_INTERNAL(("MediaIcon::_isTimeSource()\n"));

        return ((m_nodeKind & B_TIME_SOURCE) &&
                   !(m_nodeKind & B_PHYSICAL_INPUT) &&
                   !(m_nodeKind & B_PHYSICAL_OUTPUT));
}

// -------------------------------------------------------- //
// *** internal operations (private)
// -------------------------------------------------------- //

void MediaIcon::_findIconFor(
        const live_node_info &nodeInfo) {
        D_INTERNAL(("MediaIcon::_findIconFor(live_node_info)\n"));

        BMediaRoster *roster = BMediaRoster::CurrentRoster();
        if (m_nodeKind & B_FILE_INTERFACE) {
                entry_ref ref;
                if ((roster && (roster->GetRefFor(nodeInfo.node, &ref) == B_OK))
                 && (BNodeInfo::GetTrackerIcon(&ref, this, m_size) == B_OK)) {
                        return;
                }
        }
        dormant_node_info dormantNodeInfo;
        if  (roster
         && (roster->GetDormantNodeFor(nodeInfo.node, &dormantNodeInfo) == B_OK)) {
                D_INTERNAL((" -> instantiated from dormant node\n"));
                _findIconFor(dormantNodeInfo);
        }
        else {
                D_INTERNAL((" -> application internal node\n"));
                port_info portInfo;
                app_info appInfo;
                if ((get_port_info(nodeInfo.node.port, &portInfo) == B_OK)
                 && (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK)) {
                        D_INTERNAL((" -> application info found: %s\n", appInfo.signature));
                        app_info thisAppInfo;
                        if ((be_app->GetAppInfo(&thisAppInfo) != B_OK)
                         || ((strcmp(appInfo.signature, thisAppInfo.signature) != 0)
                         && (strcmp(appInfo.signature, addon_host::g_appSignature) != 0))) {
                                // only use app icon if the node doesn't belong to our team
                                // or the addon-host
                                BNodeInfo::GetTrackerIcon(&appInfo.ref, this, m_size);
                                return;
                        }
                }
                bool audioIn = false, audioOut = false, videoIn = false, videoOut = false;
                _getMediaTypesFor(nodeInfo, &audioIn, &audioOut, &videoIn, &videoOut);
                _findDefaultIconFor(audioIn, audioOut, videoIn, videoOut);
        }
}


void
MediaIcon::_findIconFor(const dormant_node_info &nodeInfo)
{
        D_INTERNAL(("MediaIcon::_findIconFor(dormant_node_info)\n"));

        dormant_flavor_info flavorInfo;
        BMediaRoster *roster = BMediaRoster::CurrentRoster();
        status_t error = roster->GetDormantFlavorInfoFor(nodeInfo, &flavorInfo);
        if (error == B_OK) {
                m_nodeKind = flavorInfo.kinds;
                bool audioIn = false, audioOut = false;
                bool videoIn = false, videoOut = false;
                _getMediaTypesFor(flavorInfo, &audioIn, &audioOut, &videoIn, &videoOut);
                _findDefaultIconFor(audioIn, audioOut, videoIn, videoOut);
        } else if (BString(nodeInfo.name).Compare("System clock") == 0) {
                BIconUtils::GetVectorIcon(M_TIME_SOURCE_ICON,
                        sizeof(M_TIME_SOURCE_ICON), this);
        } else {
                // use generic icon in case we couldn't get any info
                BIconUtils::GetVectorIcon(M_GENERIC_ICON,
                        sizeof(M_GENERIC_ICON), this);
        }
}


void
MediaIcon::_getMediaTypesFor(const live_node_info &nodeInfo, bool *audioIn,
        bool *audioOut, bool *videoIn, bool *videoOut)
{
        D_INTERNAL(("MediaIcon::_getMediaTypeFor(live_node_info)\n"));

        // get the media_types supported by this node
        const int32 numberOfInputs = 4;
        int32 numberOfFreeInputs, numberOfConnectedInputs;
        media_input inputs[numberOfInputs];
        const int32 numberOfOutputs = 4;
        int32 numberOfFreeOutputs, numberOfConnectedOutputs;
        media_output outputs[numberOfOutputs];
        BMediaRoster *roster = BMediaRoster::CurrentRoster();
        if (roster->GetFreeInputsFor(nodeInfo.node, inputs, numberOfInputs,
                        &numberOfFreeInputs) == B_OK) {
                for (int32 i = 0; i < numberOfFreeInputs; i++) {
                        if ((inputs[i].format.type == B_MEDIA_RAW_AUDIO)
                         || (inputs[i].format.type == B_MEDIA_ENCODED_AUDIO)) {
                                *audioIn = true;
                                continue;
                        }
                        if ((inputs[i].format.type == B_MEDIA_RAW_VIDEO)
                         || (inputs[i].format.type == B_MEDIA_ENCODED_VIDEO)) {
                                *videoIn = true;
                        }
                }
        }
        if (roster->GetConnectedInputsFor(nodeInfo.node, inputs, numberOfInputs,
                        &numberOfConnectedInputs) == B_OK) {
                for (int32 i = 0; i < numberOfConnectedInputs; i++) {
                        if ((inputs[i].format.type == B_MEDIA_RAW_AUDIO)
                         || (inputs[i].format.type == B_MEDIA_ENCODED_AUDIO)) {
                                *audioIn = true;
                                continue;
                        }
                        if ((inputs[i].format.type == B_MEDIA_RAW_VIDEO)
                         || (inputs[i].format.type == B_MEDIA_ENCODED_VIDEO)) {
                                *videoIn = true;
                        }
                }
        }
        if (roster->GetFreeOutputsFor(nodeInfo.node, outputs, numberOfOutputs,
                        &numberOfFreeOutputs) == B_OK) {
                for (int32 i = 0; i < numberOfFreeOutputs; i++) {
                        if ((outputs[i].format.type == B_MEDIA_RAW_AUDIO)
                         || (outputs[i].format.type == B_MEDIA_ENCODED_AUDIO)) {
                                *audioOut = true;
                                continue;
                        }
                        if ((outputs[i].format.type == B_MEDIA_RAW_VIDEO)
                         || (outputs[i].format.type == B_MEDIA_ENCODED_VIDEO)) {
                                *videoOut = true;
                        }
                }
        }
        if (roster->GetConnectedOutputsFor(nodeInfo.node, outputs, numberOfOutputs,
                        &numberOfConnectedOutputs) == B_OK) {
                for (int32 i = 0; i < numberOfConnectedOutputs; i++) {
                        if ((outputs[i].format.type == B_MEDIA_RAW_AUDIO)
                         || (outputs[i].format.type == B_MEDIA_ENCODED_AUDIO)) {
                                *audioOut = true;
                                continue;
                        }
                        if ((outputs[i].format.type == B_MEDIA_RAW_VIDEO)
                         || (outputs[i].format.type == B_MEDIA_ENCODED_VIDEO)) {
                                *videoOut = true;
                        }
                }
        }
}

void MediaIcon::_getMediaTypesFor(
        const dormant_flavor_info &flavorInfo,
        bool *audioIn,
        bool *audioOut,
        bool *videoIn,
        bool *videoOut) {
        D_INTERNAL(("MediaIcon::_getMediaTypeFor(dormant_flavor_info)\n"));

        for (int32 i = 0; i < flavorInfo.in_format_count; i++) {
                if ((flavorInfo.in_formats[i].type == B_MEDIA_RAW_AUDIO)
                 || (flavorInfo.in_formats[i].type == B_MEDIA_ENCODED_AUDIO)) {
                        *audioIn = true;
                        continue;
                }
                if ((flavorInfo.in_formats[i].type == B_MEDIA_RAW_VIDEO)
                 || (flavorInfo.in_formats[i].type == B_MEDIA_ENCODED_VIDEO)) {
                        *videoIn = true;
                }
        }
        for (int32 i = 0; i < flavorInfo.out_format_count; i++) {
                if ((flavorInfo.out_formats[i].type == B_MEDIA_RAW_AUDIO)
                 || (flavorInfo.out_formats[i].type == B_MEDIA_ENCODED_AUDIO)) {
                        *audioOut = true;
                        continue;
                }
                if ((flavorInfo.out_formats[i].type == B_MEDIA_RAW_VIDEO)
                 || (flavorInfo.out_formats[i].type == B_MEDIA_ENCODED_VIDEO)) {
                        *videoOut = true;
                }
        }
}

void MediaIcon::_findDefaultIconFor(
        bool audioIn,
        bool audioOut,
        bool videoIn,
        bool videoOut) {
        D_INTERNAL(("MediaIcon::_findDefaultIcon()\n"));

        if (_isTimeSource()) {
                BIconUtils::GetVectorIcon(M_TIME_SOURCE_ICON,
                        sizeof(M_TIME_SOURCE_ICON), this);
                return;
        }

        if (_isSystemMixer()) {
                BIconUtils::GetVectorIcon(M_AUDIO_MIXER_ICON,
                        sizeof(M_AUDIO_MIXER_ICON), this);
                return;
        }

        if (m_nodeKind & B_FILE_INTERFACE) {
                if (_isProducer()) {
                        BIconUtils::GetVectorIcon(M_FILE_READER_ICON,
                                sizeof(M_FILE_READER_ICON), this);
                        return;
                } else {
                        BIconUtils::GetVectorIcon(M_FILE_WRITER_ICON,
                                sizeof(M_FILE_WRITER_ICON), this);
                        return;
                }
        }

        if (_isPhysicalInput()) {
                if (audioIn) {
                        BIconUtils::GetVectorIcon(M_AUDIO_DEVICE_ICON,
                                sizeof(M_AUDIO_DEVICE_ICON), this);
                        return;
                } else if (audioOut) {
                        BIconUtils::GetVectorIcon(M_AUDIO_INPUT_ICON,
                                sizeof(M_AUDIO_INPUT_ICON), this);
                        return;
                } else if (videoOut) {
                        BIconUtils::GetVectorIcon(M_VIDEO_INPUT_ICON,
                                sizeof(M_VIDEO_INPUT_ICON), this);
                        return;
                }
        }
        
        if (_isPhysicalOutput()) {
                if (audioIn) {
                        BIconUtils::GetVectorIcon(M_AUDIO_OUTPUT_ICON,
                                sizeof(M_AUDIO_OUTPUT_ICON), this);
                        return;
                } else if (videoIn) {
                        BIconUtils::GetVectorIcon(M_VIDEO_OUTPUT_ICON,
                                sizeof(M_VIDEO_OUTPUT_ICON), this);
                        return;
                }
        }

        if (_isProducer()) {
                if (audioOut) {
                        BIconUtils::GetVectorIcon(M_AUDIO_PRODUCER_ICON,
                                sizeof(M_AUDIO_PRODUCER_ICON), this);
                        return;
                } else if (videoOut) {
                        BIconUtils::GetVectorIcon(M_VIDEO_PRODUCER_ICON,
                                sizeof(M_VIDEO_PRODUCER_ICON), this);
                        return;
                }
        }

        if (_isFilter()) {
                if (audioIn && audioOut && !videoIn && !videoOut) {
                        BIconUtils::GetVectorIcon(M_AUDIO_FILTER_ICON,
                                sizeof(M_AUDIO_FILTER_ICON), this);
                        return;
                } else if (audioIn && !videoIn && videoOut) {
                        BIconUtils::GetVectorIcon(M_AUDIO_CONSUMER_ICON,
                                sizeof(M_AUDIO_CONSUMER_ICON), this);
                        return;
                } else if (!audioIn && !audioOut && videoIn && videoOut) {
                        BIconUtils::GetVectorIcon(M_VIDEO_FILTER_ICON,
                                sizeof(M_VIDEO_FILTER_ICON), this);
                        return;
                }
        }

        if (_isConsumer()) {
                if (audioIn) {
                        BIconUtils::GetVectorIcon(M_AUDIO_CONSUMER_ICON,
                                sizeof(M_AUDIO_CONSUMER_ICON), this);
                        return;
                } else if (videoIn) {
                        BIconUtils::GetVectorIcon(M_VIDEO_CONSUMER_ICON,
                                sizeof(M_VIDEO_CONSUMER_ICON), this);
                        return;
                }
        }

        // assign a default icon
        BIconUtils::GetVectorIcon(M_GENERIC_ICON, sizeof(M_GENERIC_ICON), this);
}