root/src/add-ons/media/media-add-ons/firewire_dv/FireWireDVAddOn.cpp
/*
 * FireWire DV media addon for Haiku
 *
 * Copyright (c) 2008, JiSheng Zhang (jszhang3@mail.ustc.edu.cn)
 * Distributed under the terms of the MIT License.
 *
 * Based on DVB media addon 
 * Copyright (c) 2004-2007 Marcus Overhagen <marcus@overhagen.de>
 */

#include "FireWireDVAddOn.h"
#include "FireWireCard.h"
#include "FireWireDVNode.h"

#include <stdio.h>
#include <string.h>
#include <time.h>

#include <Alert.h>
#include <Directory.h>
#include <Entry.h>
#include <Path.h>

#include "debug.h"

struct device_info
{
        FireWireCard*   card;
        char            name[16];
        media_format    in_formats[1];
        media_format    out_formats[1];
        flavor_info     flavor;
};

extern "C" BMediaAddOn*
make_media_addon(image_id id)
{
        CALLED();
        return new FireWireDVAddOn(id);
}


FireWireDVAddOn::FireWireDVAddOn(image_id id)
        : BMediaAddOn(id)
{
        CALLED();
        ScanFolder("/dev/bus/fw");
}


FireWireDVAddOn::~FireWireDVAddOn()
{
        CALLED();
        FreeDeviceList();
}


status_t
FireWireDVAddOn::InitCheck(const char** out_failure_text)
{
        CALLED();
        if (!fDeviceList.CountItems()) {
                *out_failure_text = "No supported device found";
                return B_ERROR;
        }
        return B_OK;
}


int32
FireWireDVAddOn::CountFlavors()
{
        CALLED();
        return fDeviceList.CountItems();
}


status_t
FireWireDVAddOn::GetFlavorAt(int32 n, const flavor_info** out_info)
{
        CALLED();
        device_info* dev = fDeviceList.ItemAt(n);
        if (!dev)
                return B_ERROR;
        *out_info = &dev->flavor;
        return B_OK;
}


BMediaNode *
FireWireDVAddOn::InstantiateNodeFor(const flavor_info* info, BMessage* config,
        status_t* out_error)
{
        CALLED();
        device_info* dev = fDeviceList.ItemAt(info->internal_id);
        if (!dev || dev->flavor.internal_id != info->internal_id) {
                *out_error = B_ERROR;
                return NULL;
        }
        *out_error = B_OK;
        
        return new FireWireDVNode(this, dev->name, dev->flavor.internal_id, 
                dev->card);
}


bool
FireWireDVAddOn::WantsAutoStart()
{
        CALLED();
        return false;
}


status_t
FireWireDVAddOn::AutoStart(int index, BMediaNode** outNode, 
        int32* outInternalID, bool* outHasMore)
{
        CALLED();
        return B_ERROR;
}


void
FireWireDVAddOn::ScanFolder(const char* path)
{
        CALLED();
        BDirectory dir(path);
        if (dir.InitCheck() != B_OK)
                return;

        BEntry ent;

        while (dir.GetNextEntry(&ent) == B_OK) {
                BPath path(&ent);
                if (!ent.IsDirectory() && !ent.IsSymLink()) {
                        FireWireCard *card = new FireWireCard(path.Path());
                        if (card->InitCheck() == B_OK)
                                AddDevice(card, path.Path());
                        else
                                delete card;
                }
        }
}


void
FireWireDVAddOn::AddDevice(FireWireCard* card, const char* path)
{
        const char* fwnumber;
        
        // get card name, info and type
                
        // get interface number
        const char *p = strrchr(path, '/');
        fwnumber = p ? p + 1 : "";
        
        // create device_info
        device_info *dev = new device_info;
        fDeviceList.AddItem(dev);
        
        dev->card = card;
        
        sprintf(dev->name, "FireWire-%s", fwnumber);
        
        // setup supported formats (the lazy way)
        memset(dev->in_formats, 0, sizeof(dev->in_formats));
        memset(dev->out_formats, 0, sizeof(dev->out_formats));
        dev->in_formats[0].type = B_MEDIA_ENCODED_VIDEO;
        dev->out_formats[0].type = B_MEDIA_ENCODED_VIDEO;
        
        // setup flavor info
        dev->flavor.name = dev->name;
        dev->flavor.info = (char *)"The FireWireDVNode outputs to fw_raw drivers.";
        dev->flavor.kinds = B_BUFFER_CONSUMER | B_BUFFER_PRODUCER 
                | B_CONTROLLABLE | B_PHYSICAL_OUTPUT | B_PHYSICAL_INPUT;
        dev->flavor.flavor_flags = B_FLAVOR_IS_GLOBAL;
        dev->flavor.internal_id = fDeviceList.CountItems() - 1;
        dev->flavor.possible_count = 1;
        dev->flavor.in_format_count = 1;
        dev->flavor.in_format_flags = 0;
        dev->flavor.in_formats = dev->in_formats;
        dev->flavor.out_format_count = 1;
        dev->flavor.out_format_flags = 0;
        dev->flavor.out_formats = dev->out_formats;
}


void
FireWireDVAddOn::FreeDeviceList()
{
        device_info* dev;
        while ((dev = fDeviceList.RemoveItemAt(0L))) {
                delete dev->card;
                delete dev;
        }
}