shoutcast_output.cpp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636
  1. #include <windows.h>
  2. #include <Ws2tcpip.h>
  3. #include "../api.h"
  4. #include "Include/shoutcast_output.h"
  5. #include "../../sc_serv3/nmrCommon/stl/stringUtils.h"
  6. #include "../utils.h"
  7. #include "../nu/ServiceBuilder.h"
  8. #include <winamp/dsp.h>
  9. #pragma intrinsic(memcpy, memset)
  10. static char buf[1024];
  11. static char out[1024];
  12. extern int iscompatibility;
  13. extern winampDSPModule module;
  14. extern api_service *WASABI_API_SVC;
  15. static api_connection *CreateConnection(const char *url)
  16. {
  17. api_connection *conn = 0;
  18. if (WASABI_API_SVC/*module.service*/)
  19. {
  20. if (!_strnicmp(url, "https://", 8))
  21. {
  22. ServiceBuild(WASABI_API_SVC/*module.service*/, conn, sslConnectionFactoryGUID);
  23. }
  24. else
  25. {
  26. ServiceBuild(WASABI_API_SVC/*module.service*/, conn, connectionFactoryGUID);
  27. }
  28. }
  29. return conn;
  30. }
  31. static void ReleaseConnection(api_connection *&conn, const char *url)
  32. {
  33. if (!conn) {
  34. return;
  35. }
  36. waServiceFactory *connectionFactory = 0;
  37. if (WASABI_API_SVC/*mod.service*/)
  38. {
  39. if (!_strnicmp(url, "https://", 8)) {
  40. connectionFactory = WASABI_API_SVC/*mod.service*/->service_getServiceByGuid(sslConnectionFactoryGUID);
  41. } else {
  42. connectionFactory = WASABI_API_SVC/*mod.service*/->service_getServiceByGuid(connectionFactoryGUID);
  43. }
  44. }
  45. if (connectionFactory) {
  46. connectionFactory->releaseInterface(conn);
  47. }
  48. conn = 0;
  49. }
  50. int resolvenow(const char *hostname, unsigned short port, addrinfo **addr, int sockettype, char **saddress)
  51. {
  52. addrinfo hints;
  53. memset(&hints,0,sizeof(hints));
  54. hints.ai_family = PF_UNSPEC;
  55. if (hostname)
  56. hints.ai_flags = AI_NUMERICHOST;
  57. else
  58. hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
  59. hints.ai_socktype = sockettype;
  60. char portString[32] = {0};
  61. sprintf(portString, "%u", (unsigned int)port);
  62. if (getaddrinfo(hostname, portString, &hints, addr) == 0)
  63. {
  64. return 0;
  65. }
  66. else
  67. {
  68. hints.ai_flags = 0;
  69. if (getaddrinfo(hostname, portString, &hints, addr) == 0)
  70. {
  71. // need to make sure we're not using 0.0.0.0
  72. // as that will break us when using localhost
  73. bool found = false;
  74. struct addrinfo *ptr = NULL;
  75. for (ptr = *addr; ptr != NULL; ptr = ptr->ai_next)
  76. {
  77. char* address = ::inet_ntoa(((sockaddr_in*)(ptr->ai_addr))->sin_addr);
  78. if (strcmp(address, "0.0.0.0"))
  79. {
  80. *saddress = address;
  81. *addr = ptr;
  82. return 0;
  83. }
  84. }
  85. }
  86. }
  87. return -1;
  88. }
  89. void compatible_connect(T_OUTPUT *Output, int port) {
  90. // due to a bug in re-using the connection
  91. // with Winamp's jnetlib implementation we
  92. // need to do a force drop and make a new
  93. // instance so all is initialised properly
  94. if (Output->Output && iscompatibility) {
  95. Output->Output->Close();
  96. Output->Output->Release();
  97. Output->Output = NULL;
  98. }
  99. // create the connection only when it's needed
  100. if (!Output->Output) {
  101. Output->Output = CreateConnection("");
  102. if (Output->Output) {
  103. Output->Output->Open(API_DNS_AUTODNS, 16384, 16384);
  104. }
  105. }
  106. if (Output->Output) {
  107. if (iscompatibility && !strnicmp(Output->Config->Address, "localhost", 9)) {
  108. addrinfo *saddr = 0;
  109. char *address = 0;
  110. if (!resolvenow(Output->Config->Address, (Output->Config->Port) + (LOBYTE(Output->Config->protocol) == 1), &saddr, SOCK_STREAM, &address) && address) {
  111. Output->Output->connect(address, (Output->Config->Port) + (LOBYTE(Output->Config->protocol) == 1));
  112. } else {
  113. Output->Output->connect(Output->Config->Address, (Output->Config->Port) + (LOBYTE(Output->Config->protocol) == 1));
  114. }
  115. } else {
  116. Output->Output->connect(Output->Config->Address, port);
  117. }
  118. }
  119. }
  120. SHOUTCAST_OUTPUT::SHOUTCAST_OUTPUT() : lame_init(0), lame_init_params(0), lame_encode_buffer_interleaved(0), lame_encode_flush(0), libinst(NULL) {
  121. IOwnEncoder = 0;
  122. SetEncoder(DEFAULT_ENCODER);
  123. OutputManager.AddHandler(OUT_DISCONNECTED, Output_Disconnected);
  124. OutputManager.AddHandler(OUT_CONNECT, Output_Connect);
  125. OutputManager.AddHandler(OUT_REQUEST_CIPHER, Output_Request_Cipher);//cipher request
  126. OutputManager.AddHandler(OUT_RECV_CIPHER, Output_Receive_Cipher);// and process cipher
  127. OutputManager.AddHandler(OUT_SENDAUTH, Output_SendAuth);
  128. OutputManager.AddHandler(OUT_RECVAUTHRESPONSE, Output_RecvAuthResponse);
  129. OutputManager.AddHandler(OUT_SEND_MIME, Output_Send_Mime);
  130. OutputManager.AddHandler(OUT_RECV_MIME, Output_Recv_Mime);
  131. OutputManager.AddHandler(OUT_SEND_BITRATE, Output_Send_Bitrate);
  132. OutputManager.AddHandler(OUT_RECV_BITRATE, Output_Recv_Bitrate);
  133. OutputManager.AddHandler(OUT_SEND_BUFSIZE, Output_Send_Buf_Size);
  134. OutputManager.AddHandler(OUT_RECV_BUFSIZE, Output_Recv_Buf_Size);
  135. OutputManager.AddHandler(OUT_SEND_MAX, Output_Send_Max_Size);
  136. OutputManager.AddHandler(OUT_RECV_MAX, Output_Recv_Max_Size);
  137. OutputManager.AddHandler(OUT_SENDYP, Output_SendYP);
  138. OutputManager.AddHandler(OUT_SEND_INITFLUSH, Output_Send_InitFlush);
  139. OutputManager.AddHandler(OUT_RECV_INITFLUSH, Output_Recv_InitFlush);
  140. OutputManager.AddHandler(OUT_SEND_INITSTANDBY, Output_Send_InitStandby);
  141. OutputManager.AddHandler(OUT_RECV_INITSTANDBY, Output_Recv_InitStandby);
  142. //OutputManager.AddHandler(OUT_SEND_INTRO, Output_Send_Intro);
  143. //OutputManager.AddHandler(OUT_RECV_INTRO, Output_Recv_Intro);
  144. //OutputManager.AddHandler(OUT_SEND_BACKUP, Output_Send_Backup);
  145. //OutputManager.AddHandler(OUT_RECV_BACKUP, Output_Recv_Backup);
  146. OutputManager.AddHandler(OUT_SENDCONTENT, Output_SendContent);
  147. OutputManager.AddHandler(OUT_DISCONNECT, Output_Disconnect);
  148. OutputManager.AddHandler(OUT_RECONNECT, Output_Reconnect);
  149. OutputManager.AddHandler(OUT_TITLESENDUPDATE, Output_Title_SendUpdate);
  150. OutputManager.AddHandler(OUT_SEND_METADATA, Output_Send_Metadata);
  151. OutputManager.AddHandler(OUT_SEND_ARTWORK, Output_Send_Artwork);
  152. ReleaseMutex((mutex = CreateMutex(NULL, TRUE, NULL)));
  153. }
  154. void SHOUTCAST_OUTPUT::SetLame(void *init, void *params, void *encode, void *finish) {
  155. LOCK{
  156. lame_init = (void (__cdecl *)(void))init;
  157. lame_init_params = (void (__cdecl *)(lame_global_flags *))params;
  158. lame_encode_buffer_interleaved = (int (__cdecl *)(lame_global_flags *, short int pcm[], int num_samples, char *mp3buffer, int mp3buffer_size))encode;
  159. lame_encode_flush = (int (__cdecl *)(lame_global_flags *, char *mp3buffer, int size))finish;
  160. }UNLOCK
  161. }
  162. SHOUTCAST_OUTPUT::~SHOUTCAST_OUTPUT() {
  163. LOCK
  164. CloseHandle(mutex);
  165. }
  166. /*
  167. Create a Uvox frame
  168. */
  169. void SHOUTCAST_OUTPUT::createUvoxFrame(int length, char *payload_in, int type, T_OUTPUT *userData) {
  170. int len = min(length, UV_MAX_DATA_LEN);
  171. uv2xHdr hdr2 = { UV_SYNC_BYTE, UV_RESERVED, htons(type), htons(len), {UV_END}, UV_END };
  172. if (payload_in && len > 0 && len <= UV_MAX_DATA_LEN) {
  173. memcpy(hdr2.m_data, payload_in, len);
  174. }
  175. int sent = UV_HEADER_LEN + len + UV_END_LEN;
  176. userData->Output->send(&hdr2, sent);
  177. userData->Info.BytesSent += sent;
  178. }
  179. int SHOUTCAST_OUTPUT::createUvoxMetaFrame(int length, char *payload_in, int type,
  180. T_OUTPUT *userData, unsigned short id,
  181. unsigned short span) {
  182. // check for the class type and abort if it's not right - will typically be 0x0000 or 0xXXFF
  183. if ((type >= 0x3000) && (type < 0x5000)) {
  184. int artType = ((type & 0xFF00) == (MSG_METADATA_ALBUMART|MSG_METADATA_PLAYING_ART));
  185. int len = min(length, UV_MAX_META_LEN);
  186. uv2xMetadataHdr metaHdr = { UV_SYNC_BYTE, UV_RESERVED, htons(type), htons(len + UV_META_LEN),
  187. htons(id), htons(span), htons((span > 1 ? userData->Info.art_index[artType] : 0x1)),
  188. {UV_END}, UV_END };
  189. if (payload_in && len > 0 && len <= UV_MAX_META_LEN) {
  190. memcpy(metaHdr.m_data, payload_in, len);
  191. }
  192. int sent = UV_HEADER_LEN + len + UV_META_LEN + UV_END_LEN;
  193. if(userData->Output->send(&metaHdr, sent) != -1)
  194. {
  195. userData->Info.BytesSent += sent;
  196. }
  197. else
  198. {
  199. // if the send buffer is still full then we need to nudge
  200. // it all along so that we can send the metadata as not
  201. // checking for this will cause the loss of meta frames
  202. while(userData->Output->GetSendBytesAvailable())
  203. {
  204. Sleep(10); // sleep a bit and try again
  205. userData->Output->run();
  206. if(userData->Output->send(&metaHdr, sent) != -1)
  207. {
  208. userData->Info.BytesSent += sent;
  209. break;
  210. }
  211. }
  212. }
  213. return id+1;
  214. }
  215. return id;
  216. }
  217. /*
  218. Parse a Uvox Frame
  219. */
  220. int SHOUTCAST_OUTPUT::parseUvoxFrame(char *payload_in, char *payload_out) {
  221. LOCK{
  222. uv2xHdr *hdr2 = (uv2xHdr *)payload_in;
  223. int len = min(ntohs(hdr2->msgLen), UV_MAX_DATA_LEN);
  224. memmove(payload_out, hdr2->m_data, len);
  225. // just doing this to ensure its terminated correctly
  226. hdr2->m_data[len] = UV_END;
  227. }UNLOCK
  228. return 1;
  229. }
  230. /*
  231. Check for known Uvox Error responses
  232. */
  233. int SHOUTCAST_OUTPUT::checkUvoxFrameForError(char *pload_out, int state, T_OUTPUT *userData) {
  234. LOCK{
  235. if (userData->Info.Succeeded == -2 &&
  236. userData->Info.ErrorMsg) {
  237. free(userData->Info.ErrorMsg);
  238. }
  239. userData->Info.Succeeded = 1;
  240. userData->Info.ErrorMsg = 0;
  241. if (!strcmp("NAK:2.1:Deny", pload_out) || !strcmp("NAK:Deny", pload_out)) {
  242. userData->Info.Succeeded = -1;
  243. userData->Info.ErrorMsg = "NAK:Deny";
  244. UNLOCK
  245. return userData->Info.Succeeded;
  246. }
  247. if (!strcmp("NAK:2.1:Stream ID Error", pload_out)) {
  248. userData->Info.Succeeded = -1;
  249. userData->Info.ErrorMsg = "StreamID";
  250. UNLOCK
  251. return userData->Info.Succeeded;
  252. }
  253. if (!strcmp("NAK:2.1:Stream Moved", pload_out)) {
  254. userData->Info.Succeeded = -1;
  255. userData->Info.ErrorMsg = "StreamMoved";
  256. UNLOCK
  257. return userData->Info.Succeeded;
  258. }
  259. if (!strcmp("NAK:Bit Rate Error", pload_out)) {
  260. userData->Info.Succeeded = -1;
  261. userData->Info.ErrorMsg = "BitrateError";
  262. UNLOCK
  263. return userData->Info.Succeeded;
  264. }
  265. if (!strcmp("NAK:2.1:Version Error", pload_out)) {
  266. userData->Info.Succeeded = -1;
  267. userData->Info.ErrorMsg = "VersionError";
  268. UNLOCK
  269. return userData->Info.Succeeded;
  270. }
  271. if (!strcmp("NAK:2.1:Parse Error", pload_out) || !strcmp("NAK:Parse Error", pload_out)) {
  272. userData->Info.Succeeded = -1;
  273. userData->Info.ErrorMsg = "ParseError";
  274. UNLOCK
  275. return userData->Info.Succeeded;
  276. }
  277. if (!strcmp("NAK:Stream In Use", pload_out)) {
  278. userData->Info.Succeeded = -1;
  279. userData->Info.ErrorMsg = "InUse";
  280. UNLOCK
  281. return userData->Info.Succeeded;
  282. }
  283. if (!strcmp("NAK", pload_out)) {
  284. userData->Info.Succeeded = -2;
  285. // TODO
  286. userData->Info.ErrorMsg = _strdup(pload_out);
  287. UNLOCK
  288. return userData->Info.Succeeded;
  289. }
  290. if (!strcmp("ACK", pload_out)) {
  291. userData->Info.Succeeded = 1;
  292. UNLOCK
  293. return userData->Info.Succeeded;
  294. }
  295. }UNLOCK
  296. return userData->Info.Succeeded;
  297. }
  298. int SHOUTCAST_OUTPUT::Run(int mode, void *Input, int InputSize, int SaveEncoder) {
  299. int in_used = 0;
  300. LOCK{
  301. int bad = 1;
  302. if (mode & OM_OTHER) OutputManager.Run(OutputManager.GetNumJobs());
  303. for (int i = OutputManager.GetNumJobs()-1; i >= 0; i--) {
  304. T_OUTPUT *Output = OutputManager[i];
  305. if (mode & OM_OUTPUT && Output->Output) {
  306. Output->Output->run();
  307. }
  308. int state = OutputManager.GetJobState(i);
  309. if (state != OUT_DISCONNECTED) {
  310. int outstate = (Output->Output ? Output->Output->get_state() : CONNECTION_STATE_ERROR);
  311. if ((outstate == CONNECTION_STATE_ERROR || outstate == CONNECTION_STATE_CLOSED) &&
  312. state != OUT_DISCONNECT && state != OUT_RECONNECT) {
  313. if (Output->Type == OUTTYPE_SOURCE) {
  314. Output->Info.ConnectionTime = clock();
  315. Output->SlowClose = 0;
  316. OutputManager.SetJobState(i, state = OUT_DISCONNECT); // kill the connection
  317. } else if (Output->Type == OUTTYPE_TITLE) {
  318. delete OutputManager[i];
  319. OutputManager.DelJob(i); // title update failed, remove it
  320. }
  321. }
  322. if (state == OUT_SENDCONTENT) bad = 0;
  323. } else {
  324. if (Output->Type == OUTTYPE_TITLE) {
  325. #ifndef _DEBUG
  326. delete OutputManager[i];
  327. #endif
  328. OutputManager.DelJob(i); // title update succeeded, remove it
  329. }
  330. }
  331. }// for num jobs
  332. if (!bad && Input && (InputSize > 0) && Encoder && (mode & OM_ENCODE)) {
  333. while (in_used < InputSize && InputSize > 0) {
  334. int inused = 0;
  335. char EncodedData[32768] = {0};
  336. int out_used = Encoder->Encode(((char *)Input+in_used), (InputSize-in_used), EncodedData, sizeof(EncodedData), &inused);
  337. in_used += inused;
  338. for (int i = OutputManager.GetNumJobs()-1; i >= 0; i--) {
  339. T_OUTPUT *Output = OutputManager[i];
  340. int state = OutputManager.GetJobState(i);
  341. if (out_used > 0 && state == OUT_SENDCONTENT) {
  342. int sofar = 0, type = 0;
  343. // when enabled this will save the encoded output to a local file for DJ backup, etc
  344. if (SaveEncoder != -1) {
  345. WriteSaveEncoded(SaveEncoder, EncodedData, out_used);
  346. }
  347. if (strcmp("audio/aacp", Output->ContentType)==0) { type = AACP_DATA; } // aacp
  348. if (strcmp("audio/aac", Output->ContentType)==0) { type = AAC_LC_DATA; } // aac lc
  349. if (strcmp("audio/mpeg", Output->ContentType)==0) { type = MP3_DATA; } // mp3
  350. if (strcmp("audio/ogg", Output->ContentType)==0) { type = OGG_DATA; } // ogg
  351. // make sure that this doesn't go negative otherwise things will go wrong
  352. while (out_used > 0) {
  353. int delta = Output->Output->GetSendBytesAvailable();
  354. if (LOBYTE(Output->Config->protocol) != 1) {
  355. // try to clamp things so that it's within the packet size limits
  356. delta = min(delta, UV_MAX_DATA_LEN);
  357. }
  358. delta = min(delta, out_used);
  359. if (delta > 7) {
  360. if (LOBYTE(Output->Config->protocol) != 1) {
  361. // send sc2 data frames
  362. createUvoxFrame(delta, EncodedData+sofar, type, Output);
  363. } else {
  364. // send sc1 data
  365. Output->Info.BytesSent += delta;
  366. Output->Output->send(EncodedData+sofar, delta);
  367. }
  368. } else {
  369. // check for the connection having dropped and we're just spinning
  370. // and if we are then we need to abort from here else we lock up
  371. int outstate = Output->Output->get_state();
  372. if (outstate == CONNECTION_STATE_CLOSED || outstate == CONNECTION_STATE_ERROR) {
  373. break;
  374. }
  375. Sleep(10); // sleep a bit and try again
  376. Output->Output->run();
  377. }
  378. sofar+=delta;
  379. out_used-=delta;
  380. }
  381. }
  382. }
  383. if (InputSize <= 0) break;
  384. }
  385. }
  386. }UNLOCK
  387. return in_used;
  388. }
  389. int SHOUTCAST_OUTPUT::AddOutput(int Connection, T_OUTPUT_CONFIG *Config, void (*TitleCallback)(const int Connection, const int Mode)) {
  390. if (Connection >= 0 && Connection < 5) {
  391. T_OUTPUT *job = new T_OUTPUT;
  392. job->Bitrate = 0;
  393. job->ContentType = "audio/mpeg";
  394. if (Encoder) {
  395. int infosize = sizeof(T_EncoderIOVals);
  396. T_EncoderIOVals *EncSettings = (T_EncoderIOVals *)Encoder->GetExtInfo(&infosize);
  397. if (EncSettings && infosize) job->Bitrate = EncSettings->output_bitRate;
  398. job->ContentType = Encoder->GetContentType();
  399. }
  400. job->Connection = Connection;
  401. job->TitleCallback = TitleCallback;
  402. job->Config = Config;
  403. job->Info.Reconnect = Config->AutoRecon;
  404. job->Info.ReconnectTime = Config->ReconTime;
  405. job->Type = OUTTYPE_SOURCE;
  406. job->SlowClose = 0;
  407. // trigger a title update on start as artwork
  408. // is done later so does not need to set here
  409. job->Info.meta_cached = 1;
  410. int retval = -1;
  411. LOCK{
  412. retval = OutputManager.AddJob(OUT_DISCONNECTED, job);
  413. }UNLOCK
  414. return retval;
  415. }
  416. return -1;
  417. }
  418. void SHOUTCAST_OUTPUT::UpdateOutput(int Connection) {
  419. if (Connection >= 0 && Connection < 5) {
  420. LOCK{
  421. T_OUTPUT *Output = OutputManager[Connection];
  422. if (Output) {
  423. Output->Info.Reconnect = Output->Config->AutoRecon;
  424. Output->Info.ReconnectTime = Output->Config->ReconTime;
  425. }
  426. }UNLOCK
  427. }
  428. }
  429. void SHOUTCAST_OUTPUT::RemoveOutput(int Connection) {
  430. if (Connection >= 0 && Connection < 5) {
  431. LOCK{
  432. T_OUTPUT *Output = OutputManager[Connection];
  433. if (Output) {
  434. OutputManager.DelJob(Connection);
  435. delete Output;
  436. }
  437. }UNLOCK
  438. }
  439. }
  440. int SHOUTCAST_OUTPUT::ConnectOutput(int Connection) {
  441. if (Connection >= 0 && Connection < 5) {
  442. LOCK{
  443. T_OUTPUT *Output = OutputManager[Connection];
  444. if (Output && Encoder) {
  445. UpdateOutput(Connection);
  446. compatible_connect(Output, (Output->Config->Port) + (LOBYTE(Output->Config->protocol) == 1));
  447. Output->Bitrate = 0;
  448. Output->ContentType = "audio/mpeg";
  449. if (Encoder) {
  450. int infosize = sizeof(T_EncoderIOVals);
  451. T_ENCODER_MP3_INFO *EncSettings = (T_ENCODER_MP3_INFO *)Encoder->GetExtInfo(&infosize);
  452. if (EncSettings && infosize) Output->Bitrate = EncSettings->output_bitRate;
  453. Output->ContentType = Encoder->GetContentType();
  454. }
  455. OutputManager.SetJobState(Connection, OUT_CONNECT);
  456. }
  457. }UNLOCK
  458. }
  459. return 1;
  460. }
  461. int SHOUTCAST_OUTPUT::DisconnectOutput(int Connection, int withReconnect, int reconnectTime) {
  462. if (Connection >= 0 && Connection < 5) {
  463. LOCK{
  464. T_OUTPUT *Output = OutputManager[Connection];
  465. if (Output) {
  466. int state = OutputManager.GetJobState(Connection);
  467. if (state != OUT_DISCONNECTED) {
  468. Output->Info.Reconnect = withReconnect >= 0 ? withReconnect : Output->Config->AutoRecon;
  469. Output->Info.ReconnectTime = reconnectTime >= 0 ? reconnectTime : Output->Config->ReconTime;
  470. Output->SlowClose = 0;
  471. if (Encoder) {
  472. int infosize = sizeof(T_EncoderIOVals);
  473. T_ENCODER_MP3_INFO *EncSettings = (T_ENCODER_MP3_INFO *)Encoder->GetExtInfo(&infosize);
  474. if (EncSettings && infosize) Output->Bitrate = EncSettings->output_bitRate;
  475. Output->ContentType = Encoder->GetContentType();
  476. }
  477. OutputManager.SetJobState(Connection, OUT_DISCONNECT);
  478. }
  479. }
  480. }UNLOCK
  481. }
  482. return 1;
  483. }
  484. void SHOUTCAST_OUTPUT::SetEncoder(C_ENCODER *encoder, int takeOwnership) {
  485. LOCK{
  486. if (IOwnEncoder && Encoder && Encoder != DEFAULT_ENCODER)
  487. delete Encoder;
  488. if (encoder != DEFAULT_ENCODER) {
  489. IOwnEncoder = takeOwnership;
  490. Encoder = encoder;
  491. } else {
  492. try {
  493. Encoder = new C_ENCODER_MP3(lame_init, lame_init_params, lame_encode_buffer_interleaved, lame_encode_flush);
  494. IOwnEncoder = 1;
  495. } catch(...) {
  496. Encoder = NULL;
  497. }
  498. }
  499. }UNLOCK
  500. }
  501. C_ENCODER *SHOUTCAST_OUTPUT::GetEncoder() {
  502. C_ENCODER *Enc = NULL;
  503. LOCK{
  504. Enc = Encoder;
  505. }UNLOCK
  506. return Enc;
  507. }
  508. bool validateTitle(wchar_t **dest, const wchar_t* src)
  509. {
  510. bool allowed = true;
  511. int src_len = lstrlenW(src);
  512. char *str = (char*)calloc(src_len, sizeof(char));
  513. if (str)
  514. {
  515. WideCharToMultiByte(CP_ACP, 0, src, -1, str, src_len, 0, 0);
  516. std::string updinfoSong(str);
  517. if (!stringUtil::stripAlphaDigit(updinfoSong).empty())
  518. {
  519. // work on lowercase comparison as well as doing a check to see if
  520. // after removing white space + punctuation we have a valid title.
  521. std::string m_checkUpdinfoSong = stringUtil::toLower(updinfoSong);
  522. // exclude weird title updates from being accepted
  523. // as no point in giving junk to the user later on
  524. if (m_checkUpdinfoSong.find("!doctype") != string::npos ||
  525. m_checkUpdinfoSong.find("<script") != string::npos ||
  526. m_checkUpdinfoSong.find("<html") != string::npos ||
  527. m_checkUpdinfoSong.find("<body") != string::npos ||
  528. m_checkUpdinfoSong.find("<div") != string::npos ||
  529. m_checkUpdinfoSong.find("%] ") != string::npos ||
  530. m_checkUpdinfoSong.find("invalid resource") != string::npos ||
  531. (m_checkUpdinfoSong.find("nextsong") != string::npos &&
  532. m_checkUpdinfoSong.find("sctrans2next") != string::npos) ||
  533. m_checkUpdinfoSong.find("radio online") != string::npos ||
  534. m_checkUpdinfoSong.find("track ") == 0 ||
  535. m_checkUpdinfoSong.find("track0") == 0 ||
  536. m_checkUpdinfoSong.find("track1") == 0 ||
  537. m_checkUpdinfoSong.find("stream ") == 0 ||
  538. m_checkUpdinfoSong.find("no artist ") == 0 ||
  539. m_checkUpdinfoSong.find("new artist ") == 0 ||
  540. m_checkUpdinfoSong.find("line-in ") == 0 ||
  541. m_checkUpdinfoSong.find("inter_") == 0 ||
  542. m_checkUpdinfoSong.find("jj mckay - ") == 0 ||
  543. m_checkUpdinfoSong.find("artist - ") == 0 ||
  544. m_checkUpdinfoSong.find("$") == 0 ||
  545. m_checkUpdinfoSong.find("%") == 0 ||
  546. m_checkUpdinfoSong.find("&") == 0 ||
  547. m_checkUpdinfoSong.find("[") == 0 ||
  548. m_checkUpdinfoSong.find("?") == 0 ||
  549. m_checkUpdinfoSong.find("_") == 0 ||
  550. m_checkUpdinfoSong.find("- ") == 0 ||
  551. m_checkUpdinfoSong.find(". ") == 0 ||
  552. m_checkUpdinfoSong == "-" ||
  553. m_checkUpdinfoSong == "auto dj" ||
  554. m_checkUpdinfoSong == "ao vivo" ||
  555. m_checkUpdinfoSong == "unknown" ||
  556. m_checkUpdinfoSong == "test" ||
  557. m_checkUpdinfoSong == "dsp" ||
  558. m_checkUpdinfoSong == "demo" ||
  559. m_checkUpdinfoSong == "line input" ||
  560. m_checkUpdinfoSong == "dj mike llama - llama whippin` intro" ||
  561. m_checkUpdinfoSong == "preview") {
  562. allowed = false;
  563. }
  564. }
  565. else
  566. {
  567. allowed = false;
  568. }
  569. }
  570. else
  571. {
  572. allowed = false;
  573. }
  574. if (dest) {
  575. if (*dest)
  576. {
  577. free(*dest);
  578. }
  579. *dest = _wcsdup(allowed ? src : L"");
  580. }
  581. return allowed;
  582. }
  583. void SHOUTCAST_OUTPUT::UpdateTitleCache(wchar_t *Title, std::vector<std::wstring> NextList, wchar_t *Song,
  584. wchar_t *Album, wchar_t *Artist, wchar_t *Genre, wchar_t *Comment,
  585. wchar_t* Year, int Connection, bool sendNext) {
  586. int update = 0;
  587. if(!metadata.Title || wcscmp(metadata.Title, Title)) {
  588. if (metadata.Title) free(metadata.Title);
  589. metadata.Title = _wcsdup(Title);
  590. update++;
  591. }
  592. metadata.NextList.resize(0);
  593. if (!NextList.empty()) {
  594. metadata.NextList = NextList;
  595. update++;
  596. }
  597. if(!metadata.Song || wcscmp(metadata.Song, (Song ? Song : L""))) {
  598. if (validateTitle(&metadata.Song, (Song ? Song : L""))) {
  599. update++;
  600. }
  601. }
  602. if(!metadata.Album || wcscmp(metadata.Album, (Album ? Album : L""))) {
  603. if (validateTitle(&metadata.Album, (Album ? Album : L""))) {
  604. update++;
  605. }
  606. }
  607. if(!metadata.Artist || wcscmp(metadata.Artist, (Artist ? Artist : L""))) {
  608. if (validateTitle(&metadata.Artist, (Artist ? Artist : L""))) {
  609. update++;
  610. }
  611. }
  612. if(!metadata.Genre || wcscmp(metadata.Genre, (Genre ? Genre : L""))) {
  613. if (validateTitle(&metadata.Genre, (Genre ? Genre : L""))) {
  614. update++;
  615. }
  616. }
  617. if(!metadata.Comment || wcscmp(metadata.Comment, (Comment ? Comment : L""))) {
  618. if (validateTitle(&metadata.Comment, (Comment ? Comment : L""))) {
  619. update++;
  620. }
  621. }
  622. if(!metadata.Year || wcscmp(metadata.Year, (Year ? Year : L""))) {
  623. if (validateTitle(&metadata.Year, (Year ? Year : L""))) {
  624. update++;
  625. }
  626. }
  627. UpdateTitle(0, NextList, Connection, sendNext);
  628. }
  629. void SHOUTCAST_OUTPUT::UpdateAlbumArtCache(void* APIC, int APICLength, int APICType, int Connection) {
  630. int artType = ((APICType & 0xFF00) == (MSG_METADATA_ALBUMART|MSG_METADATA_PLAYING_ART));
  631. // make sure we're within the metadata limits
  632. // which is 32 * max metadata payload (523872)
  633. // and if not then we discard the artwork
  634. int prevAPICLength = metadata.APICLength[artType];
  635. if (APICLength > UV_MAX_TOTAL_META_LEN) {
  636. metadata.APICLength[artType] = 0;
  637. metadata.APIC[artType] = 0;
  638. } else {
  639. metadata.APIC[artType] = APIC;
  640. metadata.APICLength[artType] = APICLength;
  641. }
  642. metadata.APICType[artType] = APICType;
  643. // update the metadata cache usage so we can work
  644. if (Connection >= 0 && Connection < 5) {
  645. LOCK{
  646. T_OUTPUT *Output = OutputManager[Connection];
  647. if (Output) {
  648. // only update the flag if it's new stream art or is playing and is different from before
  649. if (!(!prevAPICLength && artType && (prevAPICLength == metadata.APICLength[artType]))) {
  650. Output->Info.meta_cached |= (!artType ? 2 : 4);
  651. }
  652. }
  653. }UNLOCK
  654. UpdateArtwork(Connection);
  655. }
  656. }
  657. void SHOUTCAST_OUTPUT::UpdateTitle(wchar_t *Title, std::vector<std::wstring> NextList,
  658. int Connection, bool sendNext, bool UseCache) {
  659. //LOCK{
  660. if (Connection >= 0 && Connection < 5) {
  661. T_OUTPUT *Output = OutputManager[Connection];
  662. if (Output && Output->Type == OUTTYPE_SOURCE &&
  663. (OutputManager.GetJobState(Connection) == OUT_SENDCONTENT ||
  664. OutputManager.GetJobState(Connection) == OUT_SEND_METADATA)) {
  665. // clear the metadata send flag
  666. if (Output->Info.meta_cached & 1) {
  667. Output->Info.meta_cached -= 1;
  668. }
  669. if (LOBYTE(Output->Config->protocol) == 1 && Output->Config->doTitleUpdate) {
  670. T_OUTPUT *job = new T_OUTPUT;
  671. job->Bitrate = Output->Bitrate;
  672. job->ContentType = Encoder->GetContentType();
  673. job->Config = Output->Config;
  674. job->Type = OUTTYPE_TITLE;
  675. job->SlowClose = 0;
  676. compatible_connect(job, job->Config->Port);
  677. wchar_t *title = (UseCache?metadata.Title:Title);
  678. if (title) {
  679. validateTitle(&job->Info.Title, title);
  680. validateTitle(&Output->Info.Title, title);
  681. } else {
  682. validateTitle(&job->Info.Title, Output->Info.Title);
  683. }
  684. OutputManager.AddJob(OUT_CONNECT, job);
  685. } else if (LOBYTE(Output->Config->protocol) != 1) {
  686. validateTitle(&Output->Info.Title, (UseCache?metadata.Title:Title));
  687. //#ifndef _DEBUG
  688. if (UseCache) {
  689. if (!metadata.NextList.empty()) {
  690. Output->Info.NextList = metadata.NextList;
  691. }
  692. } else {
  693. if (!NextList.empty()) {
  694. Output->Info.NextList = NextList;
  695. }
  696. }
  697. //#endif
  698. validateTitle(&Output->Info.Song, (metadata.Song && UseCache ? metadata.Song : L""));
  699. validateTitle(&Output->Info.Album, (metadata.Album && UseCache ? metadata.Album : L""));
  700. validateTitle(&Output->Info.Artist, (metadata.Artist && UseCache ? metadata.Artist : L""));
  701. validateTitle(&Output->Info.Genre, (metadata.Genre ? metadata.Genre : L""));
  702. validateTitle(&Output->Info.Comment, (metadata.Comment && UseCache ? metadata.Comment : L""));
  703. validateTitle(&Output->Info.Year, (metadata.Year && UseCache ? metadata.Year : L""));
  704. if (Output->Config->doTitleUpdate) {
  705. // only output friendlier line breaks when debugging is needed
  706. #ifdef _DEBUG
  707. #define XML_DEBUG
  708. #endif
  709. #ifdef XML_DEBUG
  710. #define EOL "\n"
  711. #define TAB "\t"
  712. #else
  713. #define EOL ""
  714. #define TAB ""
  715. #endif
  716. stringstream s;
  717. s << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n<metadata>" EOL;
  718. wchar_t * title = (Output->Info.Song && *Output->Info.Song ? Output->Info.Song : Output->Info.Title);
  719. if (validateTitle(0, title)) {
  720. s << "<TIT2>" << ConvertToUTF8Escaped(title) << "</TIT2>" EOL;
  721. }
  722. if (Output->Info.Album && Output->Info.Album[0]) s << "<TALB>" << ConvertToUTF8Escaped(Output->Info.Album) << "</TALB>" EOL;
  723. if (Output->Info.Artist && Output->Info.Artist[0]) s << "<TPE1>" << ConvertToUTF8Escaped(Output->Info.Artist) << "</TPE1>" EOL;
  724. if (Output->Info.Year && Output->Info.Year[0]) s << "<TYER>" << ConvertToUTF8Escaped(Output->Info.Year) << "</TYER>" EOL;
  725. if (Output->Info.Comment && Output->Info.Comment[0]) s << "<COMM>" << ConvertToUTF8Escaped(Output->Info.Comment) << "</COMM>" EOL;
  726. if (Output->Info.Genre && Output->Info.Genre[0]) s << "<TCON>" << ConvertToUTF8Escaped(Output->Info.Genre) << "</TCON>" EOL;
  727. s << "<TENC>SHOUTcast Source DSP v" << sourceVersion << "</TENC>" EOL;
  728. if (Output->Config->Description[0]) s << "<TRSN>" << escapeXML(Output->Config->Description) << "</TRSN>" EOL;
  729. s << "<WORS>" << escapeXML(Output->Config->ServerURL && Output->Config->ServerURL[0] ? Output->Config->ServerURL : "http://www.shoutcast.com") << "</WORS>" EOL;
  730. if (validateTitle(0, title)) {
  731. s << "<extension>" EOL TAB "<TITLE seq=\"1\">" << ConvertToUTF8Escaped(title) << "</TITLE>" EOL;
  732. if (!Output->Info.NextList.empty() && sendNext) {
  733. s << TAB;
  734. std::string soon;
  735. for (size_t idx = 0, seq = 0; idx < Output->Info.NextList.size(); idx++) {
  736. if (validateTitle(0, Output->Info.NextList[idx].c_str()))
  737. {
  738. std::string next = ConvertToUTF8Escaped(Output->Info.NextList[idx].c_str());
  739. s << "<TITLE seq=\"" << (seq+2) << "\">" << next << "</TITLE>" EOL TAB;
  740. // store the first item as that is used for the 'soon' item
  741. if (seq == 0) soon = next;
  742. seq++;
  743. }
  744. }
  745. if (!soon.empty()) {
  746. s << "<soon>" << soon << "</soon>" EOL;
  747. }
  748. }
  749. s << "</extension>" EOL;
  750. }
  751. s << "</metadata>";
  752. // TODO make sure this will split up > UV_MAX_META_FRAME_LEN blocks
  753. mid = createUvoxMetaFrame(s.str().length(),(char*)s.str().data(), MSG_METADATA_XML_NEW, Output, mid);
  754. }
  755. }
  756. }
  757. }
  758. }
  759. void SHOUTCAST_OUTPUT::UpdateArtwork(int Connection) {
  760. if (Connection >= 0 && Connection < 5) {
  761. LOCK{
  762. T_OUTPUT *Output = OutputManager[Connection];
  763. if (Output && Output->Type == OUTTYPE_SOURCE) {
  764. if (LOBYTE(Output->Config->protocol) != 1) {
  765. Output->Info.APIC[0] = metadata.APIC[0];
  766. Output->Info.APICLength[0] = metadata.APICLength[0];
  767. Output->Info.APICType[0] = metadata.APICType[0];
  768. Output->Info.APIC[1] = metadata.APIC[1];
  769. Output->Info.APICLength[1] = metadata.APICLength[1];
  770. Output->Info.APICType[1] = metadata.APICType[1];
  771. // calculate the album art span inorder to use it once we've sent the title in following callbacks
  772. for (int i = 0; i < 2; i++) {
  773. int AlbumArtSpan = (metadata.APICLength[i] / UV_MAX_DATA_LEN) + ((metadata.APICLength[i] % UV_MAX_DATA_LEN) < UV_MAX_DATA_LEN ? 1 : 0);
  774. // if over the limit then abort trying to send this
  775. if (AlbumArtSpan > UV_MAX_META_FRAGMENTS) {
  776. AlbumArtSpan = 1;
  777. Output->Info.APIC[i] = 0;
  778. }
  779. Output->Info.art_cached_span[i] = Output->Info.art_cached[i] = AlbumArtSpan;
  780. Output->Info.art_index[i] = 1;
  781. Output->Info.art_cached_length[i] = Output->Info.APICLength[i];
  782. }
  783. }
  784. }
  785. }UNLOCK
  786. }
  787. }
  788. int SHOUTCAST_OUTPUT::UpdateAlbumArt(int Connection) {
  789. if (Connection >= 0 && Connection < 5) {
  790. LOCK{
  791. T_OUTPUT *Output = OutputManager[Connection];
  792. if (Output && Output->Type == OUTTYPE_SOURCE &&
  793. OutputManager.GetJobState(Connection) == OUT_SEND_ARTWORK) {
  794. int artType = (Output->Info.meta_cached & 4 ? 1 : (Output->Info.meta_cached & 2 ? 0 : -1));
  795. if (artType != -1 && LOBYTE(Output->Config->protocol) != 1 && Output->Info.art_cached[artType] > 0) {
  796. int type = Output->Info.APICType[artType];
  797. int length = Output->Info.art_cached_length[artType];
  798. int count = Output->Info.art_cached_span[artType] - Output->Info.art_cached[artType];
  799. // attempt to process as a multi-part message as APIC most likely won't fit in just one uvox packet
  800. if (length >= UV_MAX_META_LEN) {
  801. createUvoxMetaFrame(UV_MAX_META_LEN,
  802. (char*)Output->Info.APIC[artType]+(count * UV_MAX_META_LEN),
  803. type, Output, mid, Output->Info.art_cached_span[artType]);
  804. Output->Info.art_cached_length[artType] -= UV_MAX_META_LEN;
  805. } else {
  806. createUvoxMetaFrame(length,
  807. (char*)Output->Info.APIC[artType]+(count * UV_MAX_META_LEN),
  808. type, Output, mid, Output->Info.art_cached_span[artType]);
  809. Output->Info.art_cached_length[artType] = 0;
  810. }
  811. Output->Info.art_index[artType] += 1;
  812. if (Output->Info.art_cached[artType] == 1) {
  813. mid+=1;
  814. Output->Info.meta_cached -= (artType ? 4 : 2);
  815. // reset the values so we can re-send on disconnect, etc
  816. Output->Info.art_cached[artType] = Output->Info.art_cached_span[artType];
  817. Output->Info.art_index[artType] = 1;
  818. Output->Info.art_cached_length[artType] = Output->Info.APICLength[artType];
  819. }
  820. }
  821. }
  822. }UNLOCK
  823. }
  824. return 1;
  825. }
  826. enum OUTPUTSTATE SHOUTCAST_OUTPUT::GetState(int Connection) {
  827. int retval = -1;
  828. if (Connection >= 0 && Connection < 5) {
  829. LOCK{
  830. retval = OutputManager.GetJobState(Connection);
  831. }UNLOCK
  832. }
  833. return retval == -1 ? OUT_ERROR : (enum OUTPUTSTATE)retval;
  834. }
  835. T_OUTPUT_CONFIG *SHOUTCAST_OUTPUT::operator[](int Connection) {
  836. return GetOutput(Connection);
  837. }
  838. T_OUTPUT_CONFIG *SHOUTCAST_OUTPUT::GetOutput(int Connection) {
  839. T_OUTPUT_CONFIG *Config = NULL;
  840. if (Connection >= 0 && Connection < 5) {
  841. LOCK{
  842. T_OUTPUT *Output = OutputManager[Connection];
  843. if (Output) Config = Output->Config;
  844. }UNLOCK
  845. }
  846. return Config;
  847. }
  848. T_OUTPUT_INFO *SHOUTCAST_OUTPUT::GetOutputInfo(int Connection) {
  849. T_OUTPUT_INFO *Info = NULL;
  850. if (Connection >= 0 && Connection < 5) {
  851. LOCK{
  852. T_OUTPUT *Output = OutputManager[Connection];
  853. if (Output) Info = &Output->Info;
  854. }UNLOCK
  855. }
  856. return Info;
  857. }
  858. // Protected methods
  859. int SHOUTCAST_OUTPUT::Output_Disconnected(int state, int last_state, T_OUTPUT *userData) {
  860. STATE;
  861. LOCK{
  862. userData->Config->protocol_retry = 0;
  863. }UNLOCK
  864. return state; // sit and spin
  865. }
  866. int SHOUTCAST_OUTPUT::Output_Connect(int state, int last_state, T_OUTPUT *userData) {
  867. DEBUG_STATE
  868. STATE;
  869. LOCK{
  870. userData->Config->protocol_retry = MAKEWORD(0, HIBYTE(userData->Config->protocol_retry));
  871. userData->Info.Succeeded = 1;
  872. if (userData->Output) {
  873. userData->Output->FlushSend();
  874. }
  875. if ((clock() - userData->Info.ConnectionTime) / CLOCKS_PER_SEC >= 1/*userData->Info.ReconnectTime*/) {
  876. if (userData->Output && userData->Output->get_state() == CONNECTION_STATE_CONNECTED) { // are we connected yet?
  877. userData->Info.ConnectionTime = clock();
  878. if (userData->Type == OUTTYPE_SOURCE) {
  879. userData->Info.Reconnect = userData->Config->AutoRecon;
  880. userData->Info.ReconnectTime = userData->Config->ReconTime;
  881. userData->Info.ConnectedAt = time(NULL);
  882. UNLOCK
  883. return OUT_REQUEST_CIPHER; // connected, go authenticate
  884. } else if (userData->Type == OUTTYPE_TITLE) {
  885. UNLOCK
  886. return OUT_TITLESENDUPDATE; // connected, go update the title
  887. }
  888. }
  889. }
  890. }UNLOCK
  891. return state; // sit and spin
  892. }
  893. int SHOUTCAST_OUTPUT::Output_SendContent(int state, int last_state, T_OUTPUT *userData) {
  894. DEBUG_STATE
  895. STATE;
  896. if (userData->Output->get_state() == CONNECTION_STATE_ERROR) { // connection error?
  897. return OUT_DISCONNECT; // error happened, go shut down
  898. }
  899. // check if we have any metadata or artwork to dispatch (depends on protocol)
  900. if (userData->Info.meta_cached & 1) {
  901. userData->Info.meta_cached -= 1;
  902. return OUT_SEND_METADATA;
  903. } else if (LOBYTE(userData->Config->protocol) != 1 &&
  904. (userData->Info.meta_cached & 2 || userData->Info.meta_cached & 4) &&
  905. userData->Info.art_cached > 0) {
  906. return OUT_SEND_ARTWORK;
  907. }
  908. return state; // sit and spin
  909. }
  910. int SHOUTCAST_OUTPUT::Output_Disconnect(int state, int last_state, T_OUTPUT *userData) {
  911. DEBUG_STATE
  912. //STATE;
  913. LOCK{
  914. // reset the metadata flags so it will trigger on a connection coming back
  915. // with usage of what was already cached to determine what we will re-send
  916. userData->Info.meta_cached = 1|(userData->Info.art_cached_length[0] ? 2 : 0)|(userData->Info.art_cached_length[1] ? 4 : 0);
  917. int outstate = (userData->Output ? userData->Output->get_state() : CONNECTION_STATE_ERROR);
  918. if (outstate == CONNECTION_STATE_CONNECTING) { // are we connecting? if so then just abort
  919. UNLOCK
  920. return OUT_DISCONNECTED;
  921. }
  922. if (outstate == CONNECTION_STATE_CONNECTED) { // are we connected yet?
  923. userData->Info.ConnectionTime = clock();
  924. userData->Info.ConnectedAt = 0;
  925. userData->Info.BytesSent = 0;
  926. if (LOBYTE(userData->Config->protocol) != 1) {
  927. createUvoxFrame(1, "0\0", MSG_TERMINATE, userData);
  928. if (userData->Info.Succeeded != -1) {
  929. Output_DUMMY(state, last_state, userData);
  930. }
  931. }
  932. userData->Output->Close(!userData->SlowClose);
  933. }
  934. if (outstate == CONNECTION_STATE_CLOSING) {
  935. userData->Info.ConnectionTime = clock(); // update the clock with the current time so that we don't get some weird crap for reconnections.
  936. }
  937. if (outstate == CONNECTION_STATE_CLOSED || outstate == CONNECTION_STATE_ERROR) {
  938. userData->Info.Switching = 0;
  939. if (last_state == OUT_SENDYP) {
  940. userData->Info.Succeeded = -1;
  941. userData->Info.ErrorMsg = "Blocked";
  942. } else if (userData->Type == OUTTYPE_SOURCE &&
  943. (last_state == OUT_CONNECT || last_state == OUT_REQUEST_CIPHER ||
  944. last_state == OUT_SENDAUTH || last_state == OUT_RECV_CIPHER ||
  945. last_state == OUT_DISCONNECT)) {
  946. // if using automatic mode then switch between v1 and v2 modes as needed
  947. if (HIBYTE(userData->Config->protocol) && ((LOBYTE(userData->Config->protocol_retry) > 5) ||
  948. (last_state == OUT_CONNECT && HIBYTE(userData->Config->protocol_retry) < 1))) {
  949. int protocol = (2 - (LOBYTE(userData->Config->protocol) != 1));
  950. userData->Config->protocol_retry = MAKEWORD(0, HIBYTE(userData->Config->protocol_retry)+1);
  951. userData->Info.Switching = (LOBYTE(userData->Config->protocol) != 1 ? 2 : 1);
  952. userData->Config->protocol = MAKEWORD(protocol, 1);
  953. userData->Info.ConnectionTime = clock();
  954. UNLOCK
  955. return OUT_RECONNECT;
  956. }
  957. }
  958. if (userData->Info.Reconnect && userData->Type == OUTTYPE_SOURCE) {
  959. // if using automatic mode then switch between v1 and v2 modes as needed
  960. if (HIBYTE(userData->Config->protocol)) {
  961. // TODO need to make this into a function and have it show the switching message
  962. int protocol = (2 - (LOBYTE(userData->Config->protocol) != 1));
  963. userData->Config->protocol_retry = 0;
  964. userData->Info.Switching = (LOBYTE(userData->Config->protocol) != 1 ? 2 : 1);
  965. userData->Config->protocol = MAKEWORD(protocol, 1);
  966. userData->Info.ConnectionTime = clock();
  967. }
  968. UNLOCK
  969. return OUT_RECONNECT;
  970. } else {
  971. UNLOCK
  972. return OUT_DISCONNECTED;
  973. }
  974. }
  975. }UNLOCK
  976. return state; // sit and spin
  977. }
  978. int SHOUTCAST_OUTPUT::Output_Reconnect(int state, int last_state, T_OUTPUT *userData) {
  979. DEBUG_STATE
  980. STATE;
  981. LOCK{
  982. if ((clock() - userData->Info.ConnectionTime) / CLOCKS_PER_SEC >= userData->Info.ReconnectTime) {
  983. if (userData->Output) {
  984. compatible_connect(userData, userData->Config->Port + (LOBYTE(userData->Config->protocol) == 1));
  985. }
  986. UNLOCK
  987. return OUT_CONNECT;
  988. }
  989. }UNLOCK
  990. return state; // sit and spin
  991. }
  992. void FixString(const char *in, char *out) {
  993. while (in && *in) {
  994. if ((*in >= 'A' && *in <= 'Z') ||
  995. (*in >= 'a' && *in <= 'z') ||
  996. (*in >= '0' && *in <= '9') ||
  997. (*in == '-') ||
  998. (*in == '_') ||
  999. (*in == '.') ||
  1000. (*in == '!') ||
  1001. (*in == '~') ||
  1002. (*in == '*') ||
  1003. (*in == '\'') ||
  1004. (*in == '(') ||
  1005. (*in == '[') ||
  1006. (*in == ']') ||
  1007. (*in == ')')) {
  1008. *out++=*in++;
  1009. } else if (*in >= 0 && *in < 32 && *in != 9 && *in != 10 && *in != 13) {
  1010. // strip out characters which aren't supported by the DNAS
  1011. // (only allow backspace, linefeed and carriage return)
  1012. in++;
  1013. } else {
  1014. unsigned int i=*(unsigned char *)in;
  1015. const char *t=in;
  1016. in++;
  1017. if (in == t + 1) {
  1018. if (i == '\'') i = '`';
  1019. else if (i == '<') i = '(';
  1020. else if (i == '>') i = ')';
  1021. else if (i == '\"') i='`';
  1022. else if (i == '[') i='`';
  1023. else if (i == ']') i='`';
  1024. snprintf(out, 3, "%%%02X", i);
  1025. out += 3;
  1026. } else if (in == t + 2) { // multibyte
  1027. }
  1028. }
  1029. }
  1030. *out=0;
  1031. }
  1032. /* SHOUTcast 1 title updates */
  1033. int SHOUTCAST_OUTPUT::Output_Title_SendUpdate(int state, int last_state, T_OUTPUT *userData) {
  1034. DEBUG_STATE
  1035. STATE;
  1036. LOCK{
  1037. char utf8title[1024] = {0};
  1038. char fixedtitle[3072] = {0}; // if every character is URL-encoded, we would get a maximum of 3 times the space needed
  1039. char buffer[2048] = {0};
  1040. WideCharToMultiByte(CP_ACP, 0, userData->Info.Title, -1, utf8title, sizeof(utf8title), 0, 0);
  1041. FixString(utf8title, fixedtitle);
  1042. fixedtitle[1023] = 0; // DNAS doesn't like titles bigger than 1k
  1043. // send the correct password based on dj name, etc
  1044. std::string t, u, p;
  1045. u = userData->Config->UserID;
  1046. p = userData->Config->Password;
  1047. if (!u.empty()) t = u + ":" + p;
  1048. else t = p;
  1049. snprintf(buffer, sizeof(buffer), "GET /admin.cgi?pass=%s&mode=updinfo&song=%s&dj=%s HTTP/1.0\n", (char *)t.data(), fixedtitle, userData->Config->UserID);
  1050. userData->Output->SendString(buffer);
  1051. stringstream s;
  1052. s << "User-Agent: SHOUTcast Source DSP v" << sourceVersion << " Title Update (Mozilla)\n\n";
  1053. userData->Output->SendString((char*)s.str().data());
  1054. userData->SlowClose = 1;
  1055. userData->Info.meta_cached = 1;
  1056. }UNLOCK
  1057. return OUT_DISCONNECT;
  1058. }
  1059. /* SHOUTcast 2 in-stream metada */
  1060. int SHOUTCAST_OUTPUT::Output_Send_Metadata(int state, int last_state, T_OUTPUT *userData) {
  1061. DEBUG_STATE
  1062. STATE;
  1063. LOCK{
  1064. if (userData->TitleCallback) {
  1065. if (userData->Connection >= 0 && userData->Connection < 5) {
  1066. userData->TitleCallback(userData->Connection, 0);
  1067. }
  1068. }
  1069. }UNLOCK
  1070. return OUT_SENDCONTENT;
  1071. }
  1072. /* SHOUTcast 2 in-stream metada */
  1073. int SHOUTCAST_OUTPUT::Output_Send_Artwork(int state, int last_state, T_OUTPUT *userData) {
  1074. DEBUG_STATE
  1075. STATE;
  1076. LOCK{
  1077. int artType = (userData->Info.meta_cached & 4 ? 1 : (userData->Info.meta_cached & 2 ? 0 : -1));
  1078. if (userData->TitleCallback) {
  1079. if (userData->Connection >= 0 && userData->Connection < 5) {
  1080. if (artType != -1) {
  1081. userData->TitleCallback(userData->Connection, 1);
  1082. // decrement counts to move to next part of image packets if needed
  1083. if (userData->Info.meta_cached & (artType ? 4 : 2)) {
  1084. userData->Info.art_cached[artType]--;
  1085. if (userData->Info.art_cached[artType] < 0) userData->Info.art_cached[artType] = 0;
  1086. }
  1087. }
  1088. }
  1089. } else {
  1090. if (artType != -1) {
  1091. userData->Info.art_cached[artType] = 0;
  1092. }
  1093. }
  1094. }UNLOCK
  1095. return OUT_SENDCONTENT;
  1096. }
  1097. int SHOUTCAST_OUTPUT::Output_Request_Cipher(int state, int last_state, T_OUTPUT *userData) {
  1098. DEBUG_STATE
  1099. STATE;
  1100. LOCK{
  1101. if (LOBYTE(userData->Config->protocol) != 1) {
  1102. userData->Output->FlushSend();
  1103. createUvoxFrame(3, "2.1\0", MSG_CIPHER, userData);
  1104. UNLOCK
  1105. return OUT_RECV_CIPHER;
  1106. } else {
  1107. // shoutcast 1
  1108. UNLOCK
  1109. return OUT_SENDAUTH;
  1110. }
  1111. }UNLOCK
  1112. return state;
  1113. }
  1114. int SHOUTCAST_OUTPUT::Output_Receive_Cipher(int state, int last_state, T_OUTPUT *userData) {
  1115. DEBUG_STATE
  1116. STATE;
  1117. LOCK{
  1118. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1119. memset(buf, '\0', sizeof(buf));
  1120. userData->Output->ReceiveLine(buf, sizeof(buf));
  1121. parseUvoxFrame(buf, out);
  1122. if (checkUvoxFrameForError(out, state, userData) == -1) {
  1123. UNLOCK
  1124. return OUT_DISCONNECT;
  1125. } else {
  1126. // copy the cipher key now we have it.
  1127. strcpy_s(userData->Config->cipherkey, sizeof(userData->Config->cipherkey)-1, out+4);
  1128. UNLOCK
  1129. userData->Config->protocol_retry = 0;
  1130. return OUT_SENDAUTH;
  1131. }
  1132. }
  1133. userData->Config->protocol_retry = MAKEWORD(LOBYTE(userData->Config->protocol_retry)+1, HIBYTE(userData->Config->protocol_retry));
  1134. // this handles automatic mode being enabled
  1135. if (!HIBYTE(userData->Config->protocol) &&
  1136. (LOBYTE(userData->Config->protocol_retry) > 5)) {
  1137. userData->Output->Close(!userData->SlowClose);
  1138. UNLOCK
  1139. return OUT_SENDAUTH;
  1140. }
  1141. }UNLOCK
  1142. return (LOBYTE(userData->Config->protocol_retry) > 5 ? OUT_DISCONNECT : state);
  1143. }
  1144. int SHOUTCAST_OUTPUT::Output_SendAuth(int state, int last_state, T_OUTPUT *userData) {
  1145. DEBUG_STATE
  1146. STATE;
  1147. LOCK{
  1148. userData->Output->FlushSend();
  1149. userData->Info.Succeeded = 1;
  1150. std::string s,
  1151. u = userData->Config->UserID,
  1152. p = userData->Config->Password;
  1153. if (LOBYTE(userData->Config->protocol) != 1) {
  1154. uvAuth21 * auth = new uvAuth21();
  1155. std::string k;
  1156. k = userData->Config->cipherkey;
  1157. s = "2.1:";
  1158. s += (!userData->Config->StationID[0] ? "1" : userData->Config->StationID);
  1159. s += ":";
  1160. s += auth->encrypt(u, p, k);
  1161. createUvoxFrame(s.length(), (char *)s.data(), MSG_AUTH, userData);
  1162. delete auth;
  1163. } else {
  1164. if (!u.empty()) s = u + ":" + p;
  1165. else s = p;
  1166. userData->Output->SendString((char *)s.data());
  1167. userData->Output->SendString("\n");
  1168. }
  1169. UNLOCK
  1170. return OUT_RECVAUTHRESPONSE;
  1171. }UNLOCK
  1172. return state;
  1173. }
  1174. int SHOUTCAST_OUTPUT::Output_RecvAuthResponse(int state, int last_state, T_OUTPUT *userData) {
  1175. DEBUG_STATE
  1176. STATE;
  1177. LOCK{
  1178. if (LOBYTE(userData->Config->protocol) != 1) {
  1179. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1180. memset(buf, '\0', sizeof(buf));
  1181. userData->Info.Succeeded = 1;
  1182. userData->Output->recv_bytes(buf, sizeof(buf));
  1183. parseUvoxFrame(buf, out);
  1184. int err = checkUvoxFrameForError(out, state, userData);
  1185. if (err == -1) {
  1186. UNLOCK
  1187. return OUT_DISCONNECT;
  1188. } else {
  1189. // test for a cipher failure
  1190. if (strncmp(buf, "ACK:", 4) == 0) {
  1191. userData->Info.Succeeded = -1;
  1192. userData->Info.ErrorMsg = "CipherFail";
  1193. UNLOCK
  1194. return OUT_FAIL_CIPHER;
  1195. }
  1196. UNLOCK
  1197. return OUT_SEND_MIME;
  1198. }
  1199. }
  1200. } else {
  1201. // auth shoutcast 1
  1202. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1203. userData->Output->ReceiveLine(buf, sizeof(buf));
  1204. char *ok = strstr(buf, "OK");
  1205. if (ok) { // we got OK response... shoutcast v1
  1206. userData->Info.Succeeded = 1;
  1207. UNLOCK
  1208. return OUT_SENDYP; // send the sc v1 YP stuff, now
  1209. } else {
  1210. userData->Info.Succeeded = 0;
  1211. if (strcmpi(buf, "invalid password") == 0) {
  1212. userData->Info.Succeeded = -1;
  1213. userData->Info.ErrorMsg = "NAK:Deny";
  1214. } else if (strcmpi(buf, "stream moved") == 0) {
  1215. userData->Info.Succeeded = -1;
  1216. userData->Info.ErrorMsg = "StreamMoved";
  1217. }
  1218. UNLOCK
  1219. return OUT_DISCONNECT;
  1220. }
  1221. }
  1222. }
  1223. }UNLOCK
  1224. return state;
  1225. }
  1226. int SHOUTCAST_OUTPUT::Output_Send_Mime(int state, int last_state, T_OUTPUT *userData) {
  1227. DEBUG_STATE
  1228. STATE;
  1229. LOCK{
  1230. std::string s = userData->ContentType;
  1231. userData->Output->FlushSend();
  1232. createUvoxFrame(s.length(), (char *)s.data(), MSG_MIME_TYPE, userData);
  1233. }UNLOCK
  1234. return OUT_RECV_MIME;
  1235. }
  1236. int SHOUTCAST_OUTPUT::Output_Recv_Mime(int state, int last_state, T_OUTPUT *userData) {
  1237. DEBUG_STATE
  1238. STATE;
  1239. LOCK{
  1240. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1241. memset(buf, '\0', sizeof(buf));
  1242. userData->Output->recv_bytes(buf, sizeof(buf));
  1243. parseUvoxFrame(buf, out);
  1244. UNLOCK
  1245. return OUT_SEND_BITRATE;
  1246. }
  1247. }UNLOCK
  1248. return state;
  1249. }
  1250. int SHOUTCAST_OUTPUT::Output_Send_Bitrate(int state, int last_state, T_OUTPUT *userData) {
  1251. DEBUG_STATE
  1252. STATE;
  1253. LOCK{
  1254. char bitrate[128] = {0};
  1255. std::string s;
  1256. snprintf(bitrate, sizeof(bitrate), "%d:%d", userData->Bitrate*1000, userData->Bitrate*1000);
  1257. s = bitrate;
  1258. userData->Output->FlushSend();
  1259. createUvoxFrame(s.length(), (char *)s.data(), MSG_BROADCAST_SETUP, userData);
  1260. }UNLOCK
  1261. return OUT_RECV_BITRATE;
  1262. }
  1263. int SHOUTCAST_OUTPUT::Output_Recv_Bitrate(int state, int last_state, T_OUTPUT *userData) {
  1264. DEBUG_STATE
  1265. STATE;
  1266. LOCK{
  1267. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1268. memset(buf, '\0', sizeof(buf));
  1269. userData->Output->recv_bytes(buf, sizeof(buf));
  1270. parseUvoxFrame(buf, out);
  1271. int err = checkUvoxFrameForError(out, state, userData);
  1272. if (err == -1) {
  1273. UNLOCK
  1274. return OUT_DISCONNECT;
  1275. } else {
  1276. UNLOCK
  1277. return OUT_SEND_BUFSIZE;
  1278. }
  1279. }
  1280. }UNLOCK
  1281. return state;
  1282. }
  1283. int SHOUTCAST_OUTPUT::Output_Send_Buf_Size(int state, int last_state, T_OUTPUT *userData) {
  1284. DEBUG_STATE
  1285. STATE;
  1286. LOCK{
  1287. char bsize[32] = {0};
  1288. int toSend = (userData->Bitrate * 20)/8;
  1289. snprintf(bsize, sizeof(bsize), "%d:0", toSend);
  1290. std::string s = bsize;
  1291. userData->Output->FlushSend();
  1292. createUvoxFrame(s.length(), (char *)s.data(), MSG_NEGOTIATE_BUFFER_SIZE, userData);
  1293. }UNLOCK
  1294. return OUT_RECV_BUFSIZE;
  1295. }
  1296. int SHOUTCAST_OUTPUT::Output_Recv_Buf_Size(int state, int last_state, T_OUTPUT *userData) {
  1297. DEBUG_STATE
  1298. STATE;
  1299. LOCK{
  1300. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1301. memset(buf, '\0', sizeof(buf));
  1302. userData->Output->recv_bytes(buf, sizeof(buf));
  1303. UNLOCK
  1304. return OUT_SEND_MAX;
  1305. }
  1306. }UNLOCK
  1307. return state;
  1308. }
  1309. int SHOUTCAST_OUTPUT::Output_Send_Max_Size(int state, int last_state, T_OUTPUT *userData) {
  1310. DEBUG_STATE
  1311. STATE;
  1312. LOCK{
  1313. userData->Output->FlushSend();
  1314. createUvoxFrame(7, "16377:0\0", MSG_MAX_PAYLOAD_SIZE, userData);
  1315. }UNLOCK
  1316. return OUT_RECV_MAX;
  1317. }
  1318. int SHOUTCAST_OUTPUT::Output_Recv_Max_Size(int state, int last_state, T_OUTPUT *userData) {
  1319. DEBUG_STATE
  1320. STATE;
  1321. LOCK{
  1322. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1323. memset(buf, '\0', sizeof(buf));
  1324. userData->Output->recv_bytes(buf, sizeof(buf));
  1325. parseUvoxFrame(buf, out);
  1326. UNLOCK
  1327. return OUT_SENDYP;
  1328. }
  1329. }UNLOCK
  1330. return state;
  1331. }
  1332. int SHOUTCAST_OUTPUT::Output_DUMMY(int state, int last_state, T_OUTPUT *userData) {
  1333. DEBUG_STATE
  1334. STATE;
  1335. LOCK{
  1336. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1337. memset(buf, '\0', sizeof(buf));
  1338. userData->Output->recv_bytes(buf, sizeof(buf));
  1339. parseUvoxFrame(buf, out);
  1340. }
  1341. }UNLOCK
  1342. return state;
  1343. }
  1344. int SHOUTCAST_OUTPUT::Output_SendYP(int state, int last_state, T_OUTPUT *userData) {
  1345. DEBUG_STATE
  1346. STATE;
  1347. LOCK{
  1348. if (LOBYTE(userData->Config->protocol) != 1) {
  1349. //icyname
  1350. std::string s;
  1351. s = userData->Config->Description;
  1352. createUvoxFrame(s.length(), (char *)s.data(), MSG_ICYNAME, userData);
  1353. Output_DUMMY(state, last_state, userData);
  1354. //icygenre
  1355. s = userData->Config->Genre;
  1356. createUvoxFrame(s.length(), (char *)s.data(), MSG_ICYGENRE, userData);
  1357. Output_DUMMY(state, last_state, userData);
  1358. //icyurl
  1359. s = userData->Config->ServerURL;
  1360. createUvoxFrame(s.length(), (char *)s.data(), MSG_ICYURL, userData);
  1361. Output_DUMMY(state, last_state, userData);
  1362. //icypub
  1363. char pub[2] = {0};
  1364. snprintf(pub, sizeof(pub), "%d", !!userData->Config->Public);
  1365. createUvoxFrame(1, pub, MSG_ICYPUB, userData);
  1366. Output_DUMMY(state, last_state, userData);
  1367. UNLOCK
  1368. return OUT_SEND_INITFLUSH;
  1369. } else {
  1370. char ypbuf[4096] = {0};
  1371. char ypbuf2[4096] = {0};
  1372. // send Description
  1373. snprintf(ypbuf, sizeof(ypbuf), "icy-name:%s\n", userData->Config->Description);
  1374. userData->Output->SendString(ypbuf);
  1375. // send Genre
  1376. ypbuf2[0] = 0;
  1377. if (strlen(userData->Config->Genre) > 0) {
  1378. snprintf((char *)&ypbuf2+strlen(ypbuf2), sizeof(ypbuf2), "%s", userData->Config->Genre);
  1379. }
  1380. snprintf(ypbuf, sizeof(ypbuf), "icy-genre:%s\n", ypbuf2);
  1381. userData->Output->SendString(ypbuf);
  1382. // send URL
  1383. snprintf(ypbuf, sizeof(ypbuf), "icy-url:%s\n", userData->Config->ServerURL);
  1384. userData->Output->SendString(ypbuf);
  1385. // send IRC
  1386. snprintf(ypbuf, sizeof(ypbuf), "icy-irc:%s\n", userData->Config->IRC);
  1387. userData->Output->SendString(ypbuf);
  1388. // send ICQ
  1389. snprintf(ypbuf, sizeof(ypbuf), "icy-icq:%s\n", userData->Config->ICQ);
  1390. userData->Output->SendString(ypbuf);
  1391. // send AIM
  1392. snprintf(ypbuf, sizeof(ypbuf), "icy-aim:%s\n", userData->Config->AIM);
  1393. userData->Output->SendString(ypbuf);
  1394. // send publicity
  1395. snprintf(ypbuf, sizeof(ypbuf), "icy-pub:%u\n", userData->Config->Public ? 1 : 0);
  1396. userData->Output->SendString(ypbuf);
  1397. // send bitrate (this is a huge bad big ugly hack... needs to be fixed, but this works so far)
  1398. snprintf(ypbuf, sizeof(ypbuf), "icy-br:%d\n", userData->Bitrate);
  1399. userData->Output->SendString(ypbuf);
  1400. // send content type (shouldn't be here as with the bitrate, but it works)
  1401. snprintf(ypbuf, sizeof(ypbuf), "content-type:%s\n", userData->ContentType);
  1402. userData->Output->SendString(ypbuf);
  1403. // end our list of configurations
  1404. userData->Output->SendString("\n");
  1405. UNLOCK
  1406. return OUT_SENDCONTENT;
  1407. }
  1408. }UNLOCK
  1409. return state;
  1410. }
  1411. int SHOUTCAST_OUTPUT::Output_Send_InitFlush(int state, int last_state, T_OUTPUT *userData) {
  1412. DEBUG_STATE
  1413. STATE;
  1414. LOCK{
  1415. userData->Output->FlushSend();
  1416. createUvoxFrame(1, "0\0", MSG_FLUSH_CACHED_METADATA, userData);
  1417. }UNLOCK
  1418. return OUT_RECV_INITFLUSH;
  1419. }
  1420. int SHOUTCAST_OUTPUT::Output_Recv_InitFlush(int state, int last_state, T_OUTPUT *userData) {
  1421. DEBUG_STATE
  1422. STATE;
  1423. LOCK{
  1424. Output_DUMMY(state, last_state, userData);
  1425. }UNLOCK
  1426. return OUT_SEND_INITSTANDBY;
  1427. }
  1428. int SHOUTCAST_OUTPUT::Output_Send_InitStandby(int state, int last_state, T_OUTPUT *userData) {
  1429. DEBUG_STATE
  1430. STATE;
  1431. LOCK{
  1432. userData->Output->FlushSend();
  1433. createUvoxFrame(1, "0\0", MSG_STANDBY, userData);
  1434. }UNLOCK
  1435. return OUT_RECV_INITSTANDBY;//OUT_SENDCONTENT;
  1436. }
  1437. int SHOUTCAST_OUTPUT::Output_Recv_InitStandby(int state, int last_state, T_OUTPUT *userData) {
  1438. DEBUG_STATE
  1439. STATE;
  1440. LOCK{
  1441. if (userData->Output->GetReceiveBytesAvailable() > 0) {
  1442. memset(buf, '\0', sizeof(buf));
  1443. userData->Output->ReceiveLine(buf, sizeof(buf));
  1444. parseUvoxFrame(buf, out);
  1445. if (checkUvoxFrameForError(out, state, userData) == -1) {
  1446. UNLOCK
  1447. return OUT_DISCONNECT;
  1448. } else {
  1449. UNLOCK
  1450. return OUT_SENDCONTENT;//OUT_SEND_INTRO;
  1451. }
  1452. }
  1453. }UNLOCK
  1454. return OUT_SENDCONTENT;//OUT_SEND_INTRO;
  1455. }
  1456. /*int SHOUTCAST_OUTPUT::Output_Send_Intro(int state, T_OUTPUT *userData) {
  1457. LOCK{
  1458. }UNLOCK
  1459. return OUT_RECV_INTRO;
  1460. }
  1461. int SHOUTCAST_OUTPUT::Output_Recv_Intro(int state, T_OUTPUT *userData) {
  1462. LOCK{
  1463. }UNLOCK
  1464. return OUT_SEND_BACKUP;
  1465. }
  1466. int SHOUTCAST_OUTPUT::Output_Send_Backup(int state, T_OUTPUT *userData) {
  1467. LOCK{
  1468. }UNLOCK
  1469. return OUT_RECV_BACKUP;
  1470. }
  1471. int SHOUTCAST_OUTPUT::Output_Recv_Backup(int state, T_OUTPUT *userData) {
  1472. LOCK{
  1473. }UNLOCK
  1474. return OUT_SENDCONTENT;
  1475. }*/