Ticket #8911: soundrecord.diff
File soundrecord.diff, 32.4 KB (added by , 10 years ago) |
---|
-
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 15 typedef void (*ProcessFunc)(void* cookie, 16 bigtime_t timestamp, void* data, size_t datasize, 17 const media_format& format); 18 19 typedef void (*NotifyFunc)(void* cookie, 20 int32 code, ...); 21 22 23 namespace BPrivate { namespace media { 24 25 class BMediaRecorder 26 { 27 public: 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 71 protected: 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 85 private: 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 120 using 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 15 namespace BPrivate { namespace media { 16 17 class BMediaRecorder; 18 19 class BMediaRecorderNode : public BMediaEventLooper, 20 public BBufferConsumer 21 { 22 public: 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 38 protected: 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 102 protected: 103 104 virtual ~BMediaRecorderNode(); 105 106 BMediaRecorder* fRecorder; 107 media_format fOKFormat; 108 media_input fInput; 109 BString fName; 110 }; 111 112 } 113 } 114 115 using 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 1 1 /* 2 2 * Copyright 2005, Jérôme Duval. All rights reserved. 3 * Copyright 2014, Dario Casalinuovo. All rights reserved. 3 4 * Distributed under the terms of the MIT License. 4 5 * 5 6 * Inspired by SoundCapture from Be newsletter (Media Kit Basics: … … 42 43 #include <TimeSource.h> 43 44 #include <NodeInfo.h> 44 45 46 #include "SoundUtils.h" 45 47 #include "RecorderWindow.h" 46 #include "SoundConsumer.h"47 48 #include "FileUtils.h" 48 49 49 50 #if ! NDEBUG … … RecorderWindow::RecorderWindow() 123 124 fSaveButton = NULL; 124 125 fLoopButton = NULL; 125 126 fInputField = NULL; 126 fRecord Node = 0;127 fRecorder = NULL; 127 128 fRecording = false; 128 129 fTempCount = -1; 129 130 fButtonState = btnPaused; … … RecorderWindow::RecorderWindow() 146 147 147 148 RecorderWindow::~RecorderWindow() 148 149 { 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 153 153 delete fPlayer; 154 154 155 155 if (fPlayTrack && fPlayFile) 156 156 fPlayFile->ReleaseTrack(fPlayTrack); 157 157 158 if (fPlayFile) 158 159 delete fPlayFile; 159 160 fPlayTrack = NULL; … … RecorderWindow::InitWindow() 232 233 if (error < B_OK) // there's no mixer? 233 234 goto bad_mojo; 234 235 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) 239 240 goto bad_mojo; 240 241 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 241 248 // Create the window header with controls 242 249 BRect r(Bounds()); 243 250 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 246 255 AddChild(background); 247 256 248 257 r = background->Bounds(); … … RecorderWindow::InitWindow() 451 460 dormant_node_info dni[maxInputCount]; 452 461 453 462 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 457 464 error = fRoster->GetDormantNodes(dni, &real_count, 0, &output_format, 458 465 0, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT); 459 466 if (real_count > maxInputCount) { … … RecorderWindow::InitWindow() 514 521 bad_mojo: 515 522 if (error >= 0) 516 523 error = B_ERROR; 517 if (fRecord Node)518 fRecordNode->Release();524 if (fRecorder) 525 delete fRecorder; 519 526 520 527 delete fPlayer; 521 528 if (!fInputField) … … RecorderWindow::Record(BMessage * message) 696 703 return; 697 704 } 698 705 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(); 707 707 } 708 708 709 709 … … RecorderWindow::Input(BMessage * message) 849 849 850 850 851 851 void 852 RecorderWindow::Selected(BMessage 852 RecorderWindow::Selected(BMessage* message) 853 853 { 854 854 // User selected a sound in list view 855 855 int32 selIdx = fSoundList->CurrentSelection(); … … RecorderWindow::Selected(BMessage * message) 867 867 868 868 869 869 status_t 870 RecorderWindow::MakeRecordConnection(const media_node 870 RecorderWindow::MakeRecordConnection(const media_node& input) 871 871 { 872 872 CONNECT((stderr, "RecorderWindow::MakeRecordConnection()\n")); 873 873 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; 887 876 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); 904 882 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 } 921 888 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 { 925 896 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; 929 900 } 930 901 902 903 931 904 // 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; 933 906 fRecordFormat.type = B_MEDIA_RAW_AUDIO; 934 907 935 908 // Tell the consumer where we want data to go. 936 err = fRecordNode->SetHooks(RecordFile, NotifyRecordFile, this); 909 err = fRecorder->SetHooks(RecordFile, NotifyRecordFile, this); 910 937 911 if (err < B_OK) { 938 912 CONNECT((stderr, "RecorderWindow::MakeRecordConnection():" 939 913 " couldn't set the sound recorder's hook functions\n")); 940 tsobj->Release();941 914 return err; 942 915 } 943 916 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()) { 955 918 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 } 959 931 960 tsobj->Release(); // we're done with this time source instance!961 932 return B_OK; 962 933 } 963 934 … … RecorderWindow::MakeRecordConnection(const media_node & input) 965 936 status_t 966 937 RecorderWindow::BreakRecordConnection() 967 938 { 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(); 969 946 970 // If we are the last connection, the Node will stop automatically since it971 // 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;977 947 return err; 978 948 } 979 949 … … RecorderWindow::StopRecording() 984 954 if (!fRecording) 985 955 return B_OK; 986 956 fRecording = false; 957 987 958 BreakRecordConnection(); 988 fRecordNode->SetHooks(NULL,NULL,NULL); 959 960 fRecorder->SetHooks(NULL, NULL, NULL); 961 989 962 if (fRecSize > 0) { 990 963 991 964 wave_struct header; … … RecorderWindow::RemoveCurrentSoundItem() { 1240 1213 1241 1214 void 1242 1215 RecorderWindow::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) 1244 1217 { 1245 1218 // Callback called from the SoundConsumer when receiving buffers. 1246 1219 RecorderWindow * window = (RecorderWindow *)cookie; … … RecorderWindow::RecordFile(void* cookie, bigtime_t timestamp, 1249 1222 // Write the data to file (we don't buffer or guard file access 1250 1223 // or anything) 1251 1224 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); 1253 1226 window->fRecSize += size; 1254 1227 } 1255 1228 } -
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 21 21 #include <Window.h> 22 22 23 23 #include "DrawButton.h" 24 #include "MediaRecorder.h" 24 25 #include "ScopeView.h" 25 26 #include "SoundListView.h" 26 27 #include "TransportButton.h" … … class BScrollView; 40 41 class BSlider; 41 42 class BStringView; 42 43 43 namespace BPrivate {44 class SoundConsumer;45 }46 44 45 using BPrivate::media::BMediaRecorder; 47 46 48 using BPrivate::SoundConsumer;49 47 50 51 class RecorderWindow : public BWindow{48 class RecorderWindow : public BWindow 49 { 52 50 public: 53 RecorderWindow();54 virtual ~RecorderWindow();55 status_tInitCheck();51 RecorderWindow(); 52 virtual ~RecorderWindow(); 53 status_t InitCheck(); 56 54 57 55 58 virtual bool 59 virtual void MessageReceived(BMessage* message);56 virtual bool QuitRequested(); 57 virtual void MessageReceived(BMessage* message); 60 58 61 59 enum { 62 60 RECORD = 'cw00', // command messages … … public: 77 75 POSITION_CHANGED 78 76 }; 79 77 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(); 82 82 83 83 private: 84 84 BMediaRoster * fRoster; … … private: 95 95 TrackSlider *fTrackSlider; 96 96 UpDownButton * fUpDownButton; 97 97 BMenuField * fInputField; 98 SoundConsumer * fRecordNode;98 BMediaRecorder* fRecorder; 99 99 BSoundPlayer * fPlayer; 100 100 bool fRecording; 101 101 SoundListView * fSoundList; … … private: 128 128 off_t fRecSize; 129 129 130 130 media_node fAudioInputNode; 131 media_output fAudioOutput;132 media_input fRecInput;133 131 134 132 BMediaFile *fPlayFile; 135 133 media_format fPlayFormat; … … private: 171 169 status_t UpdatePlayFile(SoundListItem *item, bool updateDisplay = false); 172 170 void ErrorAlert(const char * action, status_t err); 173 171 174 static void RecordFile(void * cookie, bigtime_t timestamp, void * data, size_t size, const media_ raw_audio_format & format);172 static void RecordFile(void * cookie, bigtime_t timestamp, void * data, size_t size, const media_format & format); 175 173 static void NotifyRecordFile(void * cookie, int32 code, ...); 176 174 177 175 static 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 ] { 19 19 SharedLibrary [ MultiArchDefaultGristFiles libmedia.so ] : 20 20 # Private Media Kit 21 21 !missing_symbols.cpp 22 MediaRecorder.cpp 23 MediaRecorderNode.cpp 22 24 SoundConsumer.cpp 23 25 24 26 # 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 16 class StNodeRelease 17 { 18 public: 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 36 private: 37 media_node& node; 38 bool rel; 39 }; 40 41 42 BMediaRecorder::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 70 BMediaRecorder::~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 86 status_t 87 BMediaRecorder::InitCheck() const 88 { 89 return fInitErr; 90 } 91 92 93 void 94 BMediaRecorder::SetAcceptedFormat(const media_format& format) 95 { 96 fNode->SetAcceptedFormat(format); 97 } 98 99 100 status_t 101 BMediaRecorder::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 112 void 113 BMediaRecorder::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 123 status_t 124 BMediaRecorder::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 136 status_t 137 BMediaRecorder::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 150 status_t 151 BMediaRecorder::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 165 status_t 166 BMediaRecorder::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 194 status_t 195 BMediaRecorder::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 230 status_t 231 BMediaRecorder::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 250 bool 251 BMediaRecorder::IsRunning() const 252 { 253 return fRunning; 254 } 255 256 257 bool 258 BMediaRecorder::IsConnected() const 259 { 260 return fConnected; 261 } 262 263 264 const media_node& 265 BMediaRecorder::Node() const 266 { 267 return fOutputNode; 268 } 269 270 271 const media_output& 272 BMediaRecorder::MediaOutput() const 273 { 274 return fOutput; 275 } 276 277 278 const media_input& 279 BMediaRecorder::MediaInput() const 280 { 281 return fInput; 282 } 283 284 285 const media_format& 286 BMediaRecorder::Format() const 287 { 288 return fOutput.format; 289 } 290 291 292 status_t 293 BMediaRecorder::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 18 BMediaRecorderNode::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 37 BMediaRecorderNode::~BMediaRecorderNode() 38 { 39 } 40 41 42 BMediaAddOn* 43 BMediaRecorderNode::AddOn(int32* internal_id) const 44 { 45 if (internal_id) 46 *internal_id = -1; 47 48 return NULL; 49 } 50 51 52 void 53 BMediaRecorderNode::SetAcceptedFormat(const media_format &format) 54 { 55 fOKFormat = format; 56 } 57 58 59 status_t 60 BMediaRecorderNode::GetInput(media_input* out_input) 61 { 62 fInput.node = Node(); 63 *out_input = fInput; 64 65 return B_OK; 66 } 67 68 69 void 70 BMediaRecorderNode::SetDataEnabled(bool enabled) 71 { 72 int32 tag; 73 74 (void)SetOutputEnabled(fInput.source, 75 fInput.destination, enabled, 0, &tag); 76 } 77 78 79 void 80 BMediaRecorderNode::HandleEvent(const media_timed_event* event, 81 bigtime_t lateness, bool realTimeEvent ) 82 { 83 // we ignore them all! 84 } 85 86 87 void 88 BMediaRecorderNode::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 99 void 100 BMediaRecorderNode::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 111 void 112 BMediaRecorderNode::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 122 void 123 BMediaRecorderNode::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 135 status_t 136 BMediaRecorderNode::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 152 status_t 153 BMediaRecorderNode::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 165 status_t 166 BMediaRecorderNode::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 178 void 179 BMediaRecorderNode::DisposeInputCookie(int32 cookie) 180 { 181 } 182 183 184 void 185 BMediaRecorderNode::BufferReceived(BBuffer* buffer) 186 { 187 fRecorder->BufferReceived(buffer->Data(), buffer->SizeUsed(), 188 *buffer->Header()); 189 190 buffer->Recycle(); 191 } 192 193 194 void 195 BMediaRecorderNode::ProducerDataStatus( 196 const media_destination& for_whom, int32 status, 197 bigtime_t at_performance_time) 198 { 199 } 200 201 202 status_t 203 BMediaRecorderNode::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 213 status_t 214 BMediaRecorderNode::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 230 void 231 BMediaRecorderNode::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 245 status_t 246 BMediaRecorderNode::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 }