Пауза / возобновление воспроизведения Twilio

Есть ли в Twilio поддержка для приостановки и возобновления воспроизведения контента. Другими словами, у меня есть довольно длинные файлы, которые будут воспроизводиться для вызывающего абонента, и я пытаюсь найти способ реализовать функцию паузы и возобновления. В середине воспроизведения некоторого контента я хочу, чтобы пользователь мог нажимать цифру для паузы, а затем снова нажимать цифру, чтобы возобновить воспроизведение с той же точки в аудиофайле, где оно было приостановлено.

Поддерживает ли Twilio что-то подобное?


person LB2    schedule 09.11.2013    source источник


Ответы (2)


Я нашел работоспособное, хотя и не идеальное решение, как приостановить и возобновить воспроизведение с помощью Twilio.

Основная идея состоит в том, чтобы вычислить разницу во времени между созданием команды воспроизведения и временем, когда Gather URL называется. Разница (при условии идеального мира на мгновение) должна заключаться в том, как далеко был воспроизведен контент, прежде чем его прервал вызывающий. Затем, когда вызывающий абонент готов возобновить работу, сгенерируйте команду Play, чтобы сервер приложений доставлял не полный контент, а скорее контент с частичным смещением, который начинается прямо в точке, где воспроизведение должно возобновиться (что, вероятно, подразумевает, что механизм для доставлять только часть содержимого аудиофайла, необходимо будет реализовать). По сути, это имитирует функцию паузы / возобновления.

Я реализовал это, и это более или менее работает. В игру вступает несовершенный мир, в котором задержка в сети, задержки в обработке (время между получением Twilio команды Play, извлечением ресурса воспроизведения и фактическим началом воспроизведения), а также задержка между нажатием кнопки и фактическим получением вызова Gather - все это влияет на точность. Но если ваши требования не слишком строгие, точность, вероятно, будет достаточно приличной для большинства случаев.

Вот доказательство концепции, которое я сделал на C # (прошло несколько месяцев - надеюсь, он по-прежнему работает так, как было опубликовано). Он также включает в себя эксперименты с быстрой перемоткой вперед и назад, которые просто регулируют, где на самом деле начинается возобновление (и пропускают команду Pause).


Приведенный ниже код предназначен для PausablePlayController.cs, который генерирует TwiML с Play, Pause и другими командами.

Play действие (не команда TwiML) создает TwiML для воспроизведения содержимого. Воспроизведение можно прерывать, поскольку оно заключено в Gather, что указывает на действие Pause. URL-адрес Gather содержит отметку времени начала воспроизведения (и в случае, если оно уже было смещено ранее, вычисляет его назад во времени).

Pause действие (не команда TwiML) генерирует TwiML для выполнения паузы или поиска. В приведенном ниже коде 4 перемотки назад, 5 перезапусков с начала, 6 перемоток вперед и любая другая клавиша делает паузу.

public class PausablePlayController : ApiController
{
    private const int seekDeltaMilliseconds = 5000;

    // GET api/pausableplay/5
    [HttpGet]
    public System.Xml.Linq.XElement Play(string audio, int millisecondsOffset)
    {
        TwilioResponse twiml = new TwilioResponse();
        twiml.BeginGather(new { action = this.Url.Link("PausablePlayPause", new { audio = audio, playStart = DateTime.UtcNow.Subtract(new TimeSpan(0, 0, 0, 0, millisecondsOffset)).Ticks/*.ToString("o", System.Globalization.CultureInfo.InvariantCulture )*/ }), method = "GET", numDigits = "1" });
        twiml.Play(this.Url.Link("OffsetPresentations", new { audio = audio, millisecondsOffset = millisecondsOffset }));
        twiml.EndGather();

        return twiml.Element;
    }

