2 * Copyright 1991-1999, Be Incorporated.
3 * Copyright (c) 1999-2000, Eric Moon.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions, and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions, and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
28 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "LogWriter.h"
39 // this is the simpleminded implementation of a lookup function;
40 // could also use some sort of map. this has the advantage of not
41 // requiring any runtime initialization.
42 static const char* log_what_to_string(log_what code
)
44 const char* s
= "Unknown log_what code!";
47 case LOG_QUIT
: s
= "LOG_QUIT"; break;
48 case LOG_SET_RUN_MODE
: s
= "LOG_SET_RUN_MODE"; break;
49 case LOG_PREROLL
: s
= "LOG_PREROLL"; break;
50 case LOG_SET_TIME_SOURCE
: s
= "LOG_SET_TIME_SOURCE"; break;
51 case LOG_REQUEST_COMPLETED
: s
= "LOG_REQUEST_COMPLETED"; break;
52 case LOG_GET_PARAM_VALUE
: s
= "LOG_GET_PARAM_VALUE"; break;
53 case LOG_SET_PARAM_VALUE
: s
= "LOG_SET_PARAM_VALUE"; break;
54 case LOG_FORMAT_SUGG_REQ
: s
= "LOG_FORMAT_SUGG_REQ"; break;
55 case LOG_FORMAT_PROPOSAL
: s
= "LOG_FORMAT_PROPOSAL"; break;
56 case LOG_FORMAT_CHANGE_REQ
: s
= "LOG_FORMAT_CHANGE_REQ"; break;
57 case LOG_SET_BUFFER_GROUP
: s
= "LOG_SET_BUFFER_GROUP"; break;
58 case LOG_VIDEO_CLIP_CHANGED
: s
= "LOG_VIDEO_CLIP_CHANGED"; break;
59 case LOG_GET_LATENCY
: s
= "LOG_GET_LATENCY"; break;
60 case LOG_PREPARE_TO_CONNECT
: s
= "LOG_PREPARE_TO_CONNECT"; break;
61 case LOG_CONNECT
: s
= "LOG_CONNECT"; break;
62 case LOG_DISCONNECT
: s
= "LOG_DISCONNECT"; break;
63 case LOG_LATE_NOTICE_RECEIVED
: s
= "LOG_LATE_NOTICE_RECEIVED"; break;
64 case LOG_ENABLE_OUTPUT
: s
= "LOG_ENABLE_OUTPUT"; break;
65 case LOG_SET_PLAY_RATE
: s
= "LOG_SET_PLAY_RATE"; break;
66 case LOG_ADDITIONAL_BUFFER
: s
= "LOG_ADDITIONAL_BUFFER"; break;
67 case LOG_LATENCY_CHANGED
: s
= "LOG_LATENCY_CHANGED"; break;
68 case LOG_HANDLE_MESSAGE
: s
= "LOG_HANDLE_MESSAGE"; break;
69 case LOG_ACCEPT_FORMAT
: s
= "LOG_ACCEPT_FORMAT"; break;
70 case LOG_BUFFER_RECEIVED
: s
= "LOG_BUFFER_RECEIVED"; break;
71 case LOG_PRODUCER_DATA_STATUS
: s
= "LOG_PRODUCER_DATA_STATUS"; break;
72 case LOG_CONNECTED
: s
= "LOG_CONNECTED"; break;
73 case LOG_DISCONNECTED
: s
= "LOG_DISCONNECTED"; break;
74 case LOG_FORMAT_CHANGED
: s
= "LOG_FORMAT_CHANGED"; break;
75 case LOG_SEEK_TAG
: s
= "LOG_SEEK_TAG"; break;
76 case LOG_REGISTERED
: s
= "LOG_REGISTERED"; break;
77 case LOG_START
: s
= "LOG_START"; break;
78 case LOG_STOP
: s
= "LOG_STOP"; break;
79 case LOG_SEEK
: s
= "LOG_SEEK"; break;
80 case LOG_TIMEWARP
: s
= "LOG_TIMEWARP"; break;
81 case LOG_HANDLE_EVENT
: s
= "LOG_HANDLE_EVENT"; break;
82 case LOG_HANDLE_UNKNOWN
: s
= "LOG_HANDLE_UNKNOWN"; break;
83 case LOG_BUFFER_HANDLED
: s
= "LOG_BUFFER_HANDLED"; break;
84 case LOG_START_HANDLED
: s
= "LOG_START_HANDLED"; break;
85 case LOG_STOP_HANDLED
: s
= "LOG_STOP_HANDLED"; break;
86 case LOG_SEEK_HANDLED
: s
= "LOG_SEEK_HANDLED"; break;
87 case LOG_WARP_HANDLED
: s
= "LOG_WARP_HANDLED"; break;
88 case LOG_DATA_STATUS_HANDLED
: s
= "LOG_DATA_STATUS_HANDLED"; break;
89 case LOG_SET_PARAM_HANDLED
: s
= "LOG_SET_PARAM_HANDLED"; break;
90 case LOG_INVALID_PARAM_HANDLED
: s
= "LOG_INVALID_PARAM_HANDLED"; break;
95 // Logging thread function
96 int32
LogWriterLoggingThread(void* arg
)
98 LogWriter
* obj
= static_cast<LogWriter
*>(arg
);
99 port_id port
= obj
->mPort
;
108 status_t n_bytes
= ::read_port(port
, &what
, &msg
, sizeof(log_message
));
111 obj
->HandleMessage((log_what
) what
, msg
);
112 if (LOG_QUIT
== what
) done
= true;
116 fprintf(stderr
, "LogWriter failed (%s) in ::read_port()!\n", strerror(n_bytes
));
120 // got the "quit" message; now we're done
124 // --------------------
125 // LogWriter class implementation
126 LogWriter::LogWriter(const entry_ref
& logRef
)
129 mPort
= ::create_port(64, "LogWriter");
130 mLogThread
= ::spawn_thread(&LogWriterLoggingThread
, "LogWriter", B_NORMAL_PRIORITY
, this);
131 mLogFile
.SetTo(&logRef
, B_WRITE_ONLY
| B_CREATE_FILE
| B_ERASE_FILE
);
132 ::resume_thread(mLogThread
);
135 LogWriter::~LogWriter()
137 printf("LogWriter::~LogWriter() called\n");
142 ::wait_for_thread(mLogThread
, &err
);
147 // This method, called by the client, really just enqueues a message to the writer thread,
148 // which will deal with it in the HandleMessage() method.
150 LogWriter::Log(log_what what
, const log_message
& data
)
152 bigtime_t now
= ::system_time();
153 log_message
& nc_data
= const_cast<log_message
&>(data
);
154 nc_data
.tstamp
= now
;
155 ::write_port(mPort
, (int32
) what
, &data
, sizeof(log_message
));
158 // Enable or disable a particular log_what code's output
160 LogWriter::SetEnabled(log_what what
, bool enable
)
162 if (enable
) mFilters
.erase(what
);
163 else mFilters
.insert(what
);
166 // enabling everything means just clearing out the filter set
168 LogWriter::EnableAllMessages()
173 // disabling everything is more tedious -- we have to add them all to the
174 // filter set, one by one
176 LogWriter::DisableAllMessages()
178 // mFilters.insert(LOG_QUIT); // don't disable our quit messages
179 mFilters
.insert(LOG_SET_RUN_MODE
);
180 mFilters
.insert(LOG_PREROLL
);
181 mFilters
.insert(LOG_SET_TIME_SOURCE
);
182 mFilters
.insert(LOG_REQUEST_COMPLETED
);
183 mFilters
.insert(LOG_GET_PARAM_VALUE
);
184 mFilters
.insert(LOG_SET_PARAM_VALUE
);
185 mFilters
.insert(LOG_FORMAT_SUGG_REQ
);
186 mFilters
.insert(LOG_FORMAT_PROPOSAL
);
187 mFilters
.insert(LOG_FORMAT_CHANGE_REQ
);
188 mFilters
.insert(LOG_SET_BUFFER_GROUP
);
189 mFilters
.insert(LOG_VIDEO_CLIP_CHANGED
);
190 mFilters
.insert(LOG_GET_LATENCY
);
191 mFilters
.insert(LOG_PREPARE_TO_CONNECT
);
192 mFilters
.insert(LOG_CONNECT
);
193 mFilters
.insert(LOG_DISCONNECT
);
194 mFilters
.insert(LOG_LATE_NOTICE_RECEIVED
);
195 mFilters
.insert(LOG_ENABLE_OUTPUT
);
196 mFilters
.insert(LOG_SET_PLAY_RATE
);
197 mFilters
.insert(LOG_ADDITIONAL_BUFFER
);
198 mFilters
.insert(LOG_LATENCY_CHANGED
);
199 mFilters
.insert(LOG_HANDLE_MESSAGE
);
200 mFilters
.insert(LOG_ACCEPT_FORMAT
);
201 mFilters
.insert(LOG_BUFFER_RECEIVED
);
202 mFilters
.insert(LOG_PRODUCER_DATA_STATUS
);
203 mFilters
.insert(LOG_CONNECTED
);
204 mFilters
.insert(LOG_DISCONNECTED
);
205 mFilters
.insert(LOG_FORMAT_CHANGED
);
206 mFilters
.insert(LOG_SEEK_TAG
);
207 mFilters
.insert(LOG_REGISTERED
);
208 mFilters
.insert(LOG_START
);
209 mFilters
.insert(LOG_STOP
);
210 mFilters
.insert(LOG_SEEK
);
211 mFilters
.insert(LOG_TIMEWARP
);
212 mFilters
.insert(LOG_HANDLE_EVENT
);
213 // mFilters.insert(LOG_HANDLE_UNKNOWN); // don't disable the "unknown message" messages
214 mFilters
.insert(LOG_BUFFER_HANDLED
);
215 mFilters
.insert(LOG_START_HANDLED
);
216 mFilters
.insert(LOG_STOP_HANDLED
);
217 mFilters
.insert(LOG_SEEK_HANDLED
);
218 mFilters
.insert(LOG_WARP_HANDLED
);
219 mFilters
.insert(LOG_DATA_STATUS_HANDLED
);
220 mFilters
.insert(LOG_SET_PARAM_HANDLED
);
221 mFilters
.insert(LOG_INVALID_PARAM_HANDLED
);
224 // Writer thread's message handling function -- this is where messages are actuall
225 // formatted and written to the log file
227 LogWriter::HandleMessage(log_what what
, const log_message
& msg
)
229 char buf
[256]; // scratch buffer for building logged output
231 // if we've been told to ignore this message type, just return without doing anything else
232 if (mFilters
.find(what
) != mFilters
.end()) return;
234 // always write the message's type and timestamp
235 sprintf(buf
, "%-24s : realtime = %" B_PRIdBIGTIME
", perftime = %" B_PRIdBIGTIME
"\n",
236 log_what_to_string(what
), msg
.tstamp
, msg
.now
);
239 // put any special per-message-type handling here
243 mWriteBuf
+= "\tLogWriter thread terminating\n";
246 case LOG_BUFFER_RECEIVED
:
247 if (msg
.buffer_data
.offset
< 0)
249 sprintf(buf
, "\tstart = %" B_PRIdBIGTIME
", offset = %" B_PRIdBIGTIME
"\n",
250 msg
.buffer_data
.start_time
, msg
.buffer_data
.offset
);
252 sprintf(buf
, "\tBuffer received *LATE*\n");
257 case LOG_SET_PARAM_HANDLED
:
258 sprintf(buf
, "\tparam id = %" B_PRId32
", value = %f\n", msg
.param
.id
, msg
.param
.value
);
262 case LOG_INVALID_PARAM_HANDLED
:
263 case LOG_GET_PARAM_VALUE
:
264 sprintf(buf
, "\tparam id = %" B_PRId32
"\n", msg
.param
.id
);
268 case LOG_BUFFER_HANDLED
:
269 sprintf(buf
, "\tstart = %" B_PRIdBIGTIME
", offset = %" B_PRIdBIGTIME
"\n",
270 msg
.buffer_data
.start_time
, msg
.buffer_data
.offset
);
272 if (msg
.buffer_data
.offset
< 0)
274 sprintf(buf
, "\tBuffer handled *LATE*\n");
279 case LOG_DATA_STATUS_HANDLED
:
280 sprintf(buf
, "\tstatus = %d\n", int(msg
.data_status
.status
));
284 case LOG_HANDLE_UNKNOWN
:
285 sprintf(buf
, "\tUNKNOWN EVENT CODE: %d\n", int(msg
.unknown
.what
));
293 // actually write the log message to the file now
294 mLogFile
.Write(mWriteBuf
.String(), mWriteBuf
.Length());