juhovh / shairplay

Apple airplay and raop protocol server
Other
1.35k stars 228 forks source link

Burst of zeroed RAOP packets when streaming client is paused #5

Closed docvvf closed 11 years ago

docvvf commented 11 years ago

Hi,

I am developing a MacOS (target SDK Mountain Lion) application using shairplay to receive audio via RAOP. Receiving audio from iTunes running on the same machine where the app is running works fine. Shairplay seems very stable. When I test streaming from an iOS device (tested from iPhone 4/iOS 6 and iPad/iOS 5) I consistently observe this behavior:

1) music player on iOS device starts streaming, no problems observed 2) music player on iOS device is paused manually 3) my app on MacOS receives a large (100-200) number of empty RAOP packets right after 2) and with the player still paused

The "burst" received in 3) lasts several seconds and all samples are zero (the sum of the absolute value of all samples is zero for every received packet).

Can you help me understand the reason for this behavior? It happens every time an iOS player is paused and is filling the ring buffer I use to store the samples with zero's.

Thx

Vincenzo

juhovh commented 11 years ago

I'll try to look into this as soon as possible. I remember having some weird behavior with iOS where it kept sending data after being paused, but it was not in a burst. The shairplay lib should just deliver the packets it receives, so if the library generates these then it's a bug.

As an offtopic note, I probably have to break shairplay API at some point, because I need to add timing information in order to be forward-compatible with screen mirroring support. But I will make a stable release before that.

Juho

On 28.1.2013, at 15.15, docvvf notifications@github.com wrote:

Hi,

I am developing a MacOS (target SDK Mountain Lion) application using shairplay to receive audio via RAOP. Receiving audio from iTunes running on the same machine where the app is running works fine. Shairplay seems very stable. When I test streaming from an iOS device (tested from iPhone 4/iOS 6 and iPad/iOS 5) I consistently observe this behavior:

1) music player on iOS device starts streaming, no problems observed 2) music player on iOS device is paused manually 3) my app on MacOS receives a large (100-200) number of empty RAOP packets right after 2) and with the player still paused

The "burst" received in 3) lasts several seconds and all samples are zero (the sum of the absolute value of all samples is zero for every received packet).

Can you help me understand the reason for this behavior? It happens every time an iOS player is paused and is filling the ring buffer I use to store the samples with zero's.

Thx

Vincenzo

\ Reply to this email directly or view it on GitHub.

docvvf commented 11 years ago

Thank you, great if you could look into this. In the meantime I will try to collect some network traces to be really sure that it is not the iOS device that actually sends these zero packets.

Vincenzo

On Jan 28, 2013, at 4:24 PM, juhovh notifications@github.com wrote:

I'll try to look into this as soon as possible. I remember having some weird behavior with iOS where it kept sending data after being paused, but it was not in a burst. The shairplay lib should just deliver the packets it receives, so if the library generates these then it's a bug.

As an offtopic note, I probably have to break shairplay API at some point, because I need to add timing information in order to be forward-compatible with screen mirroring support. But I will make a stable release before that.

Juho

On 28.1.2013, at 15.15, docvvf notifications@github.com wrote:

Hi,

I am developing a MacOS (target SDK Mountain Lion) application using shairplay to receive audio via RAOP. Receiving audio from iTunes running on the same machine where the app is running works fine. Shairplay seems very stable. When I test streaming from an iOS device (tested from iPhone 4/iOS 6 and iPad/iOS 5) I consistently observe this behavior:

1) music player on iOS device starts streaming, no problems observed 2) music player on iOS device is paused manually 3) my app on MacOS receives a large (100-200) number of empty RAOP packets right after 2) and with the player still paused

The "burst" received in 3) lasts several seconds and all samples are zero (the sum of the absolute value of all samples is zero for every received packet).

Can you help me understand the reason for this behavior? It happens every time an iOS player is paused and is filling the ring buffer I use to store the samples with zero's.

Thx

Vincenzo

\ Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub.

juhovh commented 11 years ago

Sorry it took me some time to check this out, but it seems that the iOS device actually sends empty audio packets when it is paused, they even have all the necessary headers in place. But at least in my tests they did not come in a burst, but rather at normal rate, so playing them out normally should be ok. Can you find any other reason why they would be filling out your ringbuffer?

I could add a fix of dropping zero packets on the library side, but I think it would sound a bit too hackish to me, especially since the device is actually sending them. The RTSP protocol standard also has a PAUSE command, but I checked and iOS is not sending that either. So I'm afraid I have to close this issue, since it seems to be Apple's feature rather than a bug...

docvvf commented 11 years ago

I understand, I have also seen packets via network trace continuing to stream well after the player on the device was paused on the iOS device. I agree dropping these packets it is not the role of the library, and I may as well drop them in the application if I can not find a better way - which there must be. As you suggest they should not be flooding the ring buffer.

You mentioned you may add timing information back through the API in the future for screen mirroring. I think it would be very useful for audio playthorugh to maintain synchronization.

Finally, one suggestion. In case the server socket initialization in httpd_start fails, it would be handy to pass back the actual socket error code rather than -1 so that an app can see why raop_start failed. E.g. when the application is incorrectly terminated and (quickly) restarted, the library correctly prints out an error 48 (address in use) message. If the error code would be passed back, the application after restart could decide to wait a while for the OS to close the socket, then call raop_start again. What do you think?