Ticket #8911: soundrecord.diff

File soundrecord.diff, 32.4 KB (added by Barrett, 6 years ago)

Patch to replace SoundConsumer with BMediaRecorder.

  • new file headers/private/media/MediaRecorder.h

    diff --git a/headers/private/media/MediaRecorder.h b/headers/private/media/MediaRecorder.h
    new file mode 100644
    index 0000000..b6d86b0
    - +  
     1/*
     2 * Copyright 2014, Haiku, Inc. All rights reserved.
     3 * Distributed under the terms of the MIT License.
     4 */
     5
     6#ifndef _MEDIA_RECORDER_H
     7#define _MEDIA_RECORDER_H
     8
     9#include <MediaNode.h>
     10#include <TimeSource.h>
     11
     12#include "MediaRecorderNode.h"
     13#include "SoundUtils.h"
     14
     15typedef void (*ProcessFunc)(void* cookie,
     16    bigtime_t timestamp, void* data, size_t datasize,
     17    const media_format& format);
     18
     19typedef void (*NotifyFunc)(void* cookie,
     20    int32 code, ...);
     21
     22
     23namespace BPrivate { namespace media {
     24
     25class BMediaRecorder
     26{
     27public:
     28                                BMediaRecorder(const char* name,
     29                                    int32 threadPriority = 0,
     30                                    media_type type
     31                                        = B_MEDIA_UNKNOWN_TYPE);
     32
     33    virtual                     ~BMediaRecorder();
     34
     35            status_t            InitCheck() const;
     36
     37            status_t            SetHooks(ProcessFunc recordFunc = NULL,
     38                                    NotifyFunc notifyFunc = NULL,
     39                                    void* cookie = NULL);
     40
     41            void                SetAcceptedFormat(
     42                                    const media_format& format);
     43
     44    virtual status_t            Start(bool force = false);
     45    virtual status_t            Stop(bool force = false);
     46
     47    virtual status_t            Connect(const media_format& format,
     48                                    uint32 flags = 0);
     49
     50    virtual status_t            Connect(const dormant_node_info& dormantInfo,
     51                                        const media_format* format = 0,
     52                                        uint32 flags = 0);
     53
     54    virtual status_t            Connect(const media_node& node,
     55                                        const media_output* useOutput = 0,
     56                                        const media_format* format = 0,
     57                                        uint32 flags = 0);
     58
     59    virtual status_t            Disconnect();
     60
     61            bool                IsConnected() const;
     62            bool                IsRunning() const;
     63
     64            const media_format& Format() const;
     65
     66            const media_node&   Node() const;
     67
     68            const media_output& MediaOutput() const;
     69            const media_input&  MediaInput() const;
     70
     71protected:
     72
     73    virtual void                BufferReceived(void* buffer,
     74                                    size_t size,
     75                                    const media_header& header);
     76
     77                                BMediaRecorder();
     78
     79                                BMediaRecorder(const BMediaRecorder&
     80                                    recorder);
     81
     82                                BMediaRecorder&  operator=(
     83                                    const BMediaRecorder& );
     84
     85private:
     86
     87        status_t                giga_connect(
     88                                    const media_format* format,
     89                                    uint32 flags,
     90                                    const dormant_node_info* dormantNode,
     91                                    const media_node* node,
     92                                    const media_output* output);
     93
     94        status_t                fInitErr;
     95
     96        bool                    fConnected;
     97        bool                    fRunning;
     98
     99        BMediaRecorderNode*     fNode;
     100        BTimeSource*            fTimeSource;
     101
     102        ProcessFunc             fRecordHook;
     103        NotifyFunc              fNotifyHook;
     104
     105        media_node              fOutputNode;
     106        media_output            fOutput;
     107   
     108        media_node              fInputNode;
     109        media_input             fInput;
     110
     111        void*                   fBufferCookie;
     112
     113        friend class            BMediaRecorderNode;
     114};
     115
     116}
     117
     118}
     119
     120using namespace BPrivate::media;
     121
     122#endif  //  _MEDIA_RECORDER_H
  • new file headers/private/media/MediaRecorderNode.h

    diff --git a/headers/private/media/MediaRecorderNode.h b/headers/private/media/MediaRecorderNode.h
    new file mode 100644
    index 0000000..0e8a48b
    - +  
     1//  MediaRecorderNode.h
     2//  -------------------
     3//  Copyright 1999, Be Incorporated.   All Rights Reserved.
     4//  Copyright 2014, Dario Casalinuovo. All Rights Reserved.
     5//  This file may be used under the terms of the Be Sample Code License.
     6
     7#ifndef _MEDIA_RECORDER_NODE_H
     8#define _MEDIA_RECORDER_NODE_H
     9
     10#include <BufferConsumer.h>
     11#include <MediaEventLooper.h>
     12#include <String.h>
     13
     14
     15namespace BPrivate { namespace media {
     16
     17class BMediaRecorder;
     18
     19class BMediaRecorderNode : public BMediaEventLooper,
     20public BBufferConsumer
     21{
     22public:
     23                            BMediaRecorderNode(
     24                                    const char*  name,
     25                                    BMediaRecorder*  rec,
     26                                    int32 priority,
     27                                    media_type type
     28                                        = B_MEDIA_UNKNOWN_TYPE);
     29
     30            //  TODO these are not thread safe; we should fix that...
     31            void            SetAcceptedFormat(
     32                                const media_format& format);
     33
     34            status_t        GetInput(media_input* out_input);
     35
     36            void            SetDataEnabled(bool enabled);
     37
     38protected:
     39
     40    virtual BMediaAddOn*    AddOn(int32*  internal_id) const;
     41
     42    virtual void            HandleEvent(
     43                                const media_timed_event* event,
     44                                bigtime_t lateness,
     45                                bool realTimeEvent);
     46
     47    virtual void            Start(bigtime_t performanceTime);
     48
     49    virtual void            Stop(bigtime_t performanceTime,
     50                                bool immediate);
     51
     52    virtual void            Seek(bigtime_t mediaTime,
     53                                bigtime_t performanceTime);
     54
     55    virtual void            TimeWarp(bigtime_t atRealTime,
     56                                bigtime_t to_performanceTime);
     57
     58    virtual status_t        HandleMessage(
     59                                    int32 message,
     60                                    const void*  data,
     61                                    size_t size);
     62       
     63            // Someone, probably the producer, is asking you about
     64            // this format. Give your honest opinion, possibly
     65            // modifying *format. Do not ask upstream producer about
     66            //  the format, since he's synchronously waiting for your
     67            // reply.
     68    virtual status_t        AcceptFormat(
     69                                    const media_destination& dest,
     70                                    media_format* format);
     71    virtual status_t        GetNextInput(
     72                                    int32* cookie,
     73                                    media_input* out_input);
     74    virtual void            DisposeInputCookie(
     75                                    int32 cookie);
     76    virtual void            BufferReceived(
     77                                    BBuffer* buffer);
     78    virtual void            ProducerDataStatus(
     79                                    const media_destination& for_whom,
     80                                    int32 status,
     81                                    bigtime_t at_performance_time);
     82    virtual status_t        GetLatencyFor(
     83                                    const media_destination& for_whom,
     84                                    bigtime_t*  out_latency,
     85                                    media_node_id*  out_timesource);
     86
     87    virtual status_t        Connected(
     88                                    const media_source& producer,
     89                                    const media_destination& where,
     90                                    const media_format& with_format,
     91                                    media_input* out_input);
     92    virtual void            Disconnected(
     93                                    const media_source& producer,
     94                                    const media_destination& where);
     95
     96    virtual status_t        FormatChanged(
     97                                    const media_source& producer,
     98                                    const media_destination& consumer,
     99                                    int32 change_tag,
     100                                    const media_format& format);
     101
     102protected:
     103
     104    virtual                 ~BMediaRecorderNode();
     105
     106            BMediaRecorder* fRecorder;
     107            media_format    fOKFormat;
     108            media_input     fInput;
     109            BString         fName;
     110};
     111
     112}
     113}
     114
     115using namespace BPrivate::media;
     116
     117#endif  //  _MEDIA_RECORDER_NODE_H
  • src/apps/soundrecorder/RecorderWindow.cpp

    diff --git a/src/apps/soundrecorder/RecorderWindow.cpp b/src/apps/soundrecorder/RecorderWindow.cpp
    index 91f9ea4..1c4167e 100644
    a b  
    11/*
    22 * Copyright 2005, Jérôme Duval. All rights reserved.
     3 * Copyright 2014, Dario Casalinuovo. All rights reserved.
    34 * Distributed under the terms of the MIT License.
    45 *
    56 * Inspired by SoundCapture from Be newsletter (Media Kit Basics:
     
    4243#include <TimeSource.h>
    4344#include <NodeInfo.h>
    4445
     46#include "SoundUtils.h"
    4547#include "RecorderWindow.h"
    46 #include "SoundConsumer.h"
    4748#include "FileUtils.h"
    4849
    4950#if ! NDEBUG
    RecorderWindow::RecorderWindow() 
    123124    fSaveButton = NULL;
    124125    fLoopButton = NULL;
    125126    fInputField = NULL;
    126     fRecordNode = 0;
     127    fRecorder = NULL;
    127128    fRecording = false;
    128129    fTempCount = -1;
    129130    fButtonState = btnPaused;
    RecorderWindow::RecorderWindow() 
    146147
    147148RecorderWindow::~RecorderWindow()
    148149{
    149     //  The sound consumer and producer are Nodes; it has to be released and the Roster
    150     //  will reap it when it's done.
    151     if (fRecordNode)
    152         fRecordNode->Release();
     150    //  The MediaRecorder have to be disconnected and deleted
     151    delete fRecorder;
     152
    153153    delete fPlayer;
    154154
    155155    if (fPlayTrack && fPlayFile)
    156156        fPlayFile->ReleaseTrack(fPlayTrack);
     157
    157158    if (fPlayFile)
    158159        delete fPlayFile;
    159160    fPlayTrack = NULL;
    RecorderWindow::InitWindow() 
    232233        if (error < B_OK) //    there's no mixer?
    233234            goto bad_mojo;
    234235
    235         //  Create our internal Node which records sound, and register it.
    236         fRecordNode = new SoundConsumer("Sound Recorder");
    237         error = fRoster->RegisterNode(fRecordNode);
    238         if (error < B_OK)
     236        fRecorder = new BMediaRecorder("Sound Recorder",
     237            B_REAL_TIME_PRIORITY, B_MEDIA_RAW_AUDIO);
     238
     239        if (fRecorder->InitCheck() < B_OK)
    239240            goto bad_mojo;
    240241
     242        // Set the node to accept only audio data
     243        media_format output_format;
     244        output_format.type = B_MEDIA_RAW_AUDIO;
     245        output_format.u.raw_audio = media_raw_audio_format::wildcard;
     246        fRecorder->SetAcceptedFormat(output_format);
     247
    241248        //  Create the window header with controls
    242249        BRect r(Bounds());
    243250        r.bottom = r.top + 175;
    244         BBox *background = new BBox(r, "_background", B_FOLLOW_LEFT_RIGHT
    245             | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, B_NO_BORDER);
     251        BBox *background = new BBox(r, "_background",
     252            B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, B_WILL_DRAW
     253            | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, B_NO_BORDER);
     254
    246255        AddChild(background);
    247256
    248257        r = background->Bounds();
    RecorderWindow::InitWindow() 
    451460        dormant_node_info dni[maxInputCount];
    452461
    453462        int32 real_count = maxInputCount;
    454         media_format output_format;
    455         output_format.type = B_MEDIA_RAW_AUDIO;
    456         output_format.u.raw_audio = media_raw_audio_format::wildcard;
     463
    457464        error = fRoster->GetDormantNodes(dni, &real_count, 0, &output_format,
    458465            0, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT);
    459466        if (real_count > maxInputCount) {
    RecorderWindow::InitWindow() 
    514521bad_mojo:
    515522    if (error >= 0)
    516523        error = B_ERROR;
    517     if (fRecordNode)
    518         fRecordNode->Release();
     524    if (fRecorder)
     525        delete fRecorder;
    519526
    520527    delete fPlayer;
    521528    if (!fInputField)
    RecorderWindow::Record(BMessage * message) 
    696703        return;
    697704    }
    698705
    699     //  And get it going...
    700     bigtime_t then = fRecordNode->TimeSource()->Now() + 50000LL;
    701     fRoster->StartNode(fRecordNode->Node(), then);
    702     if (fAudioInputNode.kind & B_TIME_SOURCE) {
    703         fRoster->StartNode(fAudioInputNode,
    704             fRecordNode->TimeSource()->RealTimeFor(then, 0));
    705     } else
    706         fRoster->StartNode(fAudioInputNode, then);
     706    fRecorder->Start();
    707707}
    708708
    709709
    RecorderWindow::Input(BMessage * message) 
    849849
    850850
    851851void
    852 RecorderWindow::Selected(BMessage * message)
     852RecorderWindow::Selected(BMessage* message)
    853853{
    854854    //  User selected a sound in list view
    855855    int32 selIdx = fSoundList->CurrentSelection();
    RecorderWindow::Selected(BMessage * message) 
    867867
    868868
    869869status_t
    870 RecorderWindow::MakeRecordConnection(const media_node & input)
     870RecorderWindow::MakeRecordConnection(const media_node& input)
    871871{
    872872    CONNECT((stderr, "RecorderWindow::MakeRecordConnection()\n"));
    873873
    874     //  Find an available output for the given input node.
    875     int32 count = 0;
    876     status_t err = fRoster->GetFreeOutputsFor(input, &fAudioOutput, 1, &count, B_MEDIA_RAW_AUDIO);
    877     if (err < B_OK) {
    878         CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
    879             " couldn't get free outputs from audio input node\n"));
    880         return err;
    881     }
    882     if (count < 1) {
    883         CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
    884             " no free outputs from audio input node\n"));
    885         return B_BUSY;
    886     }
     874    status_t err = B_OK;
     875    media_output audioOutput;
    887876
    888     //  Find an available input for our own Node. Note that we go through the
    889     //  MediaRoster; calling Media Kit methods directly on Nodes in our app is
    890     //  not OK (because synchronization happens in the service thread, not in
    891     //  the calling thread).
    892     // TODO: explain this
    893     err = fRoster->GetFreeInputsFor(fRecordNode->Node(), &fRecInput, 1, &count, B_MEDIA_RAW_AUDIO);
    894     if (err < B_OK) {
    895         CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
    896             " couldn't get free inputs for sound recorder\n"));
    897         return err;
    898     }
    899     if (count < 1) {
    900         CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
    901             " no free inputs for sound recorder\n"));
    902         return B_BUSY;
    903     }
     877    if (!fRecorder->IsConnected()) {
     878        //  Find an available output for the given input node.
     879        int32 count = 0;
     880        err = fRoster->GetFreeOutputsFor(input, &audioOutput, 1,
     881            &count, B_MEDIA_RAW_AUDIO);
    904882
    905     //  Find out what the time source of the input is.
    906     //  For most nodes, we just use the preferred time source (the DAC) for synchronization.
    907     //  However, nodes that record from an input need to synchronize to the audio input node
    908     //  instead for best results.
    909     //  MakeTimeSourceFor gives us a "clone" of the time source node that we can manipulate
    910     //  to our heart's content. When we're done with it, though, we need to call Release()
    911     //  on the time source node, so that it keeps an accurate reference count and can delete
    912     //  itself when it's no longer needed.
    913     // TODO: what about filters connected to audio input?
    914     media_node use_time_source;
    915     BTimeSource * tsobj = fRoster->MakeTimeSourceFor(input);
    916     if (! tsobj) {
    917         CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
    918             " couldn't clone time source from audio input node\n"));
    919         return B_MEDIA_BAD_NODE;
    920     }
     883        if (err < B_OK) {
     884            CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
     885                " couldn't get free outputs from audio input node\n"));
     886            return err;
     887        }
    921888
    922     //  Apply the time source in effect to our own Node.
    923     err = fRoster->SetTimeSourceFor(fRecordNode->Node().node, tsobj->Node().node);
    924     if (err < B_OK) {
     889        if (count < 1) {
     890            CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
     891                " no free outputs from audio input node\n"));
     892            return B_BUSY;
     893        }
     894
     895    } else {
    925896        CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
    926             " couldn't set the sound recorder's time source\n"));
    927         tsobj->Release();
    928         return err;
     897            " audio input node already connected\n"));
     898
     899        return B_BUSY;
    929900    }
    930901
     902   
     903
    931904    //  Get a format, any format.
    932     fRecordFormat.u.raw_audio = fAudioOutput.format.u.raw_audio;
     905    fRecordFormat.u.raw_audio = audioOutput.format.u.raw_audio;
    933906    fRecordFormat.type = B_MEDIA_RAW_AUDIO;
    934907
    935908    //  Tell the consumer where we want data to go.
    936     err = fRecordNode->SetHooks(RecordFile, NotifyRecordFile, this);
     909    err = fRecorder->SetHooks(RecordFile, NotifyRecordFile, this);
     910
    937911    if (err < B_OK) {
    938912        CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
    939913            " couldn't set the sound recorder's hook functions\n"));
    940         tsobj->Release();
    941914        return err;
    942915    }
    943916
    944     //  Using the same structs for input and output is OK in
    945     //  BMediaRoster::Connect().
    946     err = fRoster->Connect(fAudioOutput.source, fRecInput.destination,
    947         &fRecordFormat, &fAudioOutput, &fRecInput);
    948     if (err < B_OK) {
    949         CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
    950             " failed to connect sound recorder to audio input node.\n"));
    951         tsobj->Release();
    952         fRecordNode->SetHooks(0, 0, 0);
    953         return err;
    954     }
     917    if (!fRecorder->IsConnected()) {
    955918
    956     //  Start the time source if it's not running.
    957     if ((tsobj->Node() != input) && !tsobj->IsRunning())
    958         fRoster->StartNode(tsobj->Node(), BTimeSource::RealTime());
     919        err = fRecorder->Connect(input, &audioOutput, &fRecordFormat);
     920
     921        if (err < B_OK) {
     922            CONNECT((stderr, "RecorderWindow::MakeRecordConnection():"
     923                " failed to connect sound recorder to audio input node.\n"));
     924
     925            fRecorder->SetHooks(NULL, NULL, NULL);
     926            return err;
     927        }
     928    } else {
     929        fRecordFormat = fRecorder->Format();
     930    }
    959931
    960     tsobj->Release();   //  we're done with this time source instance!
    961932    return B_OK;
    962933}
    963934
    RecorderWindow::MakeRecordConnection(const media_node & input) 
    965936status_t
    966937RecorderWindow::BreakRecordConnection()
    967938{
    968     status_t err;
     939    status_t err = B_OK;
     940
     941    err = fRecorder->Stop(true);
     942    if (err < B_OK)
     943        return err;
     944
     945    err = fRecorder->Disconnect();
    969946
    970     //  If we are the last connection, the Node will stop automatically since it
    971     //  has nowhere to send data to.
    972     err = fRoster->StopNode(fRecInput.node, 0);
    973     err = fRoster->Disconnect(fAudioOutput.node.node, fAudioOutput.source,
    974         fRecInput.node.node, fRecInput.destination);
    975     fAudioOutput.source = media_source::null;
    976     fRecInput.destination = media_destination::null;
    977947    return err;
    978948}
    979949
    RecorderWindow::StopRecording() 
    984954    if (!fRecording)
    985955        return B_OK;
    986956    fRecording = false;
     957
    987958    BreakRecordConnection();
    988     fRecordNode->SetHooks(NULL,NULL,NULL);
     959
     960    fRecorder->SetHooks(NULL, NULL, NULL);
     961
    989962    if (fRecSize > 0) {
    990963
    991964        wave_struct header;
    RecorderWindow::RemoveCurrentSoundItem() { 
    12401213
    12411214void
    12421215RecorderWindow::RecordFile(void* cookie, bigtime_t timestamp,
    1243     void* data, size_t size, const media_raw_audio_format &format)
     1216    void* data, size_t size, const media_format &format)
    12441217{
    12451218    //  Callback called from the SoundConsumer when receiving buffers.
    12461219    RecorderWindow * window = (RecorderWindow *)cookie;
    RecorderWindow::RecordFile(void* cookie, bigtime_t timestamp, 
    12491222        //  Write the data to file (we don't buffer or guard file access
    12501223        //  or anything)
    12511224        window->fRecFile.WriteAt(window->fRecSize, data, size);
    1252         window->fVUView->ComputeLevels(data, size, format.format);
     1225        window->fVUView->ComputeLevels(data, size, format.u.raw_audio.format);
    12531226        window->fRecSize += size;
    12541227    }
    12551228}
  • src/apps/soundrecorder/RecorderWindow.h

    diff --git a/src/apps/soundrecorder/RecorderWindow.h b/src/apps/soundrecorder/RecorderWindow.h
    index 1688334..b92acd6 100644
    a b  
    2121#include <Window.h>
    2222
    2323#include "DrawButton.h"
     24#include "MediaRecorder.h"
    2425#include "ScopeView.h"
    2526#include "SoundListView.h"
    2627#include "TransportButton.h"
    class BScrollView; 
    4041class BSlider;
    4142class BStringView;
    4243
    43 namespace BPrivate {
    44 class SoundConsumer;
    45 }
    4644
     45using BPrivate::media::BMediaRecorder;
    4746
    48 using BPrivate::SoundConsumer;
    4947
    50 
    51 class RecorderWindow : public BWindow {
     48class RecorderWindow : public BWindow
     49{
    5250public:
    53         RecorderWindow();
    54     virtual ~RecorderWindow();
    55         status_t InitCheck();
     51                                RecorderWindow();
     52    virtual                     ~RecorderWindow();
     53            status_t            InitCheck();
    5654
    5755
    58     virtual bool QuitRequested();
    59     virtual void MessageReceived(BMessage * message);
     56    virtual bool                QuitRequested();
     57    virtual void                MessageReceived(BMessage* message);
    6058
    6159        enum {
    6260            RECORD = 'cw00',            //  command messages
    public: 
    7775            POSITION_CHANGED
    7876        };
    7977
    80         void AddSoundItem(const BEntry& entry, bool temp = false);
    81         void RemoveCurrentSoundItem();
     78            void                AddSoundItem(const BEntry& entry,
     79                                    bool temp = false);
     80
     81            void                RemoveCurrentSoundItem();
    8282
    8383private:
    8484        BMediaRoster * fRoster;
    private: 
    9595        TrackSlider *fTrackSlider;
    9696        UpDownButton * fUpDownButton;
    9797        BMenuField * fInputField;
    98         SoundConsumer * fRecordNode;
     98        BMediaRecorder* fRecorder;
    9999        BSoundPlayer * fPlayer;
    100100        bool fRecording;
    101101        SoundListView * fSoundList;
    private: 
    128128        off_t fRecSize;
    129129
    130130        media_node fAudioInputNode;
    131         media_output fAudioOutput;
    132         media_input fRecInput;
    133131
    134132        BMediaFile *fPlayFile;
    135133        media_format fPlayFormat;
    private: 
    171169        status_t UpdatePlayFile(SoundListItem *item, bool updateDisplay = false);
    172170        void ErrorAlert(const char * action, status_t err);
    173171
    174 static  void RecordFile(void * cookie, bigtime_t timestamp, void * data, size_t size, const media_raw_audio_format & format);
     172static  void RecordFile(void * cookie, bigtime_t timestamp, void * data, size_t size, const media_format & format);
    175173static  void NotifyRecordFile(void * cookie, int32 code, ...);
    176174
    177175static  void PlayFile(void * cookie, void * data, size_t size, const media_raw_audio_format & format);
  • src/kits/media/Jamfile

    diff --git a/src/kits/media/Jamfile b/src/kits/media/Jamfile
    index 96dd800..bdb642e 100644
    a b for architectureObject in [ MultiArchSubDirSetup ] { 
    1919        SharedLibrary [ MultiArchDefaultGristFiles libmedia.so ] :
    2020            # Private Media Kit
    2121            !missing_symbols.cpp
     22            MediaRecorder.cpp
     23            MediaRecorderNode.cpp
    2224            SoundConsumer.cpp
    2325
    2426            # Public Media Kit
  • new file src/kits/media/MediaRecorder.cpp

    diff --git a/src/kits/media/MediaRecorder.cpp b/src/kits/media/MediaRecorder.cpp
    new file mode 100644
    index 0000000..7d35f16
    - +  
     1//  MediaRecorder.cpp
     2//  -----------------
     3//  Copyright 1999, Be Incorporated.   All Rights Reserved.
     4//  Copyright 2014, Dario Casalinuovo. All Rights Reserved.
     5//  This file may be used under the terms of the Be Sample Code License.
     6
     7#include "MediaRecorder.h"
     8
     9#include <MediaAddOn.h>
     10#include <MediaRoster.h>
     11#include <TimeSource.h>
     12
     13#include "MediaRecorderNode.h"
     14
     15
     16class StNodeRelease
     17{
     18public:
     19                StNodeRelease(media_node& mediaNode, bool r = true)
     20                    :
     21                    node(mediaNode),
     22                    rel(r)
     23                    {}
     24
     25                ~StNodeRelease()
     26                {
     27                    if (rel)
     28                        BMediaRoster::Roster()->ReleaseNode(node);
     29                }
     30
     31    void        SetRelease(bool r)
     32                {
     33                    rel = r;
     34                }
     35
     36private:
     37    media_node& node;
     38    bool        rel;
     39};
     40
     41
     42BMediaRecorder::BMediaRecorder(const char* name, int32 priority,
     43    media_type type)
     44    :
     45    fInitErr(0),
     46    fConnected(false),
     47    fRunning(false),
     48    fNode(0),
     49    fTimeSource(0),
     50    fRecordHook(NULL),
     51    fNotifyHook(NULL),
     52    fBufferCookie(0)
     53{
     54    (void)BMediaRoster::Roster(&fInitErr);
     55
     56    if (fInitErr == B_OK) {
     57
     58        if (priority < 5)
     59            priority = 115;
     60
     61        fNode = new BMediaRecorderNode(name, this, priority, type);
     62        fInitErr = BMediaRoster::CurrentRoster()->RegisterNode(fNode);
     63
     64        if (fInitErr == B_OK)
     65            fOutputNode = fNode->Node();
     66    }
     67}
     68
     69
     70BMediaRecorder::~BMediaRecorder()
     71{
     72    if (fNode != 0) {
     73        (void)Stop();
     74
     75        (void)Disconnect();
     76
     77        fNode->Release();
     78    }
     79
     80    if (fTimeSource != 0)
     81        fTimeSource->Release();
     82
     83}
     84
     85
     86status_t
     87BMediaRecorder::InitCheck() const
     88{
     89    return fInitErr;
     90}
     91
     92
     93void
     94BMediaRecorder::SetAcceptedFormat(const media_format& format)
     95{
     96    fNode->SetAcceptedFormat(format);
     97}
     98
     99
     100status_t
     101BMediaRecorder::SetHooks(ProcessFunc recordFunc, NotifyFunc notifyFunc,
     102    void* cookie)
     103{
     104    fRecordHook = recordFunc;
     105    fNotifyHook = notifyFunc;
     106    fBufferCookie = cookie;
     107
     108    return B_OK;
     109}
     110
     111
     112void
     113BMediaRecorder::BufferReceived(void* data, size_t size,
     114    const media_header& header)
     115{
     116    if (fRecordHook) {
     117        (*fRecordHook)(fBufferCookie, header.start_time,
     118            data, size, Format());
     119    }
     120}
     121
     122
     123status_t
     124BMediaRecorder::Connect(const media_format& format, uint32 flags)
     125{
     126    if (fInitErr != B_OK)
     127        return fInitErr;
     128
     129    if (fConnected)
     130        return B_MEDIA_ALREADY_CONNECTED;
     131
     132    return giga_connect(&format, flags, 0, 0, 0);
     133}
     134
     135
     136status_t
     137BMediaRecorder::Connect(const dormant_node_info& info,
     138    const media_format* format, uint32 flags)
     139{
     140    if (fInitErr != B_OK)
     141        return fInitErr;
     142
     143    if (fConnected)
     144        return B_MEDIA_ALREADY_CONNECTED;
     145
     146    return giga_connect(format, flags, &info, 0, 0);
     147}
     148
     149
     150status_t
     151BMediaRecorder::Connect(const media_node& node,
     152    const media_output* use_output, const media_format* format,
     153    uint32 flags)
     154{
     155    if (fInitErr != B_OK)
     156        return fInitErr;
     157
     158    if (fConnected)
     159        return B_MEDIA_ALREADY_CONNECTED;
     160
     161    return giga_connect(format, flags, 0, &node, use_output);
     162}
     163
     164
     165status_t
     166BMediaRecorder::Disconnect()
     167{
     168    if (fInitErr != B_OK)
     169        return fInitErr;
     170
     171    if (!fConnected)
     172        return B_MEDIA_NOT_CONNECTED;
     173
     174    if (!fNode)
     175        return B_ERROR;
     176
     177    //  do the disconnect
     178    status_t err = BMediaRoster::CurrentRoster()->Disconnect(
     179        fOutputNode.node, fOutput.source,
     180            fOutputNode.node, fInput.destination);
     181
     182    if (fTimeSource != 0) {
     183        fTimeSource->Release();
     184        fTimeSource = 0;
     185    }
     186
     187    fConnected = false;
     188    fRunning = false;
     189
     190    return err;
     191}
     192
     193
     194status_t
     195BMediaRecorder::Start(bool force)
     196{
     197    if (fInitErr != B_OK)
     198        return fInitErr;
     199
     200    if (!fConnected)
     201        return B_MEDIA_NOT_CONNECTED;
     202
     203    if (fRunning && !force)
     204        return EALREADY;
     205
     206    if (!fNode)
     207        return B_ERROR;
     208
     209    //  start node here
     210    status_t err = B_OK;
     211
     212    if (fInputNode.kind & B_TIME_SOURCE) {
     213        err = BMediaRoster::CurrentRoster()->StartTimeSource(
     214            fOutputNode, BTimeSource::RealTime());
     215    } else {
     216        err = BMediaRoster::CurrentRoster()->StartNode(
     217            fOutputNode, fTimeSource->Now());
     218    }
     219
     220    //  then un-mute it
     221    if (err == B_OK)
     222        fNode->SetDataEnabled(true);
     223
     224    fRunning = (err == B_OK);
     225
     226    return err;
     227}
     228
     229
     230status_t
     231BMediaRecorder::Stop(bool force)
     232{
     233    if (fInitErr != B_OK)
     234        return fInitErr;
     235
     236    if (!fRunning && !force)
     237        return EALREADY;
     238
     239    if (!fNode)
     240        return B_ERROR;
     241
     242    //  should have the Node mute the output here
     243    fNode->SetDataEnabled(false);
     244
     245    fRunning = false;
     246    return B_OK;
     247}
     248
     249
     250bool
     251BMediaRecorder::IsRunning() const
     252{
     253    return fRunning;
     254}
     255
     256
     257bool
     258BMediaRecorder::IsConnected() const
     259{
     260    return fConnected;
     261}
     262
     263
     264const media_node&
     265BMediaRecorder::Node() const
     266{
     267    return fOutputNode;
     268}
     269
     270
     271const media_output&
     272BMediaRecorder::MediaOutput() const
     273{
     274    return fOutput;
     275}
     276
     277
     278const media_input&
     279BMediaRecorder::MediaInput() const
     280{
     281    return fInput;
     282}
     283
     284
     285const media_format&
     286BMediaRecorder::Format() const
     287{
     288    return fOutput.format;
     289}
     290
     291
     292status_t
     293BMediaRecorder::giga_connect(const media_format* in_format,
     294    uint32 in_flags, const dormant_node_info* in_dormant,
     295    const media_node* in_node, const media_output* in_output)
     296{
     297    media_format fmt;
     298    media_node node;
     299    StNodeRelease away(node, false);
     300    status_t err = B_OK;
     301    media_output out;
     302
     303    //  argument checking and set-up
     304    if (in_format != 0)
     305        fmt = *in_format;
     306
     307    if (fNode == 0)
     308        return B_ERROR;
     309
     310    if (in_node == 0 && in_output != 0)
     311        return B_MISMATCHED_VALUES;
     312
     313    if (in_dormant != 0 && (in_node != 0 || in_output != 0))
     314        return B_MISMATCHED_VALUES;
     315
     316    if (in_format == 0 && in_output != 0)
     317        fmt = in_output->format;
     318
     319    fNode->SetAcceptedFormat(fmt);
     320
     321    //  figure out the node
     322    //  instantiate?
     323    if (in_dormant != 0) {
     324        err = BMediaRoster::Roster()->InstantiateDormantNode(
     325            *in_dormant, &node, B_FLAVOR_IS_GLOBAL);
     326
     327        away.SetRelease(true);
     328
     329    } else if (in_node != 0) {
     330        // provided?
     331        node = *in_node;
     332    } else {
     333        switch (fmt.type) {
     334
     335            //  switch on format for default
     336            case B_MEDIA_RAW_AUDIO:
     337                err = BMediaRoster::Roster()->GetAudioInput(&node);
     338                away.SetRelease(true);
     339                break;
     340
     341            case B_MEDIA_RAW_VIDEO:
     342            case B_MEDIA_ENCODED_VIDEO:
     343                err = BMediaRoster::Roster()->GetVideoInput(&node);
     344                away.SetRelease(true);
     345                break;
     346
     347            //  give up?
     348            default:
     349                return B_MEDIA_BAD_FORMAT;
     350                break;
     351        }
     352    }
     353
     354    fOutputNode = node;
     355
     356    //  figure out the output
     357    //  provided?
     358
     359    if (in_output != 0) {
     360
     361        out = *in_output;
     362
     363    } else if (err == B_OK) {
     364
     365        media_output outputs[10];
     366        int32 count = 10;
     367
     368        err = BMediaRoster::Roster()->GetFreeOutputsFor(node, outputs, count,
     369            &count, fmt.type);
     370
     371        if (err == B_OK) {
     372
     373            err = B_MEDIA_BAD_SOURCE;
     374
     375            for (int i=0; i<count; i++) {
     376                if (format_is_compatible(outputs[i].format, fmt)) {
     377                    out = outputs[i];
     378                    err = B_OK;
     379                    fmt = outputs[i].format;
     380                    break;
     381                }
     382
     383            }
     384
     385        }
     386
     387    }
     388
     389    //  give up?
     390    if (err != B_OK) {
     391        return err;
     392    }
     393
     394    if (out.source == media_source::null) {
     395        return B_MEDIA_BAD_SOURCE;
     396    }
     397
     398    //  find our Node's free input
     399    media_input in;
     400    err = fNode->GetInput(&in);
     401    media_node time_source;
     402
     403    if (node.kind & B_TIME_SOURCE) {
     404        time_source = node;
     405    } else {
     406        BMediaRoster::Roster()->GetSystemTimeSource(&time_source);
     407    }
     408
     409    //  set time source
     410    if (err == B_OK) {
     411        BMediaRoster::Roster()->SetTimeSourceFor(
     412            fOutputNode.node, time_source.node);
     413
     414        fTimeSource = BMediaRoster::CurrentRoster()->MakeTimeSourceFor(
     415            fOutputNode);
     416    }
     417
     418    //  start the recorder node (it's always running)
     419    if (err == B_OK) {
     420        err = BMediaRoster::CurrentRoster()->StartNode(
     421            fOutputNode, fTimeSource->Now());
     422    }
     423
     424    //  perform the connection
     425    if (err == B_OK) {
     426        fOutput = out;
     427        fInput = in;
     428
     429        err = BMediaRoster::CurrentRoster()->Connect(fOutput.source,
     430            fInput.destination, &fmt, &fOutput, &fInput,
     431            BMediaRoster::B_CONNECT_MUTED);
     432
     433        if (err == B_OK) {
     434            fConnected = true;
     435            away.SetRelease(false);
     436        }
     437    }
     438
     439    return err;
     440}
  • new file src/kits/media/MediaRecorderNode.cpp

    diff --git a/src/kits/media/MediaRecorderNode.cpp b/src/kits/media/MediaRecorderNode.cpp
    new file mode 100644
    index 0000000..8db186d
    - +  
     1//  MediaRecorderNode.cpp
     2//  ---------------------
     3//  Copyright 1999, Be Incorporated.   All Rights Reserved.
     4//  Copyright 2014, Dario Casalinuovo. All Rights Reserved.
     5//  This file may be used under the terms of the Be Sample Code License.
     6
     7#include "MediaRecorderNode.h"
     8
     9#include <Buffer.h>
     10#include <TimedEventQueue.h>
     11#include <TimeSource.h>
     12
     13#include <stdio.h>
     14
     15#include "MediaRecorder.h"
     16
     17
     18BMediaRecorderNode::BMediaRecorderNode(const char* name,
     19    BMediaRecorder* rec, int32 priority, media_type type)
     20    :
     21    BMediaNode(name),
     22    BMediaEventLooper(),
     23    BBufferConsumer(type),
     24    fRecorder(rec)
     25{
     26    SetPriority(priority);
     27
     28    fInput.destination.id = 1;
     29    fInput.destination.port = ControlPort();
     30
     31    sprintf(fInput.name, "%.20s Input", name);
     32
     33    fName.SetTo(name);
     34}
     35
     36
     37BMediaRecorderNode::~BMediaRecorderNode()
     38{
     39}
     40
     41
     42BMediaAddOn*
     43BMediaRecorderNode::AddOn(int32* internal_id) const
     44{
     45    if (internal_id)
     46        *internal_id = -1;
     47
     48    return NULL;
     49}
     50
     51
     52void
     53BMediaRecorderNode::SetAcceptedFormat(const media_format &format)
     54{
     55    fOKFormat = format;
     56}
     57
     58
     59status_t
     60BMediaRecorderNode::GetInput(media_input*  out_input)
     61{
     62    fInput.node = Node();
     63    *out_input = fInput;
     64
     65    return B_OK;
     66}
     67
     68
     69void
     70BMediaRecorderNode::SetDataEnabled(bool enabled)
     71{
     72    int32 tag;
     73
     74    (void)SetOutputEnabled(fInput.source,
     75        fInput.destination, enabled, 0, &tag);
     76}
     77
     78
     79void
     80BMediaRecorderNode::HandleEvent(const media_timed_event* event,
     81    bigtime_t lateness, bool realTimeEvent )
     82{
     83    //  we ignore them all!
     84}
     85
     86
     87void
     88BMediaRecorderNode::Start(bigtime_t performance_time)
     89{
     90    if (fRecorder->fNotifyHook) {
     91        (*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
     92            B_WILL_START, performance_time);
     93    }
     94
     95    fRecorder->fRunning = true;
     96}
     97
     98
     99void
     100BMediaRecorderNode::Stop(bigtime_t performance_time, bool immediate)
     101{
     102    if (fRecorder->fNotifyHook) {
     103        (*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
     104            B_WILL_STOP, performance_time, immediate);
     105    }
     106
     107    fRecorder->fRunning = false;
     108}
     109
     110
     111void
     112BMediaRecorderNode::Seek(bigtime_t media_time,
     113    bigtime_t performance_time)
     114{
     115    if (fRecorder->fNotifyHook) {
     116        (*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
     117            B_WILL_SEEK, performance_time, media_time);
     118    }
     119}
     120
     121
     122void
     123BMediaRecorderNode::TimeWarp(bigtime_t real_time,
     124    bigtime_t performance_time)
     125{
     126    //  Since buffers will come pre-time-stamped, we only need to look
     127    //  at them, so we can ignore the time warp as a consumer.
     128    if (fRecorder->fNotifyHook) {
     129        (*fRecorder->fNotifyHook)(fRecorder->fBufferCookie,
     130            B_WILL_TIMEWARP, real_time, performance_time);
     131    }
     132}
     133
     134
     135status_t
     136BMediaRecorderNode::HandleMessage(int32 message,
     137    const void* data, size_t size)
     138{
     139    if (BBufferConsumer::HandleMessage(message, data, size) < 0
     140        && BMediaEventLooper::HandleMessage(message, data, size) < 0
     141        && BMediaNode::HandleMessage(message, data, size) < 0) {
     142
     143        HandleBadMessage(message, data, size);
     144
     145        return B_ERROR;
     146    }
     147
     148    return B_OK;
     149}
     150
     151
     152status_t
     153BMediaRecorderNode::AcceptFormat(const media_destination& dest,
     154    media_format* format)
     155{
     156    if (format_is_compatible(*format, fOKFormat))
     157        return B_OK;
     158
     159    *format = fOKFormat;
     160
     161    return B_MEDIA_BAD_FORMAT;
     162}
     163
     164
     165status_t
     166BMediaRecorderNode::GetNextInput(int32* cookie, media_input* out_input)
     167{
     168    if (*cookie == 0) {
     169        *cookie = -1;
     170        *out_input = fInput;
     171        return B_OK;
     172    }
     173
     174    return B_BAD_INDEX;
     175}
     176
     177
     178void
     179BMediaRecorderNode::DisposeInputCookie(int32 cookie)
     180{
     181}
     182
     183
     184void
     185BMediaRecorderNode::BufferReceived(BBuffer* buffer)
     186{
     187    fRecorder->BufferReceived(buffer->Data(), buffer->SizeUsed(),
     188        *buffer->Header());
     189
     190    buffer->Recycle();
     191}
     192
     193
     194void
     195BMediaRecorderNode::ProducerDataStatus(
     196    const media_destination&  for_whom, int32 status,
     197    bigtime_t at_performance_time)
     198{
     199}
     200
     201
     202status_t
     203BMediaRecorderNode::GetLatencyFor(const media_destination& for_whom,
     204    bigtime_t* out_latency, media_node_id* out_timesource)
     205{
     206    *out_latency = 0;
     207    *out_timesource = TimeSource()->ID();
     208
     209    return B_OK;
     210}
     211
     212
     213status_t
     214BMediaRecorderNode::Connected(const media_source &producer,
     215    const media_destination &where, const media_format &with_format,
     216    media_input* out_input)
     217{
     218    fInput.source = producer;
     219    fInput.format = with_format;
     220    *out_input = fInput;
     221
     222    fRecorder->fConnected = true;
     223    fRecorder->fInput = fInput;
     224    fRecorder->fInputNode = fInput.node;
     225
     226    return B_OK;
     227}
     228
     229
     230void
     231BMediaRecorderNode::Disconnected(const media_source& producer,
     232    const media_destination& where)
     233{
     234    fInput.source = media_source::null;
     235    sprintf(fInput.name, "%.20s Input", fName.String());
     236
     237    fRecorder->fConnected = false;
     238
     239    fRecorder->fOutput.source = media_source::null;
     240    fRecorder->fInput.destination = media_destination::null;
     241    fRecorder->fInput.format = fOKFormat;
     242}
     243
     244
     245status_t
     246BMediaRecorderNode::FormatChanged(const media_source& producer,
     247    const media_destination& consumer, int32 change_tag,
     248    const media_format& format)
     249{
     250    if (!format_is_compatible(format, fOKFormat))
     251        return B_MEDIA_BAD_FORMAT;
     252
     253    fInput.format = format;
     254
     255    return B_OK;
     256}