0

I have a python 3.6 lambda function, running on AWS, called by API gateway, that concatenates some mp3 files using ffmpeg. I want the resultant mp3 file to be returned as the lambda response.

I create the combined mp3 like this:

p = subprocess.Popen(conversion_command, stdin=stdin_parameter, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p_out, p_err = p.communicate()
p_out = bytearray(p_out)

with these parameters:

conversion_command = ['ffmpeg',
                          '-y',  # always overwrite existing files
                          '-i', 'concat:one.mp3|two.mp3|three.mp3',
                          ]

stdin_parameter = subprocess.PIPE
conversion_command += [
        "-vn",  # Drop any video streams if there are any
        "-f", "mp3",  # output options (filename last)
        "-"
    ]

The array looks like this:

bytearray(b'ID3\x04\x00\x00\x00\x00\x00#TSSE\x00\x00\x00\x0f\x00\x00\x03Lavf58.45.100\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xf38\xc4\x00\x11\xd1RH-L\x10\x00\x0cX\x05\xf6$\x03@ \x07\x04E\r\x92\x04\x82a\x81\xe2\xc7;h\xb1\xcaS\xa6fB5N\xf3\x9f\xa9\xdf\xff\xa19\xf3\x9d\xe4!\x1aB\x10\x84!\'\x00\x00"\xc1\xff\xff\xa8\x06\x0f\x9f\xff\xf2\x99\xaf\xfc\x1f~\x0f\x87\xe5\xdfX>\x08\x06\x15\xcb\xef\xf3\xfc\xff\xf5\xd7Mp<\xec1\xcd\xc0^\x94\xb3Q\t9d\xc7\x88\xff\xf38\xc4\x17\x1a\xb1\xb6\xb9\x95\x8f8\x00z.\xf2\xfa>\xe1(\x96`\xa8|\x8b\xb5\xd0\x1f\x88\x83d+\x1d\xf9c\xd8\xf4dM\xd5\xf9\xcb\x1e\x1d/\xee\xbd\x9b{\xa1\xaeMQ\xf56\xc66\xf8\xd0|\xb21\x17`\xc3\xf6w\xe9P\xb02Y\xcf\xf2\x8e\xdd\xe1\xb0p\x1f\x08\x89\x80!\xc0\x90@\xe0\x0c\xb8\xe8Q\xbf\xf0s\xfee\x02\xe9\x06R\xe9\xc5+\xccrGD\xff\xf38\xc4\x0b\x17\xf2~\xa4Q\xd8(\x00\x01\x88\x94Z\x13\xb2\xed?\xb2\xe7\xd4\xbb\xed\xf3O\xa4\x89\xc0\x0f\x1b\xe9 etc

which successfully recreates an mp3 file if I do this:

f = open('output.mp3', 'w+b')
binary_format = bytearray(p_out)
f.write(binary_format)
f.close()

I'm forming my HTTP response like this:

responseObject = {}
responseObject['statusCode'] = 200
responseObject['headers'] = {}
responseObject['headers']['Content-Type'] = 'audio/mpeg'
responseObject['isBase64Encoded'] = 'true'

response = base64.b64encode(p_out)
response = response.decode('utf-8')
responseObject['body'] = response

return responseObject

which successfully makes the browser (chrome) display a media control but I don't hear any audio. Clearly this audio isn't being presented to the HTTP response correctly but I'm not sure where I'm going wrong.

Can anyone help please?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Martin Harrison
  • 145
  • 2
  • 11
  • You're using AWS, correct? Could you share the `conversion_command`, just out of curiousity? Have you tried to serve a normal .mp3 file in your response - one that hasn't been stitched together using your script? – Paul M. Jul 17 '20 at 10:09
  • Thanks @PaulM. I have updated my post to include the conversion_command. I haven't tried an unmodified mp3 as I'm assuming the mp3 data is ok as the resultant output.mp3 file is playable. My assumption is that the encoding of the mp3 in the lambda response, or the format of the response, or both (!) is incorrect? – Martin Harrison Jul 17 '20 at 10:22
  • Different browsers tend to behave differently depending on the MIME type. Since you're using Chrome, have you tried changing your `responseObject['headers']['Content-Type']` to `audio/mp3`? – Paul M. Jul 17 '20 at 16:20

1 Answers1

0

OK, I've got it working. One simple change:

responseObject['isBase64Encoded'] = True

but the main issue is that you need to enable binary support in API gateway. This post Reading binary file and looping over each byte and the comment from @Kyler Laird gave me the direction I needed:

https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings-configure-with-console.html

I enabled support in my api by setting binary media type to /. I think audio/mpeg would be sufficient.

Martin Harrison
  • 145
  • 2
  • 11