1 // NodeHarnessWin.cpp 2 3 #include "NodeHarnessWin.h" 4 #include "LoggingConsumer.h" 5 #include <app/Application.h> 6 #include <interface/Button.h> 7 //#include <storage/Entry.h> 8 #include <Entry.h> 9 #include <media/MediaRoster.h> 10 #include <media/MediaAddOn.h> 11 #include <media/TimeSource.h> 12 #include <media/MediaTheme.h> 13 #include <stdio.h> 14 15 const int32 BUTTON_CONNECT = 'Cnct'; 16 const int32 BUTTON_START = 'Strt'; 17 const int32 BUTTON_STOP = 'Stop'; 18 19 #define TEST_WITH_AUDIO 1 20 21 // -------------------- 22 // static utility functions 23 static void ErrorCheck(status_t err, const char* msg) 24 { 25 if (err) 26 { 27 fprintf(stderr, "* FATAL ERROR (%s): %s\n", strerror(err), msg); 28 exit(1); 29 } 30 } 31 32 // -------------------- 33 // NodeHarnessWin implementation 34 NodeHarnessWin::NodeHarnessWin(BRect frame, const char *title) 35 : BWindow(frame, title, B_TITLED_WINDOW, B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS), 36 mLogNode(NULL), mIsConnected(false), mIsRunning(false) 37 { 38 // build the UI 39 BRect r(10, 10, 100, 40); 40 mConnectButton = new BButton(r, "Connect", "Connect", new BMessage(BUTTON_CONNECT)); 41 mConnectButton->SetEnabled(true); 42 AddChild(mConnectButton); 43 r.OffsetBy(0, 40); 44 mStartButton = new BButton(r, "Start", "Start", new BMessage(BUTTON_START)); 45 mStartButton->SetEnabled(false); 46 AddChild(mStartButton); 47 r.OffsetBy(0, 40); 48 mStopButton = new BButton(r, "Stop", "Stop", new BMessage(BUTTON_STOP)); 49 mStopButton->SetEnabled(false); 50 AddChild(mStopButton); 51 } 52 53 NodeHarnessWin::~NodeHarnessWin() 54 { 55 BMediaRoster* r = BMediaRoster::Roster(); 56 57 // tear down the node network 58 if (mIsRunning) StopNodes(); 59 if (mIsConnected) 60 { 61 printf("Total late buffers: %ld\n", mLogNode->LateBuffers()); 62 r->StopNode(mConnection.consumer, 0, true); 63 r->Disconnect(mConnection.producer.node, mConnection.source, 64 mConnection.consumer.node, mConnection.destination); 65 r->ReleaseNode(mConnection.producer); 66 r->ReleaseNode(mConnection.consumer); 67 } 68 } 69 70 void 71 NodeHarnessWin::Quit() 72 { 73 be_app->PostMessage(B_QUIT_REQUESTED); 74 BWindow::Quit(); 75 } 76 77 void 78 NodeHarnessWin::MessageReceived(BMessage *msg) 79 { 80 status_t err; 81 82 switch (msg->what) 83 { 84 case BUTTON_CONNECT: 85 mIsConnected = true; 86 87 // set the button states appropriately 88 mConnectButton->SetEnabled(false); 89 mStartButton->SetEnabled(true); 90 91 // set up the node network 92 { 93 BMediaRoster* r = BMediaRoster::Roster(); 94 95 // find a node that can handle an audio file 96 #if TEST_WITH_AUDIO 97 entry_ref inRef; 98 dormant_node_info info; 99 100 ::get_ref_for_path("/boot/optional/sound/virtual (void)", &inRef); 101 err = r->SniffRef(inRef, B_BUFFER_PRODUCER | B_FILE_INTERFACE, &info); 102 ErrorCheck(err, "couldn't find file reader node\n"); 103 104 err = r->InstantiateDormantNode(info, &mConnection.producer, B_FLAVOR_IS_LOCAL); 105 ErrorCheck(err, "couldn't instantiate file reader node\n"); 106 107 bigtime_t dummy_length; // output = media length; we don't use it 108 err = r->SetRefFor(mConnection.producer, inRef, false, &dummy_length); 109 ErrorCheck(err, "unable to SetRefFor() to read that sound file!\n"); 110 #else 111 r->GetVideoInput(&mConnection.producer); 112 #endif 113 114 entry_ref logRef; 115 ::get_ref_for_path("/tmp/node_log", &logRef); 116 117 mLogNode = new LoggingConsumer(logRef); 118 err = r->RegisterNode(mLogNode); 119 ErrorCheck(err, "unable to register LoggingConsumer node!\n"); 120 // make sure the Media Roster knows that we're using the node 121 r->GetNodeFor(mLogNode->Node().node, &mConnection.consumer); 122 123 // trim down the log's verbosity a touch 124 mLogNode->SetEnabled(LOG_HANDLE_EVENT, false); 125 126 // fire off a window with the LoggingConsumer's controls in it 127 BParameterWeb* web; 128 r->GetParameterWebFor(mConnection.consumer, &web); 129 BView* view = BMediaTheme::ViewFor(web); 130 BWindow* win = new BWindow(BRect(250, 200, 300, 300), "Controls", 131 B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS); 132 win->AddChild(view); 133 win->ResizeTo(view->Bounds().Width(), view->Bounds().Height()); 134 win->Show(); 135 136 // set the nodes' time sources 137 r->GetTimeSource(&mTimeSource); 138 r->SetTimeSourceFor(mConnection.consumer.node, mTimeSource.node); 139 r->SetTimeSourceFor(mConnection.producer.node, mTimeSource.node); 140 141 // got the nodes; now we find the endpoints of the connection 142 media_input logInput; 143 media_output soundOutput; 144 int32 count; 145 err = r->GetFreeOutputsFor(mConnection.producer, &soundOutput, 1, &count); 146 ErrorCheck(err, "unable to get a free output from the producer node"); 147 err = r->GetFreeInputsFor(mConnection.consumer, &logInput, 1, &count); 148 ErrorCheck(err, "unable to get a free input to the LoggingConsumer"); 149 150 // fill in the rest of the Connection object 151 mConnection.source = soundOutput.source; 152 mConnection.destination = logInput.destination; 153 154 // got the endpoints; now we connect it! 155 media_format format; 156 #if TEST_WITH_AUDIO 157 format.type = B_MEDIA_RAW_AUDIO; // !!! hmmm.. how to fully wildcard this? 158 format.u.raw_audio = media_raw_audio_format::wildcard; 159 #else 160 format.type = B_MEDIA_RAW_VIDEO; // !!! hmmm.. how to fully wildcard this? 161 format.u.raw_video = media_raw_video_format::wildcard; 162 #endif 163 err = r->Connect(mConnection.source, mConnection.destination, &format, &soundOutput, &logInput); 164 ErrorCheck(err, "unable to connect nodes"); 165 mConnection.format = format; 166 167 // for video input, we need to set the downstream latency for record -> playback 168 bigtime_t latency; 169 r->GetLatencyFor(mConnection.producer, &latency); 170 printf("Setting producer run mode latency to %Ld\n", latency); 171 r->SetProducerRunModeDelay(mConnection.producer, latency + 6000); 172 173 // preroll first, to be a good citizen 174 r->PrerollNode(mConnection.consumer); 175 r->PrerollNode(mConnection.producer); 176 177 // start the LoggingConsumer and leave it running 178 BTimeSource* ts = r->MakeTimeSourceFor(mTimeSource); 179 r->StartNode(mConnection.consumer, ts->Now()); 180 ts->Release(); 181 } 182 break; 183 184 case BUTTON_START: 185 mStartButton->SetEnabled(false); 186 mStopButton->SetEnabled(true); 187 188 // start the consumer running 189 { 190 bigtime_t latency; 191 BMediaRoster* r = BMediaRoster::Roster(); 192 BTimeSource* ts = r->MakeTimeSourceFor(mConnection.consumer); 193 r->GetLatencyFor(mConnection.producer, &latency); 194 r->StartNode(mConnection.producer, ts->Now() + latency); 195 ts->Release(); 196 mIsRunning = true; 197 } 198 break; 199 200 case BUTTON_STOP: 201 StopNodes(); 202 break; 203 204 default: 205 BWindow::MessageReceived(msg); 206 break; 207 } 208 } 209 210 // Private routines 211 void 212 NodeHarnessWin::StopNodes() 213 { 214 mStartButton->SetEnabled(true); 215 mStopButton->SetEnabled(false); 216 217 // stop the producer 218 { 219 BMediaRoster* r = BMediaRoster::Roster(); 220 r->StopNode(mConnection.producer, 0, true); // synchronous stop 221 } 222 } 223 224