The operating system used is Windows 7.
The first question that arises is: how to play mp3 in powershell?
Earlier on Habré there were mentions of a similar question:
How to play mp3 from the command line in Windows 7?How can you use PowerShell?Due to the lack of a satisfactory answer, it was decided to use the Media Control Interface or mci.
The advantages are as follows: built-in to the system, sufficiently low-level, it is possible to send commands as a string.
Mci is known to many by answering the question: “how to open a CD-ROM reader / writer programmatically?”, Although it provides many other possibilities. Below are some usage scenarios.
Removing a CD-ROM:
mci 'set cdaudio door open'
Play local mp3 file:
mci 'play C:\\temp\\Kalimba.mp3' mci 'status C:\\temp\\Kalimba.mp3 mode'
Writing to a wav file:
mci 'open new type waveaudio alias RecWavFile' mci 'set RecWavFile bitspersample 16 samplespersec 44100 channels 2' mci 'record RecWavFile' mci 'stop RecWavFile' mci 'save RecWavFile C:\\temp\\RecWavFile.wav' mci 'close RecWavFile' mci 'play C:\\temp\\RecWavFile.wav wait'
A simple option to play the stream from the network:
mci 'play http://some-radio-server.com:80/some-radio-channel.mp3'
Advanced version of the playback stream from the network:
mci 'open http://some-radio-server.com:80/some-radio-channel.mp3 type mpegvideo alias radio' #mci 'open http://other-radio-server/other-radio-channel.fake.mp3 type mpegvideo alias radio' mci 'status radio volume' mci 'setaudio radio volume to 100' mci 'play radio' mci 'status radio mode' mci 'stop radio' mci 'close radio'
')
It may seem strange, but initially in powershell there is no such method (the author did not find it) working with mci. To make this work possible, you need to write a wrapper over the mciSendStringA function. At the same time, in order to have a full-fledged command line interface, in addition to entering commands, output of the result of the function execution and decoding of error codes is required. The first is needed, for example, to request status with the status command. The second is convenient, since you do not need to look for a description of the error each time.
mci powershell wrapper: $MemDef =@" [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern int mciSendStringA( string lpstrCommand, [Out] byte[] lpstrReturnString, int uReturnLength, IntPtr hwndCallback); [DllImport("winmm.dll", CharSet = CharSet.Ansi)] public static extern int mciGetErrorStringA( int dwError, [Out] byte[] lpstrBuffer, int uLength); "@ $winmm = Add-Type -memberDefinition $MemDef -ErrorAction 'SilentlyContinue' -passthru -name mciSendString function mci($strSend) { $buffer = New-Object byte[] 128 [int]$error = $winmm::mciSendStringA( $strSend, $buffer, 128, 0 ) [Text.Encoding]::ASCII.GetString($buffer) $error_buffer = New-Object byte[] 128 [void]$winmm::mciGetErrorStringA( $error, $error_buffer, 128 ) [Text.Encoding]::GetEncoding('windows-1251').GetString($error_buffer) }
Some explanations may be helpful.
Inside $ MemDef contains a piece of C # code. And inside $ winmm is the result of its compilation.
To get a text string you need from the library function:
- declare the type of the returned string (in C # code, which means that the register matters) as [Out] byte [];
- when you call to prepare the buffer;
- transfer buffer and buffer size;
- interpret received bytes as a string in a specific encoding.
It may seem that the use of C # inclusions, especially for declaring winapi-shnyh functions, is not very correct. But here it is the convenience of use that is important, not the way to achieve it: the string with the mci command harmoniously merges with the powershell style.
A list of mci commands can be found
here or by searching for “Multimedia Command Strings”.
PS Through mci, you can watch movies.
As can be seen from the examples: it is possible to specify not only local files as a name, but also a URL.
But for some servers (such as other-radio-server) there is a problem: playback starts only after a forced disconnection. Your own HTTP proxy "correcting" the "wrong" packages can help here. In particular, for immediate playback, it is enough to add the header 'content-length' to the response.
To write your own proxy, node.js would be the best choice.
After starting and connecting the proxy, you can use the commented line instead of the previous one.
The end of the url ".fake.mp3" talks about the need for proxy manipulations. Below is the far from the optimal server code.
node / proxy_server.js: require('./simple_cli').run() var http = require('http') var url = require('url') http.createServer(function(request, response) { var u = url.parse(request.url) var options = { port : u['port'] || 80, host : u['hostname'], method : request.method, path : u['pathname'], headers : request.headers } console.log(request.url) delete options.headers['proxy-connection'] if( request.url.substr(-9) === ".fake.mp3" ) { var p = options['path'] options['path'] = p.substr(0, p.length - 9) options['icy-metadata'] = '0' } console.log(options) var proxy_request = http.request(options); proxy_request.on('response', function (proxy_response) { console.log(proxy_response.headers) if( request.url.substr(-9) === ".fake.mp3" ) { proxy_response.headers['content-length'] = '221183499' } proxy_response.pipe(response); response.writeHead(proxy_response.statusCode, proxy_response.headers); }); request.pipe(proxy_request); }).listen(8080); console.log('Server running...');
PS Proxy can also be useful, for example, for viewing or preprocessing sent requests and received answers.
Sometimes, for the convenience of viewing the headers passing through the server, you need to clear the console. The simplest command line interface allows you to achieve this.
node / simple_cli.js module.exports.run = function(){ process.stdin.resume(); process.stdin.setEncoding('utf8'); process.stdin.on('data', function (data) { data = data.toString().trim(); switch (data) { case 'exit': process.exit(); break; case 'clear': process.stdout.write('\u001B[2J\u001B[0;0f'); break; case 'help': process.stdout.write('exit, clear, help\n'); break; default: process.stdout.write('unrecognize: '+data+'\n'); } }); }
This is needed for easy server startup:
run_proxy_server.cmd "%~d0%~p0node.exe" "%~d0%~p0node\proxy_server.js" pause
The final recipe:
- download node.exe to the working folder from “ nodejs.org/download ”
After creating all the files in it, we get the following tree:
+
| -node.exe
| -run_proxy_server.cmd
| + node
| | -proxy_server.js
| | -simple_cli.js
- Run http proxy:
run_proxy_server.cmd - set the local proxy:
windows + R, control, ctrl + F, pr
"Proxy server settings", "Network settings", "Proxy server", "Use proxy server ...."
Address: 127.0.0.1 Port: 8080
OK - interactively execute the wrapper code
- interactively execute examples
For the last two points, you can use, for example, any of the options:
- poweshell from command line
- Windows powershell
- Windows PowerShell ISE
PS As some-radio-server and some-radio-channel, you can take, for example, icy-e-05.sharp-stream and kiss100low respectively, and as other-radio-server and other-radio-channel - pub5.5. .fm and di_eurodance.