From 2470692fe08800fb94b7fed16d494cb65c5f3311 Mon Sep 17 00:00:00 2001 From: MichaÅ‚ CichoÅ„ Date: Sat, 5 Dec 2015 12:15:09 +0100 Subject: Move files around. --- src/http.c | 481 ------------------------------------------------ src/http.h | 46 ----- src/http/http.c | 481 ++++++++++++++++++++++++++++++++++++++++++++++++ src/http/http.h | 46 +++++ src/libpiano/response.c | 2 +- src/main.h | 4 +- src/player/player2.c | 409 ++++++++++++++++++++++++++++++++++++++++ src/player/player2.h | 52 ++++++ src/player2.c | 409 ---------------------------------------- src/player2.h | 52 ------ src/ui.h | 2 +- 11 files changed, 992 insertions(+), 992 deletions(-) delete mode 100644 src/http.c delete mode 100644 src/http.h create mode 100644 src/http/http.c create mode 100644 src/http/http.h create mode 100644 src/player/player2.c create mode 100644 src/player/player2.h delete mode 100644 src/player2.c delete mode 100644 src/player2.h diff --git a/src/http.c b/src/http.c deleted file mode 100644 index 2c86b44..0000000 --- a/src/http.c +++ /dev/null @@ -1,481 +0,0 @@ -/* -Copyright (c) 2015 - MichaÅ‚ CichoÅ„ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include "config.h" -#include "http.h" -#include -#include -#pragma comment(lib, "winhttp.lib") - -struct _http_t { - HINTERNET session; - HINTERNET connection; - wchar_t* endpoint; - wchar_t* securePort; - wchar_t* autoProxy; - wchar_t* proxy; - wchar_t* proxyUsername; - wchar_t* proxyPassword; - char* error; -}; - -static char* HttpToString(const wchar_t* wideString, int size); -static wchar_t* HttpToWideString(const char* string, int size); -static bool HttpCreateConnection (http_t http); -static void HttpCloseConnection (http_t http); -static void HttpSetLastError (http_t http, const char* message); -static void HttpSetLastErrorFromWinHttp (http_t http); -static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module); -static char* HttpFormatWinHttpError (DWORD errorCode); -static void HttpClearProxy (http_t http); - -# define WINHTTP_SAFE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); return false; } while (false) -# define WINHTTP_SAFE_DONE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); goto done; } while (false) - -static char* HttpToString(const wchar_t* wideString, int size) { - int utfSize = WideCharToMultiByte(CP_UTF8, 0, wideString, size, NULL, 0, NULL, NULL); - char* utfMessage = malloc(utfSize + 1); - if (utfMessage) { - utfMessage[utfSize] = 0; - WideCharToMultiByte(CP_UTF8, 0, wideString, size, utfMessage, utfSize, NULL, NULL); - } - return utfMessage; -} - -static wchar_t* HttpToWideString(const char* string, int size) { - int wideSize = MultiByteToWideChar(CP_UTF8, 0, string, size, NULL, 0); - int wideBytes = (wideSize + 1) * sizeof(wchar_t); - wchar_t* wideMessage = malloc(wideBytes); - if (wideMessage) { - wideMessage[wideSize] = 0; - MultiByteToWideChar(CP_UTF8, 0, string, size, wideMessage, wideSize); - } - return wideMessage; -} - - -static bool HttpCreateConnection (http_t http) { - INTERNET_PORT defaultPort = INTERNET_DEFAULT_PORT; - - HttpCloseConnection (http); - - http->session = WinHttpOpen( - L"WinHTTP/1.0", - WINHTTP_ACCESS_TYPE_NO_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, - 0); - WINHTTP_SAFE(http->session != NULL); - - WinHttpSetTimeouts(http->session, - 60 * 1000, // DNS time-out - 60 * 1000, // connect time-out - 30 * 1000, // send time-out - 30 * 1000); // receive time-out - - http->connection = WinHttpConnect( - http->session, - http->endpoint, - defaultPort, - 0); - WINHTTP_SAFE(http->connection != NULL); - - return true; -} - -static void HttpCloseConnection (http_t http) { - if (http->connection) { - WinHttpCloseHandle(http->connection); - http->connection = NULL; - } - - if (http->session) { - WinHttpCloseHandle(http->session); - http->session = NULL; - } -} - -static void HttpSetLastError (http_t http, const char* message) { - free(http->error); - http->error = NULL; - - if (message) - http->error = strdup(message); -} - -static void HttpSetLastErrorFromWinHttp (http_t http) { - free(http->error); - http->error = NULL; - - DWORD error = GetLastError(); - if (error) - http->error = HttpFormatWinHttpError(error); -} - -static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module) { - const int source_flag = module ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM; - - HLOCAL buffer = NULL; - int bufferLength = FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | source_flag, - (void*)module, - errorCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPWSTR)&buffer, - 0, - NULL); - - if (bufferLength > 0) { - char* message; - - wchar_t* wideMessage = (wchar_t*)buffer; - - /* Drop new line from the end. */ - wchar_t* wideMessageBack = wideMessage + bufferLength - 1; - while (wideMessageBack > wideMessage && (*wideMessageBack == '\r' || *wideMessageBack == '\n')) - --wideMessageBack; - - message = HttpToString (wideMessage, wideMessageBack - wideMessage + 1); - - LocalFree(buffer); - - return message; - } - else - return NULL; -} - -static char* HttpFormatWinHttpError (DWORD errorCode) { - if (errorCode >= WINHTTP_ERROR_BASE && errorCode <= WINHTTP_ERROR_LAST) { - HMODULE module = GetModuleHandleW(L"WinHTTP.dll"); - if (module) { - char* message = HttpFormatWinApiError(errorCode, module); - if (message) - return message; - } - } - - return HttpFormatWinApiError(errorCode, NULL); -} - -bool HttpInit(http_t* http, const char* endpoint, const char* securePort) { - http_t out = malloc(sizeof(struct _http_t)); - if (!out) - return false; - memset(out, 0, sizeof(struct _http_t)); - - out->endpoint = HttpToWideString(endpoint, -1); - out->securePort = HttpToWideString(securePort, -1); - - if (!HttpCreateConnection (out)) { - HttpDestroy (out); - return false; - } - - *http = out; - return true; -} - -void HttpDestroy(http_t http) { - if (http) { - free(http->endpoint); - free(http->securePort); - http->endpoint = NULL; - http->securePort = NULL; - HttpCloseConnection (http); - HttpClearProxy (http); - } - free(http); -} - -static void HttpClearProxy (http_t http) { - if (http->autoProxy) { - free(http->autoProxy); - http->autoProxy = NULL; - } - - if (http->proxy) { - free(http->proxy); - http->proxy = NULL; - } - - if (http->proxyUsername) { - free(http->proxyUsername); - http->proxyUsername = NULL; - } - - if (http->proxyPassword) { - free(http->proxyPassword); - http->proxyPassword = NULL; - } -} - -bool HttpSetAutoProxy (http_t http, const char* url) { - HttpClearProxy (http); - if (HttpSetProxy (http, url)) { - http->autoProxy = http->proxy; - http->proxy = NULL; - return true; - } - else - return false; -} - -bool HttpSetProxy (http_t http, const char* url) { - URL_COMPONENTS urlComponents; - wchar_t* wideUrl = NULL; - wchar_t* wideUrl2 = NULL; - wchar_t* wideUsername = NULL; - wchar_t* widePassword = NULL; - - ZeroMemory(&urlComponents, sizeof(urlComponents)); - urlComponents.dwStructSize = sizeof(urlComponents); - urlComponents.dwUserNameLength = -1; - urlComponents.dwPasswordLength = -1; - - wideUrl = HttpToWideString(url, -1); - if (WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) { - if (urlComponents.lpszUserName && urlComponents.dwUserNameLength > 0) { - wideUsername = wcsdup(urlComponents.lpszUserName); - wideUsername[urlComponents.dwUserNameLength] = 0; - } - if (urlComponents.lpszPassword && urlComponents.dwPasswordLength > 0) { - widePassword = wcsdup(urlComponents.lpszPassword); - widePassword[urlComponents.dwPasswordLength] = 0; - } - } - - ZeroMemory(&urlComponents, sizeof(urlComponents)); - urlComponents.dwStructSize = sizeof(urlComponents); - urlComponents.dwHostNameLength = -1; - urlComponents.dwUrlPathLength = -1; - - if (!WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) { - free(wideUsername); - free(widePassword); - return false; - } - - if (urlComponents.lpszHostName && urlComponents.dwHostNameLength > 0) { - wideUrl2 = wcsdup(urlComponents.lpszHostName); - wideUrl2[urlComponents.lpszUrlPath - urlComponents.lpszHostName] = 0; - } - - free(wideUrl); - - HttpClearProxy(http); - http->proxy = wideUrl2; - http->proxyUsername = wideUsername; - http->proxyPassword = widePassword; - return true; -} - -bool HttpRequest(http_t http, PianoRequest_t * const request) { - HINTERNET handle = NULL; - wchar_t* wideQuery = NULL; - bool requestSent = false; - bool complete = false; - int retryLimit = 3; - size_t responseDataSize; - - wideQuery = HttpToWideString(request->urlPath, -1); - WINHTTP_SAFE_DONE(wideQuery != NULL); - - handle = WinHttpOpenRequest( - http->connection, - L"POST", - wideQuery, - L"HTTP/1.1", - WINHTTP_NO_REFERER, - WINHTTP_DEFAULT_ACCEPT_TYPES, - request->secure ? WINHTTP_FLAG_SECURE : 0); - WINHTTP_SAFE_DONE(handle != NULL); - - if (http->proxy || http->autoProxy) { - wchar_t* fullUrl; - DWORD fullUrlSize = 0; - WINHTTP_PROXY_INFO proxyInfo; - bool success; - - if (http->autoProxy) { - WINHTTP_AUTOPROXY_OPTIONS proxyOptions = { 0 }; - - success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, NULL, &fullUrlSize); - WINHTTP_SAFE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER); - fullUrl = calloc(1, fullUrlSize + 1); - success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, fullUrl, &fullUrlSize); - if (!success) { - free(fullUrl); - WINHTTP_SAFE(success); - } - - proxyOptions.lpszAutoConfigUrl = http->autoProxy; - proxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; - - if (!(success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo))) { - proxyOptions.fAutoLogonIfChallenged = true; - success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo); - } - - if (!success) { - free(fullUrl); - WINHTTP_SAFE(success); - } - } - else { - proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; - proxyInfo.lpszProxy = http->proxy; - proxyInfo.lpszProxyBypass = NULL; - } - - WINHTTP_SAFE(WinHttpSetOption(handle, - WINHTTP_OPTION_PROXY, - &proxyInfo, sizeof(proxyInfo))); - - if (http->proxyUsername && http->proxyPassword) { - WINHTTP_SAFE(WinHttpSetCredentials(handle, - WINHTTP_AUTH_TARGET_PROXY, - WINHTTP_AUTH_SCHEME_BASIC, - http->proxyUsername, - http->proxyPassword, - NULL)); - } - } - - while (retryLimit > 0) { - DWORD errorCode, statusCode, statusCodeSize; - bool succeeded = false; - bool retry = false; - - if (!requestSent) { - size_t postDataSize = strlen(request->postData); - succeeded = WinHttpSendRequest(handle, - WINHTTP_NO_ADDITIONAL_HEADERS, - 0, - request->postData, - postDataSize, - postDataSize, - 0); - - if (succeeded) - requestSent = true; - } - - if (requestSent) - succeeded = WinHttpReceiveResponse(handle, NULL); - - errorCode = GetLastError(); - - statusCode = 0; - statusCodeSize = sizeof(statusCode); - if (!WinHttpQueryHeaders(handle, - WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, - WINHTTP_HEADER_NAME_BY_INDEX, - &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) { - statusCode = 0; - } - - if (succeeded && statusCode == 407) { - requestSent = false; - retry = true; - } - else { - if (errorCode == ERROR_SUCCESS) - break; - - switch (errorCode) { - case ERROR_WINHTTP_RESEND_REQUEST: - requestSent = false; - /* pass trough */ - - case ERROR_WINHTTP_NAME_NOT_RESOLVED: - case ERROR_WINHTTP_CANNOT_CONNECT: - case ERROR_WINHTTP_TIMEOUT: - retry = true; - break; - - default: - HttpSetLastErrorFromWinHttp (http); - goto done; - } - } - - if (retry) - --retryLimit; - } - - responseDataSize = 0; - while (retryLimit > 0) - { - DWORD bytesLeft; - char* writePtr; - - DWORD bytesAvailable = 0; - if (!WinHttpQueryDataAvailable(handle, &bytesAvailable)) { - WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT); - --retryLimit; - continue; - } - - if (0 == bytesAvailable) - break; - - responseDataSize += bytesAvailable; - request->responseData = realloc(request->responseData, responseDataSize + 1); - - writePtr = request->responseData + responseDataSize - bytesAvailable; - writePtr[bytesAvailable] = 0; - - bytesLeft = bytesAvailable; - while (bytesLeft > 0) - { - DWORD bytesRead = 0; - if (!WinHttpReadData(handle, writePtr, bytesLeft, &bytesRead)) - { - WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT); - if (--retryLimit == 0) - break; - - continue; - } - - bytesLeft -= bytesRead; - writePtr += bytesRead; - } - - if (bytesLeft > 0) - HttpSetLastError (http, "Maximum retries count exceeded"); - } - - complete = true; - - HttpSetLastError (http, NULL); - -done: - free(wideQuery); - return complete; -} - -const char* HttpGetError(http_t http) { - return http->error; -} diff --git a/src/http.h b/src/http.h deleted file mode 100644 index a321cd3..0000000 --- a/src/http.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright (c) 2015 - MichaÅ‚ CichoÅ„ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef SRC_HTTP_H_CN979RE9 -#define SRC_HTTP_H_CN979RE9 - -#include "config.h" - -#include - -#include "piano.h" -#include "settings.h" - -typedef struct _http_t *http_t; - -bool HttpInit (http_t*, const char*, const char*); -void HttpDestroy (http_t); - -bool HttpSetAutoProxy (http_t, const char*); -bool HttpSetProxy(http_t, const char*); - -bool HttpRequest (http_t, PianoRequest_t * const); -const char* HttpGetError (http_t); - -#endif /* SRC_HTTP_H_CN979RE9 */ - diff --git a/src/http/http.c b/src/http/http.c new file mode 100644 index 0000000..dd64ad1 --- /dev/null +++ b/src/http/http.c @@ -0,0 +1,481 @@ +/* +Copyright (c) 2015 + MichaÅ‚ CichoÅ„ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "config.h" +#include "http.h" +#include +#include +#pragma comment(lib, "winhttp.lib") + +struct _http_t { + HINTERNET session; + HINTERNET connection; + wchar_t* endpoint; + wchar_t* securePort; + wchar_t* autoProxy; + wchar_t* proxy; + wchar_t* proxyUsername; + wchar_t* proxyPassword; + char* error; +}; + +static char* HttpToString(const wchar_t* wideString, int size); +static wchar_t* HttpToWideString(const char* string, int size); +static bool HttpCreateConnection (http_t http); +static void HttpCloseConnection (http_t http); +static void HttpSetLastError (http_t http, const char* message); +static void HttpSetLastErrorFromWinHttp (http_t http); +static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module); +static char* HttpFormatWinHttpError (DWORD errorCode); +static void HttpClearProxy (http_t http); + +# define WINHTTP_SAFE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); return false; } while (false) +# define WINHTTP_SAFE_DONE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); goto done; } while (false) + +static char* HttpToString(const wchar_t* wideString, int size) { + int utfSize = WideCharToMultiByte(CP_UTF8, 0, wideString, size, NULL, 0, NULL, NULL); + char* utfMessage = malloc(utfSize + 1); + if (utfMessage) { + utfMessage[utfSize] = 0; + WideCharToMultiByte(CP_UTF8, 0, wideString, size, utfMessage, utfSize, NULL, NULL); + } + return utfMessage; +} + +static wchar_t* HttpToWideString(const char* string, int size) { + int wideSize = MultiByteToWideChar(CP_UTF8, 0, string, size, NULL, 0); + int wideBytes = (wideSize + 1) * sizeof(wchar_t); + wchar_t* wideMessage = malloc(wideBytes); + if (wideMessage) { + wideMessage[wideSize] = 0; + MultiByteToWideChar(CP_UTF8, 0, string, size, wideMessage, wideSize); + } + return wideMessage; +} + + +static bool HttpCreateConnection (http_t http) { + INTERNET_PORT defaultPort = INTERNET_DEFAULT_PORT; + + HttpCloseConnection (http); + + http->session = WinHttpOpen( + L"WinHTTP/1.0", + WINHTTP_ACCESS_TYPE_NO_PROXY, + WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, + 0); + WINHTTP_SAFE(http->session != NULL); + + WinHttpSetTimeouts(http->session, + 60 * 1000, // DNS time-out + 60 * 1000, // connect time-out + 30 * 1000, // send time-out + 30 * 1000); // receive time-out + + http->connection = WinHttpConnect( + http->session, + http->endpoint, + defaultPort, + 0); + WINHTTP_SAFE(http->connection != NULL); + + return true; +} + +static void HttpCloseConnection (http_t http) { + if (http->connection) { + WinHttpCloseHandle(http->connection); + http->connection = NULL; + } + + if (http->session) { + WinHttpCloseHandle(http->session); + http->session = NULL; + } +} + +static void HttpSetLastError (http_t http, const char* message) { + free(http->error); + http->error = NULL; + + if (message) + http->error = strdup(message); +} + +static void HttpSetLastErrorFromWinHttp (http_t http) { + free(http->error); + http->error = NULL; + + DWORD error = GetLastError(); + if (error) + http->error = HttpFormatWinHttpError(error); +} + +static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module) { + const int source_flag = module ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM; + + HLOCAL buffer = NULL; + int bufferLength = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | source_flag, + (void*)module, + errorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR)&buffer, + 0, + NULL); + + if (bufferLength > 0) { + char* message; + + wchar_t* wideMessage = (wchar_t*)buffer; + + /* Drop new line from the end. */ + wchar_t* wideMessageBack = wideMessage + bufferLength - 1; + while (wideMessageBack > wideMessage && (*wideMessageBack == '\r' || *wideMessageBack == '\n')) + --wideMessageBack; + + message = HttpToString (wideMessage, wideMessageBack - wideMessage + 1); + + LocalFree(buffer); + + return message; + } + else + return NULL; +} + +static char* HttpFormatWinHttpError (DWORD errorCode) { + if (errorCode >= WINHTTP_ERROR_BASE && errorCode <= WINHTTP_ERROR_LAST) { + HMODULE module = GetModuleHandleW(L"WinHTTP.dll"); + if (module) { + char* message = HttpFormatWinApiError(errorCode, module); + if (message) + return message; + } + } + + return HttpFormatWinApiError(errorCode, NULL); +} + +bool HttpInit(http_t* http, const char* endpoint, const char* securePort) { + http_t out = malloc(sizeof(struct _http_t)); + if (!out) + return false; + memset(out, 0, sizeof(struct _http_t)); + + out->endpoint = HttpToWideString(endpoint, -1); + out->securePort = HttpToWideString(securePort, -1); + + if (!HttpCreateConnection (out)) { + HttpDestroy (out); + return false; + } + + *http = out; + return true; +} + +void HttpDestroy(http_t http) { + if (http) { + free(http->endpoint); + free(http->securePort); + http->endpoint = NULL; + http->securePort = NULL; + HttpCloseConnection (http); + HttpClearProxy (http); + } + free(http); +} + +static void HttpClearProxy (http_t http) { + if (http->autoProxy) { + free(http->autoProxy); + http->autoProxy = NULL; + } + + if (http->proxy) { + free(http->proxy); + http->proxy = NULL; + } + + if (http->proxyUsername) { + free(http->proxyUsername); + http->proxyUsername = NULL; + } + + if (http->proxyPassword) { + free(http->proxyPassword); + http->proxyPassword = NULL; + } +} + +bool HttpSetAutoProxy (http_t http, const char* url) { + HttpClearProxy (http); + if (HttpSetProxy (http, url)) { + http->autoProxy = http->proxy; + http->proxy = NULL; + return true; + } + else + return false; +} + +bool HttpSetProxy (http_t http, const char* url) { + URL_COMPONENTS urlComponents; + wchar_t* wideUrl = NULL; + wchar_t* wideUrl2 = NULL; + wchar_t* wideUsername = NULL; + wchar_t* widePassword = NULL; + + ZeroMemory(&urlComponents, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + urlComponents.dwUserNameLength = -1; + urlComponents.dwPasswordLength = -1; + + wideUrl = HttpToWideString(url, -1); + if (WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) { + if (urlComponents.lpszUserName && urlComponents.dwUserNameLength > 0) { + wideUsername = wcsdup(urlComponents.lpszUserName); + wideUsername[urlComponents.dwUserNameLength] = 0; + } + if (urlComponents.lpszPassword && urlComponents.dwPasswordLength > 0) { + widePassword = wcsdup(urlComponents.lpszPassword); + widePassword[urlComponents.dwPasswordLength] = 0; + } + } + + ZeroMemory(&urlComponents, sizeof(urlComponents)); + urlComponents.dwStructSize = sizeof(urlComponents); + urlComponents.dwHostNameLength = -1; + urlComponents.dwUrlPathLength = -1; + + if (!WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) { + free(wideUsername); + free(widePassword); + return false; + } + + if (urlComponents.lpszHostName && urlComponents.dwHostNameLength > 0) { + wideUrl2 = wcsdup(urlComponents.lpszHostName); + wideUrl2[urlComponents.lpszUrlPath - urlComponents.lpszHostName] = 0; + } + + free(wideUrl); + + HttpClearProxy(http); + http->proxy = wideUrl2; + http->proxyUsername = wideUsername; + http->proxyPassword = widePassword; + return true; +} + +bool HttpRequest(http_t http, PianoRequest_t * const request) { + HINTERNET handle = NULL; + wchar_t* wideQuery = NULL; + bool requestSent = false; + bool complete = false; + int retryLimit = 3; + size_t responseDataSize; + + wideQuery = HttpToWideString(request->urlPath, -1); + WINHTTP_SAFE_DONE(wideQuery != NULL); + + handle = WinHttpOpenRequest( + http->connection, + L"POST", + wideQuery, + L"HTTP/1.1", + WINHTTP_NO_REFERER, + WINHTTP_DEFAULT_ACCEPT_TYPES, + request->secure ? WINHTTP_FLAG_SECURE : 0); + WINHTTP_SAFE_DONE(handle != NULL); + + if (http->proxy || http->autoProxy) { + wchar_t* fullUrl; + DWORD fullUrlSize = 0; + WINHTTP_PROXY_INFO proxyInfo; + bool success; + + if (http->autoProxy) { + WINHTTP_AUTOPROXY_OPTIONS proxyOptions = { 0 }; + + success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, NULL, &fullUrlSize); + WINHTTP_SAFE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER); + fullUrl = calloc(1, fullUrlSize + 1); + success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, fullUrl, &fullUrlSize); + if (!success) { + free(fullUrl); + WINHTTP_SAFE(success); + } + + proxyOptions.lpszAutoConfigUrl = http->autoProxy; + proxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL; + + if (!(success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo))) { + proxyOptions.fAutoLogonIfChallenged = true; + success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo); + } + + if (!success) { + free(fullUrl); + WINHTTP_SAFE(success); + } + } + else { + proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY; + proxyInfo.lpszProxy = http->proxy; + proxyInfo.lpszProxyBypass = NULL; + } + + WINHTTP_SAFE(WinHttpSetOption(handle, + WINHTTP_OPTION_PROXY, + &proxyInfo, sizeof(proxyInfo))); + + if (http->proxyUsername && http->proxyPassword) { + WINHTTP_SAFE(WinHttpSetCredentials(handle, + WINHTTP_AUTH_TARGET_PROXY, + WINHTTP_AUTH_SCHEME_BASIC, + http->proxyUsername, + http->proxyPassword, + NULL)); + } + } + + while (retryLimit > 0) { + DWORD errorCode, statusCode, statusCodeSize; + bool succeeded = false; + bool retry = false; + + if (!requestSent) { + size_t postDataSize = strlen(request->postData); + succeeded = WinHttpSendRequest(handle, + WINHTTP_NO_ADDITIONAL_HEADERS, + 0, + request->postData, + postDataSize, + postDataSize, + 0); + + if (succeeded) + requestSent = true; + } + + if (requestSent) + succeeded = WinHttpReceiveResponse(handle, NULL); + + errorCode = GetLastError(); + + statusCode = 0; + statusCodeSize = sizeof(statusCode); + if (!WinHttpQueryHeaders(handle, + WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, + WINHTTP_HEADER_NAME_BY_INDEX, + &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) { + statusCode = 0; + } + + if (succeeded && statusCode == 407) { + requestSent = false; + retry = true; + } + else { + if (errorCode == ERROR_SUCCESS) + break; + + switch (errorCode) { + case ERROR_WINHTTP_RESEND_REQUEST: + requestSent = false; + /* pass trough */ + + case ERROR_WINHTTP_NAME_NOT_RESOLVED: + case ERROR_WINHTTP_CANNOT_CONNECT: + case ERROR_WINHTTP_TIMEOUT: + retry = true; + break; + + default: + HttpSetLastErrorFromWinHttp (http); + goto done; + } + } + + if (retry) + --retryLimit; + } + + responseDataSize = 0; + while (retryLimit > 0) + { + DWORD bytesLeft; + char* writePtr; + + DWORD bytesAvailable = 0; + if (!WinHttpQueryDataAvailable(handle, &bytesAvailable)) { + WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT); + --retryLimit; + continue; + } + + if (0 == bytesAvailable) + break; + + responseDataSize += bytesAvailable; + request->responseData = realloc(request->responseData, responseDataSize + 1); + + writePtr = request->responseData + responseDataSize - bytesAvailable; + writePtr[bytesAvailable] = 0; + + bytesLeft = bytesAvailable; + while (bytesLeft > 0) + { + DWORD bytesRead = 0; + if (!WinHttpReadData(handle, writePtr, bytesLeft, &bytesRead)) + { + WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT); + if (--retryLimit == 0) + break; + + continue; + } + + bytesLeft -= bytesRead; + writePtr += bytesRead; + } + + if (bytesLeft > 0) + HttpSetLastError (http, "Maximum retries count exceeded"); + } + + complete = true; + + HttpSetLastError (http, NULL); + +done: + free(wideQuery); + return complete; +} + +const char* HttpGetError(http_t http) { + return http->error; +} diff --git a/src/http/http.h b/src/http/http.h new file mode 100644 index 0000000..a321cd3 --- /dev/null +++ b/src/http/http.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 2015 + MichaÅ‚ CichoÅ„ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef SRC_HTTP_H_CN979RE9 +#define SRC_HTTP_H_CN979RE9 + +#include "config.h" + +#include + +#include "piano.h" +#include "settings.h" + +typedef struct _http_t *http_t; + +bool HttpInit (http_t*, const char*, const char*); +void HttpDestroy (http_t); + +bool HttpSetAutoProxy (http_t, const char*); +bool HttpSetProxy(http_t, const char*); + +bool HttpRequest (http_t, PianoRequest_t * const); +const char* HttpGetError (http_t); + +#endif /* SRC_HTTP_H_CN979RE9 */ + diff --git a/src/libpiano/response.c b/src/libpiano/response.c index 783e2f0..8b6ed52 100644 --- a/src/libpiano/response.c +++ b/src/libpiano/response.c @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "../config.h" +#include "config.h" #include #include diff --git a/src/main.h b/src/main.h index f16a168..6c34d71 100644 --- a/src/main.h +++ b/src/main.h @@ -28,8 +28,8 @@ THE SOFTWARE. #include -#include "player2.h" -#include "http.h" +#include "player/player2.h" +#include "http/http.h" #include "settings.h" #include "ui_readline.h" diff --git a/src/player/player2.c b/src/player/player2.c new file mode 100644 index 0000000..01fe33c --- /dev/null +++ b/src/player/player2.c @@ -0,0 +1,409 @@ +/* +Copyright (c) 2015 + Micha³ Cichoñ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* receive/play audio stream */ + +/* based on DShow example player */ + +#include "config.h" +#include "player2.h" +#define COBJMACROS +#define INITGUID +#include +#include +#pragma comment(lib, "strmiids.lib") + +# define WM_GRAPH_EVENT (WM_APP + 1) + +enum { NO_GRAPH, RUNNING, PAUSED, STOPPED }; + +static struct _player_static_t { + bool done; + bool initialized; + bool hasCOM; +} BarPlayerGlobal = { 0 }; + +struct _player_t { + int state; + IGraphBuilder* graph; + IMediaControl* control; + IMediaEventEx* event; + IBasicAudio* audio; + IMediaSeeking* media; + float volume; // dB + float gain; // dB +}; + +static bool BarPlayer2StaticInit(); +static void BarPlayer2StaticTerm(void); + +static bool BarPlayer2StaticInit () { + if (BarPlayerGlobal.done) + return BarPlayerGlobal.initialized; + + BarPlayerGlobal.done = true; + + atexit(BarPlayer2StaticTerm); + + if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + return false; + + BarPlayerGlobal.hasCOM = true; + + BarPlayerGlobal.initialized = true; + + return true; +} + +static void BarPlayer2StaticTerm(void) { + if (!BarPlayerGlobal.done) + return; + + if (BarPlayerGlobal.hasCOM) { + CoUninitialize(); + BarPlayerGlobal.hasCOM = false; + } + + BarPlayerGlobal.initialized = false; + BarPlayerGlobal.done = false; +} + +static void BarPlayer2ApplyVolume(player2_t player) { + long v = (long)((player->volume + player->gain) * 100.0f); + + if (!player->audio) + return; + + if (v < -10000) + v = -10000; + if (v > 0) + v = 0; + + IBasicAudio_put_Volume(player->audio, v); +} + +static void BarPlayer2TearDown(player2_t player) { + /* TODO: send final event */ + + if (player->graph) { + IGraphBuilder_Release(player->graph); + player->graph = NULL; + } + + if (player->control) { + IMediaControl_Release(player->control); + player->control = NULL; + } + + if (player->event) { + IMediaEventEx_Release(player->event); + player->event = NULL; + } + + if (player->audio) { + IBasicAudio_Release(player->audio); + player->audio = NULL; + } + + if (player->media) { + IMediaSeeking_Release(player->media); + player->media = NULL; + } + + player->state = NO_GRAPH; +} + +static HRESULT BarPlayer2Build(player2_t player) { + HRESULT hr; + + BarPlayer2TearDown(player); + + hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, &player->graph); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaControl, &player->control); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaEventEx, &player->event); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IBasicAudio, &player->audio); + if (FAILED(hr)) + return hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaSeeking, &player->media); + if (FAILED(hr)) + return hr; + + hr = IMediaEventEx_SetNotifyWindow(player->event, (OAHWND)NULL, WM_GRAPH_EVENT, (LONG_PTR)player); + if (FAILED(hr)) + return hr; + + player->state = STOPPED; + + return S_OK; +} + +static HRESULT BarPlayer2AddFilterByCLSID(IGraphBuilder *pGraph, REFGUID clsid, IBaseFilter **ppF, LPCWSTR wszName) { + IBaseFilter *pFilter = NULL; + HRESULT hr; + *ppF = 0; + + hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, &pFilter); + if (FAILED(hr)) + goto done; + + hr = IGraphBuilder_AddFilter(pGraph, pFilter, wszName); + if (FAILED(hr)) + goto done; + + *ppF = pFilter; + + IBaseFilter_AddRef(*ppF); + +done: + if (pFilter) + IBaseFilter_Release(pFilter); + + return hr; +} + +static HRESULT BarPlayer2Render(player2_t player, IBaseFilter* source) { + BOOL bRenderedAnyPin = FALSE; + + IPin* pin = NULL; + IEnumPins *enumPins = NULL; + IBaseFilter *audioRenderer = NULL; + IFilterGraph2* filter = NULL; + + HRESULT hr; + + hr = IGraphBuilder_QueryInterface(player->graph, &IID_IFilterGraph2, &filter); + if (FAILED(hr)) + return hr; + + hr = BarPlayer2AddFilterByCLSID(player->graph, &CLSID_DSoundRender, &audioRenderer, L"Audio Renderer"); + if (FAILED(hr)) + goto done; + + hr = IBaseFilter_EnumPins(source, &enumPins); + if (FAILED(hr)) + goto done; + + while (S_OK == IEnumPins_Next(enumPins, 1, &pin, NULL)) + { + HRESULT hr2 = IFilterGraph2_RenderEx(filter, pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL); + + IPin_Release(pin); + if (SUCCEEDED(hr2)) + bRenderedAnyPin = TRUE; + } + +done: + if (enumPins) + IEnumPins_Release(enumPins); + if (enumPins) + IBaseFilter_Release(audioRenderer); + if (enumPins) + IFilterGraph2_Release(filter); + + if (SUCCEEDED(hr) && !bRenderedAnyPin) + hr = VFW_E_CANNOT_RENDER; + + return hr; +} + +bool BarPlayer2Init(player2_t* player) { + + if (!BarPlayer2StaticInit ()) + return false; + + player2_t out = malloc(sizeof(struct _player_t)); + if (!out) + return false; + + memset(out, 0, sizeof(struct _player_t)); + + *player = out; + + return true; +} + +void BarPlayer2Destroy(player2_t player) { + BarPlayer2TearDown(player); + free(player); +} + +void BarPlayer2SetVolume(player2_t player, float volume) { + player->volume = volume; + BarPlayer2ApplyVolume(player); +} + +float BarPlayer2GetVolume(player2_t player) { + return player->volume; +} + +void BarPlayer2SetGain(player2_t player, float gain) { + player->gain = gain; + BarPlayer2ApplyVolume(player); +} + +float BarPlayer2GetGain(player2_t player) { + return player->gain; +} + +double BarPlayer2GetDuration(player2_t player) { + LONGLONG time; + if (SUCCEEDED(IMediaSeeking_GetDuration(player->media, &time))) + return time / 10000000.0; + else + return 0; +} + +double BarPlayer2GetTime(player2_t player) { + LONGLONG time; + if (SUCCEEDED(IMediaSeeking_GetCurrentPosition(player->media, &time))) + return time / 10000000.0; + else + return 0; +} + +bool BarPlayer2Open(player2_t player, const char* url) { + IBaseFilter* source = NULL; + HRESULT hr; + wchar_t* wideUrl = NULL; + size_t urlSize; + int result; + + hr = BarPlayer2Build(player); + if (FAILED(hr)) + goto done; + + urlSize = strlen(url); + result = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, url, urlSize, NULL, 0); + wideUrl = malloc((result + 1) * sizeof(wchar_t)); + if (!wideUrl) { + hr = E_OUTOFMEMORY; + goto done; + } + memset(wideUrl, 0, (result + 1) * sizeof(wchar_t)); + + MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, url, urlSize, wideUrl, result); + + hr = IGraphBuilder_AddSourceFilter(player->graph, wideUrl, NULL, &source); + if (FAILED(hr)) + goto done; + + hr = BarPlayer2Render(player, source); + + BarPlayer2ApplyVolume(player); + +done: + if (wideUrl) + free(wideUrl); + if (FAILED(hr)) + BarPlayer2TearDown(player); + if (source) + IBaseFilter_Release(source); + + return SUCCEEDED(hr); +} + +bool BarPlayer2Play(player2_t player) { + HRESULT hr; + + if (player->state != PAUSED && player->state != STOPPED) + return false; /* wrong state */ + + hr = IMediaControl_Run(player->control); + if (SUCCEEDED(hr)) + player->state = RUNNING; + + return SUCCEEDED(hr); +} + +bool BarPlayer2Pause(player2_t player) { + HRESULT hr; + + if (player->state != RUNNING) + return false; /* wrong state */ + + hr = IMediaControl_Pause(player->control); + if (SUCCEEDED(hr)) + player->state = PAUSED; + + return SUCCEEDED(hr); +} + +bool BarPlayer2Stop(player2_t player) { + HRESULT hr; + + if (player->state != RUNNING && player->state != PAUSED) + return false; /* wrong state */ + + hr = IMediaControl_Stop(player->control); + if (SUCCEEDED(hr)) + player->state = STOPPED; + + return SUCCEEDED(hr); +} + +bool BarPlayer2Finish(player2_t player) { + if (!player->control) + return false; + + BarPlayer2TearDown(player); + return true; +} + +bool BarPlayer2IsPlaying(player2_t player) { + return player->state == RUNNING; +} + +bool BarPlayer2IsPaused(player2_t player) { + return player->state == PAUSED; +} + +bool BarPlayer2IsStopped(player2_t player) { + return player->state == STOPPED; +} + +bool BarPlayer2IsFinished(player2_t player) { + LONGLONG time; + LONGLONG duration; + + if (!player->media || player->state == NO_GRAPH) + return true; + + if (player->state != RUNNING && player->state != STOPPED) + return false; + + if (FAILED(IMediaSeeking_GetDuration(player->media, &duration)) || + FAILED(IMediaSeeking_GetCurrentPosition(player->media, &time))) + return true; + + return time >= duration; +} diff --git a/src/player/player2.h b/src/player/player2.h new file mode 100644 index 0000000..b426ee2 --- /dev/null +++ b/src/player/player2.h @@ -0,0 +1,52 @@ +/* +Copyright (c) 2015 + Micha³ Cichoñ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef SRC_PLAYER2_H_CN979RE9 +#define SRC_PLAYER2_H_CN979RE9 + +#include "config.h" + +#include + +typedef struct _player_t *player2_t; + +bool BarPlayer2Init (player2_t*); +void BarPlayer2Destroy (player2_t); +void BarPlayer2SetVolume (player2_t,float); +float BarPlayer2GetVolume (player2_t); +void BarPlayer2SetGain (player2_t, float); +float BarPlayer2GetGain (player2_t); +double BarPlayer2GetDuration (player2_t); +double BarPlayer2GetTime (player2_t); +bool BarPlayer2Open (player2_t, const char*); +bool BarPlayer2Play (player2_t); +bool BarPlayer2Pause (player2_t); +bool BarPlayer2Stop (player2_t); +bool BarPlayer2Finish (player2_t); +bool BarPlayer2IsPlaying (player2_t); +bool BarPlayer2IsPaused (player2_t); +bool BarPlayer2IsStopped (player2_t); +bool BarPlayer2IsFinished (player2_t); + +#endif /* SRC_PLAYER2_H_CN979RE9 */ + diff --git a/src/player2.c b/src/player2.c deleted file mode 100644 index 01fe33c..0000000 --- a/src/player2.c +++ /dev/null @@ -1,409 +0,0 @@ -/* -Copyright (c) 2015 - Micha³ Cichoñ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -/* receive/play audio stream */ - -/* based on DShow example player */ - -#include "config.h" -#include "player2.h" -#define COBJMACROS -#define INITGUID -#include -#include -#pragma comment(lib, "strmiids.lib") - -# define WM_GRAPH_EVENT (WM_APP + 1) - -enum { NO_GRAPH, RUNNING, PAUSED, STOPPED }; - -static struct _player_static_t { - bool done; - bool initialized; - bool hasCOM; -} BarPlayerGlobal = { 0 }; - -struct _player_t { - int state; - IGraphBuilder* graph; - IMediaControl* control; - IMediaEventEx* event; - IBasicAudio* audio; - IMediaSeeking* media; - float volume; // dB - float gain; // dB -}; - -static bool BarPlayer2StaticInit(); -static void BarPlayer2StaticTerm(void); - -static bool BarPlayer2StaticInit () { - if (BarPlayerGlobal.done) - return BarPlayerGlobal.initialized; - - BarPlayerGlobal.done = true; - - atexit(BarPlayer2StaticTerm); - - if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) - return false; - - BarPlayerGlobal.hasCOM = true; - - BarPlayerGlobal.initialized = true; - - return true; -} - -static void BarPlayer2StaticTerm(void) { - if (!BarPlayerGlobal.done) - return; - - if (BarPlayerGlobal.hasCOM) { - CoUninitialize(); - BarPlayerGlobal.hasCOM = false; - } - - BarPlayerGlobal.initialized = false; - BarPlayerGlobal.done = false; -} - -static void BarPlayer2ApplyVolume(player2_t player) { - long v = (long)((player->volume + player->gain) * 100.0f); - - if (!player->audio) - return; - - if (v < -10000) - v = -10000; - if (v > 0) - v = 0; - - IBasicAudio_put_Volume(player->audio, v); -} - -static void BarPlayer2TearDown(player2_t player) { - /* TODO: send final event */ - - if (player->graph) { - IGraphBuilder_Release(player->graph); - player->graph = NULL; - } - - if (player->control) { - IMediaControl_Release(player->control); - player->control = NULL; - } - - if (player->event) { - IMediaEventEx_Release(player->event); - player->event = NULL; - } - - if (player->audio) { - IBasicAudio_Release(player->audio); - player->audio = NULL; - } - - if (player->media) { - IMediaSeeking_Release(player->media); - player->media = NULL; - } - - player->state = NO_GRAPH; -} - -static HRESULT BarPlayer2Build(player2_t player) { - HRESULT hr; - - BarPlayer2TearDown(player); - - hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, &player->graph); - if (FAILED(hr)) - return hr; - - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaControl, &player->control); - if (FAILED(hr)) - return hr; - - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaEventEx, &player->event); - if (FAILED(hr)) - return hr; - - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IBasicAudio, &player->audio); - if (FAILED(hr)) - return hr; - - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IMediaSeeking, &player->media); - if (FAILED(hr)) - return hr; - - hr = IMediaEventEx_SetNotifyWindow(player->event, (OAHWND)NULL, WM_GRAPH_EVENT, (LONG_PTR)player); - if (FAILED(hr)) - return hr; - - player->state = STOPPED; - - return S_OK; -} - -static HRESULT BarPlayer2AddFilterByCLSID(IGraphBuilder *pGraph, REFGUID clsid, IBaseFilter **ppF, LPCWSTR wszName) { - IBaseFilter *pFilter = NULL; - HRESULT hr; - *ppF = 0; - - hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, &pFilter); - if (FAILED(hr)) - goto done; - - hr = IGraphBuilder_AddFilter(pGraph, pFilter, wszName); - if (FAILED(hr)) - goto done; - - *ppF = pFilter; - - IBaseFilter_AddRef(*ppF); - -done: - if (pFilter) - IBaseFilter_Release(pFilter); - - return hr; -} - -static HRESULT BarPlayer2Render(player2_t player, IBaseFilter* source) { - BOOL bRenderedAnyPin = FALSE; - - IPin* pin = NULL; - IEnumPins *enumPins = NULL; - IBaseFilter *audioRenderer = NULL; - IFilterGraph2* filter = NULL; - - HRESULT hr; - - hr = IGraphBuilder_QueryInterface(player->graph, &IID_IFilterGraph2, &filter); - if (FAILED(hr)) - return hr; - - hr = BarPlayer2AddFilterByCLSID(player->graph, &CLSID_DSoundRender, &audioRenderer, L"Audio Renderer"); - if (FAILED(hr)) - goto done; - - hr = IBaseFilter_EnumPins(source, &enumPins); - if (FAILED(hr)) - goto done; - - while (S_OK == IEnumPins_Next(enumPins, 1, &pin, NULL)) - { - HRESULT hr2 = IFilterGraph2_RenderEx(filter, pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL); - - IPin_Release(pin); - if (SUCCEEDED(hr2)) - bRenderedAnyPin = TRUE; - } - -done: - if (enumPins) - IEnumPins_Release(enumPins); - if (enumPins) - IBaseFilter_Release(audioRenderer); - if (enumPins) - IFilterGraph2_Release(filter); - - if (SUCCEEDED(hr) && !bRenderedAnyPin) - hr = VFW_E_CANNOT_RENDER; - - return hr; -} - -bool BarPlayer2Init(player2_t* player) { - - if (!BarPlayer2StaticInit ()) - return false; - - player2_t out = malloc(sizeof(struct _player_t)); - if (!out) - return false; - - memset(out, 0, sizeof(struct _player_t)); - - *player = out; - - return true; -} - -void BarPlayer2Destroy(player2_t player) { - BarPlayer2TearDown(player); - free(player); -} - -void BarPlayer2SetVolume(player2_t player, float volume) { - player->volume = volume; - BarPlayer2ApplyVolume(player); -} - -float BarPlayer2GetVolume(player2_t player) { - return player->volume; -} - -void BarPlayer2SetGain(player2_t player, float gain) { - player->gain = gain; - BarPlayer2ApplyVolume(player); -} - -float BarPlayer2GetGain(player2_t player) { - return player->gain; -} - -double BarPlayer2GetDuration(player2_t player) { - LONGLONG time; - if (SUCCEEDED(IMediaSeeking_GetDuration(player->media, &time))) - return time / 10000000.0; - else - return 0; -} - -double BarPlayer2GetTime(player2_t player) { - LONGLONG time; - if (SUCCEEDED(IMediaSeeking_GetCurrentPosition(player->media, &time))) - return time / 10000000.0; - else - return 0; -} - -bool BarPlayer2Open(player2_t player, const char* url) { - IBaseFilter* source = NULL; - HRESULT hr; - wchar_t* wideUrl = NULL; - size_t urlSize; - int result; - - hr = BarPlayer2Build(player); - if (FAILED(hr)) - goto done; - - urlSize = strlen(url); - result = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, url, urlSize, NULL, 0); - wideUrl = malloc((result + 1) * sizeof(wchar_t)); - if (!wideUrl) { - hr = E_OUTOFMEMORY; - goto done; - } - memset(wideUrl, 0, (result + 1) * sizeof(wchar_t)); - - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, url, urlSize, wideUrl, result); - - hr = IGraphBuilder_AddSourceFilter(player->graph, wideUrl, NULL, &source); - if (FAILED(hr)) - goto done; - - hr = BarPlayer2Render(player, source); - - BarPlayer2ApplyVolume(player); - -done: - if (wideUrl) - free(wideUrl); - if (FAILED(hr)) - BarPlayer2TearDown(player); - if (source) - IBaseFilter_Release(source); - - return SUCCEEDED(hr); -} - -bool BarPlayer2Play(player2_t player) { - HRESULT hr; - - if (player->state != PAUSED && player->state != STOPPED) - return false; /* wrong state */ - - hr = IMediaControl_Run(player->control); - if (SUCCEEDED(hr)) - player->state = RUNNING; - - return SUCCEEDED(hr); -} - -bool BarPlayer2Pause(player2_t player) { - HRESULT hr; - - if (player->state != RUNNING) - return false; /* wrong state */ - - hr = IMediaControl_Pause(player->control); - if (SUCCEEDED(hr)) - player->state = PAUSED; - - return SUCCEEDED(hr); -} - -bool BarPlayer2Stop(player2_t player) { - HRESULT hr; - - if (player->state != RUNNING && player->state != PAUSED) - return false; /* wrong state */ - - hr = IMediaControl_Stop(player->control); - if (SUCCEEDED(hr)) - player->state = STOPPED; - - return SUCCEEDED(hr); -} - -bool BarPlayer2Finish(player2_t player) { - if (!player->control) - return false; - - BarPlayer2TearDown(player); - return true; -} - -bool BarPlayer2IsPlaying(player2_t player) { - return player->state == RUNNING; -} - -bool BarPlayer2IsPaused(player2_t player) { - return player->state == PAUSED; -} - -bool BarPlayer2IsStopped(player2_t player) { - return player->state == STOPPED; -} - -bool BarPlayer2IsFinished(player2_t player) { - LONGLONG time; - LONGLONG duration; - - if (!player->media || player->state == NO_GRAPH) - return true; - - if (player->state != RUNNING && player->state != STOPPED) - return false; - - if (FAILED(IMediaSeeking_GetDuration(player->media, &duration)) || - FAILED(IMediaSeeking_GetCurrentPosition(player->media, &time))) - return true; - - return time >= duration; -} diff --git a/src/player2.h b/src/player2.h deleted file mode 100644 index b426ee2..0000000 --- a/src/player2.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -Copyright (c) 2015 - Micha³ Cichoñ - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef SRC_PLAYER2_H_CN979RE9 -#define SRC_PLAYER2_H_CN979RE9 - -#include "config.h" - -#include - -typedef struct _player_t *player2_t; - -bool BarPlayer2Init (player2_t*); -void BarPlayer2Destroy (player2_t); -void BarPlayer2SetVolume (player2_t,float); -float BarPlayer2GetVolume (player2_t); -void BarPlayer2SetGain (player2_t, float); -float BarPlayer2GetGain (player2_t); -double BarPlayer2GetDuration (player2_t); -double BarPlayer2GetTime (player2_t); -bool BarPlayer2Open (player2_t, const char*); -bool BarPlayer2Play (player2_t); -bool BarPlayer2Pause (player2_t); -bool BarPlayer2Stop (player2_t); -bool BarPlayer2Finish (player2_t); -bool BarPlayer2IsPlaying (player2_t); -bool BarPlayer2IsPaused (player2_t); -bool BarPlayer2IsStopped (player2_t); -bool BarPlayer2IsFinished (player2_t); - -#endif /* SRC_PLAYER2_H_CN979RE9 */ - diff --git a/src/ui.h b/src/ui.h index c9b3d70..705bbab 100644 --- a/src/ui.h +++ b/src/ui.h @@ -29,7 +29,7 @@ THE SOFTWARE. #include #include "settings.h" -#include "player2.h" +#include "player/player2.h" #include "main.h" #include "ui_readline.h" #include "ui_types.h" -- cgit v1.2.3