    [HttpGet]
    public System.Xml.Linq.XElement Pause(string audio, long playStart, int digits)
    {
        DateTime playStartDate = new DateTime(playStart, DateTimeKind.Utc);
        int millisecondsOffset = (int)DateTime.UtcNow.Subtract(playStartDate).TotalMilliseconds;
        TwilioResponse twiml = new TwilioResponse();
        switch(digits)
        {
            case 4:
                millisecondsOffset -= (millisecondsOffset < seekDeltaMilliseconds) ? millisecondsOffset : seekDeltaMilliseconds;
                return Play(audio, millisecondsOffset);
            case 5:
                return Play(audio, 0);
            case 6:
                millisecondsOffset += seekDeltaMilliseconds;
                return Play(audio, millisecondsOffset);
            default:
                {
                    twiml.BeginGather(new { action = this.Url.Link("PausablePlayPlay", new { audio = audio, millisecondsOffset = millisecondsOffset }), method = "GET", numDigits = "1" });
                    twiml.Pause(120);
                    twiml.EndGather();
                    twiml.Say("Goodbye!");
                }
                break;
        }
        return twiml.Element;
    }
}

Остальная часть трюка заключается в следующем контроллере, который передает частичный аудиоконтент (части кода, которые я нашел в другом сообщении, на которое, к сожалению, у меня больше нет ссылки). Все, что он делает, это просто вычисляет, где начинается аудиоконтент для заданных миллисекунд смещения, и передает остальную часть контента из этой точки.

public class OffsetedContentController : ApplicationController
{
    const int BufferSize = 32 * 1024;

    // GET api/prompts/5
    public Task<HttpResponseMessage> Get(string audio, [FromUri]int millisecondsOffset)
    {
        string contentFilePath = audio;  // Build physical path for your audio content

        if (!File.Exists(contentFilePath)) 
        { 
            return Task.FromResult(Request.CreateResponse(HttpStatusCode.NotFound)); 
        }            
        // Open file and read response from it. If read fails then return 503 Service Not Available                       
        try            
        {                
            // Create StreamContent from FileStream. FileStream will get closed when StreamContent is closed                
            FileStream fStream = new FileStream(contentFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, useAsync: true);
            fStream.Position = getPositionOffset(millisecondsOffset);
            HttpResponseMessage response = Request.CreateResponse();
            response.Content = new StreamContent(fStream);
            response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("audio/ulaw");
            return Task.FromResult(response);    
        }
        catch (Exception e)          
        {             
            return Task.FromResult(Request.CreateErrorResponse(HttpStatusCode.ServiceUnavailable, e)); 
        }
    }

    private long getPositionOffset(int millisecondsOffset)
    {
        long bytePosition = millisecondsOffset * 4;
        return bytePosition;
    }
}
person LB2    schedule 20.04.2014

Это невозможно сделать с помощью TwiML. Вы можете иметь эту логику только на своем сервере, а затем повторно инициализировать аудиофайл с помощью другого тега Play, но я считаю, что это приведет к небольшой задержке, поскольку Twilio нужно будет загрузить аудиофайл с вашего сервера, а затем перекодировать его перед этим. можно воспроизводить (помимо времени, необходимого вашему серверу для регенерации нового аудиофайла)

person ABros    schedule 25.11.2013
comment
Это примерно тот подход, который я использую - задача состоит в том, чтобы выяснить, в какой момент во время воспроизведения произошло прерывание. Думаю, у меня есть решение, следите за новостями ... - person LB2; 16.12.2013
comment
@ LB2, вы нашли для этого решение? Можно ли узнать, где прогрессировало воспроизведение файла при вводе? - person jdmcnair; 02.04.2014
comment
@ LB2 Я нашел способ подделать это (и опубликую подход, вероятно, на следующей неделе), хотя он не идеален и подвержен изменениям сетевой задержки и другим боковым ветрам. У меня нет доступа к моему доказательству концепции, чтобы опубликовать мой ответ прямо сейчас, так что следите за обновлениями ... - person LB2; 02.04.2014
comment
@jdmcnair Я только что опубликовал ответ на свой вопрос о том, как мне удалось сделать паузу с Twilio. - person LB2; 21.04.2014